Fast dense graphs¶
For an overview of graph data structures in sage, see
overview
.
Usage Introduction¶
sage: from sage.graphs.base.dense_graph import DenseGraph
>>> from sage.all import *
>>> from sage.graphs.base.dense_graph import DenseGraph
Dense graphs are initialized as follows:
sage: D = DenseGraph(nverts=10, extra_vertices=10)
>>> from sage.all import *
>>> D = DenseGraph(nverts=Integer(10), extra_vertices=Integer(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]
>>> from sage.all import *
>>> D.verts()
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> D.add_vertex(Integer(9))
9
>>> 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]
>>> from sage.all import *
>>> D.add_vertex(Integer(10))
10
>>> 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
>>> from sage.all import *
>>> D.add_arc(Integer(0), Integer(1))
>>> D.add_arc(Integer(1), Integer(2))
>>> D.add_arc(Integer(1), Integer(0))
>>> D.has_arc(Integer(7), Integer(3))
False
>>> D.has_arc(Integer(0), Integer(1))
True
>>> D.in_neighbors(Integer(1))
[0]
>>> D.out_neighbors(Integer(1))
[0, 2]
>>> D.del_all_arcs(Integer(0), Integer(1))
>>> D.has_arc(Integer(0), Integer(1))
False
>>> D.has_arc(Integer(1), Integer(2))
True
>>> D.del_vertex(Integer(7))
>>> D.has_arc(Integer(7), Integer(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
>>> from sage.all import *
>>> T = DenseGraph(nverts=Integer(3), extra_vertices=Integer(2))
>>> T.add_arc(Integer(0), Integer(1))
>>> T.add_arc(Integer(1), Integer(2))
>>> T.add_arc(Integer(2), Integer(0))
>>> T.has_arc(Integer(0), Integer(1))
True
sage: for _ in range(10): D.add_arc(5, 4)
sage: D.has_arc(5,4 )
True
>>> from sage.all import *
>>> for _ in range(Integer(10)): D.add_arc(Integer(5), Integer(4))
>>> D.has_arc(Integer(5),Integer(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
>>> from sage.all import *
>>> T.has_arc(Integer(1), Integer(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 binary_matrix_t edges
Note
As the edges are stored as the adjacency matrix of the graph, enumerating
the edges of the graph has complexity \(O(n^2)\) and enumerating the neighbors
of a vertex has complexity \(O(n)\) (where \(n\) in the size of the bitset
active_vertices).
So, the class DenseGraph
should be used for graphs such that the number
of edges is close to the square of the number of vertices.
- class sage.graphs.base.dense_graph.DenseGraph[source]¶
Bases:
CGraph
Compiled dense graphs.
sage: from sage.graphs.base.dense_graph import DenseGraph
>>> from sage.all import * >>> from sage.graphs.base.dense_graph import DenseGraph
Dense graphs are initialized as follows:
sage: D = DenseGraph(nverts=10, extra_vertices=10)
>>> from sage.all import * >>> D = DenseGraph(nverts=Integer(10), extra_vertices=Integer(10))
INPUT:
nverts
– nonnegative integer; the number of verticesextra_vertices
– nonnegative integer (default: 10); how many extra vertices to allocateverts
– list (default:None
); optional list of vertices to addarcs
– list (default:None
); optional list of arcs to adddirected
– boolean (default:None
); whether the graph is directed
The first
nverts
are created as vertices of the graph, and the nextextra_vertices
can be freely added without reallocation. See top level documentation for more details. The inputverts
andarcs
are mainly for use in pickling.- complement()[source]¶
Replace 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
>>> from sage.all import * >>> from sage.graphs.base.dense_graph import DenseGraph >>> G = DenseGraph(Integer(5)) >>> G.add_arc(Integer(0), Integer(1)) >>> G.has_arc(Integer(0), Integer(1)) True >>> G.complement() >>> G.has_arc(Integer(0), Integer(1)) False
- realloc(total_verts)[source]¶
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
>>> from sage.all import * >>> from sage.graphs.base.dense_graph import DenseGraph >>> D = DenseGraph(nverts=Integer(4), extra_vertices=Integer(4)) >>> D.current_allocation() 8 >>> D.add_vertex(Integer(6)) 6 >>> D.current_allocation() 8 >>> D.add_vertex(Integer(10)) 10 >>> D.current_allocation() 16 >>> D.add_vertex(Integer(40)) Traceback (most recent call last): ... RuntimeError: requested vertex is past twice the allocated range: use realloc >>> D.realloc(Integer(50)) >>> D.add_vertex(Integer(40)) 40 >>> D.current_allocation() 50 >>> D.realloc(Integer(30)) -1 >>> D.current_allocation() 50 >>> D.del_vertex(Integer(40)) >>> D.realloc(Integer(30)) >>> D.current_allocation() 30
- class sage.graphs.base.dense_graph.DenseGraphBackend[source]¶
Bases:
CGraphBackend
Backend for Sage graphs using DenseGraphs.
sage: from sage.graphs.base.dense_graph import DenseGraphBackend
>>> from sage.all import * >>> 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, sparse=False) sage: G.add_edges([(0, 1), (0, 3), (4, 5), (9, 23)]) sage: G.edges(sort=True, labels=False) [(0, 1), (0, 3), (4, 5), (9, 23)]
>>> from sage.all import * >>> G = Graph(Integer(30), sparse=False) >>> G.add_edges([(Integer(0), Integer(1)), (Integer(0), Integer(3)), (Integer(4), Integer(5)), (Integer(9), Integer(23))]) >>> G.edges(sort=True, 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: sorted(list(G), ....: key=lambda x: (isinstance(x, tuple), x)) [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
>>> from sage.all import * >>> G.add_vertex((Integer(0), Integer(1), Integer(2))) >>> sorted(list(G), ... key=lambda x: (isinstance(x, tuple), x)) [0, ... 29, (0, 1, 2)] >>> from sage.graphs.base.dense_graph import DenseGraph >>> DG = DenseGraph(Integer(30)) >>> DG.add_vertex((Integer(0), Integer(1), Integer(2))) Traceback (most recent call last): ... TypeError: an integer is required
- add_edges(edges, directed, remove_loops=False)[source]¶
Add edges from a list.
INPUT:
edges
– an iterable of edges to be added; each edge can either be of the form(u, v)
or(u, v, l)
directed
– ifFalse
, adds(v, u)
as well as(u, v)
remove_loops
– ifTrue
, remove loops
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)]
>>> from sage.all import * >>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9)) >>> D.add_edges([(Integer(0), Integer(1)), (Integer(2), Integer(3)), (Integer(4), Integer(5)), (Integer(5), Integer(6))], False) >>> list(D.iterator_edges(range(Integer(9)), True)) [(0, 1, None), (2, 3, None), (4, 5, None), (5, 6, None)]
- get_edge_label(u, v)[source]¶
Return 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
>>> from sage.all import * >>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9)) >>> D.add_edges([(Integer(0), Integer(1)), (Integer(2), Integer(3), Integer(7)), (Integer(4), Integer(5)), (Integer(5), Integer(6))], False) >>> list(D.iterator_edges(range(Integer(9)), True)) [(0, 1, None), (2, 3, None), (4, 5, None), (5, 6, None)] >>> D.del_edge(Integer(0), Integer(1), None, True) >>> list(D.iterator_out_edges(range(Integer(9)), True)) [(1, 0, None), (2, 3, None), (3, 2, None), (4, 5, None), (5, 4, None), (5, 6, None), (6, 5, None)] >>> D.get_edge_label(Integer(2), Integer(3)) >>> D.get_edge_label(Integer(2), Integer(4)) Traceback (most recent call last): ... LookupError: (2, 4) is not an edge of the graph
- has_edge(u, v, l)[source]¶
Check whether this graph has edge
(u, v)
.Note
The input
l
is for consistency with other backends.INPUT:
u
,v
– the vertices of the edgel
– 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
>>> from sage.all import * >>> D = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9)) >>> D.add_edges([(Integer(0), Integer(1)), (Integer(2), Integer(3)), (Integer(4), Integer(5)), (Integer(5), Integer(6))], False) >>> D.has_edge(Integer(0), Integer(1), None) True
- multiple_edges(new)[source]¶
Get/set whether or not
self
allows multiple edges.INPUT:
new
– boolean (to set) orNone
(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
>>> from sage.all import * >>> import sage.graphs.base.dense_graph >>> G = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9)) >>> G.multiple_edges(True) Traceback (most recent call last): ... NotImplementedError: dense graphs do not support multiple edges >>> G.multiple_edges(None) False
- set_edge_label(u, v, l, directed)[source]¶
Label the edge
(u, v)
byl
.INPUT:
u
,v
– the vertices of the edgel
– the edge labeldirected
– ifFalse
, also set(v, u)
with labell
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
>>> from sage.all import * >>> import sage.graphs.base.dense_graph >>> G = sage.graphs.base.dense_graph.DenseGraphBackend(Integer(9)) >>> G.set_edge_label(Integer(1), Integer(2), 'a', True) Traceback (most recent call last): ... NotImplementedError: dense graphs do not support edge labels