Path: blob/master/src/sage/graphs/base/sparse_graph.pyx
8815 views
r"""1Fast sparse graphs23Usage Introduction4------------------56::78sage: from sage.graphs.base.sparse_graph import SparseGraph910Sparse graphs are initialized as follows::1112sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)1314This example initializes a sparse graph with room for twenty vertices, the first15ten of which are in the graph. In general, the first ``nverts`` are "active."16For example, see that 9 is already in the graph::1718sage: S._num_verts()191020sage: S.add_vertex(9)21922sage: S._num_verts()23102425But 10 is not, until we add it::2627sage: S._num_verts()281029sage: S.add_vertex(10)301031sage: S._num_verts()32113334You can begin working with unlabeled arcs right away as follows::3536sage: S.add_arc(0,1)37sage: S.add_arc(1,2)38sage: S.add_arc(1,0)39sage: S.has_arc(7,3)40False41sage: S.has_arc(0,1)42True43sage: S.in_neighbors(1)44[0]45sage: S.out_neighbors(1)46[0, 2]47sage: S.del_all_arcs(0,1)48sage: S.all_arcs(0,1)49[]50sage: S.all_arcs(1,2)51[0]52sage: S.del_vertex(7)53sage: S.all_arcs(7,3)54Traceback (most recent call last):55...56LookupError: Vertex (7) is not a vertex of the graph.57sage: S._num_verts()581059sage: S._num_arcs()6026162Sparse graphs support multiple edges and labeled edges, but requires that the63labels be positive integers (the case label = 0 is treated as no label).6465::6667sage: S.add_arc_label(0,1,-1)68Traceback (most recent call last):69...70ValueError: Label (-1) must be a nonnegative integer.71sage: S.add_arc(0,1)72sage: S.arc_label(0,1)7307475Note that ``arc_label`` only returns the first edge label found in the specified76place, and this can be in any order (if you want all arc labels, use77``all_arcs``)::7879sage: S.add_arc_label(0,1,1)80sage: S.arc_label(0,1)81182sage: S.all_arcs(0,1)83[0, 1]8485Zero specifies only that there is no labeled arc::8687sage: S.arc_label(1,2)8808990So do not be fooled::9192sage: S.all_arcs(1,2)93[0]94sage: S.add_arc(1,2)95sage: S.arc_label(1,2)9609798Instead, if you work with unlabeled edges, be sure to use the right functions::99100sage: T = SparseGraph(nverts = 3, expected_degree = 2)101sage: T.add_arc(0,1)102sage: T.add_arc(1,2)103sage: T.add_arc(2,0)104sage: T.has_arc(0,1)105True106107Sparse graphs are by their nature directed. As of this writing, you need to do108operations in pairs to treat the undirected case (or use a backend or a Sage109graph)::110111sage: T.has_arc(1,0)112False113114Multiple unlabeled edges are also possible::115116sage: for _ in range(10): S.add_arc(5,4)117sage: S.all_arcs(5,4)118[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]119120The curious developer is encouraged to check out the ``unsafe`` functions,121which do not check input but which run in pure C.122123Underlying Data Structure124-------------------------125126The class ``SparseGraph`` contains the following variables which are inherited127from ``CGraph`` (for explanation, refer to the documentation there)::128129cdef int num_verts130cdef int num_arcs131cdef int *in_degrees132cdef int *out_degrees133cdef bitset_t active_vertices134135It also contains the following variables::136137cdef int hash_length138cdef int hash_mask139cdef SparseGraphBTNode **vertices140141For each vertex ``u``, a hash table of length ``hash_length`` is instantiated.142An arc ``(u, v)`` is stored at ``u * hash_length + hash(v)`` of the array143``vertices``, where ``hash`` should be thought of as an arbitrary but fixed hash144function which takes values in ``0 <= hash < hash_length``. Each address may145represent different arcs, say ``(u, v1)`` and ``(u, v2)`` where146``hash(v1) == hash(v2)``. Thus, a binary tree structure is used at this step to147speed access to individual arcs, whose nodes (each of which represents a pair148``(u,v)``) are instances of the following type::149150cdef struct SparseGraphBTNode:151int vertex152int number153SparseGraphLLNode *labels154SparseGraphBTNode *left155SparseGraphBTNode *right156157Which range of the ``vertices`` array the root of the tree is in determines158``u``, and ``vertex`` stores ``v``. The integer ``number`` stores only the159number of unlabeled arcs from ``u`` to ``v``.160161Currently, labels are stored in a simple linked list, whose nodes are instances162of the following type::163164cdef struct SparseGraphLLNode:165int label166int number167SparseGraphLLNode *next168169The int ``label`` must be a positive integer, since 0 indicates no label, and170negative numbers indicate errors. The int ``number`` is the number of arcs with171the given label.172173TODO: Optimally, edge labels would also be represented by a binary tree, which174would help performance in graphs with many overlapping edges. Also, a more175efficient binary tree structure could be used, although in practice the trees176involved will usually have very small order, unless the degree of vertices177becomes significantly larger than the ``expected_degree`` given, because this is178the size of each hash table. Indeed, the expected size of the binary trees is179`\frac{\text{actual degree}}{\text{expected degree}}`. Ryan Dingman, e.g., is180working on a general-purpose Cython-based red black tree, which would be optimal181for both of these uses.182"""183184#*******************************************************************************185# Copyright (C) 2008-9 Robert L. Miller <[email protected]>186#187# Distributed under the terms of the GNU General Public License (GPL)188# http://www.gnu.org/licenses/189#*******************************************************************************190191include 'sage/misc/bitset.pxi'192193cdef enum:194BT_REORDERING_CONSTANT = 145533211195# Since the binary tree will often see vertices coming in already sorted,196# we don't use the normal ordering on integers, instead multiplying by a197# randomly chosen number and (after reducing mod the size of integers)198# comparing the result. This isn't necessarily the most efficient way to do199# things, but it may just be on binary trees that are never bigger than two200# or three nodes.201202cdef inline int compare(int a, int b):203# Here we rely on the fact that C performs arithmetic on unsigned204# ints modulo 2^wordsize.205cdef unsigned int aa = a, bb = b # signed ints lead to badness like a>b>c>a...206if aa*BT_REORDERING_CONSTANT > bb*BT_REORDERING_CONSTANT:207return 1208elif aa*BT_REORDERING_CONSTANT < bb*BT_REORDERING_CONSTANT:209return -1210return 0211212class id_dict:213"""214This is a helper class for pickling sparse graphs. It emulates a dictionary215``d`` which contains all objects, and always, ``d[x] == x``.216217EXAMPLE::218219sage: from sage.graphs.base.sparse_graph import id_dict220sage: d = id_dict()221sage: d[None] is None222True223sage: d[7]2247225sage: d[{}]226{}227sage: d[()]228()229230"""231def __getitem__(self, x):232"""233Implements d[x].234235EXAMPLE:236237sage: from sage.graphs.base.sparse_graph import id_dict238sage: d = id_dict()239sage: d[None] is None240True241sage: d[7]2427243sage: d[{}]244{}245sage: d[()]246()247248"""249return x250251cdef class SparseGraph(CGraph):252"""253Compiled sparse graphs.254255::256257sage: from sage.graphs.base.sparse_graph import SparseGraph258259Sparse graphs are initialized as follows::260261sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)262263INPUT:264265- ``nverts`` - non-negative integer, the number of vertices.266- ``expected_degree`` - non-negative integer (default: 16), expected upper267bound on degree of vertices.268- ``extra_vertices`` - non-negative integer (default: 0), how many extra269vertices to allocate.270- ``verts`` - optional list of vertices to add271- ``arcs`` - optional list of arcs to add272273The first ``nverts`` are created as vertices of the graph, and the next274``extra_vertices`` can be freely added without reallocation. See top level275documentation for more details. The input ``verts`` and ``arcs`` are mainly276for use in pickling.277278"""279280def __cinit__(self, int nverts, int expected_degree = 16, int extra_vertices = 10, verts=None, arcs=None):281"""282Allocation and initialization happen in one place.283284Memory usage is roughly285286O( (nverts + extra_vertices)*expected_degree + num_arcs ).287288EXAMPLE::289290sage: from sage.graphs.base.sparse_graph import SparseGraph291sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)292293TESTS::294295sage: Graph(-1)296Traceback (most recent call last):297...298ValueError: The number of vertices cannot be strictly negative!299"""300cdef int i = 1301if nverts < 0:302raise ValueError("The number of vertices cannot be strictly negative!")303if nverts == 0 and extra_vertices == 0:304raise RuntimeError('Sparse graphs must allocate space for vertices!')305self.num_verts = nverts306nverts += extra_vertices307self.num_arcs = 0308while i < expected_degree:309i = i << 1310self.hash_length = i311self.hash_mask = i - 1312313# Allocating memory314self.vertices = <SparseGraphBTNode **> \315sage_malloc(nverts * self.hash_length * sizeof(SparseGraphBTNode *))316self.in_degrees = <int *> sage_malloc(nverts * sizeof(int))317self.out_degrees = <int *> sage_malloc(nverts * sizeof(int))318319# Checking the memory was actually allocated320if not self.vertices or not self.in_degrees or not self.out_degrees:321if self.vertices: sage_free(self.vertices)322if self.in_degrees: sage_free(self.in_degrees)323if self.out_degrees: sage_free(self.out_degrees)324raise RuntimeError("Failure allocating memory.")325326# Initializing variables:327#328# self.vertices[i] = 0329memset(self.vertices, <int> NULL, nverts * self.hash_length * sizeof(SparseGraphBTNode *))330331# self.in_degrees[i] = 0332memset(self.in_degrees, 0, nverts * sizeof(int))333334# self.out_degrees[i] = 0335memset(self.out_degrees, 0, nverts * sizeof(int))336337bitset_init(self.active_vertices, self.num_verts + extra_vertices)338bitset_set_first_n(self.active_vertices, self.num_verts)339340if verts is not None:341self.add_vertices(verts)342343if arcs is not None:344for u,v,l in arcs:345self.add_arc_label(u,v,l)346347def __dealloc__(self):348"""349New and dealloc are both tested at class level.350"""351cdef SparseGraphBTNode **temp352cdef SparseGraphLLNode *label_temp353cdef int i354355# Freeing the list of arcs attached to each vertex356for i from 0 <= i < self.active_vertices.size * self.hash_length:357temp = &(self.vertices[i])358359# While temp[0]=self.vertices[i] is not NULL, find a leaf in the360# tree rooted at temp[0] and free it. Then go back to temp[0] and do361# it again. When self.vertices[i] is NULL, go for self.vertices[i+1]362while temp[0] != NULL:363if temp[0].left != NULL:364temp = &(temp[0].left)365elif temp[0].right != NULL:366temp = &(temp[0].right)367else:368label_temp = temp[0].labels369while label_temp != NULL:370temp[0].labels = label_temp.next371sage_free(label_temp)372label_temp = temp[0].labels373sage_free(temp[0])374temp[0] = NULL375temp = &(self.vertices[i])376377sage_free(self.vertices)378sage_free(self.in_degrees)379sage_free(self.out_degrees)380bitset_free(self.active_vertices)381382def __reduce__(self):383"""384Return a tuple used for pickling this graph.385386TESTS::387388sage: from sage.graphs.base.sparse_graph import SparseGraph389sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)390sage: S.add_arc(0,1)391sage: S.add_arc(0,1)392sage: S.all_arcs(0,1)393[0, 0]394sage: S.all_arcs(1,2)395[]396sage: S.add_arc_label(0,0,3)397sage: S.all_arcs(0,0)398[3]399sage: LS = loads(dumps(S))400sage: LS.all_arcs(0,1)401[0, 0]402sage: LS.all_arcs(1,2)403[]404sage: LS.all_arcs(0,0)405[3]406407Test for the trac 10916 -- are multiedges and loops pickled408correctly?::409410sage: DG = DiGraph({0:{0:[0, 1], 1:[0, 1]}})411sage: loads(dumps(DG)).edges()412[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)]413414"""415from sage.graphs.all import DiGraph416D = DiGraph(implementation='c_graph', sparse=True, multiedges=True, loops=True)417D._backend._cg = self418cdef int i419D._backend.vertex_labels = {}420for i from 0 <= i < self.active_vertices.size:421if bitset_in(self.active_vertices, i):422D._backend.vertex_labels[i] = i423D._backend.vertex_ints = D._backend.vertex_labels424D._backend.edge_labels = id_dict()425arcs = [(u,v,l) if l is not None else (u,v,0) for u,v,l in D.edges(labels=True)]426return (SparseGraph, (0, self.hash_length, self.active_vertices.size, self.verts(), arcs))427428cpdef realloc(self, int total):429"""430Reallocate the number of vertices to use, without actually adding any.431432INPUT:433434- ``total`` - integer, the total size to make the array435436Returns -1 and fails if reallocation would destroy any active vertices.437438EXAMPLES::439440sage: from sage.graphs.base.sparse_graph import SparseGraph441sage: S = SparseGraph(nverts=4, extra_vertices=4)442sage: S.current_allocation()4438444sage: S.add_vertex(6)4456446sage: S.current_allocation()4478448sage: S.add_vertex(10)44910450sage: S.current_allocation()45116452sage: S.add_vertex(40)453Traceback (most recent call last):454...455RuntimeError: Requested vertex is past twice the allocated range: use realloc.456sage: S.realloc(50)457sage: S.add_vertex(40)45840459sage: S.current_allocation()46050461sage: S.realloc(30)462-1463sage: S.current_allocation()46450465sage: S.del_vertex(40)466sage: S.realloc(30)467sage: S.current_allocation()46830469470"""471if total == 0:472raise RuntimeError('Sparse graphs must allocate space for vertices!')473cdef bitset_t bits474if total < self.active_vertices.size:475bitset_init(bits, self.active_vertices.size)476bitset_set_first_n(bits, total)477if not bitset_issubset(self.active_vertices, bits):478bitset_free(bits)479return -1480bitset_free(bits)481482self.vertices = <SparseGraphBTNode **> sage_realloc(self.vertices, total * self.hash_length * sizeof(SparseGraphBTNode *))483self.in_degrees = <int *> sage_realloc(self.in_degrees, total * sizeof(int))484self.out_degrees = <int *> sage_realloc(self.out_degrees, total * sizeof(int))485486cdef int new_vertices = total - self.active_vertices.size487488# Initializing the entries corresponding to new vertices if any489if new_vertices>0:490491# self.vertices492memset(self.vertices+self.active_vertices.size * self.hash_length,493<int> NULL,494new_vertices * self.hash_length * sizeof(SparseGraphBTNode *))495496# self.int_degrees497memset(self.in_degrees+self.active_vertices.size, 0, new_vertices * sizeof(int))498499# self.out_degrees500memset(self.out_degrees+self.active_vertices.size, 0, new_vertices * sizeof(int))501502# self.active_vertices503bitset_realloc(self.active_vertices, total)504505###################################506# Unlabeled arc functions507###################################508509cdef int add_arc_unsafe(self, int u, int v) except? -1:510"""511Adds arc (u, v) to the graph with no label.512513INPUT:514u, v -- non-negative integers515"""516cdef int i = (u * self.hash_length) + (v & self.hash_mask)517cdef int compared518cdef SparseGraphBTNode **ins_pt = &(self.vertices[i])519while ins_pt[0] != NULL:520compared = compare(ins_pt[0].vertex, v)521if compared > 0:522ins_pt = &(ins_pt[0].left)523elif compared < 0:524ins_pt = &(ins_pt[0].right)525else:526ins_pt[0].number += 1527break528if ins_pt[0] == NULL:529ins_pt[0] = <SparseGraphBTNode *> sage_malloc(sizeof(SparseGraphBTNode))530if not ins_pt[0]:531raise RuntimeError("Failure allocating memory.")532ins_pt[0].vertex = v533ins_pt[0].number = 1534ins_pt[0].left = NULL535ins_pt[0].right = NULL536ins_pt[0].labels = NULL537self.in_degrees[v] += 1538self.out_degrees[u] += 1539self.num_arcs += 1540541cpdef add_arc(self, int u, int v):542"""543Adds arc ``(u, v)`` to the graph with no label.544545INPUT:546547- ``u, v`` -- non-negative integers, must be in self548549EXAMPLE::550551sage: from sage.graphs.base.sparse_graph import SparseGraph552sage: G = SparseGraph(5)553sage: G.add_arc(0,1)554sage: G.add_arc(4,7)555Traceback (most recent call last):556...557LookupError: Vertex (7) is not a vertex of the graph.558sage: G.has_arc(1,0)559False560sage: G.has_arc(0,1)561True562563"""564self.check_vertex(u)565self.check_vertex(v)566self.add_arc_unsafe(u,v)567568cdef int has_arc_unsafe(self, int u, int v):569"""570Checks whether arc (u, v) is in the graph.571572INPUT:573u, v -- non-negative integers, must be in self574575OUTPUT:5760 -- False5771 -- True578579"""580cdef int i = (u * self.hash_length) + (v & self.hash_mask)581cdef SparseGraphBTNode *temp = self.vertices[i]582while temp != NULL:583if temp.vertex == v:584return 1585if compare(temp.vertex, v) > 0:586temp = temp.left587else: # note compare < 0588temp = temp.right589return 0590591cpdef bint has_arc(self, int u, int v):592"""593Checks whether arc ``(u, v)`` is in the graph.594595INPUT:596- ``u, v`` - integers597598EXAMPLE::599600sage: from sage.graphs.base.sparse_graph import SparseGraph601sage: G = SparseGraph(5)602sage: G.add_arc_label(0,1)603sage: G.has_arc(1,0)604False605sage: G.has_arc(0,1)606True607608"""609if u < 0 or u >= self.active_vertices.size or not bitset_in(self.active_vertices, u):610return False611if v < 0 or v >= self.active_vertices.size or not bitset_in(self.active_vertices, v):612return False613return self.has_arc_unsafe(u,v)614615cdef int del_arc_unsafe(self, int u, int v):616"""617Deletes *all* arcs from u to v.618619INPUT:620u, v -- non-negative integers, must be in self621622OUTPUT:6230 -- No error.6241 -- No arc to delete.625626"""627cdef int i = (u * self.hash_length) + (v & self.hash_mask)628cdef int compared, left_len, right_len629cdef SparseGraphBTNode *temp, **left_child, **right_child630cdef SparseGraphBTNode **parent = &self.vertices[i]631cdef SparseGraphLLNode *labels632633# Assigning to parent the SparseGraphBTNode corresponding to arc (u,v)634while parent[0] != NULL:635compared = compare(parent[0].vertex, v)636if compared > 0:637parent = &(parent[0].left)638elif compared < 0:639parent = &(parent[0].right)640else:# if parent[0].vertex == v:641break642643# If not found, there is no arc to delete !644if parent[0] == NULL:645return 1646647# now parent[0] points to the BT node corresponding to (u,v)648labels = parent[0].labels649i = parent[0].number650self.in_degrees[v] -= i651self.out_degrees[u] -= i652self.num_arcs -= i653654# Freeing the labels655while labels != NULL:656i = labels.number657parent[0].labels = parent[0].labels.next658sage_free(labels)659labels = parent[0].labels660self.in_degrees[v] -= i661self.out_degrees[u] -= i662self.num_arcs -= i663664# Now, if the SparseGraphBTNode element is to be removed, it has to be665# replaced in the binary tree by one of its children.666667# If there is no left child668if parent[0].left == NULL:669temp = parent[0]670parent[0] = parent[0].right671sage_free(temp)672return 0673674# If there is no right child675elif parent[0].right == NULL:676temp = parent[0]677parent[0] = parent[0].left678sage_free(temp)679return 0680681# Both children682else:683left_len = 0684right_len = 0685left_child = &(parent[0].left)686right_child = &(parent[0].right)687688# left_len is equal to the maximum length of a path LR...R. The689# last element of this path is the value of left_child690691while left_child[0].right != NULL:692left_len += 1693left_child = &(left_child[0].right)694# right_len is equal to the maximum length of a path RL...L. The695# last element of this path is the value of right_child696697while right_child[0].left != NULL:698right_len += 1699right_child = &(right_child[0].left)700701# According to the respective lengths, replace parent by the left or702# right child and place the other child at its expected place.703if left_len > right_len:704left_child[0].right = parent[0].right705temp = parent[0]706parent[0] = left_child[0]707left_child[0] = left_child[0].left708parent[0].left = temp.left709sage_free(temp)710return 0711else:712right_child[0].left = parent[0].left713temp = parent[0]714parent[0] = right_child[0]715right_child[0] = right_child[0].right716parent[0].right = temp.right717sage_free(temp)718return 0719720cpdef del_all_arcs(self, int u, int v):721"""722Deletes all arcs from ``u`` to ``v``.723724INPUT:725- ``u, v`` - integers726727EXAMPLE::728729sage: from sage.graphs.base.sparse_graph import SparseGraph730sage: G = SparseGraph(5)731sage: G.add_arc_label(0,1,0)732sage: G.add_arc_label(0,1,1)733sage: G.add_arc_label(0,1,2)734sage: G.add_arc_label(0,1,3)735sage: G.del_all_arcs(0,1)736sage: G.has_arc(0,1)737False738sage: G.arc_label(0,1)7390740sage: G.del_all_arcs(0,1)741742"""743self.check_vertex(u)744self.check_vertex(v)745self.del_arc_unsafe(u,v)746747###################################748# Neighbor functions749###################################750751cdef int out_neighbors_unsafe(self, int u, int *neighbors, int size) except? -2:752"""753Gives all v such that (u, v) is an arc of the graph.754755INPUT:756u -- non-negative integer, must be in self757neighbors -- must be a pointer to an (allocated) integer array758size -- the length of the array759760OUTPUT:761nonnegative integer -- the number of v such that (u, v) is an arc762-1 -- indicates that the array has been filled with neighbors, but763there were more764765"""766cdef int i, num_nbrs = 0, current_nbr = 0767if self.out_degrees[u] == 0:768return 0769cdef SparseGraphBTNode **pointers = <SparseGraphBTNode **> \770sage_malloc(size * sizeof(SparseGraphBTNode *))771if not pointers:772raise RuntimeError("Failure allocating memory.")773for i from u * self.hash_length <= i < (u+1) * self.hash_length:774if self.vertices[i] == NULL:775continue776if num_nbrs == size:777sage_free(pointers)778return -1779pointers[num_nbrs] = self.vertices[i]780neighbors[num_nbrs] = self.vertices[i].vertex781num_nbrs += 1782783# While all the neighbors have not been added to the list, explore784# element pointers[current_nbr] and append its children to the end785# of pointers if necessary, the increment current_nbr.786while current_nbr < num_nbrs:787if pointers[current_nbr].left != NULL:788if num_nbrs == size:789sage_free(pointers)790return -1791pointers[num_nbrs] = pointers[current_nbr].left792neighbors[num_nbrs] = pointers[current_nbr].left.vertex793num_nbrs += 1794if pointers[current_nbr].right != NULL:795if num_nbrs == size:796sage_free(pointers)797return -1798pointers[num_nbrs] = pointers[current_nbr].right799neighbors[num_nbrs] = pointers[current_nbr].right.vertex800num_nbrs += 1801current_nbr += 1802sage_free(pointers)803return num_nbrs804805cpdef list out_neighbors(self, int u):806"""807Gives all ``v`` such that ``(u, v)`` is an arc of the graph.808809INPUT:810- ``u`` - integer811812EXAMPLES::813814sage: from sage.graphs.base.sparse_graph import SparseGraph815sage: G = SparseGraph(5)816sage: G.add_arc(0,1)817sage: G.add_arc(1,2)818sage: G.add_arc(1,3)819sage: G.out_neighbors(0)820[1]821sage: G.out_neighbors(1)822[2, 3]823824"""825cdef int i, num_nbrs826self.check_vertex(u)827if self.out_degrees[u] == 0:828return []829cdef int size = self.out_degrees[u]830cdef int *neighbors = <int *> sage_malloc(size * sizeof(int))831if not neighbors:832raise RuntimeError("Failure allocating memory.")833num_nbrs = self.out_neighbors_unsafe(u, neighbors, size)834output = [neighbors[i] for i from 0 <= i < num_nbrs]835sage_free(neighbors)836return output837838cpdef int out_degree(self, int u):839"""840Returns the out-degree of ``v``841842INPUT:843- ``u`` - integer844845EXAMPLES::846847sage: from sage.graphs.base.sparse_graph import SparseGraph848sage: G = SparseGraph(5)849sage: G.add_arc(0,1)850sage: G.add_arc(1,2)851sage: G.add_arc(1,3)852sage: G.out_degree(0)8531854sage: G.out_degree(1)8552856"""857return self.out_degrees[u]858859860cdef int in_neighbors_unsafe(self, int v, int *neighbors, int size):861"""862Gives all u such that (u, v) is an arc of the graph.863864INPUT:865v -- non-negative integer, must be in self866neighbors -- must be a pointer to an (allocated) integer array867size -- the length of the array868869OUTPUT:870nonnegative integer -- the number of u such that (u, v) is an arc871-1 -- indicates that the array has been filled with neighbors, but872there were more873874NOTE: Due to the implementation of SparseGraph, this method is much more875expensive than out_neighbors_unsafe.876877"""878cdef int i, num_nbrs = 0879if self.in_degrees[v] == 0:880return 0881for i from 0 <= i < self.active_vertices.size:882if not bitset_in(self.active_vertices, i): continue883if self.has_arc_unsafe(i, v):884if num_nbrs == size:885return -1886neighbors[num_nbrs] = i887num_nbrs += 1888return num_nbrs889890cpdef list in_neighbors(self, int v):891"""892Gives all ``u`` such that ``(u, v)`` is an arc of the graph.893894INPUT:895- ``v`` - integer896897EXAMPLES::898899sage: from sage.graphs.base.sparse_graph import SparseGraph900sage: G = SparseGraph(5)901sage: G.add_arc(0,1)902sage: G.add_arc(3,1)903sage: G.add_arc(1,3)904sage: G.in_neighbors(1)905[0, 3]906sage: G.in_neighbors(3)907[1]908909NOTE: Due to the implementation of SparseGraph, this method is much more910expensive than neighbors_unsafe.911"""912cdef int i, num_nbrs913self.check_vertex(v)914if self.in_degrees[v] == 0:915return []916cdef int size = self.in_degrees[v]917cdef int *neighbors = <int *> sage_malloc(size * sizeof(int))918if not neighbors:919raise RuntimeError("Failure allocating memory.")920num_nbrs = self.in_neighbors_unsafe(v, neighbors, size)921output = [neighbors[i] for i from 0 <= i < num_nbrs]922sage_free(neighbors)923return output924925cpdef int in_degree(self, int u):926"""927Returns the in-degree of ``v``928929INPUT:930- ``u`` - integer931932EXAMPLES::933934sage: from sage.graphs.base.sparse_graph import SparseGraph935sage: G = SparseGraph(5)936sage: G.add_arc(0,1)937sage: G.add_arc(1,2)938sage: G.add_arc(1,3)939sage: G.in_degree(0)9400941sage: G.in_degree(1)9421943"""944return self.in_degrees[u]945946947###################################948# Labeled arc functions949###################################950951cdef int add_arc_label_unsafe(self, int u, int v, int l) except? -1:952"""953Adds arc (u, v) to the graph with label l.954955INPUT:956u, v -- non-negative integers957l -- a positive integer label, or zero for no label958959OUTPUT:9600 -- No error.961962"""963cdef int i = (u * self.hash_length) + (v & self.hash_mask)964cdef int compared965cdef SparseGraphBTNode **ins_pt = &(self.vertices[i])966cdef SparseGraphLLNode *label_ptr967while ins_pt[0] != NULL:968compared = compare(ins_pt[0].vertex, v)969if compared > 0:970ins_pt = &(ins_pt[0].left)971elif compared < 0:972ins_pt = &(ins_pt[0].right)973else:974break975if ins_pt[0] == NULL:976ins_pt[0] = <SparseGraphBTNode *> sage_malloc(sizeof(SparseGraphBTNode))977if not ins_pt[0]:978raise RuntimeError("Failure allocating memory.")979ins_pt[0].number = 0980ins_pt[0].vertex = v981ins_pt[0].left = NULL982ins_pt[0].right = NULL983ins_pt[0].labels = NULL984if l:985label_ptr = ins_pt[0].labels986while label_ptr != NULL and label_ptr.label != l:987label_ptr = label_ptr.next988if label_ptr == NULL:989label_ptr = <SparseGraphLLNode *> sage_malloc(sizeof(SparseGraphLLNode))990if not label_ptr:991sage_free(ins_pt[0])992raise RuntimeError("Failure allocating memory.")993label_ptr.label = l994label_ptr.number = 1995label_ptr.next = ins_pt[0].labels996ins_pt[0].labels = label_ptr997else:998label_ptr.number += 1999else:1000ins_pt[0].number += 11001self.in_degrees[v] += 11002self.out_degrees[u] += 11003self.num_arcs += 110041005def add_arc_label(self, int u, int v, int l=0):1006"""1007Adds arc ``(u, v)`` to the graph with label ``l``.10081009INPUT:1010- ``u, v`` - non-negative integers, must be in self1011- ``l`` - a positive integer label, or zero for no label10121013EXAMPLE::10141015sage: from sage.graphs.base.sparse_graph import SparseGraph1016sage: G = SparseGraph(5)1017sage: G.add_arc_label(0,1)1018sage: G.add_arc_label(4,7)1019Traceback (most recent call last):1020...1021LookupError: Vertex (7) is not a vertex of the graph.1022sage: G.has_arc(1,0)1023False1024sage: G.has_arc(0,1)1025True1026sage: G.add_arc_label(1,2,2)1027sage: G.arc_label(1,2)1028210291030"""1031self.check_vertex(u)1032self.check_vertex(v)1033if l < 0:1034raise ValueError("Label ({0}) must be a nonnegative integer.".format(l))1035self.add_arc_label_unsafe(u,v,l)10361037cdef int arc_label_unsafe(self, int u, int v):1038"""1039Retrieves the first label found associated with (u, v) (a positive1040integer).10411042INPUT:1043u, v -- integers from 0, ..., n-1, where n is the number of vertices10441045OUTPUT:1046positive integer -- indicates that there is a label on (u, v).10470 -- either the arc (u, v) is unlabeled, or there is no arc at all.10481049"""1050cdef int i = (u * self.hash_length) + (v & self.hash_mask)1051cdef int compared1052cdef SparseGraphBTNode *temp = self.vertices[i]1053while temp != NULL:1054compared = compare(temp.vertex, v)1055if compared > 0:1056temp = temp.left1057elif compared < 0:1058temp = temp.right1059else:1060break1061if temp == NULL or temp.labels == NULL:1062return 01063return temp.labels.label10641065cpdef int arc_label(self, int u, int v):1066"""1067Retrieves the first label found associated with ``(u, v)``.10681069INPUT:1070- ``u, v`` - non-negative integers, must be in self10711072OUTPUT:1073- positive integer - indicates that there is a label on ``(u, v)``.1074- 0 - either the arc ``(u, v)`` is unlabeled, or there is no arc at all.10751076EXAMPLE::10771078sage: from sage.graphs.base.sparse_graph import SparseGraph1079sage: G = SparseGraph(5)1080sage: G.add_arc_label(3,4,7)1081sage: G.arc_label(3,4)1082710831084NOTES:10851086To this function, an unlabeled arc is indistinguishable from a non-arc::10871088sage: G.add_arc_label(1,0)1089sage: G.arc_label(1,0)109001091sage: G.arc_label(1,1)1092010931094This function only returns the *first* label it finds from ``u`` to ``v``::10951096sage: G.add_arc_label(1,2,1)1097sage: G.add_arc_label(1,2,2)1098sage: G.arc_label(1,2)1099211001101"""1102self.check_vertex(u)1103self.check_vertex(v)1104return self.arc_label_unsafe(u,v)11051106cdef int all_arcs_unsafe(self, int u, int v, int *arc_labels, int size):1107"""1108Gives the labels of all arcs (u, v).11091110INPUT:1111u, v -- integers from 0, ..., n-1, where n is the number of vertices1112arc_labels -- must be a pointer to an (allocated) integer array1113size -- the length of the array11141115OUTPUT:1116integer -- the number of arcs (u, v)1117-1 -- indicates that the array has been filled with labels, but1118there were more11191120"""1121cdef int i = (u * self.hash_length) + (v & self.hash_mask), j1122cdef int compared, num_arcs1123cdef SparseGraphBTNode *temp = self.vertices[i]1124cdef SparseGraphLLNode *label1125while temp != NULL:1126compared = compare(temp.vertex, v)1127if compared > 0:1128temp = temp.left1129elif compared < 0:1130temp = temp.right1131else: # temp.vertex == v:1132break1133if temp == NULL:1134return 01135j = 01136num_arcs = temp.number1137while j < num_arcs and j < size:1138arc_labels[j] = 01139j += 11140label = temp.labels1141while label != NULL:1142num_arcs += label.number1143while j < num_arcs and j < size:1144arc_labels[j] = label.label1145j += 11146label = label.next1147if j == size and label != NULL:1148return -11149return num_arcs11501151cpdef list all_arcs(self, int u, int v):1152"""1153Gives the labels of all arcs ``(u, v)``. An unlabeled arc is interpreted as1154having label 0.11551156EXAMPLE::11571158sage: from sage.graphs.base.sparse_graph import SparseGraph1159sage: G = SparseGraph(5)1160sage: G.add_arc_label(1,2,1)1161sage: G.add_arc_label(1,2,2)1162sage: G.add_arc_label(1,2,2)1163sage: G.add_arc_label(1,2,2)1164sage: G.add_arc_label(1,2,3)1165sage: G.add_arc_label(1,2,3)1166sage: G.add_arc_label(1,2,4)1167sage: G.all_arcs(1,2)1168[4, 3, 3, 2, 2, 2, 1]11691170"""1171cdef int size, num_arcs, i1172cdef int *arc_labels1173cdef list output1174self.check_vertex(u)1175self.check_vertex(v)1176if self.in_degrees[v] < self.out_degrees[u]:1177size = self.in_degrees[v]1178else:1179size = self.out_degrees[u]1180arc_labels = <int *> sage_malloc(size * sizeof(int))1181if not arc_labels:1182raise RuntimeError("Failure allocating memory.")1183num_arcs = self.all_arcs_unsafe(u, v, arc_labels, size)1184if num_arcs == -1:1185sage_free(arc_labels)1186raise RuntimeError("There was an error: there seem to be more arcs than self.in_degrees or self.out_degrees indicate.")1187output = [arc_labels[i] for i from 0 <= i < num_arcs]1188sage_free(arc_labels)1189return output11901191cdef int del_arc_label_unsafe(self, int u, int v, int l):1192"""1193Delete an arc (u, v) with label l.11941195INPUT:1196u, v -- integers from 0, ..., n-1, where n is the number of vertices1197l -- a positive integer label, or zero for no label11981199OUTPUT:12000 -- No error.12011 -- No arc with label l.12021203"""1204cdef int i = (u * self.hash_length) + (v & self.hash_mask)1205cdef int compared1206cdef SparseGraphBTNode **parent = &self.vertices[i]1207cdef SparseGraphLLNode **labels, *label1208while parent[0] != NULL:1209compared = compare(parent[0].vertex, v)1210if compared > 0:1211parent = &(parent[0].left)1212elif compared < 0:1213parent = &(parent[0].right)1214else: # if parent[0].vertex == v:1215break1216if parent[0] == NULL:1217return 1 # indicate an error1218if l == 0:1219if parent[0].number > 1: parent[0].number -= 11220elif parent[0].number == 1:1221if parent[0].labels == NULL:1222self.del_arc_unsafe(u, v)1223return 01224else: parent[0].number -= 11225else: return 1 # indicate an error1226else:1227labels = &(parent[0].labels)1228while labels[0] != NULL and labels[0].label != l:1229labels = &(labels[0].next)1230if labels[0] == NULL:1231return 11232label = labels[0]1233if label.number > 1:1234label.number -= 11235else:1236labels[0] = labels[0].next1237sage_free(label)1238if labels == &(parent[0].labels) and labels[0] == NULL and parent[0].number == 0:1239# here we need to delete an "empty" binary tree node1240self.del_arc_unsafe(u, v)1241self.in_degrees[v] -= 11242self.out_degrees[u] -= 11243self.num_arcs -= 112441245cpdef del_arc_label(self, int u, int v, int l):1246"""1247Delete an arc ``(u, v)`` with label ``l``.12481249INPUT:1250- ``u, v`` - non-negative integers, must be in self1251- ``l`` - a positive integer label, or zero for no label12521253EXAMPLE::12541255sage: from sage.graphs.base.sparse_graph import SparseGraph1256sage: G = SparseGraph(5)1257sage: G.add_arc_label(0,1,0)1258sage: G.add_arc_label(0,1,1)1259sage: G.add_arc_label(0,1,2)1260sage: G.add_arc_label(0,1,2)1261sage: G.add_arc_label(0,1,3)1262sage: G.del_arc_label(0,1,2)1263sage: G.all_arcs(0,1)1264[0, 3, 2, 1]1265sage: G.del_arc_label(0,1,0)1266sage: G.all_arcs(0,1)1267[3, 2, 1]12681269"""1270self.check_vertex(u)1271self.check_vertex(v)1272if l < 0:1273raise ValueError("Label ({0}) must be a nonnegative integer.".format(l))1274self.del_arc_label_unsafe(u,v,l)12751276cdef int has_arc_label_unsafe(self, int u, int v, int l):1277"""1278Indicates whether there is an arc (u, v) with label l.12791280INPUT:1281u, v -- integers from 0, ..., n-1, where n is the number of vertices1282l -- a positive integer label, or zero for no label12831284OUTPUT:12850 -- False12861 -- True12871288"""1289cdef int i = (u * self.hash_length) + (v & self.hash_mask)1290cdef int compared1291cdef SparseGraphBTNode *temp = self.vertices[i]1292cdef SparseGraphLLNode *label1293while temp != NULL:1294compared = compare(temp.vertex, v)1295if compared > 0:1296temp = temp.left1297elif compared < 0:1298temp = temp.right1299else:# if temp.vertex == v:1300break1301if temp == NULL:1302return 01303if l == 0 and temp.number > 0:1304return 11305label = temp.labels1306while label != NULL:1307if label.label == l:1308return 11309label = label.next1310return 013111312cpdef bint has_arc_label(self, int u, int v, int l):1313"""1314Indicates whether there is an arc ``(u, v)`` with label ``l``.13151316INPUT:1317- ``u, v`` -- non-negative integers, must be in self1318- ``l`` -- a positive integer label, or zero for no label13191320EXAMPLE::13211322sage: from sage.graphs.base.sparse_graph import SparseGraph1323sage: G = SparseGraph(5)1324sage: G.add_arc_label(0,1,0)1325sage: G.add_arc_label(0,1,1)1326sage: G.add_arc_label(0,1,2)1327sage: G.add_arc_label(0,1,2)1328sage: G.has_arc_label(0,1,1)1329True1330sage: G.has_arc_label(0,1,2)1331True1332sage: G.has_arc_label(0,1,3)1333False13341335"""1336self.check_vertex(u)1337self.check_vertex(v)1338if l < 0:1339raise ValueError("Label ({0}) must be a nonnegative integer.".format(l))1340return self.has_arc_label_unsafe(u,v,l) == 113411342##############################1343# Further tests. Unit tests for methods, functions, classes defined with cdef.1344##############################13451346def random_stress():1347"""1348Randomly search for mistakes in the code.13491350DOCTEST (No output indicates that no errors were found)::13511352sage: from sage.graphs.base.sparse_graph import random_stress1353sage: for _ in xrange(20):1354... random_stress()13551356"""1357cdef int i, j, k, l, m, n1358cdef SparseGraph Gnew1359num_verts = 101360Gnew = SparseGraph(num_verts)1361# This code deliberately uses random instead of sage.misc.prandom,1362# so that every time it is run it does different tests, instead of1363# doing the same random stress test every time. (Maybe it should1364# use sage.misc.random_testing?)1365from random import randint1366from sage.graphs.all import DiGraph1367from sage.misc.misc import uniq1368Gold = DiGraph(multiedges=True, loops=True, implementation='networkx')1369Gold.add_vertices(xrange(num_verts))1370for n from 0 <= n < 10:1371i = randint(0,num_verts-1)1372j = randint(0,num_verts-1)1373l = randint(1,num_verts-1)1374k = randint(0,num_verts-1)1375if k > 7:1376# print 'G.add_arc_label(%d,%d,%d);'%( i, j, l ) + ' Gold.add_edge(%d,%d,%d)'%( i, j, l )1377if i not in Gold:1378Gnew.add_vertex(i)1379if j not in Gold:1380Gnew.add_vertex(j)1381Gold.add_edge(i,j,l)1382Gnew.add_arc_label_unsafe(i,j,l)1383elif k > 5:1384m = randint(1,7)1385# print 'G.add_vertices(range(num_verts, num_verts+%d)); '%m + ' Gold.add_vertices(range(num_verts, num_verts+%d));'%m + ' num_verts += %d'%m1386Gold.add_vertices(range(num_verts, num_verts+m))1387Gnew.add_vertices(range(num_verts, num_verts+m))1388num_verts += m1389elif k > 3:1390m = randint(0,num_verts-1)1391if m in Gold:1392# print 'G.del_vertex(%d); '%m + ' Gold.delete_vertex(%d); num_verts -= 1'%(m)1393Gold.delete_vertex(m)1394Gnew.del_vertex(m)1395num_verts -= 11396elif k > 1:1397# print 'G.del_all_arcs(%d,%d);'%( i, j ) + ' Gold.delete_edges([(u,v,ll) for u,v,ll in Gold.edges() if u==%d and v==%d])'%(i,j)1398Gold.delete_edges([(u,v,ll) for u,v,ll in Gold.edges() if u==i and v==j])1399Gnew.del_arc_unsafe(i,j)1400else:1401# print 'G.del_arc_label(%d,%d,%d);'%( i, j, l ) + ' Gold.delete_edge(%d,%d,%d)'%( i, j, l )1402Gold.delete_edge(i,j,l)1403Gnew.del_arc_label_unsafe(i,j,l)1404if Gnew.num_arcs != Gold.size():1405#print Gnew.num_arcs, Gold.size()1406raise RuntimeError( "NO:size" )1407for i in Gold:1408if Gnew.out_degrees[i] != Gold.out_degree(i):1409raise RuntimeError( "NO:out degree" )1410if Gnew.in_degrees[i] != Gold.in_degree(i):1411raise RuntimeError( "NO:in degree" )1412if sorted(Gnew.out_neighbors(i)) != uniq([v for u,v,l in Gold.outgoing_edge_iterator(i)]):1413raise RuntimeError( "NO:out neighbors" )1414if sorted(Gnew.in_neighbors(i)) != uniq([u for u,v,l in Gold.incoming_edge_iterator(i)]):1415# print i1416# print list(Gold.incoming_edge_iterator(i))1417# print list(Gnew.in_neighbors(i))1418raise RuntimeError( "NO:in neighbors %s %s %s "%((i,uniq([u for u,v,l in Gold.incoming_edge_iterator(i)]),Gnew.in_neighbors(i))) )1419for j in Gold:1420l = Gnew.arc_label_unsafe(i,j)1421if l != 0:1422if not Gold.has_edge(i,j,l):1423raise RuntimeError( "NO:has_edge" )1424else:1425if Gold.has_edge(i,j):1426raise RuntimeError( "NO:has_edge" )1427list1 = Gnew.all_arcs(i,j)1428list2 = [l for (u,v,l) in Gold.edges() if u==i and v==j]1429if sorted(list1) != sorted(list2):1430raise RuntimeError("NO:edges")1431for l from 1 <= l < num_verts:1432if Gold.has_edge(i,j,l) != Gnew.has_arc_label(i,j,l):1433raise RuntimeError("NO:edges")1434Gnew = SparseGraph(num_verts)1435Gold = DiGraph(loops=True, multiedges=True, implementation='networkx')1436Gold.add_vertices(xrange(num_verts))1437for n from 0 <= n < 100:1438i = randint(0,num_verts-1)1439j = randint(0,num_verts-1)1440k = randint(0,num_verts-1)1441if k != 0:1442Gold.add_edge(i,j)1443Gnew.add_arc_unsafe(i,j)1444else:1445while Gold.has_edge(i,j):1446Gold.delete_edge(i,j)1447Gnew.del_arc_unsafe(i,j)1448if Gnew.num_arcs != Gold.size():1449raise RuntimeError( "NO" )1450for i from 0 <= i < num_verts:1451if Gnew.out_degrees[i] != Gold.out_degree(i):1452raise RuntimeError( "NO" )1453if Gnew.in_degrees[i] != Gold.in_degree(i):1454raise RuntimeError( "NO" )1455if sorted(Gnew.out_neighbors(i)) != uniq([v for u,v,_ in Gold.outgoing_edge_iterator(i)]):1456raise RuntimeError( "NO" )1457if sorted(Gnew.in_neighbors(i)) != uniq([u for u,v,_ in Gold.incoming_edge_iterator(i)]):1458raise RuntimeError( "NO" )1459for j from 0 <= j < num_verts:1460if Gnew.has_arc_unsafe(i,j) != Gold.has_edge(i,j):1461raise RuntimeError( "NO" )14621463def _test_adjacency_sequence_out():1464"""1465Randomly test the method ``SparseGraph.adjacency_sequence_out()``. No output1466indicates that no errors were found.14671468TESTS::14691470sage: from sage.graphs.base.sparse_graph import _test_adjacency_sequence_out1471sage: _test_adjacency_sequence_out() # long time1472"""1473from sage.graphs.digraph import DiGraph1474from sage.graphs.graph_generators import GraphGenerators1475from sage.misc.prandom import randint, random1476low = 01477high = 10001478randg = DiGraph(GraphGenerators().RandomGNP(randint(low, high), random()))1479n = randg.order()1480# set all labels to 01481E = [(u, v, 0) for u, v in randg.edges(labels=False)]1482cdef SparseGraph g = SparseGraph(n,1483verts=randg.vertices(),1484arcs=E)1485assert g._num_verts() == randg.order(), (1486"Graph order mismatch: %s vs. %s" % (g._num_verts(), randg.order()))1487assert g._num_arcs() == randg.size(), (1488"Graph size mismatch: %s vs. %s" % (g._num_arcs(), randg.size()))1489M = randg.adjacency_matrix()1490cdef int *V = <int *>sage_malloc(n * sizeof(int))1491cdef int i = 01492for v in randg.vertex_iterator():1493V[i] = v1494i += 11495cdef int *seq = <int *> sage_malloc(n * sizeof(int))1496for 0 <= i < randint(50, 101):1497u = randint(low, n - 1)1498g.adjacency_sequence_out(n, V, u, seq)1499A = [seq[k] for k in range(n)]1500try:1501assert A == list(M[u])1502except AssertionError:1503sage_free(V)1504sage_free(seq)1505raise AssertionError("Graph adjacency mismatch")1506sage_free(seq)1507sage_free(V)15081509###########################################1510# Sparse Graph Backend1511###########################################15121513from c_graph import CGraphBackend1514from c_graph cimport get_vertex, check_vertex, vertex_label15151516cdef int new_edge_label(object l, dict edge_labels):1517"""1518Returns a new unique int representing the arbitrary label l.1519"""1520if l is None:1521return 01522cdef int l_int, max = 01523for l_int in edge_labels:1524if max < l_int:1525max = l_int1526edge_labels[max+1] = l1527return max+115281529class SparseGraphBackend(CGraphBackend):1530"""1531Backend for Sage graphs using SparseGraphs.15321533::15341535sage: from sage.graphs.base.sparse_graph import SparseGraphBackend15361537This class is only intended for use by the Sage Graph and DiGraph class.1538If you are interested in using a SparseGraph, you probably want to do1539something like the following example, which creates a Sage Graph instance1540which wraps a SparseGraph object::15411542sage: G = Graph(30, implementation="c_graph", sparse=True)1543sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])1544sage: G.edges(labels=False)1545[(0, 1), (0, 3), (4, 5), (9, 23)]15461547Note that Sage graphs using the backend are more flexible than SparseGraphs1548themselves. This is because SparseGraphs (by design) do not deal with Python1549objects::15501551sage: G.add_vertex((0,1,2))1552sage: G.vertices()1553[0,1554...155529,1556(0, 1, 2)]1557sage: from sage.graphs.base.sparse_graph import SparseGraph1558sage: SG = SparseGraph(30)1559sage: SG.add_vertex((0,1,2))1560Traceback (most recent call last):1561...1562TypeError: an integer is required15631564"""15651566def __init__(self, int n, directed=True):1567"""1568Initialize a sparse graph with n vertices.15691570EXAMPLE:15711572sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)1573sage: D.add_edge(0,1,None,False)1574sage: list(D.iterator_edges(range(9), True))1575[(0, 1, None)]15761577"""1578self._cg = SparseGraph(n)1579self._cg_rev = SparseGraph(n) if directed else self._cg1580self._directed = directed1581self.vertex_labels = {}1582self.vertex_ints = {}1583self.edge_labels = {}15841585def add_edge(self, object u, object v, object l, bint directed):1586"""1587Adds the edge ``(u,v)`` to self.15881589INPUT:15901591- ``u,v`` - the vertices of the edge1592- ``l`` - the edge label1593- ``directed`` - if False, also add ``(v,u)``15941595EXAMPLE::15961597sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)1598sage: D.add_edge(0,1,None,False)1599sage: list(D.iterator_edges(range(9), True))1600[(0, 1, None)]16011602TESTS::16031604sage: D = DiGraph(implementation='c_graph', sparse=True)1605sage: D.add_edge(0,1,2)1606sage: D.add_edge(0,1,3)1607sage: D.edges()1608[(0, 1, 3)]16091610"""1611if u is None: u = self.add_vertex(None)1612if v is None: v = self.add_vertex(None)16131614cdef int u_int = check_vertex(u, self.vertex_ints, self.vertex_labels,1615self._cg, self._cg_rev, self._directed)1616cdef int v_int = check_vertex(v, self.vertex_ints, self.vertex_labels,1617self._cg, self._cg_rev, self._directed)16181619cdef int l_int1620if l is None:1621l_int = 01622else:1623l_int = new_edge_label(l, self.edge_labels)16241625if (not self.loops(None)) and u_int == v_int:1626return1627if not self.multiple_edges(None):1628if self._cg.has_arc_label(u_int, v_int, l_int):1629return1630else:1631self._cg.del_all_arcs(u_int, v_int)1632if not directed:1633self._cg.del_all_arcs(v_int, u_int)1634if directed:1635self._cg.add_arc_label(u_int, v_int, l_int)1636self._cg_rev.add_arc_label(v_int, u_int, l_int)1637elif u_int == v_int:1638self._cg.add_arc_label(u_int, v_int, l_int)1639else:1640self._cg.add_arc_label(u_int, v_int, l_int)1641self._cg.add_arc_label(v_int, u_int, l_int)16421643def add_edges(self, object edges, bint directed):1644"""1645Add edges from a list.16461647INPUT:16481649- ``edges`` - the edges to be added - can either be of the form1650``(u,v)`` or ``(u,v,l)``1651- ``directed`` - if False, add ``(v,u)`` as well as ``(u,v)``16521653EXAMPLE::16541655sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)1656sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)1657sage: list(D.iterator_edges(range(9), True))1658[(0, 1, None),1659(2, 3, None),1660(4, 5, None),1661(5, 6, None)]16621663"""1664cdef object u,v,l,e1665for e in edges:1666try:1667u,v,l = e1668except Exception:1669u,v = e1670l = None1671self.add_edge(u,v,l,directed)16721673def del_edge(self, object u, object v, object l, bint directed):1674"""1675Delete edge ``(u,v,l)``.16761677INPUT:16781679- ``u,v`` - the vertices of the edge1680- ``l`` - the edge label1681- ``directed`` - if False, also delete ``(v,u,l)``16821683EXAMPLE::16841685sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)1686sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)1687sage: list(D.iterator_edges(range(9), True))1688[(0, 1, None),1689(2, 3, None),1690(4, 5, None),1691(5, 6, None)]1692sage: D.del_edge(0,1,None,True)1693sage: list(D.iterator_out_edges(range(9), True))1694[(1, 0, None),1695(2, 3, None),1696(3, 2, None),1697(4, 5, None),1698(5, 4, None),1699(5, 6, None),1700(6, 5, None)]17011702TESTS::17031704sage: G = Graph(implementation='c_graph', sparse=True)1705sage: G.add_edge(0,1,2)1706sage: G.delete_edge(0,1)1707sage: G.edges()1708[]17091710sage: G = Graph(multiedges=True, implementation='c_graph', sparse=True)1711sage: G.add_edge(0,1,2)1712sage: G.add_edge(0,1,None)1713sage: G.delete_edge(0,1)1714sage: G.edges()1715[(0, 1, 2)]17161717Do we remove loops correctly? (:trac:`12135`)::17181719sage: g=Graph({0:[0,0,0]}, implementation='c_graph', sparse=True)1720sage: g.edges(labels=False)1721[(0, 0), (0, 0), (0, 0)]1722sage: g.delete_edge(0,0); g.edges(labels=False)1723[(0, 0), (0, 0)]1724"""1725if not ( self.has_vertex(u) and self.has_vertex(v) ):1726return1727cdef int u_int = check_vertex(u, self.vertex_ints, self.vertex_labels,1728self._cg, self._cg_rev, self._directed)1729cdef int v_int = check_vertex(v, self.vertex_ints, self.vertex_labels,1730self._cg, self._cg_rev, self._directed)17311732if l is None:1733if self._cg.has_arc_label(u_int, v_int, 0):1734l_int = 01735else:1736l_int = self._cg.arc_label(u_int, v_int)1737else:1738for l_int in self.edge_labels:1739if self.edge_labels[l_int] == l and self._cg.has_arc_label(u_int, v_int, l_int):1740break1741else:1742return17431744if directed:1745self._cg.del_arc_label(u_int, v_int, l_int)1746self._cg_rev.del_arc_label(v_int, u_int, l_int)1747if l_int:1748self.edge_labels.pop(l_int)1749else:1750self._cg.del_arc_label(u_int, v_int, l_int)1751if v_int != u_int: self._cg.del_arc_label(v_int, u_int, l_int)1752if l_int:1753self.edge_labels.pop(l_int)17541755def get_edge_label(self, object u, object v):1756"""1757Returns the edge label for ``(u,v)``.17581759INPUT:17601761- ``u,v`` - the vertices of the edge17621763EXAMPLE::17641765sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)1766sage: D.add_edges([(0,1,1), (2,3,2), (4,5,3), (5,6,2)], False)1767sage: list(D.iterator_edges(range(9), True))1768[(0, 1, 1), (2, 3, 2), (4, 5, 3), (5, 6, 2)]1769sage: D.get_edge_label(3,2)1770217711772"""1773cdef int l_int1774if not self.has_vertex(u):1775raise LookupError("({0}) is not a vertex of the graph.".format(repr(u)))1776if not self.has_vertex(v):1777raise LookupError("({0}) is not a vertex of the graph.".format(repr(v)))1778cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels,1779self._cg)1780cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels,1781self._cg)1782if not (<SparseGraph>self._cg).has_arc_unsafe(u_int, v_int):1783raise LookupError("({0}, {1}) is not an edge of the graph.".format(repr(u),repr(v)))1784if self.multiple_edges(None):1785return [self.edge_labels[l_int] if l_int != 0 else None1786for l_int in self._cg.all_arcs(u_int, v_int)]1787l_int = self._cg.arc_label(u_int, v_int)1788return self.edge_labels[l_int] if l_int else None17891790def has_edge(self, object u, object v, object l):1791"""1792Returns whether this graph has edge ``(u,v)`` with label ``l``. If ``l``1793is ``None``, return whether this graph has an edge ``(u,v)`` with any1794label.17951796INPUT:17971798- ``u,v`` - the vertices of the edge1799- ``l`` - the edge label, or ``None``18001801EXAMPLE::18021803sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)1804sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)1805sage: D.has_edge(0,1,None)1806True18071808"""1809if not ( self.has_vertex(u) and self.has_vertex(v) ):1810return False1811cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels,1812self._cg)1813cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels,1814self._cg)1815if l is None:1816return self._cg.has_arc(u_int, v_int)1817for l_int in self.edge_labels:1818if self.edge_labels[l_int] == l and self._cg.has_arc_label(u_int, v_int, l_int):1819return True1820return False18211822def iterator_edges(self, object vertices, bint labels):1823"""1824Iterate over the edges incident to a sequence of vertices. Edges are1825assumed to be undirected.18261827INPUT:18281829- ``vertices`` - a list of vertex labels1830- ``labels`` - boolean, whether to return labels as well18311832EXAMPLE::18331834sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)1835sage: G.add_edge(1,2,3,False)1836sage: list(G.iterator_edges(range(9), False))1837[(1, 2)]1838sage: list(G.iterator_edges(range(9), True))1839[(1, 2, 3)]18401841"""1842# Improvement possible in the code below !1843#1844# It is through this function that Sage answers to G.edges(). That's so1845# inefficient that it hurts to see it. Basically, to answer G.edges(),1846# Sage first builds the list L of all vertices, then and returns all the1847# edges which have at least one endpoint in L. That is, absolutely *ALL*1848# the edges, but it checks this condition on the endpoints for each of1849# them. It tests containment in a LIST, not even a set. That should1850# REALLY be updated.1851cdef object u, v, l, L1852vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels,1853self._cg) for v in vertices if self.has_vertex(v)]1854cdef int u_int, v_int, l_int1855if labels:1856for v_int in vertices:1857v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)1858for u_int in self._cg.out_neighbors(v_int):1859if u_int >= v_int or u_int not in vertices:1860u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)1861for l_int in self._cg.all_arcs(v_int, u_int):1862if l_int == 0:1863l = None1864else:1865l = self.edge_labels[l_int]1866yield tuple(sorted((v, u))) + (l,)1867else:1868for v_int in vertices:1869v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)1870for u_int in self._cg.out_neighbors(v_int):1871if u_int >= v_int or u_int not in vertices:1872u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)1873for l_int in self._cg.all_arcs(v_int, u_int):1874yield tuple(sorted((v, u)))18751876def iterator_in_edges(self, object vertices, bint labels):1877"""1878Iterate over the incoming edges incident to a sequence of vertices.18791880INPUT:18811882- ``vertices`` - a list of vertex labels1883- ``labels`` - boolean, whether to return labels as well18841885EXAMPLE::18861887sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)1888sage: G.add_edge(1,2,3,True)1889sage: list(G.iterator_in_edges([1], False))1890[]1891sage: list(G.iterator_in_edges([2], False))1892[(1, 2)]1893sage: list(G.iterator_in_edges([2], True))1894[(1, 2, 3)]18951896"""1897cdef object u, v, L, l1898vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels,1899self._cg) for v in vertices if self.has_vertex(v)]1900cdef int u_int, v_int, l_int1901if self.multiple_edges(None):1902if labels:1903for v_int in vertices:1904v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)1905for u_int in self._cg_rev.out_neighbors(v_int):1906u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)1907for l_int in self._cg.all_arcs(u_int, v_int):1908yield (u, v, None if l_int == 0 else self.edge_labels[l_int])1909else:1910for v_int in vertices:1911v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)1912for u_int in self._cg_rev.out_neighbors(v_int):1913u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)1914for l_int in self._cg.all_arcs(u_int, v_int):1915yield (u, v)1916else:1917if labels:1918for v_int in vertices:1919v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)1920for u_int in self._cg_rev.out_neighbors(v_int):1921l_int = self._cg.arc_label(u_int, v_int)1922yield (vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg),1923v,1924None if l_int == 0 else self.edge_labels[l_int])1925else:1926for v_int in vertices:1927v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)1928for u_int in self._cg_rev.out_neighbors(v_int):1929yield (vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg),1930v)19311932def iterator_out_edges(self, object vertices, bint labels):1933"""1934Iterate over the outbound edges incident to a sequence of vertices.19351936INPUT:1937- ``vertices`` - a list of vertex labels1938- ``labels`` - boolean, whether to return labels as well19391940EXAMPLE::19411942sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)1943sage: G.add_edge(1,2,3,True)1944sage: list(G.iterator_out_edges([2], False))1945[]1946sage: list(G.iterator_out_edges([1], False))1947[(1, 2)]1948sage: list(G.iterator_out_edges([1], True))1949[(1, 2, 3)]19501951"""1952cdef object u, v, L, l1953vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels,1954self._cg) for v in vertices if self.has_vertex(v)]1955cdef int u_int, v_int, l_int1956if self.multiple_edges(None):1957if labels:1958for v_int in vertices:1959v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)1960for u_int in self._cg.out_neighbors(v_int):1961u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)1962for l_int in self._cg.all_arcs(v_int, u_int):1963yield (v, u, None if l_int == 0 else self.edge_labels[l_int])1964else:1965for v_int in vertices:1966v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)1967for u_int in self._cg.out_neighbors(v_int):1968u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)1969for l_int in self._cg.all_arcs(v_int, u_int):1970yield (v, u)1971else:1972if labels:1973for v_int in vertices:1974v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)1975for u_int in self._cg.out_neighbors(v_int):1976l_int = self._cg.arc_label(v_int, u_int)1977yield (v,1978vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg),1979None if l_int == 0 else self.edge_labels[l_int])1980else:1981for v_int in vertices:1982v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)1983for u_int in self._cg.out_neighbors(v_int):1984yield (v,1985vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg))19861987def multiple_edges(self, new):1988"""1989Get/set whether or not ``self`` allows multiple edges.19901991INPUT:19921993- ``new`` - boolean (to set) or ``None`` (to get)19941995EXAMPLES::19961997sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)1998sage: G.multiple_edges(True)1999sage: G.multiple_edges(None)2000True2001sage: G.multiple_edges(False)2002sage: G.multiple_edges(None)2003False2004sage: G.add_edge(0,1,0,True)2005sage: G.add_edge(0,1,0,True)2006sage: list(G.iterator_edges(range(9), True))2007[(0, 1, 0)]20082009"""2010if new is None:2011return self._multiple_edges2012self._multiple_edges = bool(new)20132014def set_edge_label(self, object u, object v, object l, bint directed):2015"""2016Label the edge ``(u,v)`` by ``l``.20172018INPUT:20192020- ``u,v`` - the vertices of the edge2021- ``l`` - the edge label2022- ``directed`` - if False, also set ``(v,u)`` with label ``l``20232024EXAMPLE::20252026sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)2027sage: G.add_edge(1,2,None,True)2028sage: G.set_edge_label(1,2,'a',True)2029sage: list(G.iterator_edges(range(9), True))2030[(1, 2, 'a')]20312032Note that it fails silently if there is no edge there::20332034sage: G.set_edge_label(2,1,'b',True)2035sage: list(G.iterator_edges(range(9), True))2036[(1, 2, 'a')]20372038"""2039if not self.has_edge(u, v, None):2040return2041if self.multiple_edges(None):2042if len(self.get_edge_label(u, v)) > 1:2043raise RuntimeError("Cannot set edge label, since there are multiple edges from %s to %s."%(u,v))2044# now we know there is exactly one edge from u to v2045cdef int l_int, ll_int2046if l is None:2047l_int = 02048else:2049l_int = new_edge_label(l, self.edge_labels)2050cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels,2051self._cg)2052cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels,2053self._cg)2054if not (<SparseGraph>self._cg).has_arc_unsafe(u_int, v_int):2055return2056ll_int = (<SparseGraph>self._cg).arc_label_unsafe(u_int, v_int)2057if ll_int:2058self.edge_labels.pop(ll_int)2059if directed:2060self._cg.del_arc_label(u_int, v_int, ll_int)2061self._cg_rev.del_arc_label(v_int, u_int, ll_int)2062self._cg.add_arc_label(u_int, v_int, l_int)2063self._cg_rev.add_arc_label(v_int, u_int, l_int)2064elif u_int == v_int:2065self._cg.del_arc_label(u_int, v_int, ll_int)2066self._cg.add_arc_label(u_int, v_int, l_int)2067else:2068self._cg.del_arc_label(u_int, v_int, ll_int)2069self._cg.del_arc_label(v_int, u_int, ll_int)2070self._cg.add_arc_label(u_int, v_int, l_int)2071self._cg.add_arc_label(v_int, u_int, l_int)207220732074