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
– non-negative integer; the number of verticesextra_vertices
– non-negative 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 beof 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