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

more libgap in permutation groups ; get rid of _libgap_init_ #36889

Merged
merged 7 commits into from
Jan 14, 2024

Conversation

fchapoton
Copy link
Contributor

Moving forward from gap pexpect interface to libgap interface :

  • using more libgap in the permutation groups code

  • get rid of the barely used _libgap_init_ method in favor of the unique _gap_init_ method.

📝 Checklist

  • The title is concise, informative, and self-explanatory.
  • The description explains in detail what this PR is about.
  • I have created tests covering the changes.

@@ -123,20 +125,20 @@ def __init__(self, G, values):
if isinstance(values, GapElement) and gap.IsClassFunction(values):
self._gap_classfunction = values
else:
self._gap_classfunction = gap.ClassFunction(G, list(values))
self._gap_classfunction = gap.ClassFunction(G, gap(values))
Copy link
Member

Choose a reason for hiding this comment

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

What is the point of calling gap() here? This is a call to pexpect GAP, what were getting rid of, right?

Copy link
Contributor Author

@fchapoton fchapoton Dec 17, 2023

Choose a reason for hiding this comment

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

Well, this is inside Classfunction_gap. I have made so that Classfunction now calls ClassFunction_libgap by default, unless the second argument is a GapPexpect element.

Of course, it would be better to get rid completely of Classfunction_gap but maybe in another ticket ?

Do you have any idea about the failing doctests in class_function.py ?

Copy link
Member

Choose a reason for hiding this comment

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

Do you have any idea about the failing doctests in class_function.py ?

it comes from the fact that GAP operates on characters associated to a character table,
not to a group, and is unable to identify these tables for $\chi_1$ and $\chi_2$ in the 1st failing test.
Not clear how to fix this easily.

sage: chi1 = ClassFunction(G, [3, 1, -1, 0, -1])
sage: isinstance(chi1, ClassFunction_libgap)
True
sage: chi2 = ClassFunction(G, [1, -1, 1, 1, -1])
sage: isinstance(chi2, ClassFunction_libgap)
True
sage: chi1._gap_classfunction
ClassFunction( CharacterTable( Sym( [ 1 .. 4 ] ) ), [ 3, 1, -1, 0, -1 ] )
sage: chi2._gap_classfunction
ClassFunction( CharacterTable( Sym( [ 1 .. 4 ] ) ), [ 1, -1, 1, 1, -1 ] )
sage: chi1._gap_classfunction*chi2._gap_classfunction
---------------------------------------------------------------------------
GAPError                                  Traceback (most recent call last)
Cell In[11], line 1
----> 1 chi1._gap_classfunction*chi2._gap_classfunction

File /mnt/opt/Sage/sage-clang/src/sage/structure/element.pyx:1513, in sage.structure.element.Element.__mul__()
   1511 cdef int cl = classify_elements(left, right)
   1512 if HAVE_SAME_PARENT(cl):
-> 1513     return (<Element>left)._mul_(right)
   1514 if BOTH_ARE_ELEMENT(cl):
   1515     return coercion_model.bin_op(left, right, mul)

File /mnt/opt/Sage/sage-clang/src/sage/libs/gap/element.pyx:1056, in sage.libs.gap.element.GapElement._mul_()
   1054 try:
   1055     sig_GAP_Enter()
-> 1056     sig_on()
   1057     result = GAP_PROD(self.value, (<GapElement>right).value)
   1058     sig_off()

GAPError: Error, no product of class functions of different tables

@dimpase
Copy link
Member

dimpase commented Dec 17, 2023

there also seems to be a disconnect between Sage's conjugacy classes of $S_n$ and underlying (lib)GAP.
One has to tell the underlying GAP that these is the classes to use, otherwise it seems it's just by luck no discrepancies come in here.
E.g. in this failing test for character multiplication it seems it's just a coincidence that GAP uses the same ordering of conjugacy classes as in G.conjugacy_classes().

@fchapoton
Copy link
Contributor Author

fchapoton commented Dec 21, 2023

the failure can be traced to the fact that the underlying character tables are not identical:

sage: ct1 = chi1._libgap_().UnderlyingCharacterTable()
sage: ct2 = chi2._libgap_().UnderlyingCharacterTable()
sage: ct1.IsIdenticalObj(ct2)
false

although they share the same group but not quite :

sage: g1=ct1.UnderlyingGroup()
sage: g2=ct2.UnderlyingGroup()
sage: g1.IsIdenticalObj(g2)
false

see https://github.com/gap-system/gap/blob/master/lib/ctblfuns.gi

@fchapoton
Copy link
Contributor Author

fchapoton commented Dec 21, 2023

and one can find that

sage: S = SymmetricGroup(4)
sage: g1 = S._libgap_()
sage: g2 = S._libgap_()
sage: g1.IsIdenticalObj(g2)
false

@dimpase
Copy link
Member

dimpase commented Dec 21, 2023

this is very strange. I would expect the 1st call to _libgap_() to create a record in S, and subsequent calls to reuse it

@fchapoton
Copy link
Contributor Author

the good old expect interface behaves better :

sage: S = SymmetricGroup(4)
sage: g1 = S._gap_()
sage: g2 = S._gap_()
sage: g1.IsIdenticalObj(g2)
true

@dimpase
Copy link
Member

dimpase commented Dec 21, 2023

I don't know permgroup.py code.
How about

--- a/src/sage/groups/perm_gps/permgroup.py
+++ b/src/sage/groups/perm_gps/permgroup.py
@@ -684,7 +684,8 @@ class PermutationGroup_generic(FiniteGroup):
         """
         if self._libgap is not None:
             return self._libgap
-        return super()._libgap_()
+        self._libgap = super()._libgap_()
+        return self._libgap
 
     # Override the default _libgap_ to use the caching as self._libgap
     _libgap_ = gap

This fixes this weird false.

@dimpase
Copy link
Member

dimpase commented Dec 21, 2023

now all tests in class_function.py pass. Some noise in doctests of permutation_group.py (same groups, different sets of generators, will fix them now)

@dimpase
Copy link
Member

dimpase commented Dec 21, 2023

OK, I'm not 100% sure about the fix

             sage: G = PermutationGroup([[(1,2,3,4)],[(1,2)]])
             sage: G.strong_generating_system()
             [[(), (1,2)(3,4), (1,3)(2,4), (1,4)(2,3)],
-             [(), (2,4), (2,3,4)], [(), (3,4)], [()]]
+            [(), (2,4,3), (2,3,4)],
+            [(), (3,4)],
+            [()]]

originally one had the sequence of subgroups $A_4$, $S_3$, $S_2$, and now it's
$A_4$, $A_3$, $S_2$. Note that in both cases it's not a sequence of sugroups, each subgroup of the previous - and this contracts to what I know about such systems.
(cf https://en.wikipedia.org/wiki/Strong_generating_set too)

It seems it's a bug, which now manifests itself differently. Something funny is going on, but I don't think it's due to my change.


EDIT
It's actually OK, I think, cause each list $\ell_j$ of permutations shoud be added to
$\ell_{j+1}, \ell_{j+2},\dots$ to generate $H_j$.
So in both cases one has $H_4=id$, $H_3=S_2$, $H_2=S_3$, $H_1=S_4$.

@fchapoton
Copy link
Contributor Author

still one broken doctest in src/sage/algebras/fusion_rings/fusion_double.py that needs to be investigated

@fchapoton
Copy link
Contributor Author

The issue in fusion rings may be caused by the fact that the trivial character no longer comes first in the list :

sage: G = groups.permutation.Cyclic(2)
sage: [list(t) for t in G.irreducible_characters()]
[[1, -1], [1, 1]]

but I am not sure.

@fchapoton
Copy link
Contributor Author

there is indeed a difference of behaviour :


sage: [list(ClassFunction(G,irr)) for irr in G._gap_().Irr()]
[[1, 1], [1, -1]]
sage: [list(ClassFunction(G,irr)) for irr in G._libgap_().Irr()]
[[1, -1], [1, 1]]

@dimpase
Copy link
Member

dimpase commented Dec 22, 2023

I can try to look at it tonight.

@dimpase
Copy link
Member

dimpase commented Dec 22, 2023

Yes, that's in line 426 of src/sage/algebras/fusion_rings/fusion_double.py.

I don't see what they do there, let's ask @dwbump @tscrim

Do you assume any fixed order of the irreducible characters in the character tables?
(e.g. that the trivial character is always 1st ?)

@dimpase
Copy link
Member

dimpase commented Dec 22, 2023

I tried modifying irreducible_characters() and character_table() in permgroup.py so that the trivial character always comes 1st, and it allows this doctest to pass. So, indeed, this appears to be the root cause here.

@dimpase
Copy link
Member

dimpase commented Dec 22, 2023

However, doing such a change in SageMath is bound to cause a discrepancy, as we really don't want G.character_table() and G._libgap_().Irr() to give different orders.

@fchapoton
Copy link
Contributor Author

fchapoton commented Dec 23, 2023

The method _one_basis_ is assuming that 0 is the index of the unit in the fusion ring

@tscrim
Copy link
Collaborator

tscrim commented Dec 24, 2023

I don’t think there is anything else besides the one_basis method that uses that the trivial character is the first one. So it is easy enough to fix the issue by just searching in the list of characters for it.

@dimpase
Copy link
Member

dimpase commented Dec 24, 2023

OK, thanks.

@fchapoton
Copy link
Contributor Author

here is a tentative

@dimpase
Copy link
Member

dimpase commented Dec 27, 2023

as a side job, can we unify irreducible_characters and character_table for permutation groups? Both use libgap's Irr(), probably the latter should use the former instead.

fchapoton and others added 4 commits December 27, 2023 13:40
This fixes weird

sage: S = SymmetricGroup(4)
sage: g1 = S._libgap_()
sage: g2 = S._libgap_()
sage: g1.IsIdenticalObj(g2)
false

(one gets true now)
@dimpase
Copy link
Member

dimpase commented Dec 28, 2023

Let us do the following change:

--- a/src/sage/structure/sage_object.pyx
+++ b/src/sage/structure/sage_object.pyx
@@ -755,7 +755,7 @@ cdef class SageObject:
 
     def _libgap_(self):
         from sage.libs.gap.libgap import libgap
-        return libgap.eval(self._gap_init_())
+        return libgap.eval(self)
 
     def _gp_(self, G=None):
         if G is None:

Your libgap.eval(self._gap_init_()) creates a pexpect GAP handle for every libgap object used in Sage, and then passes it in text form to libgap. This is very inefficient.

Copy link

Documentation preview for this PR (built with commit b20ef4f; changes) is ready! 🎉

Copy link
Member

@dimpase dimpase left a comment

Choose a reason for hiding this comment

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

looks good to me

vbraun pushed a commit to vbraun/sage that referenced this pull request Jan 2, 2024
…gap_init_

    
Moving forward from gap pexpect interface to libgap interface :

- using more libgap in the permutation groups code

- get rid of the barely used `_libgap_init_` method in favor of the
unique `_gap_init_` method.

### 📝 Checklist

- [x] The title is concise, informative, and self-explanatory.
- [x] The description explains in detail what this PR is about.
- [x] I have created tests covering the changes.
    
URL: sagemath#36889
Reported by: Frédéric Chapoton
Reviewer(s): Dima Pasechnik, Frédéric Chapoton
vbraun pushed a commit to vbraun/sage that referenced this pull request Jan 5, 2024
…gap_init_

    
Moving forward from gap pexpect interface to libgap interface :

- using more libgap in the permutation groups code

- get rid of the barely used `_libgap_init_` method in favor of the
unique `_gap_init_` method.

### 📝 Checklist

- [x] The title is concise, informative, and self-explanatory.
- [x] The description explains in detail what this PR is about.
- [x] I have created tests covering the changes.
    
URL: sagemath#36889
Reported by: Frédéric Chapoton
Reviewer(s): Dima Pasechnik, Frédéric Chapoton
@vbraun vbraun merged commit b3d1c67 into sagemath:develop Jan 14, 2024
19 of 20 checks passed
@mkoeppe mkoeppe added this to the sage-10.3 milestone Jan 14, 2024
@fchapoton fchapoton deleted the get_rid_libgap_init branch January 15, 2024 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants