Skip to content

Commit

Permalink
gh-35969: Improve method reverse for digraphs
Browse files Browse the repository at this point in the history
    
We improve method ``reverse`` to ensure that the returned digraph has
the same attributes than the original digraph (mutability, multiple
edges, loops, vertex positions, etc.). We also add parameter `immutable`
to decide if the return graph should have the same setting as the
original digraph or forced it to be (im)mutable.

On the way, we do minor corrections in method `feedback_edge_set`.


### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->
<!-- If your change requires a documentation PR, please link it
appropriately -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
<!-- Feel free to remove irrelevant items. -->

- [x] The title is concise, informative, and self-explanatory.
- [x] The description explains in detail what this PR is about.
- [ ] I have linked a relevant issue or discussion.
- [x] I have created tests covering the changes.
- [ ] I have updated the documentation accordingly.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on
- #12345: short description why this is a dependency
- #34567: ...
-->

<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
    
URL: #35969
Reported by: David Coudert
Reviewer(s): David Coudert, Matthias Köppe
  • Loading branch information
Release Manager committed Aug 12, 2023
2 parents de15e88 + 05e3ba6 commit df198d0
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 88 deletions.
140 changes: 72 additions & 68 deletions src/sage/combinat/posets/hasse_diagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ def dual(self):
sage: H.is_isomorphic( H.dual() ) # optional - sage.combinat
False
"""
H = self.reverse()
H = self.reverse(immutable=False)
H.relabel(perm=list(range(H.num_verts() - 1, -1, -1)), inplace=True)
return HasseDiagram(H)

Expand Down Expand Up @@ -1068,28 +1068,27 @@ def moebius_function_matrix(self, algorithm='cython'):
TESTS::
sage: H.moebius_function_matrix().is_immutable() # optional - sage.libs.flint sage.modules
sage: # needs sage.modules sage.libs.flint
sage: H.moebius_function_matrix().is_immutable()
True
sage: hasattr(H,'_moebius_function_matrix') # optional - sage.libs.flint sage.modules
sage: hasattr(H,'_moebius_function_matrix')
True
sage: H.moebius_function == H._moebius_function_from_matrix # optional - sage.libs.flint sage.modules
sage: H.moebius_function == H._moebius_function_from_matrix
True
sage: H = posets.TamariLattice(3)._hasse_diagram
sage: M = H.moebius_function_matrix('matrix'); M # optional - sage.modules
sage: M = H.moebius_function_matrix('matrix'); M
[ 1 -1 -1 0 1]
[ 0 1 0 0 -1]
[ 0 0 1 -1 0]
[ 0 0 0 1 -1]
[ 0 0 0 0 1]
sage: _ = H.__dict__.pop('_moebius_function_matrix') # optional - sage.modules
sage: H.moebius_function_matrix('cython') == M # optional - sage.libs.flint sage.modules
sage: _ = H.__dict__.pop('_moebius_function_matrix')
sage: H.moebius_function_matrix('cython') == M
True
sage: _ = H.__dict__.pop('_moebius_function_matrix') # optional - sage.libs.flint sage.modules
sage: H.moebius_function_matrix('recursive') == M # optional - sage.modules
sage: _ = H.__dict__.pop('_moebius_function_matrix')
sage: H.moebius_function_matrix('recursive') == M
True
sage: _ = H.__dict__.pop('_moebius_function_matrix') # optional - sage.modules
sage: _ = H.__dict__.pop('_moebius_function_matrix')
sage: H.moebius_function_matrix('banana')
Traceback (most recent call last):
...
Expand Down Expand Up @@ -1160,25 +1159,27 @@ def coxeter_transformation(self, algorithm='cython'):
EXAMPLES::
sage: P = posets.PentagonPoset()._hasse_diagram # optional - sage.modules
sage: M = P.coxeter_transformation(); M # optional - sage.libs.flint sage.modules
sage: # needs sage.libs.flint sage.modules
sage: P = posets.PentagonPoset()._hasse_diagram
sage: M = P.coxeter_transformation(); M
[ 0 0 0 0 -1]
[ 0 0 0 1 -1]
[ 0 1 0 0 -1]
[-1 1 1 0 -1]
[-1 1 0 1 -1]
sage: P.__dict__['coxeter_transformation'].clear_cache() # optional - sage.libs.flint sage.modules
sage: P.coxeter_transformation(algorithm="matrix") == M # optional - sage.libs.flint sage.modules
sage: P.__dict__['coxeter_transformation'].clear_cache()
sage: P.coxeter_transformation(algorithm="matrix") == M
True
TESTS::
sage: P = posets.PentagonPoset()._hasse_diagram # optional - sage.modules
sage: M = P.coxeter_transformation() # optional - sage.libs.flint sage.modules
sage: M**8 == 1 # optional - sage.libs.flint sage.modules
sage: # needs sage.libs.flint sage.modules
sage: P = posets.PentagonPoset()._hasse_diagram
sage: M = P.coxeter_transformation()
sage: M**8 == 1
True
sage: P.__dict__['coxeter_transformation'].clear_cache() # optional - sage.libs.flint sage.modules
sage: P.coxeter_transformation(algorithm="banana") # optional - sage.libs.flint sage.modules
sage: P.__dict__['coxeter_transformation'].clear_cache()
sage: P.coxeter_transformation(algorithm="banana")
Traceback (most recent call last):
...
ValueError: unknown algorithm
Expand Down Expand Up @@ -2222,24 +2223,22 @@ def antichains_iterator(self):
EXAMPLES::
sage: P = posets.PentagonPoset() # optional - sage.modules
sage: H = P._hasse_diagram # optional - sage.modules
sage: H.antichains_iterator() # optional - sage.modules
sage: # needs sage.modules
sage: P = posets.PentagonPoset()
sage: H = P._hasse_diagram
sage: H.antichains_iterator()
<generator object ...antichains_iterator at ...>
sage: list(H.antichains_iterator()) # optional - sage.modules
sage: list(H.antichains_iterator())
[[], [4], [3], [2], [1], [1, 3], [1, 2], [0]]
sage: from sage.combinat.posets.hasse_diagram import HasseDiagram
sage: H = HasseDiagram({0:[1,2],1:[4],2:[3],3:[4]})
sage: list(H.antichains_iterator()) # optional - sage.modules
sage: list(H.antichains_iterator())
[[], [4], [3], [2], [1], [1, 3], [1, 2], [0]]
sage: H = HasseDiagram({0:[],1:[],2:[]})
sage: list(H.antichains_iterator()) # optional - sage.modules
sage: list(H.antichains_iterator())
[[], [2], [1], [1, 2], [0], [0, 2], [0, 1], [0, 1, 2]]
sage: H = HasseDiagram({0:[1],1:[2],2:[3],3:[4]})
sage: list(H.antichains_iterator()) # optional - sage.modules
sage: list(H.antichains_iterator())
[[], [4], [3], [2], [1], [0]]
TESTS::
Expand Down Expand Up @@ -2279,12 +2278,13 @@ def are_incomparable(self, i, j):
EXAMPLES::
sage: P = posets.PentagonPoset() # optional - sage.modules
sage: H = P._hasse_diagram # optional - sage.modules
sage: H.are_incomparable(1,2) # optional - sage.modules
sage: # needs sage.modules
sage: P = posets.PentagonPoset()
sage: H = P._hasse_diagram
sage: H.are_incomparable(1,2)
True
sage: V = H.vertices(sort=True) # optional - sage.modules
sage: [ (i,j) for i in V for j in V if H.are_incomparable(i,j)] # optional - sage.modules
sage: V = H.vertices(sort=True)
sage: [ (i,j) for i in V for j in V if H.are_incomparable(i,j)]
[(1, 2), (1, 3), (2, 1), (3, 1)]
"""
if i == j:
Expand All @@ -2304,12 +2304,13 @@ def are_comparable(self, i, j):
EXAMPLES::
sage: P = posets.PentagonPoset() # optional - sage.modules
sage: H = P._hasse_diagram # optional - sage.modules
sage: H.are_comparable(1,2) # optional - sage.modules
sage: # needs sage.modules
sage: P = posets.PentagonPoset()
sage: H = P._hasse_diagram
sage: H.are_comparable(1,2)
False
sage: V = H.vertices(sort=True) # optional - sage.modules
sage: [ (i,j) for i in V for j in V if H.are_comparable(i,j)] # optional - sage.modules
sage: V = H.vertices(sort=True)
sage: [ (i,j) for i in V for j in V if H.are_comparable(i,j)]
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 4),
(2, 0), (2, 2), (2, 3), (2, 4), (3, 0), (3, 2), (3, 3), (3, 4),
(4, 0), (4, 1), (4, 2), (4, 3), (4, 4)]
Expand All @@ -2331,26 +2332,27 @@ def antichains(self, element_class=list):
EXAMPLES::
sage: P = posets.PentagonPoset() # optional - sage.modules
sage: H = P._hasse_diagram # optional - sage.modules
sage: A = H.antichains() # optional - sage.modules
sage: list(A) # optional - sage.modules
sage: # needs sage.modules
sage: P = posets.PentagonPoset()
sage: H = P._hasse_diagram
sage: A = H.antichains()
sage: list(A)
[[], [0], [1], [1, 2], [1, 3], [2], [3], [4]]
sage: A.cardinality() # optional - sage.modules
sage: A.cardinality()
8
sage: [1,3] in A # optional - sage.modules
sage: [1,3] in A
True
sage: [1,4] in A # optional - sage.modules
sage: [1,4] in A
False
TESTS::
sage: TestSuite(A).run() # optional - sage.modules
sage: A = Poset()._hasse_diagram.antichains() # optional - sage.modules
sage: list(A) # optional - sage.modules
sage: # needs sage.modules
sage: TestSuite(A).run()
sage: A = Poset()._hasse_diagram.antichains()
sage: list(A)
[[]]
sage: TestSuite(A).run() # optional - sage.modules
sage: TestSuite(A).run()
"""
from sage.combinat.subsets_pairwise import PairwiseCompatibleSubsets
return PairwiseCompatibleSubsets(self.vertices(sort=True),
Expand Down Expand Up @@ -2382,23 +2384,25 @@ def chains(self, element_class=list, exclude=None, conversion=None):
EXAMPLES::
sage: P = posets.PentagonPoset() # optional - sage.modules
sage: H = P._hasse_diagram # optional - sage.modules
sage: A = H.chains() # optional - sage.modules
sage: list(A) # optional - sage.modules
sage: # needs sage.modules
sage: P = posets.PentagonPoset()
sage: H = P._hasse_diagram
sage: A = H.chains()
sage: list(A)
[[], [0], [0, 1], [0, 1, 4], [0, 2], [0, 2, 3], [0, 2, 3, 4], [0, 2, 4],
[0, 3], [0, 3, 4], [0, 4], [1], [1, 4], [2], [2, 3], [2, 3, 4], [2, 4],
[3], [3, 4], [4]]
sage: A.cardinality() # optional - sage.modules
sage: A.cardinality()
20
sage: [1,3] in A # optional - sage.modules
sage: [1,3] in A
False
sage: [1,4] in A # optional - sage.modules
sage: [1,4] in A
True
One can exclude some vertices::
sage: list(H.chains(exclude=[4, 3])) # optional - sage.modules
sage: # needs sage.modules
sage: list(H.chains(exclude=[4, 3]))
[[], [0], [0, 1], [0, 2], [1], [2]]
The ``element_class`` keyword determines how the chains are
Expand Down Expand Up @@ -2426,16 +2430,16 @@ def is_linear_interval(self, t_min, t_max) -> bool:
This means that this interval is a total order.
EXAMPLES::
sage: P = posets.PentagonPoset() # optional - sage.modules
sage: H = P._hasse_diagram # optional - sage.modules
sage: H.is_linear_interval(0, 4) # optional - sage.modules
sage: # needs sage.modules
sage: P = posets.PentagonPoset()
sage: H = P._hasse_diagram
sage: H.is_linear_interval(0, 4)
False
sage: H.is_linear_interval(0, 3) # optional - sage.modules
sage: H.is_linear_interval(0, 3)
True
sage: H.is_linear_interval(1, 3) # optional - sage.modules
sage: H.is_linear_interval(1, 3)
False
sage: H.is_linear_interval(1, 1) # optional - sage.modules
sage: H.is_linear_interval(1, 1)
True
TESTS::
Expand Down
Loading

0 comments on commit df198d0

Please sign in to comment.