Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Fast dense graphs
For an overview of graph data structures in sage, see :mod:`~sage.graphs.base.overview`.
Usage Introduction ------------------
::
sage: from sage.graphs.base.dense_graph import DenseGraph
Dense graphs are initialized as follows::
sage: D = DenseGraph(nverts = 10, extra_vertices = 10)
This example initializes a dense graph with room for twenty vertices, the first ten of which are in the graph. In general, the first ``nverts`` are "active." For example, see that 9 is already in the graph::
sage: D.verts() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] sage: D.add_vertex(9) 9 sage: D.verts() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
But 10 is not, until we add it::
sage: D.add_vertex(10) 10 sage: D.verts() [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
You can begin working right away as follows::
sage: D.add_arc(0,1) sage: D.add_arc(1,2) sage: D.add_arc(1,0) sage: D.has_arc(7,3) False sage: D.has_arc(0,1) True sage: D.in_neighbors(1) [0] sage: D.out_neighbors(1) [0, 2] sage: D.del_all_arcs(0,1) sage: D.has_arc(0,1) False sage: D.has_arc(1,2) True sage: D.del_vertex(7) sage: D.has_arc(7,3) False
Dense graphs do not support multiple or labeled edges.
::
sage: T = DenseGraph(nverts = 3, extra_vertices = 2) sage: T.add_arc(0,1) sage: T.add_arc(1,2) sage: T.add_arc(2,0) sage: T.has_arc(0,1) True
::
sage: for _ in range(10): D.add_arc(5,4) sage: D.has_arc(5,4) True
Dense graphs are by their nature directed. As of this writing, you need to do operations in pairs to treat the undirected case (or use a backend or a Sage graph)::
sage: T.has_arc(1,0) False
The curious developer is encouraged to check out the ``unsafe`` functions, which do not check input but which run in pure C.
Underlying Data Structure -------------------------
The class ``DenseGraph`` contains the following variables which are inherited from ``CGraph`` (for explanation, refer to the documentation there)::
cdef int num_verts cdef int num_arcs cdef int *in_degrees cdef int *out_degrees cdef bitset_t active_vertices
It also contains the following variables::
cdef int num_longs cdef unsigned long *edges
The array ``edges`` is a series of bits which are turned on or off, and due to this, dense graphs only support graphs without edge labels and with no multiple edges. ``num_longs`` stores the length of the ``edges`` array. Recall that this length reflects the number of available vertices, not the number of "actual" vertices. For more details about this, refer to the documentation for ``CGraph``. """
#***************************************************************************** # Copyright (C) 2008-9 Robert L. Miller <rlmillster@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import absolute_import
include 'sage/data_structures/bitset.pxi'
from libc.string cimport memcpy
from cysignals.memory cimport sig_calloc, sig_realloc, sig_free
cdef int radix = sizeof(unsigned long) * 8 # number of bits per 'unsigned long' cdef int radix_mod_mask = radix - 1 # (assumes that radis is a power of 2)
cdef class DenseGraph(CGraph): """ Compiled dense graphs.
::
sage: from sage.graphs.base.dense_graph import DenseGraph
Dense graphs are initialized as follows::
sage: D = DenseGraph(nverts = 10, extra_vertices = 10)
INPUT:
- ``nverts`` - non-negative integer, the number of vertices. - ``extra_vertices`` - non-negative integer (default: 0), how many extra vertices to allocate. - ``verts`` - optional list of vertices to add - ``arcs`` - optional list of arcs to add
The first ``nverts`` are created as vertices of the graph, and the next ``extra_vertices`` can be freely added without reallocation. See top level documentation for more details. The input ``verts`` and ``arcs`` are mainly for use in pickling.
""" def __cinit__(self, int nverts, int extra_vertices = 10, verts = None, arcs = None): """ Allocation and initialization happen in one place.
Memory usage is
O( (nverts + extra_vertices)^2 ).
EXAMPLES::
sage: from sage.graphs.base.dense_graph import DenseGraph sage: D = DenseGraph(nverts = 10, extra_vertices = 10) """ raise RuntimeError('Dense graphs must allocate space for vertices!')
# self.num_longs = "ceil(total_verts/radix)"
sig_free(self.edges) sig_free(self.in_degrees) sig_free(self.out_degrees) raise MemoryError
self.add_vertices(verts)
for u,v in arcs: self.add_arc(u,v)
def __dealloc__(self): """ New and dealloc are both tested at class level. """
cpdef realloc(self, int total_verts): """ Reallocate the number of vertices to use, without actually adding any.
INPUT:
- ``total`` - integer, the total size to make the array
Returns -1 and fails if reallocation would destroy any active vertices.
EXAMPLES::
sage: from sage.graphs.base.dense_graph import DenseGraph sage: D = DenseGraph(nverts=4, extra_vertices=4) sage: D.current_allocation() 8 sage: D.add_vertex(6) 6 sage: D.current_allocation() 8 sage: D.add_vertex(10) 10 sage: D.current_allocation() 16 sage: D.add_vertex(40) Traceback (most recent call last): ... RuntimeError: Requested vertex is past twice the allocated range: use realloc. sage: D.realloc(50) sage: D.add_vertex(40) 40 sage: D.current_allocation() 50 sage: D.realloc(30) -1 sage: D.current_allocation() 50 sage: D.del_vertex(40) sage: D.realloc(30) sage: D.current_allocation() 30
""" cdef int i, j raise RuntimeError('Dense graphs must allocate space for vertices!')
cdef bitset_t bits else:
# self.num_longs = "ceil(total_verts/radix)"
# Resize of self.edges
################################### # Unlabeled arc functions ###################################
cdef int add_arc_unsafe(self, int u, int v) except -1: """ Adds arc (u, v) to the graph.
INPUT: u, v -- non-negative integers
"""
cpdef add_arc(self, int u, int v): """ Adds arc ``(u, v)`` to the graph.
INPUT:
- ``u, v`` -- non-negative integers, must be in self
EXAMPLES::
sage: from sage.graphs.base.dense_graph import DenseGraph sage: G = DenseGraph(5) sage: G.add_arc(0,1) sage: G.add_arc(4,7) Traceback (most recent call last): ... LookupError: Vertex (7) is not a vertex of the graph. sage: G.has_arc(1,0) False sage: G.has_arc(0,1) True
"""
cdef int has_arc_unsafe(self, int u, int v) except -1: """ Checks whether arc (u, v) is in the graph.
INPUT: u, v -- non-negative integers, must be in self
OUTPUT: 0 -- False 1 -- True
"""
cpdef bint has_arc(self, int u, int v) except -1: """ Checks whether arc ``(u, v)`` is in the graph.
INPUT: u, v -- integers
EXAMPLES::
sage: from sage.graphs.base.dense_graph import DenseGraph sage: G = DenseGraph(5) sage: G.add_arc(0,1) sage: G.has_arc(1,0) False sage: G.has_arc(0,1) True
""" return False
cdef int del_arc_unsafe(self, int u, int v) except -1: """ Deletes the arc from u to v, if it exists.
INPUT: u, v -- non-negative integers, must be in self
"""
cpdef del_all_arcs(self, int u, int v): """ Deletes the arc from ``u`` to ``v``.
INPUT: - ``u, v`` - integers
NOTE: The naming of this function is for consistency with ``SparseGraph``. Of course, there can be at most one arc for a ``DenseGraph``.
EXAMPLES::
sage: from sage.graphs.base.dense_graph import DenseGraph sage: G = DenseGraph(5) sage: G.add_arc(0,1) sage: G.has_arc(0,1) True sage: G.del_all_arcs(0,1) sage: G.has_arc(0,1) False
"""
def complement(self): r""" Replaces the graph with its complement
.. NOTE::
Assumes that the graph has no loop.
EXAMPLES::
sage: from sage.graphs.base.dense_graph import DenseGraph sage: G = DenseGraph(5) sage: G.add_arc(0,1) sage: G.has_arc(0,1) True sage: G.complement() sage: G.has_arc(0,1) False """
# The following cast assumes that mp_limb_t is an unsigned long. # (this assumption is already made in bitset.pxi) cdef unsigned long * active_vertices_bitset
cdef int i,j
################################### # Neighbor functions ###################################
cdef int out_neighbors_unsafe(self, int u, int *neighbors, int size) except -2: """ Gives all v such that (u, v) is an arc of the graph.
INPUT: u -- non-negative integer, must be in self neighbors -- must be a pointer to an (allocated) integer array size -- the length of the array
OUTPUT: nonnegative integer -- the number of v such that (u, v) is an arc -1 -- indicates that the array has been filled with neighbors, but there were more
""" cdef unsigned long word, data return -1
cpdef list out_neighbors(self, int u): """ Gives all ``v`` such that ``(u, v)`` is an arc of the graph.
INPUT: - ``u`` - integer
EXAMPLES::
sage: from sage.graphs.base.dense_graph import DenseGraph sage: G = DenseGraph(5) sage: G.add_arc(0,1) sage: G.add_arc(1,2) sage: G.add_arc(1,3) sage: G.out_neighbors(0) [1] sage: G.out_neighbors(1) [2, 3]
""" cdef int i, num_nbrs raise MemoryError
cdef int in_neighbors_unsafe(self, int v, int *neighbors, int size) except -2: """ Gives all u such that (u, v) is an arc of the graph.
INPUT: v -- non-negative integer, must be in self neighbors -- must be a pointer to an (allocated) integer array size -- the length of the array
OUTPUT: nonnegative integer -- the number of u such that (u, v) is an arc -1 -- indicates that the array has been filled with neighbors, but there were more
""" return -1
cpdef list in_neighbors(self, int v): """ Gives all ``u`` such that ``(u, v)`` is an arc of the graph.
INPUT: - ``v`` - integer
EXAMPLES::
sage: from sage.graphs.base.dense_graph import DenseGraph sage: G = DenseGraph(5) sage: G.add_arc(0,1) sage: G.add_arc(3,1) sage: G.add_arc(1,3) sage: G.in_neighbors(1) [0, 3] sage: G.in_neighbors(3) [1]
""" cdef int i, num_nbrs raise MemoryError
############################## # Further tests. Unit tests for methods, functions, classes defined with cdef. ##############################
def _test_adjacency_sequence_out(): """ Randomly test the method ``DenseGraph.adjacency_sequence_out()``. No output indicates that no errors were found.
TESTS::
sage: from sage.graphs.base.dense_graph import _test_adjacency_sequence_out sage: _test_adjacency_sequence_out() # long time """ from sage.graphs.digraph import DiGraph from sage.graphs.graph_generators import GraphGenerators from sage.misc.prandom import randint, random low = 0 high = 500 randg = DiGraph(GraphGenerators().RandomGNP(randint(low, high), random())) n = randg.order() cdef DenseGraph g = DenseGraph(n, verts=randg.vertices(), arcs=randg.edges(labels=False)) assert g.num_verts == randg.order(), ( "Graph order mismatch: %s vs. %s" % (g.num_verts, randg.order())) assert g.num_arcs == randg.size(), ( "Graph size mismatch: %s vs. %s" % (g.num_arcs, randg.size())) M = randg.adjacency_matrix() cdef int *V = <int *>sig_malloc(n * sizeof(int)) cdef int i = 0 for v in randg.vertex_iterator(): V[i] = v i += 1 cdef int *seq = <int *> sig_malloc(n * sizeof(int)) for 0 <= i < randint(50, 101): u = randint(low, n - 1) g.adjacency_sequence_out(n, V, u, seq) A = [seq[k] for k in range(n)] try: assert A == list(M[u]) except AssertionError: sig_free(V) sig_free(seq) raise AssertionError("Graph adjacency mismatch") sig_free(seq) sig_free(V)
########################################### # Dense Graph Backend ###########################################
from .c_graph cimport CGraphBackend
cdef class DenseGraphBackend(CGraphBackend): """ Backend for Sage graphs using DenseGraphs.
::
sage: from sage.graphs.base.dense_graph import DenseGraphBackend
This class is only intended for use by the Sage Graph and DiGraph class. If you are interested in using a DenseGraph, you probably want to do something like the following example, which creates a Sage Graph instance which wraps a DenseGraph object::
sage: G = Graph(30, implementation="c_graph", sparse=False) sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)]) sage: G.edges(labels=False) [(0, 1), (0, 3), (4, 5), (9, 23)]
Note that Sage graphs using the backend are more flexible than DenseGraphs themselves. This is because DenseGraphs (by design) do not deal with Python objects::
sage: G.add_vertex((0,1,2)) sage: G.vertices() [0, ... 29, (0, 1, 2)] sage: from sage.graphs.base.dense_graph import DenseGraph sage: DG = DenseGraph(30) sage: DG.add_vertex((0,1,2)) Traceback (most recent call last): ... TypeError: an integer is required
"""
def __init__(self, n, directed=True): """ Initialize a dense graph with n vertices.
EXAMPLES::
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: D.add_edge(0,1,None,False) sage: list(D.iterator_edges(range(9), True)) [(0, 1, None)]
"""
def add_edge(self, object u, object v, object l, bint directed): """ Adds the edge ``(u,v)`` to self.
INPUT:
- ``u,v`` - the vertices of the edge - ``l`` - the edge label (ignored) - ``directed`` - if False, also add ``(v,u)``
NOTE: The input ``l`` is for consistency with other backends.
EXAMPLES::
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: D.add_edge(0,1,None,False) sage: list(D.iterator_edges(range(9), True)) [(0, 1, None)]
TESTS:
Check :trac:`22991`::
sage: G = Graph(3, sparse=False) sage: G.add_edge(0,0) Traceback (most recent call last): ... ValueError: cannot add edge from 0 to 0 in graph without loops sage: G = Graph(3, sparse=True, loops=True) sage: G.add_edge(0,0); G.edges() [(0, 0, None)] """
else:
def add_edges(self, object edges, bint directed): """ Add edges from a list.
INPUT:
- ``edges`` - the edges to be added - can either be of the form ``(u,v)`` or ``(u,v,l)`` - ``directed`` - if False, add ``(v,u)`` as well as ``(u,v)``
EXAMPLES::
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False) sage: list(D.iterator_edges(range(9), True)) [(0, 1, None), (2, 3, None), (4, 5, None), (5, 6, None)]
"""
def del_edge(self, object u, object v, object l, bint directed): """ Delete edge ``(u,v)``.
INPUT:
- ``u,v`` - the vertices of the edge - ``l`` - the edge label (ignored) - ``directed`` - if False, also delete ``(v,u,l)``
NOTE: The input ``l`` is for consistency with other backends.
EXAMPLES::
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False) sage: list(D.iterator_edges(range(9), True)) [(0, 1, None), (2, 3, None), (4, 5, None), (5, 6, None)] sage: D.del_edge(0,1,None,True) sage: list(D.iterator_out_edges(range(9), True)) [(1, 0, None), (2, 3, None), (3, 2, None), (4, 5, None), (5, 4, None), (5, 6, None), (6, 5, None)]
""" return u, v = u[:2] else:
def get_edge_label(self, object u, object v): """ Returns the edge label for ``(u,v)``. Always None, since dense graphs do not support edge labels.
INPUT:
- ``u,v`` - the vertices of the edge
EXAMPLES::
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: D.add_edges([(0,1), (2,3,7), (4,5), (5,6)], False) sage: list(D.iterator_edges(range(9), True)) [(0, 1, None), (2, 3, None), (4, 5, None), (5, 6, None)] sage: D.del_edge(0,1,None,True) sage: list(D.iterator_out_edges(range(9), True)) [(1, 0, None), (2, 3, None), (3, 2, None), (4, 5, None), (5, 4, None), (5, 6, None), (6, 5, None)] sage: D.get_edge_label(2,3) sage: D.get_edge_label(2,4) Traceback (most recent call last): ... LookupError: (2, 4) is not an edge of the graph.
"""
def has_edge(self, object u, object v, object l): """ Returns whether this graph has edge ``(u,v)``.
NOTE: The input ``l`` is for consistency with other backends.
INPUT:
- ``u,v`` - the vertices of the edge - ``l`` - the edge label (ignored)
EXAMPLES::
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False) sage: D.has_edge(0,1,None) True
""" return False
def iterator_edges(self, object vertices, bint labels): """ Iterate over the edges incident to a sequence of vertices. Edges are assumed to be undirected.
INPUT: - ``vertices`` - a list of vertex labels - ``labels`` - boolean, whether to return labels as well
EXAMPLES::
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: G.add_edge(1,2,None,False) sage: list(G.iterator_edges(range(9), False)) [(1, 2)] sage: list(G.iterator_edges(range(9), True)) [(1, 2, None)]
""" cdef object v cdef int u_int, v_int else: )))
def iterator_in_edges(self, object vertices, bint labels): """ Iterate over the incoming edges incident to a sequence of vertices.
INPUT: - ``vertices`` - a list of vertex labels - ``labels`` - boolean, whether to return labels as well
EXAMPLES::
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: G.add_edge(1,2,None,True) sage: list(G.iterator_in_edges([1], False)) [] sage: list(G.iterator_in_edges([2], False)) [(1, 2)] sage: list(G.iterator_in_edges([2], True)) [(1, 2, None)]
""" cdef object v cdef int u_int, v_int None) else:
def iterator_out_edges(self, object vertices, bint labels): """ Iterate over the outbound edges incident to a sequence of vertices.
INPUT: - ``vertices`` - a list of vertex labels - ``labels`` - boolean, whether to return labels as well
EXAMPLES::
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: G.add_edge(1,2,None,True) sage: list(G.iterator_out_edges([2], False)) [] sage: list(G.iterator_out_edges([1], False)) [(1, 2)] sage: list(G.iterator_out_edges([1], True)) [(1, 2, None)]
""" cdef object u, v cdef int u_int, v_int None) else:
def multiple_edges(self, new): """ Get/set whether or not ``self`` allows multiple edges.
INPUT:
- ``new`` - boolean (to set) or ``None`` (to get)
EXAMPLES::
sage: import sage.graphs.base.dense_graph sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: G.multiple_edges(True) Traceback (most recent call last): ... NotImplementedError: Dense graphs do not support multiple edges. sage: G.multiple_edges(None) False
"""
def set_edge_label(self, object u, object v, object l, bint directed): """ Label the edge ``(u,v)`` by ``l``.
INPUT:
- ``u,v`` - the vertices of the edge - ``l`` - the edge label - ``directed`` - if False, also set ``(v,u)`` with label ``l``
EXAMPLES::
sage: import sage.graphs.base.dense_graph sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9) sage: G.set_edge_label(1,2,'a',True) Traceback (most recent call last): ... NotImplementedError: Dense graphs do not support edge labels. """ |