Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some improvements for braids computations #35214

Merged
merged 51 commits into from
Apr 1, 2023
Merged
Changes from 12 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
670fc7a
conjugating
enriqueartal Feb 26, 2023
74ffbd3
first version of a shorter conjugating_braid
enriqueartal Feb 26, 2023
362108a
adding pure_conjugating_braid method
enriqueartal Feb 26, 2023
960e0b4
some trail white spaces
enriqueartal Feb 26, 2023
5f1952b
add left_normal_form and simplify previous code
enriqueartal Feb 27, 2023
c158a0a
Description and more examples
enriqueartal Feb 27, 2023
5c42b98
extra spaces removed
enriqueartal Feb 27, 2023
eea3f55
Move a comment from TODO to NOTE
enriqueartal Feb 28, 2023
56d33d8
More examples
enriqueartal Feb 28, 2023
690c5d5
- Correct error for conjugating_braid and pure_conjugating_braid when…
enriqueartal Mar 2, 2023
89d50fb
Merge branch 'sagemath:develop' into braids
enriqueartal Mar 3, 2023
eef2f8d
Merge branch 'sagemath:develop' into braids
enriqueartal Mar 13, 2023
fedd35e
Update src/sage/groups/braid.py
enriqueartal Mar 14, 2023
d10343d
Last leftnormalform in pure_conjugating_braid may produce long braids
enriqueartal Mar 14, 2023
b4c0ded
Update src/sage/groups/braid.py
enriqueartal Mar 14, 2023
f343579
more explanations
enriqueartal Mar 14, 2023
536dd75
Check if the conjugating braid is shorter after left normal form
enriqueartal Mar 14, 2023
f8930f1
partial changes for review
enriqueartal Mar 14, 2023
a1de926
use libbraiding algorithm for left_normal_form
enriqueartal Mar 16, 2023
76baf01
indent
enriqueartal Mar 16, 2023
d7a1145
simplify and cached left_normal_form
enriqueartal Mar 17, 2023
2d53fd3
permutation method output in SymmetricGroup
enriqueartal Mar 17, 2023
0691a8d
change == by is
enriqueartal Mar 17, 2023
1fb924a
change the default of permutation method
enriqueartal Mar 18, 2023
4d31ba4
style typo
enriqueartal Mar 18, 2023
05b02e8
more style typos
enriqueartal Mar 18, 2023
6987456
typo finally found
enriqueartal Mar 18, 2023
544832e
documentation
enriqueartal Mar 18, 2023
6e240c9
typo in pure_conjugating_braid
enriqueartal Mar 18, 2023
ee744be
typo in doc
enriqueartal Mar 18, 2023
be8b114
use tscrim code
enriqueartal Mar 19, 2023
905f40a
Merge branch 'sagemath:develop' into braids
enriqueartal Mar 19, 2023
8ab98f2
Update src/sage/groups/braid.py
enriqueartal Mar 20, 2023
6ab2fd4
Update src/sage/groups/braid.py
enriqueartal Mar 20, 2023
3b1f50b
Update src/sage/groups/braid.py
enriqueartal Mar 20, 2023
01ffa05
Update src/sage/groups/braid.py
enriqueartal Mar 20, 2023
10533b8
Update src/sage/groups/braid.py
enriqueartal Mar 20, 2023
9137908
Update src/sage/groups/braid.py
enriqueartal Mar 20, 2023
768aa79
Update src/sage/groups/braid.py
enriqueartal Mar 20, 2023
78ead55
tests
enriqueartal Mar 20, 2023
1689aae
Merge branch 'braids' of github.com:enriqueartal/sage into braids
enriqueartal Mar 20, 2023
cdede32
Update src/sage/groups/braid.py
enriqueartal Mar 20, 2023
3ad1ed1
Added more examples for left_normal_form, conjugating_braid, and pure…
enriqueartal Mar 20, 2023
d92e0e5
There were typos in the docs of reduced_burau_matrix, jones_polynomia…
enriqueartal Mar 25, 2023
c7e4d83
lint problems
enriqueartal Mar 26, 2023
1cd0e79
Merge branch 'sagemath:develop' into braids
enriqueartal Mar 26, 2023
39ce62e
Added blank line and plenty of style spaces
enriqueartal Mar 28, 2023
57f49f1
Some lint typos
enriqueartal Mar 28, 2023
791c9ae
Revert style changes, except blank line
enriqueartal Mar 29, 2023
6041d12
Merge branch 'braids' of github.com:enriqueartal/sage into braids
enriqueartal Mar 29, 2023
30d6be1
Keep only required blank line
enriqueartal Mar 29, 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
153 changes: 145 additions & 8 deletions src/sage/groups/braid.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
from sage.misc.misc_c import prod
from sage.categories.groups import Groups
from sage.groups.free_group import FreeGroup, is_FreeGroup
from sage.groups.perm_gps.permgroup_named import SymmetricGroup
from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing
from sage.matrix.constructor import identity_matrix, matrix
from sage.combinat.permutation import Permutations
Expand All @@ -89,7 +90,7 @@


lazy_import('sage.libs.braiding',
['rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor',
['leftnormalform','rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor',
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
['leftnormalform','rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor',
['leftnormalform', 'rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor',

'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset',
'thurston_type', 'rigidity', 'sliding_circuits'],
feature=PythonModule('sage.libs.braiding', spkg='libbraiding'))
Expand Down Expand Up @@ -1447,6 +1448,33 @@ def annular_khovanov_homology(self, qagrad=None, ring=IntegerRing()):
return {qa: C[qa].homology() for qa in C}
return self.annular_khovanov_complex(qagrad, ring).homology()

def left_normal_form(self):
r"""
Return the left normal form of the braid.

A tuple of simple generators in the left normal form. The first
element is a power of `\Delta`, and the rest are elements of the
natural section lift from the corresponding symmetric group.

EXAMPLES::

sage: B = BraidGroup(4)
sage: b = B([1, 2, 3, -1, 2, -3])
sage: b.left_normal_form()
(s0^-1*s1^-1*s2^-1*s0^-1*s1^-1*s0^-1, s0*s1*s2*s1*s0, s0*s2*s1)
sage: c = B([1])
sage: c.left_normal_form()
(1, s0)
sage: B = BraidGroup(3)
sage: B([1,2,-1]).left_normal_form()
(s0^-1*s1^-1*s0^-1, s1*s0, s0*s1)
sage: B([1,2,1]).left_normal_form()
(s0*s1*s0,)
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

You might consider adding tests for trivial examples.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for your comments. I completed the descriptions and added more examples.

l = leftnormalform(self)
B = self.parent()
return tuple([B.delta()**l[0][0]] + [B(b) for b in l[1:]] )

def _left_normal_form_coxeter(self):
r"""
Return the left normal form of the braid, in permutation form.
Expand All @@ -1471,6 +1499,11 @@ def _left_normal_form_coxeter(self):
(-2, [3, 5, 4, 2, 6, 1], [1, 6, 3, 5, 2, 4], [5, 6, 2, 4, 1, 3],
[3, 2, 4, 1, 5, 6], [1, 5, 2, 3, 4, 6])

.. NOTE::

This method is not used anymore since the above left_normal_form is faster.
It is kept here since it may be used elsewhere.

.. TODO::

Remove this method and use the default one from
Expand Down Expand Up @@ -1517,8 +1550,12 @@ def _left_normal_form_coxeter(self):
return tuple([-delta] + form)

def right_normal_form(self):
"""
r"""
Return the right normal form of the braid.

A tuple of simple generators in the right normal form. The last
Copy link
Contributor

Choose a reason for hiding this comment

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

You could leave the original "Return the right normal form" and have your additions on the next line after a blank line.

element is a power of `\Delta`, and the rest are elements of the
natural section lift from the corresponding symmetric group.

EXAMPLES::

Expand Down Expand Up @@ -1622,19 +1659,43 @@ def conjugating_braid(self, other):
sage: a = B([2, 2, -1, -1])
sage: b = B([2, 1, 2, 1])
sage: c = b * a / b
sage: d = a.conjugating_braid(c)
sage: d * c / d == a
True
sage: d
sage: d1 = a.conjugating_braid(c)
sage: print (d1)
s1*s0
sage: d * a / d == c
sage: d1 * c / d1 == a
True
sage: d1 * a / d1 == c
False
sage: l = sage.groups.braid.conjugatingbraid(a,c)
sage: d1 == B._element_from_libbraiding(l)
True
sage: b = B([2, 2, 2, 2, 1])
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe I'm not understanding something, but you could leave the already existing tests and just add to them below.

sage: c = b * a / b
sage: d1 = a.conjugating_braid(c)
sage: print (len(d1.Tietze()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

PEP8

Suggested change
sage: print (len(d1.Tietze()))
sage: print(len(d1.Tietze()))

and similar below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

7
sage: d1 * c / d1 == a
True
sage: d1 * a / d1 == c
False
sage: d1
s1^2*s0^2*s1^2*s0
sage: l = sage.groups.braid.conjugatingbraid(a,c)
sage: d2 = B._element_from_libbraiding(l)
sage: print (len(d2.Tietze()))
13
sage: print (c.conjugating_braid(b))
None
"""
l = conjugatingbraid(self, other)
if not l:
return None
else:
return self.parent()._element_from_libbraiding(l)
B = self.parent()
n = B.strands()
Copy link
Contributor

Choose a reason for hiding this comment

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

what is the reason for getting the number of strands?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To define the symmetric group

Copy link
Collaborator

Choose a reason for hiding this comment

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

You no longer define it here.

k = int(l[0][0] % 2)
b0 = B.delta() ** k * B(prod(B(a) for a in l[1:]))
return b0
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
n = B.strands()
k = int(l[0][0] % 2)
b0 = B.delta() ** k * B(prod(B(a) for a in l[1:]))
return b0
l[0][0] %= 2
return B._element_from_libbraiding(l)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


def is_conjugated(self, other):
"""
Expand All @@ -1657,6 +1718,82 @@ def is_conjugated(self, other):
"""
l = conjugatingbraid(self, other)
return bool(l)

def pure_conjugating_braid(self, other):
r"""
Return a pure conjugating braid, if it exists.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Add a more detailed description; in particular, including the definition of a pure conjugating braid.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Copy link
Collaborator

Choose a reason for hiding this comment

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

It should not be part of the one-line description. Spend a little bit of time/mathematical notation spelling it out a bit more.

INPUT:

- ``other`` -- the other braid to look for conjugating braid
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


This comment was marked as resolved.

EXAMPLES::

sage: B = BraidGroup(4)
sage: a = B([1, 2, 3])
sage: b = B([3, 2,])
sage: c = b ^ 12 * a / b ^ 12
sage: d1 = a.conjugating_braid(c)
sage: print (len(d1.Tietze()))
30
sage: print (d1.permutation())
[3, 4, 1, 2]
sage: d1 * c / d1 == a
True
sage: d1 * a / d1 == c
False
sage: d2 = a.pure_conjugating_braid(c)
sage: print (len(d2.Tietze()))
24
sage: print (d2.permutation())
[1, 2, 3, 4]
sage: d2 * c / d2 == a
True
sage: print (d2)
(s0*s1*s2^2*s1*s0)^4
sage: print(a.conjugating_braid(b))
None
sage: print(a.pure_conjugating_braid(b))
None
sage: a1=B([1])
sage: a2=B([2])
Copy link
Collaborator

Choose a reason for hiding this comment

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

PEP8

Suggested change
sage: a1=B([1])
sage: a2=B([2])
sage: a1 = B([1])
sage: a2 = B([2])

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

sage: a1.conjugating_braid(a2)
s1*s0
sage: a1.permutation()
[2, 1, 3, 4]
sage: a2.permutation()
[1, 3, 2, 4]
sage: print (a1.pure_conjugating_braid(a2))
None
sage: (a1^2).conjugating_braid(a2^2)
s1*s0
sage: print ((a1^2).pure_conjugating_braid(a2^2))
None
"""
B = self.parent()
n = B.strands()
G = SymmetricGroup(n)
p1 = G(self.permutation())
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would only convert to G when it becomes necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I move the definition of G few lines below, and eliminate some conversions

p2 = G(other.permutation())
if p1 != p2:
return None
b0 = self.conjugating_braid(other)
if not b0:
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
if not b0:
if b0 is not None:

It is better to check explicitly against None.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done but putting if b0 is None

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, right, whoops. Thanks.

return None
p3 = G(b0.permutation().inverse())
if p3.is_one():
return b0
LB = self.centralizer()
LP = [G(a.permutation()) for a in LB]
if p3 not in G.subgroup(LP):
return None
P = p3.word_problem(LP, display = False, as_list = True)
enriqueartal marked this conversation as resolved.
Show resolved Hide resolved
b1 = prod(LB[LP.index(G(a))] ** b for a,b in P)
Copy link
Collaborator

Choose a reason for hiding this comment

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

What happens if P is empty? Add a doctest checking for this corner case (if it can occur).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Additionally, if you make LP a dict from permutations to braids, this becomes faster and you can still pass it off to G.subgroup().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the first question a previous if makes impossible to have P empty. I could not pass the dict to subgroup and even if it would be possible, I think I cannot pass it to word_problem

Copy link
Collaborator

Choose a reason for hiding this comment

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

For the first question a previous if makes impossible to have P empty.

I might say also the previous p3.is_one() also makes that the case. However, again this case should have a doctest.

I could not pass the dict to subgroup and even if it would be possible, I think I cannot pass it to word_problem

You can pass a dict to subgroup:

sage: G = groups.permutation.Symmetric(5)
sage: d = {G.random_element(): i for i in range(5)}
sage: d
{(1,5,2,4): 0, (1,5)(2,3): 1, (1,3,5,2): 2, (1,5,3,2): 3, (1,5)(2,4,3): 4}
sage: G.subgroup(d)
Subgroup generated by [(1,3,5,2), (1,5,3,2), (1,5)(2,3), (1,5)(2,4,3), (1,5,2,4)] of (Symmetric group of order 5! as a permutation group)

Indeed for word_problem, you cannot pass the dict, but you can do list(d), which will have a list in the same order the dict d was constructed (Python3 guarantees this).

b0 = b1 * b0
L = leftnormalform(b0)
k = int(L[0][0] % 2)
b0 = B.delta() ** k * B(prod(B(a) for a in L[1:]))
return b0
enriqueartal marked this conversation as resolved.
Show resolved Hide resolved

def ultra_summit_set(self):
"""
Expand Down