Example #1
0
def weighted_content_placement(topology, contents, source_weights, seed=None):
    """Places content objects to source nodes randomly according to the weight
    of the source node.
    
    Parameters
    ----------
    topology : Topology
        The topology object
   contents : iterable
        Iterable of content objects
    source_weights : dict
        Dict mapping nodes nodes of the topology which are content sources and
        the weight according to which content placement decision is made.
        
    Returns
    -------
    cache_placement : dict
        Dictionary mapping content objects to source nodes

    Notes
    -----
    A deterministic placement of objects (e.g., for reproducing results) can be
    achieved by using a fix seed value
    """
    random.seed(seed)
    norm_factor = float(sum(source_weights.values()))
    source_pdf = dict((k, v / norm_factor) for k, v in source_weights.items())
    content_placement = collections.defaultdict(set)
    for c in contents:
        content_placement[random_from_pdf(source_pdf)].add(c)
    apply_content_placement(content_placement, topology)
Example #2
0
def set_capacities_random(topology, capacity_pdf, capacity_unit='Mbps'):
    """
    Set random link capacities according to a given probability density
    function

    Parameters
    ----------
    topology : Topology
        The topology to which link capacities will be set
    capacity_pdf : dict
        A dictionary representing the probability that a capacity value is
        assigned to a link
    capacity_unit : str, optional
        The unit in which capacity value is expressed (e.g. Mbps, Gbps etc..)
    links : list, optional
        List of links, represented as (u, v) tuples to which capacity will be
        set. If None or not specified, the capacity will be applied to all
        links.

    Examples
    --------
    >>> import fnss
    >>> topology = fnss.erdos_renyi_topology(50, 0.1)
    >>> pdf = {10: 0.5, 100: 0.2, 1000: 0.3}
    >>> fnss.set_capacities_constant(topology, pdf, 'Mbps')
    """
    if not capacity_unit in capacity_units:
        raise ValueError("The capacity_unit argument is not valid")
    if any((capacity < 0 for capacity in capacity_pdf.keys())):
        raise ValueError('All capacities in capacity_pdf must be positive')
    topology.graph['capacity_unit'] = capacity_unit
    for u, v in topology.edges():
        topology.adj[u][v]['capacity'] = random_from_pdf(capacity_pdf)
    return
Example #3
0
def weighted_content_placement(topology, contents, source_weights, seed=None):
    """Places content objects to source nodes randomly according to the weight
    of the source node.

    Parameters
    ----------
    topology : Topology
        The topology object
   contents : iterable
        Iterable of content objects
    source_weights : dict
        Dict mapping nodes nodes of the topology which are content sources and
        the weight according to which content placement decision is made.

    Returns
    -------
    cache_placement : dict
        Dictionary mapping content objects to source nodes

    Notes
    -----
    A deterministic placement of objects (e.g., for reproducing results) can be
    achieved by using a fix seed value
    """
    random.seed(seed)
    norm_factor = float(sum(source_weights.values()))
    source_pdf = dict((k, v / norm_factor) for k, v in source_weights.items())
    content_placement = collections.defaultdict(set)
    for c in contents:
        content_placement[random_from_pdf(source_pdf)].add(c)
    apply_content_placement(content_placement, topology)
Example #4
0
def set_capacities_random(topology, capacity_pdf, capacity_unit='Mbps'):
    """
    Set random link capacities according to a given probability density
    function

    Parameters
    ----------
    topology : Topology
        The topology to which link capacities will be set
    capacity_pdf : dict
        A dictionary representing the probability that a capacity value is
        assigned to a link
    capacity_unit : str, optional
        The unit in which capacity value is expressed (e.g. Mbps, Gbps etc..)
    links : list, optional
        List of links, represented as (u, v) tuples to which capacity will be
        set. If None or not specified, the capacity will be applied to all
        links.

    Examples
    --------
    >>> import fnss
    >>> topology = fnss.erdos_renyi_topology(50, 0.1)
    >>> pdf = {10: 0.5, 100: 0.2, 1000: 0.3}
    >>> fnss.set_capacities_constant(topology, pdf, 'Mbps')
    """
    if not capacity_unit in capacity_units:
        raise ValueError("The capacity_unit argument is not valid")
    if any((capacity < 0 for capacity in capacity_pdf.keys())):
        raise ValueError('All capacities in capacity_pdf must be positive')
    topology.graph['capacity_unit'] = capacity_unit
    for u, v in topology.edges():
        topology.adj[u][v]['capacity'] = random_from_pdf(capacity_pdf)
    return
Example #5
0
 def add_m_links(G, pi):
     """Add m links between existing nodes to the graph"""
     n_nodes = G.number_of_nodes()
     n_edges = G.number_of_edges()
     max_n_edges = (n_nodes * (n_nodes - 1)) / 2
     if n_edges + m > max_n_edges:  # cannot add m links
         add_node(G, pi)  # add a new node instead
         # return in any case because before doing another operation
         # (add node or links) we need to recalculate pi
         return
     new_links = 0
     while new_links < m:
         u = random_from_pdf(pi)
         v = random_from_pdf(pi)
         if u != v and not G.has_edge(u, v):
             G.add_edge(u, v)
             new_links += 1
Example #6
0
 def add_m_links(G, pi):
     """Add m links between existing nodes to the graph"""
     n_nodes = G.number_of_nodes()
     n_edges = G.number_of_edges()
     max_n_edges = (n_nodes * (n_nodes - 1)) / 2
     if n_edges + m > max_n_edges:  # cannot add m links
         add_node(G, pi)  # add a new node instead
         # return in any case because before doing another operation
         # (add node or links) we need to recalculate pi
         return
     new_links = 0
     while new_links < m:
         u = random_from_pdf(pi)
         v = random_from_pdf(pi)
         if u != v and not G.has_edge(u, v):
             G.add_edge(u, v)
             new_links += 1
Example #7
0
 def add_node(G, pi):
     """Add one node to the graph and connect it to m existing nodes"""
     new_node = G.number_of_nodes()
     G.add_node(new_node)
     new_links = 0
     while new_links < m:
         existing_node = random_from_pdf(pi)
         if not G.has_edge(new_node, existing_node):
             G.add_edge(new_node, existing_node)
             new_links += 1
Example #8
0
 def add_node(G, pi):
     """Add one node to the graph and connect it to m existing nodes"""
     new_node = G.number_of_nodes()
     G.add_node(new_node)
     new_links = 0
     while new_links < m:
         existing_node = random_from_pdf(pi)
         if not G.has_edge(new_node, existing_node):
             G.add_edge(new_node, existing_node)
             new_links += 1
Example #9
0
def extended_barabasi_albert_topology(n, m, m0, p, q, seed=None):
    r"""
    Return a random topology using the extended Barabasi-Albert preferential
    attachment model.

    Differently from the original Barabasi-Albert model, this model takes into
    account the presence of local events, such as the addition of new links or
    the rewiring of existing links.

    More precisely, the Barabasi-Albert topology is built as follows. First, a
    topology with *m0* isolated nodes is created. Then, at each step:
    with probability *p* add *m* new links between existing nodes, selected
    with probability:

    .. math::
        \Pi(i) = \frac{deg(i) + 1}{\sum_{v \in V} (deg(v) + 1)}

    with probability *q* rewire *m* links. Each link to be rewired is selected as
    follows: a node i is randomly selected and a link is randomly removed from
    it. The node i is then connected to a new node randomly selected with
    probability :math:`\Pi(i)`,
    with probability :math:`1-p-q` add a new node and attach it to m nodes of
    the existing topology selected with probability :math:`\Pi(i)`

    Repeat the previous step until the topology comprises n nodes in total.

    Parameters
    ----------
    n : int
        Number of nodes
    m : int
        Number of edges to attach from a new node to existing nodes
    m0 : int
        Number of edges initially attached to the network
    p : float
        The probability that new links are added
    q : float
        The probability that existing links are rewired
    seed : int, optional
        Seed for random number generator (default=None).

    Returns
    -------
    G : Topology

    References
    ----------
    .. [1] A. L. Barabasi and R. Albert "Topology of evolving networks: local
       events and universality", Physical Review Letters 85(24), 2000.
    """
    def calc_pi(G):
        """Calculate extended-BA Pi function for all nodes of the graph"""
        degree = G.degree()
        den = float(sum(degree.values()) + G.number_of_nodes())
        return {node: (degree[node] + 1) / den for node in G.nodes_iter()}

    # input parameters
    if n < 1 or m < 1 or m0 < 1:
        raise ValueError('n, m and m0 must be a positive integer')
    if m >= m0:
        raise ValueError('m must be <= m0')
    if n < m0:
        raise ValueError('n must be > m0')
    if p > 1 or p < 0:
        raise ValueError('p must be included between 0 and 1')
    if q > 1 or q < 0:
        raise ValueError('q must be included between 0 and 1')
    if p + q > 1:
        raise ValueError('p + q must be <= 1')
    if seed is not None:
        random.seed(seed)
    G = Topology(type='extended_ba')
    G.name = "ext_ba_topology(%d, %d, %d, %f, %f)" % (n, m, m0, p, q)
    # Step 1: Add m0 isolated nodes
    G.add_nodes_from(range(m0))

    while G.number_of_nodes() < n:
        pi = calc_pi(G)
        r = random.random()

        if r <= p:
            # add m new links with probability p
            n_nodes = G.number_of_nodes()
            n_edges = G.number_of_edges()
            max_n_edges = (n_nodes * (n_nodes - 1)) / 2
            if n_edges + m > max_n_edges:  # cannot add m links
                continue  # rewire or add nodes
            new_links = 0
            while new_links < m:
                u = random_from_pdf(pi)
                v = random_from_pdf(pi)
                if u is not v and not G.has_edge(u, v):
                    G.add_edge(u, v)
                    new_links += 1

        elif r > p and r <= p + q:
            # rewire m links with probability q
            rewired_links = 0
            while rewired_links < m:
                i = random.choice(G.nodes())  # pick up node randomly (uniform)
                if len(G.edge[i]) is 0:  # if i has no edges, I cannot rewire
                    break
                j = random.choice(list(
                    G.edge[i].keys()))  # node to be disconnected
                k = random_from_pdf(pi)  # new node to be connected
                if i is not k and j is not k and not G.has_edge(i, k):
                    G.remove_edge(i, j)
                    G.add_edge(i, k)
                    rewired_links += 1
        else:
            # add a new node with probability 1 - p - q
            new_node = G.number_of_nodes()
            G.add_node(new_node)
            new_links = 0
            while new_links < m:
                existing_node = random_from_pdf(pi)
                if not G.has_edge(new_node, existing_node):
                    G.add_edge(new_node, existing_node)
                    new_links += 1
    return G
Example #10
0
def barabasi_albert_topology(n, m, m0, seed=None):
    r"""
    Return a random topology using Barabasi-Albert preferential attachment
    model.

    A topology of n nodes is grown by attaching new nodes each with m links
    that are preferentially attached to existing nodes with high degree.

    More precisely, the Barabasi-Albert topology is built as follows. First, a
    line topology with m0 nodes is created. Then at each step, one node is
    added and connected to m existing nodes. These nodes are selected randomly
    with probability

    .. math::
            \Pi(i) = \frac{deg(i)}{sum_{v \in V} deg V}.

    Where i is the selected node and V is the set of nodes of the graph.

    Parameters
    ----------
    n : int
        Number of nodes
    m : int
        Number of edges to attach from a new node to existing nodes
    m0 : int
        Number of nodes initially attached to the network
    seed : int, optional
        Seed for random number generator (default=None).

    Returns
    -------
    G : Topology

    Notes
    -----
    The initialization is a graph with with m nodes connected by :math:`m -1`
    edges.
    It does not use the Barabasi-Albert method provided by NetworkX because it
    does not allow to specify *m0* parameter.
    There are no disconnected subgraphs in the topology.

    References
    ----------
    .. [1] A. L. Barabasi and R. Albert "Emergence of scaling in
       random networks", Science 286, pp 509-512, 1999.
    """
    def calc_pi(G):
        """Calculate BA Pi function for all nodes of the graph"""
        degree = G.degree()
        den = float(sum(degree.values()))
        return {node: degree[node] / den for node in G.nodes_iter()}

    # input parameters
    if n < 1 or m < 1 or m0 < 1:
        raise ValueError('n, m and m0 must be positive integers')
    if m >= m0:
        raise ValueError('m must be <= m0')
    if n < m0:
        raise ValueError('n must be > m0')
    if seed is not None:
        random.seed(seed)
    # Step 1: Add m0 nodes. These nodes are interconnected together
    # because otherwise they will end up isolated at the end
    G = Topology(nx.path_graph(m0))
    G.name = "ba_topology(%d,%d,%d)" % (n, m, m0)
    G.graph['type'] = 'ba'

    # Step 2: Add one node and connect it with m links
    while G.number_of_nodes() < n:
        pi = calc_pi(G)
        u = G.number_of_nodes()
        G.add_node(u)
        new_links = 0
        while new_links < m:
            v = random_from_pdf(pi)
            if not G.has_edge(u, v):
                G.add_edge(u, v)
                new_links += 1
    return G
Example #11
0
def extended_barabasi_albert_topology(n, m, m0, p, q, seed=None):
    r"""
    Return a random topology using the extended Barabasi-Albert preferential
    attachment model.

    Differently from the original Barabasi-Albert model, this model takes into
    account the presence of local events, such as the addition of new links or
    the rewiring of existing links.

    More precisely, the Barabasi-Albert topology is built as follows. First, a
    topology with *m0* isolated nodes is created. Then, at each step:
    with probability *p* add *m* new links between existing nodes, selected
    with probability:

    .. math::
        \Pi(i) = \frac{deg(i) + 1}{\sum_{v \in V} (deg(v) + 1)}

    with probability *q* rewire *m* links. Each link to be rewired is selected as
    follows: a node i is randomly selected and a link is randomly removed from
    it. The node i is then connected to a new node randomly selected with
    probability :math:`\Pi(i)`,
    with probability :math:`1-p-q` add a new node and attach it to m nodes of
    the existing topology selected with probability :math:`\Pi(i)`

    Repeat the previous step until the topology comprises n nodes in total.

    Parameters
    ----------
    n : int
        Number of nodes
    m : int
        Number of edges to attach from a new node to existing nodes
    m0 : int
        Number of edges initially attached to the network
    p : float
        The probability that new links are added
    q : float
        The probability that existing links are rewired
    seed : int, optional
        Seed for random number generator (default=None).

    Returns
    -------
    G : Topology

    References
    ----------
    .. [1] A. L. Barabasi and R. Albert "Topology of evolving networks: local
       events and universality", Physical Review Letters 85(24), 2000.
    """
    def calc_pi(G):
        """Calculate extended-BA Pi function for all nodes of the graph"""
        degree = dict(G.degree())
        den = float(sum(degree.values()) + G.number_of_nodes())
        return {node: (degree[node] + 1) / den for node in G.nodes()}

    # input parameters
    if n < 1 or m < 1 or m0 < 1:
        raise ValueError('n, m and m0 must be a positive integer')
    if m >= m0:
        raise ValueError('m must be <= m0')
    if n < m0:
        raise ValueError('n must be > m0')
    if p > 1 or p < 0:
        raise ValueError('p must be included between 0 and 1')
    if q > 1 or q < 0:
        raise ValueError('q must be included between 0 and 1')
    if p + q > 1:
        raise ValueError('p + q must be <= 1')
    if seed is not None:
        random.seed(seed)
    G = Topology(type='extended_ba')
    G.name = "ext_ba_topology(%d, %d, %d, %f, %f)" % (n, m, m0, p, q)
    # Step 1: Add m0 isolated nodes
    G.add_nodes_from(range(m0))

    while G.number_of_nodes() < n:
        pi = calc_pi(G)
        r = random.random()

        if r <= p:
            # add m new links with probability p
            n_nodes = G.number_of_nodes()
            n_edges = G.number_of_edges()
            max_n_edges = (n_nodes * (n_nodes - 1)) / 2
            if n_edges + m > max_n_edges:  # cannot add m links
                continue  # rewire or add nodes
            new_links = 0
            while new_links < m:
                u = random_from_pdf(pi)
                v = random_from_pdf(pi)
                if u is not v and not G.has_edge(u, v):
                    G.add_edge(u, v)
                    new_links += 1

        elif r > p and r <= p + q:
            # rewire m links with probability q
            rewired_links = 0
            while rewired_links < m:
                i = random.choice(list(G.nodes()))  # pick up node randomly (uniform)
                if len(G.adj[i]) is 0:  # if i has no edges, I cannot rewire
                    break
                j = random.choice(list(G.adj[i].keys()))  # node to be disconnected
                k = random_from_pdf(pi)  # new node to be connected
                if i is not k and j is not k and not G.has_edge(i, k):
                    G.remove_edge(i, j)
                    G.add_edge(i, k)
                    rewired_links += 1
        else:
            # add a new node with probability 1 - p - q
            new_node = G.number_of_nodes()
            G.add_node(new_node)
            new_links = 0
            while new_links < m:
                existing_node = random_from_pdf(pi)
                if not G.has_edge(new_node, existing_node):
                    G.add_edge(new_node, existing_node)
                    new_links += 1
    return G
Example #12
0
def barabasi_albert_topology(n, m, m0, seed=None):
    r"""
    Return a random topology using Barabasi-Albert preferential attachment
    model.

    A topology of n nodes is grown by attaching new nodes each with m links
    that are preferentially attached to existing nodes with high degree.

    More precisely, the Barabasi-Albert topology is built as follows. First, a
    line topology with m0 nodes is created. Then at each step, one node is
    added and connected to m existing nodes. These nodes are selected randomly
    with probability

    .. math::
            \Pi(i) = \frac{deg(i)}{sum_{v \in V} deg V}.

    Where i is the selected node and V is the set of nodes of the graph.

    Parameters
    ----------
    n : int
        Number of nodes
    m : int
        Number of edges to attach from a new node to existing nodes
    m0 : int
        Number of nodes initially attached to the network
    seed : int, optional
        Seed for random number generator (default=None).

    Returns
    -------
    G : Topology

    Notes
    -----
    The initialization is a graph with with m nodes connected by :math:`m -1`
    edges.
    It does not use the Barabasi-Albert method provided by NetworkX because it
    does not allow to specify *m0* parameter.
    There are no disconnected subgraphs in the topology.

    References
    ----------
    .. [1] A. L. Barabasi and R. Albert "Emergence of scaling in
       random networks", Science 286, pp 509-512, 1999.
    """
    def calc_pi(G):
        """Calculate BA Pi function for all nodes of the graph"""
        degree = dict(G.degree())
        den = float(sum(degree.values()))
        return {node: degree[node] / den for node in G.nodes()}

    # input parameters
    if n < 1 or m < 1 or m0 < 1:
        raise ValueError('n, m and m0 must be positive integers')
    if m >= m0:
        raise ValueError('m must be <= m0')
    if n < m0:
        raise ValueError('n must be > m0')
    if seed is not None:
        random.seed(seed)
    # Step 1: Add m0 nodes. These nodes are interconnected together
    # because otherwise they will end up isolated at the end
    G = Topology(nx.path_graph(m0))
    G.name = "ba_topology(%d,%d,%d)" % (n, m, m0)
    G.graph['type'] = 'ba'

    # Step 2: Add one node and connect it with m links
    while G.number_of_nodes() < n:
        pi = calc_pi(G)
        u = G.number_of_nodes()
        G.add_node(u)
        new_links = 0
        while new_links < m:
            v = random_from_pdf(pi)
            if not G.has_edge(u, v):
                G.add_edge(u, v)
                new_links += 1
    return G
def weighted_repo_content_placement(topology,
                                    contents,
                                    freshness_per,
                                    shelf_life,
                                    msg_size,
                                    topics_weights,
                                    types_weights,
                                    max_replications,
                                    source_weights,
                                    service_weights,
                                    max_label_nos,
                                    seed=None):
    """Places content objects to source nodes randomly according to the weight
    of the source node.

    TODO: This should be modified, or another one created, to include content
        placement parameters, like the freshness periods, shelf-lives, topics/types
        of labels and placement possibilities, maybe depending on hashes, placement
        of nodes and possibly other scenario-specific/service-specific parameters.
        ADD SERVICE TYPE TO MESSAGE PROPERTIES!

    Parameters
    ----------
    topology : Topology
        The topology object
    contents : iterable
        Iterable of content objects
    topics :

    types :

    freshness_per :

    shelf_life :

    msg_size :

    source_weights : dict
        Dict mapping nodes of the topology which are content sources and
        the weight according to which content placement decision is made.

    Returns
    -------
    cache_placement : dict
       Dictionary mapping content objects to source nodes

    Notes
    -----
    A deterministic placement of objects (e.g., for reproducing results) can be
    achieved by using a fix seed value
    """

    # TODO: This is the format that each datum (message) shuold have
    #       placed_data = {content, msg_topics, msg_type, freshness_per,
    #                       shelf_life, msg_size}

    placed_data = dict()
    random.seed(seed)
    norm_factor = float(sum(source_weights.values()))
    # TODO: These ^\/^\/^ might need redefining, to make label-specific
    #  source weights, and then the labels distributed according to these.
    #  OR the other way around, distributing sources according to label weights
    if types_weights is not None:
        types_labels_norm_factor = float(sum(types_weights.values()))
        types_labels_pdf = dict((k, v / types_labels_norm_factor)
                                for k, v in types_weights.items())
    topics_labels_norm_factor = float(sum(topics_weights.values()))
    service_labels_norm_factor = float(sum(service_weights.values()))
    # TODO: Think about a way to randomise, but still maintain a certain
    #  distribution among the users that receive data with certain labels.
    #  Maybe associate the pdf with labels, rather than contents, SOMEHOW!
    source_pdf = dict((k, v / norm_factor) for k, v in source_weights.items())
    topics_labels_pdf = dict(
        (k, v / topics_labels_norm_factor) for k, v in topics_weights.items())
    service_labels_pdf = dict((k, v / service_labels_norm_factor)
                              for k, v in service_weights.items())
    service_association = collections.defaultdict(set)
    labels_association = collections.defaultdict(set)
    content_placement = collections.defaultdict(set)
    # Further TODO: Add all the other data characteristics and maybe place
    #           content depending on those at a later point (create other
    #           placement strategies)
    # NOTE: All label names will come as a list of strings
    for c in contents:
        alter = False
        if freshness_per is not None:
            if placed_data.has_key(contents[c]['content']):
                placed_data[contents[c]['content']].update(
                    freshness_per=freshness_per)
            else:
                placed_data[contents[c]['content']] = dict()
                placed_data[contents[c]
                            ['content']]['freshness_per'] = freshness_per
        if shelf_life is not None:
            placed_data[contents[c]['content']].update(shelf_life=shelf_life)
        if max_replications:
            placed_data[contents[c]['content']].update(
                max_replications=max_replications)
            placed_data[contents[c]['content']].update(replications=0)
        service_association[random_from_pdf(service_labels_pdf)].add(c)
        placed_data[contents[c]['content']].update(content=c)
        placed_data[contents[c]['content']].update(msg_size=msg_size)
        placed_data[contents[c]['content']]["receiveTime"] = 0
        placed_data[contents[c]['content']]['labels'] = contents[c]['labels']
        placed_data[contents[c]['content']]['service_type'] = "non-proc"
        if not placed_data[contents[c]['content']]['labels']:
            for i in range(0, max_label_nos):
                if types_weights is not None and not alter:
                    labels_association[random_from_pdf(types_labels_pdf)].add(
                        c)
                    alter = True
                elif topics_weights is not None and alter:
                    labels_association[random_from_pdf(topics_labels_pdf)].add(
                        c)
                    alter = False
                elif topics_weights is not None:
                    labels_association[random_from_pdf(topics_labels_pdf)].add(
                        c)

    placed_data = apply_labels_association(labels_association, placed_data)
    #placed_data = apply_service_association(service_association, placed_data)
    for d in placed_data:
        rand = random_from_pdf(source_pdf)
        if not content_placement[rand]:
            content_placement[rand] = dict()
        if content_placement[rand].has_key(d):
            content_placement[rand][d].update(placed_data[d])
        else:
            content_placement[rand][d] = dict()
            content_placement[rand][d] = placed_data[d]
    apply_content_placement(content_placement, topology)
    topology.placed_data = placed_data