Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
trac #17408: Faster transitive_reduction (=> faster Poset creation)
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanncohen committed Dec 5, 2014
1 parent d22956c commit 253fc21
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 13 deletions.
3 changes: 2 additions & 1 deletion src/sage/combinat/posets/posets.py
Expand Up @@ -549,7 +549,8 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio

# Determine cover relations, if necessary.
if cover_relations is False:
D = D.transitive_reduction()
from sage.graphs.generic_graph_pyx import transitive_reduction_acyclic
D = transitive_reduction_acyclic(D)

# Check that the digraph does not contain loops, multiple edges
# and is transitively reduced.
Expand Down
2 changes: 1 addition & 1 deletion src/sage/graphs/base/static_dense_graph.pyx
Expand Up @@ -41,7 +41,7 @@ Functions
---------
"""

cdef dict dense_graph_init(binary_matrix_t m, g, translation = False):
cdef dict dense_graph_init(binary_matrix_t m, g, translation=False):
r"""
Initializes the binary matrix from a Sage (di)graph.
Expand Down
19 changes: 8 additions & 11 deletions src/sage/graphs/generic_graph.py
Expand Up @@ -14575,15 +14575,9 @@ def transitive_closure(self):
sage: digraphs.Path(5).copy(immutable=True).transitive_closure()
Transitive closure of Path: Digraph on 5 vertices
"""
from copy import copy
G = self.copy(immutable=False)
G.name('Transitive closure of ' + self.name())
for v in G:
# todo optimization opportunity: we are adding edges that
# are already in the graph and we are adding edges
# one at a time.
for e in G.breadth_first_search(v):
G.add_edge((v,e))
G.add_edges((v,e) for v in G for e in G.breadth_first_search(v))
return G

def transitive_reduction(self):
Expand Down Expand Up @@ -14612,14 +14606,17 @@ def transitive_reduction(self):
sage: g.transitive_reduction().size()
5
"""
from copy import copy
from sage.rings.infinity import Infinity
G = copy(self)
if self.is_directed_acyclic():
from sage.graphs.generic_graph_pyx import transitive_reduction_acyclic
return transitive_reduction_acyclic(self)

G = self.copy(immutable=False)
n = G.order()
for e in self.edge_iterator():
# Try deleting the edge, see if we still have a path
# between the vertices.
G.delete_edge(e)
if G.distance(e[0],e[1])==Infinity:
if G.distance(e[0],e[1]) > n:
# oops, we shouldn't have deleted it
G.add_edge(e)
return G
Expand Down
64 changes: 64 additions & 0 deletions src/sage/graphs/generic_graph_pyx.pyx
Expand Up @@ -18,6 +18,7 @@ AUTHORS:
include "sage/ext/interrupt.pxi"
include 'sage/ext/cdefs.pxi'
include 'sage/ext/stdsage.pxi'
include "sage/misc/binary_matrix.pxi"

# import from Python standard library
from sage.misc.prandom import random
Expand Down Expand Up @@ -1280,3 +1281,66 @@ cpdef tuple find_hamiltonian( G, long max_iter=100000, long reset_bound=30000, l

return (True,output)

def transitive_reduction_acyclic(G):
r"""
Returns the transitive reduction of an acyclic digraph
INPUT:
- ``G`` -- an acyclic digraph.
EXAMPLE::
sage: from sage.graphs.generic_graph_pyx import transitive_reduction_acyclic
sage: G = posets.BooleanLattice(4).hasse_diagram()
sage: G == transitive_reduction_acyclic(G.transitive_closure())
True
"""
cdef int n = G.order()
cdef dict v_to_int = {vv:i for i,vv in enumerate(G.vertices())}
cdef int u,v,i

cdef list linear_extension = G.topological_sort()
linear_extension.reverse()

cdef binary_matrix_t closure

# Build the transitive closure of G
#
# A point is reachable from u if it is one of its neighbours, or if it is
# reachable from one of its neighbours.
binary_matrix_init(closure,n,n)
binary_matrix_fill(closure,0)
for uu in linear_extension:
u = v_to_int[uu]
for vv in G.neighbors_out(uu):
v = v_to_int[vv]
binary_matrix_set1(closure,u,v)
for i in range(closure.width):
closure.rows[u][i] |= closure.rows[v][i]

# Build the transitive reduction of G
#
# An edge uv belongs to the transitive reduction of G if no outneighbor of u
# can reach v (except v itself, of course).
linear_extension.reverse()
cdef list useful_edges = []
for uu in linear_extension:
u = v_to_int[uu]
for vv in G.neighbors_out(uu):
v = v_to_int[vv]
for i in range(closure.width):
closure.rows[u][i] &= ~closure.rows[v][i]
for vv in G.neighbors_out(uu):
v = v_to_int[vv]
if binary_matrix_get(closure,u,v):
useful_edges.append((uu,vv))

from sage.graphs.digraph import DiGraph
reduced = DiGraph()
reduced.add_edges(useful_edges)
reduced.add_vertices(linear_extension)

binary_matrix_free(closure)

return reduced

0 comments on commit 253fc21

Please sign in to comment.