def from_networkx(G): """ Convert a NetworkX graph into a Zen graph object. In creating the object, the NetworkX node object and node/edge data will be copied over (a shallow copy). **Returns**: The return type depends on the input type. * :py:class:`zen.Graph` if the input graph was a :py:class:`networkx.Graph`. * :py:class:`zen.DiGraph` if the input graph was a :py:class:`networkx.DiGraph`. """ Gdest = None if type(G) == networkx.DiGraph: Gdest = DiGraph() elif type(G) == networkx.Graph: Gdest = Graph() else: raise Exception('Unable to convert graph object type %s' % str(type(G))) # add nodes for n, nd in G.nodes_iter(data=True): Gdest.add_node(n, nd) # add edges for x, y, ed in G.edges_iter(data=True): Gdest.add_edge(x, y, ed) return Gdest
def duplication_divergence_iky(n, s, **kwargs): """ Generate a random graph using the duplication-divergence model proposed by Ispolatov, Krapivski, and Yuryev (2008). **Args**: * ``n`` (int): the target size of the network. * ``s`` (float): the probability that a link connected to a newly duplicated node will exist **KwArgs**: * ``directed [=False]`` (boolean): whether to build the graph directed. If ``True``, then the ``m`` edges created by a node upon its creation are instantiated as out-edges. All others are in-edges to that node. * ``seed [=-1]`` (int): a seed for the random number generator * ``graph [=None]`` (:py:class:`zen.Graph` or :py:class:`zen.DiGraph`): this is the actual graph instance to populate. It must be empty and its directionality must agree with the value of ``directed``. **Returns**: :py:class:`zen.Graph` or :py:class:`zen.DiGraph`. The graph generated. If ``directed = True``, then a :py:class:`DiGraph` will be returned. .. note:: Source: I. Ispolatov, P. L. Krapivski, and A. Yuryev "Duplication-divergence model of protein interaction network", ??, 2008. """ seed = kwargs.pop('seed',None) directed = kwargs.pop('directed',False) graph = kwargs.pop('graph',None) if graph is not None: if len(graph) > 0: raise ZenException, 'the graph must be empty, if provided' if graph.is_directed() != directed: raise ZenException, 'graph and directed arguments must agree' if len(kwargs) > 0: raise ZenException, 'Unknown arguments: %s' % ', '.join(kwargs.keys()) if seed is None: seed = -1 # initialize the random number generator if seed >= 0: random.seed(seed) if type(n) != int: raise ZenException, 'Parameter n must be an integer' if type(s) != float and type(s) != int and type(s) != double: print type(s) raise ZenException, 'Parameter s must be a float, double, or an int' G = graph if graph is None: if directed: G = DiGraph() else: G = Graph() # initialize the graph with two connected nodes G.add_edge(0,1) # build the rest of the graph i = 2 while i < n: # pick an existing node to copy cn_seed = random.randint(0,100000) u = choose_node(G,seed=cn_seed) ##### # create the partial copy G.add_node(i) # copy edges if not directed: for w in G.neighbors(u): if random.random() <= s: G.add_edge(i,w) else: for w in G.in_neighbors(u): if random.random() <= s: G.add_edge(w,i) for w in G.out_neighbors(u): if random.random() <= s: G.add_edge(i,w) # if the node doesn't have any connections, then ditch it if G.degree(i) == 0: G.rm_node(i) else: i += 1 # done! return G
def duplication_divergence_iky(n, s, **kwargs): """ Generate a random graph using the duplication-divergence model proposed by Ispolatov, Krapivski, and Yuryev (2008). **Args**: * ``n`` (int): the target size of the network. * ``s`` (float): the probability that a link connected to a newly duplicated node will exist **KwArgs**: * ``directed [=False]`` (boolean): whether to build the graph directed. If ``True``, then the ``m`` edges created by a node upon its creation are instantiated as out-edges. All others are in-edges to that node. * ``seed [=-1]`` (int): a seed for the random number generator * ``graph [=None]`` (:py:class:`zen.Graph` or :py:class:`zen.DiGraph`): this is the actual graph instance to populate. It must be empty and its directionality must agree with the value of ``directed``. **Returns**: :py:class:`zen.Graph` or :py:class:`zen.DiGraph`. The graph generated. If ``directed = True``, then a :py:class:`DiGraph` will be returned. .. note:: Source: I. Ispolatov, P. L. Krapivski, and A. Yuryev "Duplication-divergence model of protein interaction network", ??, 2008. """ seed = kwargs.pop('seed', None) directed = kwargs.pop('directed', False) graph = kwargs.pop('graph', None) if graph is not None: if len(graph) > 0: raise ZenException, 'the graph must be empty, if provided' if graph.is_directed() != directed: raise ZenException, 'graph and directed arguments must agree' if len(kwargs) > 0: raise ZenException, 'Unknown arguments: %s' % ', '.join(kwargs.keys()) if seed is None: seed = -1 # initialize the random number generator if seed >= 0: random.seed(seed) if type(n) != int: raise ZenException, 'Parameter n must be an integer' if type(s) != float and type(s) != int and type(s) != double: print type(s) raise ZenException, 'Parameter s must be a float, double, or an int' G = graph if graph is None: if directed: G = DiGraph() else: G = Graph() # initialize the graph with two connected nodes G.add_edge(0, 1) # build the rest of the graph i = 2 while i < n: # pick an existing node to copy cn_seed = random.randint(0, 100000) u = choose_node(G, seed=cn_seed) ##### # create the partial copy G.add_node(i) # copy edges if not directed: for w in G.neighbors(u): if random.random() <= s: G.add_edge(i, w) else: for w in G.in_neighbors(u): if random.random() <= s: G.add_edge(w, i) for w in G.out_neighbors(u): if random.random() <= s: G.add_edge(i, w) # if the node doesn't have any connections, then ditch it if G.degree(i) == 0: G.rm_node(i) else: i += 1 # done! return G
def read_str(sbuffer, **kwargs): """ Read graph data from the ascii string in the binary edge list format. **Args**: ``sbuffer`` is the string from which the network data will be read. **KwArgs**: * ``node_obj_fxn [= str]``: unlike the default definition, this function accepts integers and returns the node object * ``directed [= False]`` (boolean): indicates whether the data is read as directed * ``ignore_duplicate_edges [= False]`` (boolean): applies only when loading an undirected graph. If True, then a check will be made to ensure that no duplicate edges are attempted to be added (in case the underlying graph was originally directed). Checking incurs a small performance cost due to the check. **Returns**: :py:class:`zen.Graph` or :py:class:`zen.DiGraph`. The graph read from the input string. The ``directed`` parameter decides whether a directed or undirected graph is constructed. """ # handle the keyword arguments node_obj_fxn = kwargs.pop('node_obj_fxn', str) directed = kwargs.pop('directed', False) check_for_duplicates = kwargs.pop('ignore_duplicate_edges', False) if len(kwargs) > 0: raise ZenException, 'Unknown keyword arguments: %s' % ', '.join( kwargs.keys()) if check_for_duplicates and directed: raise ZenException, 'ignore_duplicate_edges can only be set when directed = False' # build the graph G = None if directed == True: G = DiGraph() elif directed == False: G = Graph() else: raise ZenException, 'directed must be either True or False.' ##### # convert the string into a bitvector bv = BitVector(size=len(sbuffer) * 8) offset = 0 for c in sbuffer: v = ord(c) dec2bv(v, bv, offset, 8) offset += 8 ##### # read the header offset = 0 # read the version version = bv2dec(bv, offset, VERSION_LEN) offset += VERSION_LEN if version != 1: raise Exception, 'Invalid file format or version number' # read the num of indexes last_idx = bv2dec(bv, offset, NUM_INDEX_LEN) idx_size = int(math.ceil(math.log(last_idx + 1, 2))) offset += NUM_INDEX_LEN idx2node = [None] * (last_idx + 1) # build all nodes right now if node_obj_fxn is not None: for x in xrange(last_idx + 1): n = node_obj_fxn(x) G.add_node(n) else: G.add_nodes(last_idx + 1) # read the number of edges num_edges = bv2dec(bv, offset, NUM_EDGES_LEN) offset += NUM_EDGES_LEN ##### # Read the content: every edge if directed: for ei in xrange(num_edges): idx1 = bv2dec(bv, offset, idx_size) offset += idx_size idx2 = bv2dec(bv, offset, idx_size) offset += idx_size G.add_edge_(idx1, idx2) else: for ei in xrange(num_edges): idx1 = bv2dec(bv, offset, idx_size) offset += idx_size idx2 = bv2dec(bv, offset, idx_size) offset += idx_size if check_for_duplicates and G.has_edge_(idx1, idx2): continue G.add_edge_(idx1, idx2) # done! return G
def local_attachment(n, m, r, **kwargs): """ Generate a random graph using the local attachment model. **Args**: * ``n`` (int): the number of nodes to add to the graph * ``m`` (int): the number of edges a new node will add to the graph * ``r`` (int): the number of edges (of the ``m``) that a node will add to uniformly selected random nodes. All others will be added to neighbors of the ``r`` selected nodes. **KwArgs**: * ``seed [=-1]`` (int): a seed for the random number generator * ``graph [=None]`` (:py:class:`zen.DiGraph`): the graph that will be populated. If the graph is ``None``, then a new graph will be created. **Returns**: :py:class:`zen.DiGraph`. The graph generated. .. note:: Source: M. O. Jackson and B. O. Rogers "Meeting strangers and friends of friends: How random are social networks?" The American Economic Review, 2007. """ seed = kwargs.pop('seed', None) graph = kwargs.pop('graph', None) if graph is not None and not graph.is_directed(): raise ZenException, 'The graph provided must be directed' if graph is not None and len(graph) > 0: raise ZenException, 'The graph provided is not empty' if len(kwargs) > 0: raise ZenException, 'Unknown arguments: %s' % ', '.join(kwargs.keys()) if type(r) != int: raise ZenException, 'r must be an integer' elif r < 1: raise ZenException, 'r must be 1 or larger' if seed is None: seed = -1 if seed >= 0: random.seed(seed) ##### # build the initial graph G = graph if G is None: G = DiGraph() # populate with nodes for i in range(m + 1): G.add_node(i) # according to Jackson's paper, all initial nodes have m neighbors. for i in range(m + 1): for j in range(m + 1): if j != i: G.add_edge(j, i) ###### # Build the rest of the graph node_list = list(range(m + 1)) for i in range(m + 1, n): G.add_node(i) # pick random neighbors (the parents) parents = random.sample(node_list, r) # pick neighbors from the parents' neighborhoods potentials = set() for n in parents: potentials.update(G.out_neighbors(n)) potentials.difference_update(parents) nsize = min([m - r, len(potentials)]) neighbors = random.sample(potentials, nsize) # connect for v in (parents + neighbors): G.add_edge(i, v) node_list.append(i) # done return G
def read_str(sbuffer, **kwargs): """ Read graph data from the ascii string in the binary edge list format. **Args**: ``sbuffer`` is the string from which the network data will be read. **KwArgs**: * ``node_obj_fxn [= str]``: unlike the default definition, this function accepts integers and returns the node object * ``directed [= False]`` (boolean): indicates whether the data is read as directed * ``ignore_duplicate_edges [= False]`` (boolean): applies only when loading an undirected graph. If True, then a check will be made to ensure that no duplicate edges are attempted to be added (in case the underlying graph was originally directed). Checking incurs a small performance cost due to the check. **Returns**: :py:class:`zen.Graph` or :py:class:`zen.DiGraph`. The graph read from the input string. The ``directed`` parameter decides whether a directed or undirected graph is constructed. """ # handle the keyword arguments node_obj_fxn = kwargs.pop('node_obj_fxn',str) directed = kwargs.pop('directed',False) check_for_duplicates = kwargs.pop('ignore_duplicate_edges',False) if len(kwargs) > 0: raise ZenException, 'Unknown keyword arguments: %s' % ', '.join(kwargs.keys()) if check_for_duplicates and directed: raise ZenException, 'ignore_duplicate_edges can only be set when directed = False' # build the graph G = None if directed == True: G = DiGraph() elif directed == False: G = Graph() else: raise ZenException, 'directed must be either True or False.' ##### # convert the string into a bitvector bv = BitVector(size = len(sbuffer) * 8) offset = 0 for c in sbuffer: v = ord(c) dec2bv(v,bv,offset,8) offset += 8 ##### # read the header offset = 0 # read the version version = bv2dec(bv,offset,VERSION_LEN) offset += VERSION_LEN if version != 1: raise Exception, 'Invalid file format or version number' # read the num of indexes last_idx = bv2dec(bv,offset,NUM_INDEX_LEN) idx_size = int(math.ceil(math.log(last_idx+1,2))) offset += NUM_INDEX_LEN idx2node = [None] * (last_idx + 1) # build all nodes right now if node_obj_fxn is not None: for x in xrange(last_idx+1): n = node_obj_fxn(x) G.add_node(n) else: G.add_nodes(last_idx+1) # read the number of edges num_edges = bv2dec(bv,offset,NUM_EDGES_LEN) offset += NUM_EDGES_LEN ##### # Read the content: every edge if directed: for ei in xrange(num_edges): idx1 = bv2dec(bv,offset,idx_size) offset += idx_size idx2 = bv2dec(bv,offset,idx_size) offset += idx_size G.add_edge_(idx1,idx2) else: for ei in xrange(num_edges): idx1 = bv2dec(bv,offset,idx_size) offset += idx_size idx2 = bv2dec(bv,offset,idx_size) offset += idx_size if check_for_duplicates and G.has_edge_(idx1,idx2): continue G.add_edge_(idx1,idx2) # done! return G
def read_str(sbuffer, **kwargs): #node_fxn=lambda x: x, edge_fxn=None, G = UNDIRECTED, build_all_nodes = False): """ Read graph data from the ascii string in the binary edge list format. """ # handle the keyword arguments node_obj_fxn = kwargs.pop('node_obj_fxn',str) directed = kwargs.pop('directed',False) check_for_duplicates = kwargs.pop('check_for_duplicates',False) if len(kwargs) > 0: raise ZenException, 'Unknown keyword arguments: %s' % ', '.join(kwargs.keys()) if check_for_duplicates and directed: raise ZenException, 'check_for_duplicates can only be set when directed = False' # build the graph G = None if directed == True: G = DiGraph() elif directed == False: G = Graph() else: raise ZenException, 'directed must be either True or False.' ##### # convert the string into a bitvector bv = BitVector(size = len(sbuffer) * 8) offset = 0 for c in sbuffer: v = ord(c) dec2bv(v,bv,offset,8) offset += 8 ##### # read the header offset = 0 # read the version version = bv2dec(bv,offset,VERSION_LEN) offset += VERSION_LEN if version != 1: raise Exception, 'Invalid file format or version number' # read the num of indexes last_idx = bv2dec(bv,offset,NUM_INDEX_LEN) idx_size = int(math.ceil(math.log(last_idx+1,2))) offset += NUM_INDEX_LEN idx2node = [None] * (last_idx + 1) # build all nodes right now if node_obj_fxn is not None: for x in xrange(last_idx+1): n = node_obj_fxn(x) G.add_node(n) else: G.add_nodes(last_idx+1) # read the number of edges num_edges = bv2dec(bv,offset,NUM_EDGES_LEN) offset += NUM_EDGES_LEN ##### # Read the content: every edge if directed: for ei in xrange(num_edges): idx1 = bv2dec(bv,offset,idx_size) offset += idx_size idx2 = bv2dec(bv,offset,idx_size) offset += idx_size G.add_edge_(idx1,idx2) else: for ei in xrange(num_edges): idx1 = bv2dec(bv,offset,idx_size) offset += idx_size idx2 = bv2dec(bv,offset,idx_size) offset += idx_size if check_for_duplicates and G.has_edge_(idx1,idx2): continue G.add_edge_(idx1,idx2) # done! return G
def local_attachment(n, m, r, **kwargs): """ Generate a random graph using the local attachment model. **Args**: * ``n`` (int): the number of nodes to add to the graph * ``m`` (int): the number of edges a new node will add to the graph * ``r`` (int): the number of edges (of the ``m``) that a node will add to uniformly selected random nodes. All others will be added to neighbors of the ``r`` selected nodes. **KwArgs**: * ``seed [=-1]`` (int): a seed for the random number generator * ``graph [=None]`` (:py:class:`zen.DiGraph`): the graph that will be populated. If the graph is ``None``, then a new graph will be created. **Returns**: :py:class:`zen.DiGraph`. The graph generated. .. note:: Source: M. O. Jackson and B. O. Rogers "Meeting strangers and friends of friends: How random are social networks?" The American Economic Review, 2007. """ seed = kwargs.pop('seed',None) graph = kwargs.pop('graph',None) if graph is not None and not graph.is_directed(): raise ZenException, 'The graph provided must be directed' if graph is not None and len(graph) > 0: raise ZenException, 'The graph provided is not empty' if len(kwargs) > 0: raise ZenException, 'Unknown arguments: %s' % ', '.join(kwargs.keys()) if type(r) != int: raise ZenException, 'r must be an integer' elif r < 1: raise ZenException, 'r must be 1 or larger' if seed is None: seed = -1 if seed >= 0: random.seed(seed) ##### # build the initial graph G = graph if G is None: G = DiGraph() # populate with nodes for i in range(m+1): G.add_node(i) # according to Jackson's paper, all initial nodes have m neighbors. for i in range(m+1): for j in range(m+1): if j != i: G.add_edge(j,i) ###### # Build the rest of the graph node_list = list(range(m+1)) for i in range(m+1,n): G.add_node(i) # pick random neighbors (the parents) parents = random.sample(node_list,r) # pick neighbors from the parents' neighborhoods potentials = set() for n in parents: potentials.update(G.out_neighbors(n)) potentials.difference_update(parents) nsize = min([m-r,len(potentials)]) neighbors = random.sample(potentials,nsize) # connect for v in (parents + neighbors): G.add_edge(i,v) node_list.append(i) # done return G