Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
6d7ab9c
initial commit
mantepse Oct 18, 2022
6149eb2
make the linter happier
mantepse Oct 18, 2022
9d4bfb9
remove useless assignment
mantepse Oct 18, 2022
6ee34e1
make initialisation more efficient
mantepse Oct 18, 2022
1a14bcf
consistently name variable
mantepse Oct 18, 2022
0901ec7
slightly improve documentation
mantepse Oct 19, 2022
c39d653
non-copying intersection, to save memory when there are almost no res…
mantepse Nov 2, 2022
2f0bb0e
Merge branch 'develop' of trac.sagemath.org:sage into t/33238/a_bijec…
mantepse Dec 5, 2022
321ba43
start to cache solutions
mantepse Dec 5, 2022
306395c
finish implementation of cache
mantepse Dec 21, 2022
1a8e564
Merge branch 'develop' of trac.sagemath.org:sage into t/33238/a_bijec…
mantepse Dec 21, 2022
1ac0978
add some documentation and doctests, slightly simplify code
mantepse Dec 21, 2022
47945ac
add missing documentation in table of contents
mantepse Dec 22, 2022
19c3d8f
mark doctests as long, slightly simplify logic
mantepse Dec 22, 2022
eca857e
slightly simplify, more doctests
mantepse Dec 22, 2022
a04d146
doctest _find_counter_example
mantepse Dec 22, 2022
3508426
doctest add_distribution_constraints and add_intertwing_relation_cons…
mantepse Dec 22, 2022
0ac618c
doctest _preprocess_intertwining_relations, _solution, _show_bmilp, _…
mantepse Dec 22, 2022
d50b62c
expand docstring of main class
mantepse Dec 23, 2022
288e391
copy milp instead of adding and removing constraints
mantepse Dec 23, 2022
d57c8e5
derandomize a test, mark example as random
mantepse Dec 23, 2022
7353fb5
correct typo, remove useless assignment
mantepse Dec 23, 2022
db850f0
add and remove constraints instead of copying the whole program
mantepse Dec 23, 2022
ec3271c
fix problem with SCIP, add timings
mantepse Dec 23, 2022
dfdc6ba
use convert for MixedIntegerLinearProgram.get_values
mantepse Dec 24, 2022
d0836cb
include information on MILP also in public documentation
mantepse Dec 25, 2022
563af98
remove unnecessary copy
mantepse Dec 25, 2022
590bae2
add possibility to constrain to involutions
mantepse Dec 26, 2022
da0655b
correct indentation
mantepse Dec 26, 2022
03b1fb8
better handling of empty constraints
mantepse Dec 29, 2022
a3364de
move _show to the _BijectionistMILP class
mantepse Dec 29, 2022
9d83a6c
remove unused code for backends that do not support removing constraints
mantepse Dec 30, 2022
864029d
make _solution a public method of _BijectionistMILP, simplify solve
mantepse Dec 30, 2022
64101a8
eliminate _initialize_new_bmilp
mantepse Dec 30, 2022
2d34911
slightly simplify logic of _forced_constant_blocks, use defaultdict
mantepse Dec 30, 2022
c2f0062
slight simplification
mantepse Dec 30, 2022
78968ae
copy (instead of deepcopy) should be correct
mantepse Dec 31, 2022
6ddaeae
slightly simplify _preprocess_intertwining_relations
mantepse Dec 31, 2022
60286e6
slightly improve non_copying_intersection
mantepse Dec 31, 2022
c38f5b9
add some internal documentation
mantepse Dec 31, 2022
6fb06f0
untangle _preprocess_intertwining_relations
mantepse Jan 2, 2023
706056e
add possibility to require a homomesy
mantepse Jan 2, 2023
d8a0663
Merge branch 'u/mantepse/mixedintegerlinearprogram_add_constraint__re…
mantepse Jan 2, 2023
4e90280
Merge branch 'u/mantepse/allow_to_remove_no_constraints' of trac.sage…
mantepse Jan 2, 2023
65b0c4a
preserve the cache of solutions after computing the optimal constant …
mantepse Jan 2, 2023
21cb54f
make _BijectionistMILP.solution the only entrypoint
mantepse Jan 3, 2023
a573bb4
remove unnecessary calls to list in doctests
mantepse Jan 3, 2023
6868261
move iterator over all solutions to _BijectionistMILP
mantepse Jan 3, 2023
61e97bc
merge _solve, solution and __iter__
mantepse Jan 4, 2023
db8947b
pycodestyle stuff
mantepse Jan 4, 2023
9678717
Merge branch 'develop' of trac.sagemath.org:sage into t/33238/a_bijec…
mantepse Jan 20, 2023
53506aa
rename pseudo_inverse to quadratic
mantepse Jan 20, 2023
d61c630
Merge branch 'u/mantepse/a_bijectionist_s_toolkit' of https://github.…
mantepse Feb 10, 2023
fefe54a
Merge branch 'develop' of github.com:sagemath/sage into develop
mantepse Feb 10, 2023
31bfb69
fix docstrings, simplify some tests
mantepse Feb 11, 2023
24e4084
change lambda to def
mantepse Feb 11, 2023
e7e063d
Merge branch 'develop' into develop
mantepse Feb 13, 2023
dc3009a
reviewer's suggestions
mantepse Feb 13, 2023
a457b99
Merge branch 'develop' of github.com:mantepse/sage into develop
mantepse Feb 13, 2023
6a738b6
Merge branch 'develop' into develop
mantepse Feb 13, 2023
cb2c82a
Merge branch 'develop' into develop
mantepse Feb 20, 2023
109f9e4
Merge branch 'develop' into develop
mantepse Mar 11, 2023
f87c437
sort result of doctest to avoid random failures
mantepse Mar 11, 2023
a72bd65
Merge pull request #1 from mantepse/bijectionist
mantepse Mar 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
change lambda to def
  • Loading branch information
mantepse committed Feb 11, 2023
commit 24e408410c55144abb075f402eb0afe354646f13
114 changes: 57 additions & 57 deletions src/sage/combinat/bijectionist.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@

sage: N = 3
sage: A = B = [pi for n in range(N+1) for pi in Permutations(n)]
sage: alpha1 = lambda p: len(p.weak_excedences())
sage: alpha2 = lambda p: len(p.fixed_points())
sage: beta1 = lambda p: len(p.descents(final_descent=True)) if p else 0
sage: beta2 = lambda p: len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1])
sage: def alpha1(p): return len(p.weak_excedences())
sage: def alpha2(p): return len(p.fixed_points())
sage: def beta1(p): return len(p.descents(final_descent=True)) if p else 0
sage: def beta2(p): return len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1])
sage: tau = Permutation.longest_increasing_subsequence_length
sage: def rotate_permutation(p):
....: cycle = Permutation(tuple(range(1, len(p)+1)))
Expand Down Expand Up @@ -125,7 +125,7 @@
sage: N = 8;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
sage: N = 8;
sage: N = 8

sage: A = [SetPartition(d.to_noncrossing_partition()) for n in range(N) for d in DyckWords(n)]
sage: B = [t for n in range(1, N+1) for t in OrderedTrees(n)]
sage: theta = lambda m: SetPartition([[i % m.size() + 1 for i in b] for b in m])
sage: def theta(m): return SetPartition([[i % m.size() + 1 for i in b] for b in m])

The following code is equivalent to ``tau = findstat(397)``::

Expand Down Expand Up @@ -195,7 +195,7 @@
TESTS::

sage: N = 4; A = B = [permutation for n in range(N) for permutation in Permutations(n)]
sage: theta = lambda pi: Permutation([x+1 if x != len(pi) else 1 for x in pi[-1:]+pi[:-1]])
sage: def theta(pi): return Permutation([x+1 if x != len(pi) else 1 for x in pi[-1:]+pi[:-1]])
sage: def tau(pi):
....: n = len(pi)
....: return sum([1 for i in range(1, n+1) for j in range(1, n+1)
Expand All @@ -213,9 +213,9 @@
A test including intertwining relations::

sage: N = 2; A = B = [dyck_word for n in range(N+1) for dyck_word in DyckWords(n)]
sage: alpha = lambda D: (D.area(), D.bounce())
sage: beta = lambda D: (D.bounce(), D.area())
sage: tau = lambda D: D.number_of_touch_points()
sage: def alpha(D): return (D.area(), D.bounce())
sage: def beta(D): return (D.bounce(), D.area())
sage: def tau(D): return D.number_of_touch_points()

The following looks correct::

Expand Down Expand Up @@ -263,9 +263,9 @@
Repeating some tests, but using the constructor instead of set_XXX() methods:

sage: N = 2; A = B = [dyck_word for n in range(N+1) for dyck_word in DyckWords(n)]
sage: alpha = lambda D: (D.area(), D.bounce())
sage: beta = lambda D: (D.bounce(), D.area())
sage: tau = lambda D: D.number_of_touch_points()
sage: def alpha(D): return (D.area(), D.bounce())
sage: def beta(D): return (D.bounce(), D.area())
sage: def tau(D): return D.number_of_touch_points()

sage: bij = Bijectionist(A, B, tau, alpha_beta=((lambda d: d.semilength(), lambda d: d.semilength()),))
sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))):
Expand All @@ -276,8 +276,8 @@
Constant blocks::

sage: A = B = 'abcd'
sage: pi = lambda p1, p2: 'abcdefgh'[A.index(p1) + A.index(p2)]
sage: rho = lambda s1, s2: (s1 + s2) % 2
sage: def pi(p1, p2): return 'abcdefgh'[A.index(p1) + A.index(p2)]
sage: def rho(s1, s2): return (s1 + s2) % 2
sage: bij = Bijectionist(A, B, lambda x: B.index(x) % 2, P=[['a', 'c']], pi_rho=((2, pi, rho),))
sage: list(bij.solutions_iterator())
[{'a': 0, 'b': 1, 'c': 0, 'd': 1}]
Expand All @@ -298,7 +298,7 @@

Intertwining relations::

sage: concat = lambda p1, p2: Permutation(p1 + [i + len(p1) for i in p2])
sage: def concat(p1, p2): return Permutation(p1 + [i + len(p1) for i in p2])

sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)]
sage: bij = Bijectionist(A, B, Permutation.number_of_fixed_points, alpha_beta=((len, len),), pi_rho=((2, concat, lambda x, y: x + y),))
Expand All @@ -311,9 +311,9 @@
Statistics::

sage: N = 4; A = B = [permutation for n in range(N) for permutation in Permutations(n)]
sage: wex = lambda p: len(p.weak_excedences())
sage: fix = lambda p: len(p.fixed_points())
sage: des = lambda p: len(p.descents(final_descent=True)) if p else 0
sage: def wex(p): return len(p.weak_excedences())
sage: def fix(p): return len(p.fixed_points())
sage: def des(p): return len(p.descents(final_descent=True)) if p else 0
sage: bij = Bijectionist(A, B, fix, alpha_beta=((wex, des), (len, len)))
sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))):
....: print(solution)
Expand Down Expand Up @@ -567,8 +567,8 @@ def set_constant_blocks(self, P):

We now add a map that combines some blocks::

sage: pi = lambda p1, p2: 'abcdefgh'[A.index(p1) + A.index(p2)]
sage: rho = lambda s1, s2: (s1 + s2) % 2
sage: def pi(p1, p2): return 'abcdefgh'[A.index(p1) + A.index(p2)]
sage: def rho(s1, s2): return (s1 + s2) % 2
sage: bij.set_intertwining_relations((2, pi, rho))
sage: list(bij.solutions_iterator())
[{'a': 0, 'b': 1, 'c': 0, 'd': 1}]
Expand Down Expand Up @@ -672,10 +672,10 @@ def set_statistics(self, *alpha_beta):
of fixed points of `S(\pi)` equals `s(\pi)`::

sage: N = 4; A = B = [permutation for n in range(N) for permutation in Permutations(n)]
sage: wex = lambda p: len(p.weak_excedences())
sage: fix = lambda p: len(p.fixed_points())
sage: des = lambda p: len(p.descents(final_descent=True)) if p else 0
sage: adj = lambda p: len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1])
sage: def wex(p): return len(p.weak_excedences())
sage: def fix(p): return len(p.fixed_points())
sage: def des(p): return len(p.descents(final_descent=True)) if p else 0
sage: def adj(p): return len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1])
sage: bij = Bijectionist(A, B, fix)
sage: bij.set_statistics((wex, des), (len, len))
sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))):
Expand Down Expand Up @@ -708,9 +708,9 @@ def set_statistics(self, *alpha_beta):
Calling ``set_statistics`` without arguments should restore the previous state::

sage: N = 3; A = B = [permutation for n in range(N) for permutation in Permutations(n)]
sage: wex = lambda p: len(p.weak_excedences())
sage: fix = lambda p: len(p.fixed_points())
sage: des = lambda p: len(p.descents(final_descent=True)) if p else 0
sage: def wex(p): return len(p.weak_excedences())
sage: def fix(p): return len(p.fixed_points())
sage: def des(p): return len(p.descents(final_descent=True)) if p else 0
sage: bij = Bijectionist(A, B, fix)
sage: bij.set_statistics((wex, des), (len, len))
sage: for solution in bij.solutions_iterator():
Expand Down Expand Up @@ -783,10 +783,10 @@ def statistics_fibers(self):

sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)]
sage: tau = Permutation.longest_increasing_subsequence_length
sage: wex = lambda p: len(p.weak_excedences())
sage: fix = lambda p: len(p.fixed_points())
sage: des = lambda p: len(p.descents(final_descent=True)) if p else 0
sage: adj = lambda p: len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1])
sage: def wex(p): return len(p.weak_excedences())
sage: def fix(p): return len(p.fixed_points())
sage: def des(p): return len(p.descents(final_descent=True)) if p else 0
sage: def adj(p): return len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1])
sage: bij = Bijectionist(A, B, tau)
sage: bij.set_statistics((len, len), (wex, des), (fix, adj))
sage: table([[key, AB[0], AB[1]] for key, AB in bij.statistics_fibers().items()])
Expand Down Expand Up @@ -828,10 +828,10 @@ def statistics_table(self, header=True):

sage: A = B = [permutation for n in range(4) for permutation in Permutations(n)]
sage: tau = Permutation.longest_increasing_subsequence_length
sage: wex = lambda p: len(p.weak_excedences())
sage: fix = lambda p: len(p.fixed_points())
sage: des = lambda p: len(p.descents(final_descent=True)) if p else 0
sage: adj = lambda p: len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1])
sage: def wex(p): return len(p.weak_excedences())
sage: def fix(p): return len(p.fixed_points())
sage: def des(p): return len(p.descents(final_descent=True)) if p else 0
sage: def adj(p): return len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1])
sage: bij = Bijectionist(A, B, tau)
sage: bij.set_statistics((wex, des), (fix, adj))
sage: a, b = bij.statistics_table()
Expand Down Expand Up @@ -1193,8 +1193,8 @@ def set_distributions(self, *elements_distributions):
Another example with statistics::

sage: bij = Bijectionist(A, B, tau)
sage: alpha = lambda p: p(1) if len(p) > 0 else 0
sage: beta = lambda p: p(1) if len(p) > 0 else 0
sage: def alpha(p): return p(1) if len(p) > 0 else 0
sage: def beta(p): return p(1) if len(p) > 0 else 0
sage: bij.set_statistics((alpha, beta), (len, len))
sage: for sol in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))):
....: print(sol)
Expand Down Expand Up @@ -1304,7 +1304,7 @@ def set_intertwining_relations(self, *pi_rho):
of the second permutation by the length of the first
permutation::

sage: concat = lambda p1, p2: Permutation(p1 + [i + len(p1) for i in p2])
sage: def concat(p1, p2): return Permutation(p1 + [i + len(p1) for i in p2])

We may be interested in statistics on permutations which are
equidistributed with the number of fixed points, such that
Expand Down Expand Up @@ -1496,7 +1496,7 @@ def _forced_constant_blocks(self):

sage: N = 4
sage: A = B = [permutation for n in range(2, N) for permutation in Permutations(n)]
sage: tau = lambda p: p[0] if len(p) else 0
sage: def tau(p): return p[0] if len(p) else 0
sage: add_n = lambda p1: Permutation(p1 + [1 + len(p1)])
sage: add_1 = lambda p1: Permutation([1] + [1 + i for i in p1])
sage: bij = Bijectionist(A, B, tau)
Expand Down Expand Up @@ -1528,8 +1528,8 @@ def _forced_constant_blocks(self):
sage: bij.constant_blocks()
{{[2, 3, 1], [3, 1, 2]}}

sage: concat = lambda p1, p2: Permutation(p1 + [i + len(p1) for i in p2])
sage: union = lambda p1, p2: Partition(sorted(list(p1) + list(p2), reverse=True))
sage: def concat(p1, p2): return Permutation(p1 + [i + len(p1) for i in p2])
sage: def union(p1, p2): return Partition(sorted(list(p1) + list(p2), reverse=True))
sage: bij.set_intertwining_relations((2, concat, union))

In this case we do not discover constant blocks by looking at the intertwining_relations only::
Expand All @@ -1546,10 +1546,10 @@ def _forced_constant_blocks(self):

sage: N = 4
sage: A = B = [permutation for n in range(N + 1) for permutation in Permutations(n)]
sage: alpha1 = lambda p: len(p.weak_excedences())
sage: alpha2 = lambda p: len(p.fixed_points())
sage: beta1 = lambda p: len(p.descents(final_descent=True)) if p else 0
sage: beta2 = lambda p: len([e for (e, f) in zip(p, p[1:] + [0]) if e == f + 1])
sage: def alpha1(p): return len(p.weak_excedences())
sage: def alpha2(p): return len(p.fixed_points())
sage: def beta1(p): return len(p.descents(final_descent=True)) if p else 0
sage: def beta2(p): return len([e for (e, f) in zip(p, p[1:] + [0]) if e == f + 1])
sage: tau = Permutation.longest_increasing_subsequence_length
sage: def rotate_permutation(p):
....: cycle = Permutation(tuple(range(1, len(p) + 1)))
Expand Down Expand Up @@ -1826,7 +1826,7 @@ def minimal_subdistributions_iterator(self):
Another example::

sage: N = 2; A = B = [dyck_word for n in range(N+1) for dyck_word in DyckWords(n)]
sage: tau = lambda D: D.number_of_touch_points()
sage: def tau(D): return D.number_of_touch_points()
sage: bij = Bijectionist(A, B, tau)
sage: bij.set_statistics((lambda d: d.semilength(), lambda d: d.semilength()))
sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))):
Expand Down Expand Up @@ -1974,7 +1974,7 @@ def minimal_subdistributions_blocks_iterator(self):
Another example::

sage: N = 2; A = B = [dyck_word for n in range(N+1) for dyck_word in DyckWords(n)]
sage: tau = lambda D: D.number_of_touch_points()
sage: def tau(D): return D.number_of_touch_points()
sage: bij = Bijectionist(A, B, tau)
sage: bij.set_statistics((lambda d: d.semilength(), lambda d: d.semilength()))
sage: for solution in sorted(list(bij.solutions_iterator()), key=lambda d: tuple(sorted(d.items()))):
Expand Down Expand Up @@ -2143,8 +2143,8 @@ def _preprocess_intertwining_relations(self):

sage: A = B = 'abcd'
sage: bij = Bijectionist(A, B, lambda x: B.index(x) % 2)
sage: pi = lambda p1, p2: 'abcdefgh'[A.index(p1) + A.index(p2)]
sage: rho = lambda s1, s2: (s1 + s2) % 2
sage: def pi(p1, p2): return 'abcdefgh'[A.index(p1) + A.index(p2)]
sage: def rho(s1, s2): return (s1 + s2) % 2
sage: bij.set_intertwining_relations((2, pi, rho))
sage: bij._preprocess_intertwining_relations()
sage: bij._P
Expand Down Expand Up @@ -2909,8 +2909,8 @@ def add_intertwining_relation_constraints(self):

sage: A = B = 'abcd'
sage: bij = Bijectionist(A, B, lambda x: B.index(x) % 2)
sage: pi = lambda p1, p2: 'abcdefgh'[A.index(p1) + A.index(p2)]
sage: rho = lambda s1, s2: (s1 + s2) % 2
sage: def pi(p1, p2): return 'abcdefgh'[A.index(p1) + A.index(p2)]
sage: def rho(s1, s2): return (s1 + s2) % 2
sage: bij.set_intertwining_relations((2, pi, rho))
sage: from sage.combinat.bijectionist import _BijectionistMILP
sage: bmilp = _BijectionistMILP(bij) # indirect doctest
Expand Down Expand Up @@ -3127,8 +3127,8 @@ def _non_copying_intersection(sets):
Note that adding ``[(2,-2,-1), (2,2,-1), (2,-2,1), (2,2,1)]`` makes
it take (seemingly) forever.::
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it take (seemingly) forever.::
it take (seemingly) forever::


sage: c1 = lambda a, b: (a[0]+b[0], a[1]*b[1], a[2]*b[2])
sage: c2 = lambda a: (a[0], -a[1], a[2])
sage: def c1(a, b): return (a[0]+b[0], a[1]*b[1], a[2]*b[2])
sage: def c2(a): return (a[0], -a[1], a[2])

sage: bij = Bijectionist(sum(As, []), sum(Bs, []))
sage: bij.set_statistics((lambda x: x[0], lambda x: x[0]))
Expand Down Expand Up @@ -3168,10 +3168,10 @@ def _non_copying_intersection(sets):
Our benchmark example::

sage: from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition
sage: alpha1 = lambda p: len(p.weak_excedences())
sage: alpha2 = lambda p: len(p.fixed_points())
sage: beta1 = lambda p: len(p.descents(final_descent=True)) if p else 0
sage: beta2 = lambda p: len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1])
sage: def alpha1(p): return len(p.weak_excedences())
sage: def alpha2(p): return len(p.fixed_points())
sage: def beta1(p): return len(p.descents(final_descent=True)) if p else 0
sage: def beta2(p): return len([e for (e, f) in zip(p, p[1:]+[0]) if e == f+1])
sage: gamma = Permutation.longest_increasing_subsequence_length
sage: def rotate_permutation(p):
....: cycle = Permutation(tuple(range(1, len(p)+1)))
Expand Down