Skip to content

Commit

Permalink
Trac #15623: Immutable graph backend for Posets
Browse files Browse the repository at this point in the history
At long, long last, it passes all tests `:-P`

Thank you Simon for your help with all this !!!

Nathann

URL: http://trac.sagemath.org/15623
Reported by: ncohen
Ticket author(s): Nathann Cohen
Reviewer(s): Simon King
  • Loading branch information
Release Manager authored and vbraun committed Feb 1, 2014
2 parents 35a046d + c5b6d59 commit 12b415d
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 31 deletions.
5 changes: 0 additions & 5 deletions src/sage/combinat/posets/hasse_diagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ class HasseDiagram(DiGraph):
Hasse diagram of a poset containing 4 elements
sage: TestSuite(H).run()
"""

# Hasse diagrams are immutable. This temporary hack enables the
# __hash__ method of DiGraph
_immutable = True

def _repr_(self):
r"""
TESTS::
Expand Down
18 changes: 10 additions & 8 deletions src/sage/combinat/posets/posets.py
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ def __classcall__(cls, hasse_diagram, elements = None, category = None, facade =
facade = hasse_diagram in Sets().Facades()
hasse_diagram = hasse_diagram._hasse_diagram
else:
hasse_diagram = HasseDiagram(hasse_diagram)
hasse_diagram = HasseDiagram(hasse_diagram, data_structure="static_sparse")
if elements is None:
elements = hasse_diagram.vertices()
if facade is None:
Expand Down Expand Up @@ -1477,21 +1477,23 @@ def to_graph(self):
EXAMPLES::
sage: P = Poset({0:[1,2],1:[3],2:[3],3:[]})
sage: P.to_graph()
Graph on 4 vertices
sage: P = Poset()
sage: G = P.to_graph(); G
Graph on 4 vertices
sage: S = Poset()
sage: H = S.to_graph(); H
Graph on 0 vertices
Check that it is hashable::
Check that it is hashable and coincides with the Hasse diagram as a
graph::
sage: hash(G) == hash(G)
True
sage: G == Graph(P.hasse_diagram())
True
"""
from sage.graphs.graph import Graph
G = Graph(self.hasse_diagram())
G._immutable = True
return G
return Graph(self.hasse_diagram(), immutable=True)

def level_sets(self):
"""
Expand Down
34 changes: 28 additions & 6 deletions src/sage/graphs/base/static_sparse_backend.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ from sage.graphs.base.static_sparse_graph cimport (init_short_digraph,
from c_graph import CGraphBackend
from sage.misc.bitset cimport FrozenBitset
from libc.stdint cimport uint32_t
include 'sage/misc/bitset.pxi'

cdef class StaticSparseCGraph(CGraph):
"""
Expand All @@ -64,10 +65,14 @@ cdef class StaticSparseCGraph(CGraph):
has_labels = any(not l is None for _,_,l in G.edge_iterator())
self.directed = G.is_directed()

init_short_digraph(self.g,G, edge_labelled = has_labels)
init_short_digraph(self.g, G, edge_labelled = has_labels)
if self.directed:
init_reverse(self.g_rev,self.g)

# Defining the meaningless set of 'active' vertices. Because of CGraph.
bitset_init(self.active_vertices, self.g.n+1)
bitset_set_first_n(self.active_vertices, self.g.n)

def __dealloc__(self):
r"""
Freeing the memory
Expand All @@ -77,6 +82,7 @@ cdef class StaticSparseCGraph(CGraph):
sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
sage: g = StaticSparseCGraph(graphs.PetersenGraph())
"""
bitset_free(self.active_vertices)
free_short_digraph(self.g)
if self.g_rev != NULL:
free_short_digraph(self.g_rev)
Expand Down Expand Up @@ -361,7 +367,9 @@ class StaticSparseBackend(CGraphBackend):
"""
cdef StaticSparseCGraph cg = <StaticSparseCGraph> StaticSparseCGraph(G)
self._cg = cg
self._directed = cg.directed

# .directed and not ._directed. Because of CGraph.
self.directed = cg.directed

vertices = G.vertices()
self._order = len(vertices)
Expand All @@ -374,6 +382,12 @@ class StaticSparseBackend(CGraphBackend):
self._vertex_to_labels = vertices
self._vertex_to_int = {v:i for i,v in enumerate(vertices)}

# Needed by CGraph. The first one is just an alias, and the second is
# useless : accessing _vertex_to_labels (which is a list) is faster than
# vertex_labels (which is a dictionary)
self.vertex_ints = self._vertex_to_int
self.vertex_labels = {i:v for i,v in enumerate(vertices)}

def __reduce__(self):
"""
Return a tuple used for pickling this graph.
Expand Down Expand Up @@ -416,7 +430,7 @@ class StaticSparseBackend(CGraphBackend):
sage: loads(dumps(gi)) == gi
True
"""
if self._directed:
if self.directed:
from sage.graphs.digraph import DiGraph
G = DiGraph(loops=self._loops, multiedges=self._multiedges)
G.add_edges(list(self.iterator_out_edges(self.iterator_verts(None),True)))
Expand Down Expand Up @@ -592,6 +606,13 @@ class StaticSparseBackend(CGraphBackend):
[(0, 1), (0, 4), (0, 5)]
sage: list(g.iterator_in_edges([0],True))
[(0, 1, None), (0, 4, None), (0, 5, None)]
::
sage: DiGraph(digraphs.Path(5),immutable=False).incoming_edges([2])
[(1, 2, None)]
sage: DiGraph(digraphs.Path(5),immutable=True).incoming_edges([2])
[(1, 2, None)]
"""
cdef StaticSparseCGraph cg = self._cg
if not cg.directed:
Expand All @@ -609,11 +630,11 @@ class StaticSparseBackend(CGraphBackend):
vi = self._vertex_to_labels[i]
for j in range(out_degree(cg.g_rev,i)):
if labels:
yield (vi,
self._vertex_to_labels[cg.g_rev.neighbors[i][j]],
yield (self._vertex_to_labels[cg.g_rev.neighbors[i][j]],
vi,
edge_label(cg.g_rev,cg.g_rev.neighbors[i]+j))
else:
yield vi,self._vertex_to_labels[cg.g_rev.neighbors[i][j]]
yield self._vertex_to_labels[cg.g_rev.neighbors[i][j]], vi

def iterator_out_edges(self, object vertices, bint labels):
"""
Expand All @@ -633,6 +654,7 @@ class StaticSparseBackend(CGraphBackend):
[(0, 1), (0, 4), (0, 5)]
sage: list(g.iterator_out_edges([0],True))
[(0, 1, None), (0, 4, None), (0, 5, None)]
"""
try:
vertices = [self._vertex_to_int[x] for x in vertices]
Expand Down
10 changes: 0 additions & 10 deletions src/sage/graphs/generic_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -16636,21 +16636,11 @@ def relabel(self, perm=None, inplace=True, return_map=False, check_input = True,
Traceback (most recent call last):
...
ValueError: To relabel an immutable graph use inplace=False

A couple of lines to remove when hasse diagrams will not have a
``._immutable`` attribute by default::

sage: from sage.combinat.posets.hasse_diagram import HasseDiagram
sage: if getattr(HasseDiagram,'_immutable', "YES") == "YES":
....: print "two lines must be removed from this function"

"""
from sage.groups.perm_gps.permgroup_element import PermutationGroupElement

if not inplace:
G = self.copy(immutable=False)
if getattr(G, "_immutable", False): # can be removed when posets
G._immutable = False # have immutable backends
perm2 = G.relabel(perm,
return_map= return_map,
check_input = check_input,
Expand Down
3 changes: 1 addition & 2 deletions src/sage/graphs/linearextensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,7 @@ def __init__(self, dag):
################
#Precomputation#
################
from copy import copy
dag_copy = copy(dag)
dag_copy = dag.copy(immutable=False)
le = []
a = []
b = []
Expand Down

0 comments on commit 12b415d

Please sign in to comment.