Skip to content

Commit d6a2dcc

Browse files
author
Release Manager
committed
gh-36792: Use the system GAP Resurrect #29644 and add an `spkg-configure.m4` for GAP. Some other changes were made to make this possible / nicer: 1. `GAP_LIB_DIR` and `GAP_SHARE_DIR` are merged into `GAP_ROOT_PATHS`. This was suggested by @tornaria and is the right approach, especially now that `GAP_SO` has been removed. Nothing else needs those two directories and GAP itself doesn't care about them -- it only cares about the package search path, i.e. `GAP_ROOT_PATHS`. So changing the variable(s) brings us in line with the way GAP works. 2. We no longer pass the `-r` flag to GAP. Particularly when using the system GAP, we do want the user to be able to install his own packages and run his own initialization. 3. We begin to pass `-A` to GAP. This tells GAP not to autoload the big set of "recommended" packages at start-up, which avoids the inevitable error messages when those packages are not installed on the system GAP. We could check for all of them in `spkg-configure.m4`, but it's a long list, and loading them slows down GAP initialization for no benefit -- Sage itself uses only one such package. Users can autoload them via gaprc or gap.ini in light of (2). 4. After adding `-A` to the initialization, we try to load the PolyCyclic package if it's installed. This is the one "recommended" package that Sage itself uses. 5. The "recommended" packages are all moved from the gap SPKG to gap_packages because we no longer need them, except (maybe) for PolyCyclic. Should keep polycyclic installed by default? The tests all pass without it, but it is used a few places in sagelib. 6. Various stale doctest fixes. 7. The expected output from a few tests has changed. Where possible, I've made the test more robust. In one case I had to drop the printing of a matrix, because if you dig into the source code for GAP's `NormalSubgroups()`, it chooses a `Representative()` inconsistently, and that eventually affects the entries of the matrix. All tests are passing afterwards... except one, a heisenbug: ``` sage -t --warn-long 187.7 --random- seed=96688270013898650573232209016248663009 src/sage/groups/matrix_gps/finitely_generated_gap.py ********************************************************************** File "src/sage/groups/matrix_gps/finitely_generated_gap.py", line 123, in sage.groups.matrix_gps.finitely_generated_gap.FinitelyGeneratedMatrix Group_gap.as_permutation_group Failed example: P == Psmaller Expected: False Got: True ********************************************************************** ``` If anyone knows what's going on there, I'd be grateful. The GAP docs for `SmallerDegreePermutationRepresentation()` say, > The methods used might involve the use of random elements and the permutation representation (or even the degree of the representation) is not guaranteed to be the same for different calls of SmallerDegreePermutationRepresentation. So maybe this isn't really a bug, but I would find it strange if that randomness could mean that sometimes the smaller degree option just wouldn't work at all. Anyway, have at it, and let me know what you think. URL: #36792 Reported by: Michael Orlitzky Reviewer(s): Dima Pasechnik, François Bissey, Gonzalo Tornaría, Matthias Köppe, Michael Orlitzky, Tobias Diez
2 parents 9deea7b + 404f23a commit d6a2dcc

File tree

31 files changed

+412
-178
lines changed

31 files changed

+412
-178
lines changed

build/pkgs/gap/distros/debian.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
gap
12
libgap-dev

build/pkgs/gap/distros/fedora.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
gap
2+
gap-core
3+
gap-devel
4+
gap-libs
5+
libgap

build/pkgs/gap/spkg-configure.m4

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
SAGE_SPKG_CONFIGURE([gap], [
2+
# Default to installing the SPKG, if the check is run at all.
3+
sage_spkg_install_gap=yes
4+
5+
m4_pushdef([GAP_MINVER],["4.12.2"])
6+
7+
SAGE_SPKG_DEPCHECK([ncurses readline zlib], [
8+
AC_PATH_PROG(GAP, gap)
9+
AS_IF([test -n "${GAP}"], [
10+
AC_MSG_CHECKING([for gap version GAP_MINVER or newer])
11+
12+
# GAP will later add the "user" path to the list of root paths
13+
# so long as we don't initialize GAP with -r in Sage. But we
14+
# don't want to include it in the hard-coded list.
15+
GAPRUN="${GAP} -r -q --bare --nointeract -c"
16+
_cmd='Display(GAPInfo.KernelInfo.KERNEL_VERSION);'
17+
GAP_VERSION=$( ${GAPRUN} "${_cmd}" 2>/dev/null )
18+
AX_COMPARE_VERSION(["${GAP_VERSION}"], [ge], [GAP_MINVER], [
19+
AC_MSG_RESULT([yes])
20+
AC_MSG_CHECKING([for gap root paths])
21+
_cmd='Display(JoinStringsWithSeparator(GAPInfo.RootPaths,";"));'
22+
SYS_GAP_ROOT_PATHS=$( ${GAPRUN} "${_cmd}" 2>/dev/null )
23+
AC_MSG_RESULT([$SYS_GAP_ROOT_PATHS])
24+
AS_IF([test -n "${SYS_GAP_ROOT_PATHS}"], [
25+
AC_MSG_CHECKING([for the PrimGrp, SmallGrp, and TransGrp packages])
26+
# Check for a very minimal set of packages without which the
27+
# sage test suite will fail. The crazy thing below is a
28+
# "quadrigraph" for a square bracket.
29+
_cmd="Display(@<:@"
30+
_cmd="${_cmd} TestPackageAvailability(\"PrimGrp\"),"
31+
_cmd="${_cmd} TestPackageAvailability(\"SmallGrp\"),"
32+
_cmd="${_cmd} TestPackageAvailability(\"TransGrp\")"
33+
_cmd="${_cmd} @:>@);"
34+
_output=$( ${GAPRUN} "${_cmd}" 2>/dev/null )
35+
AS_IF([test $? -eq 0], [
36+
AS_CASE([$_output],
37+
[*fail*],[AC_MSG_RESULT([no (at least one package missing)])],[
38+
# default case, i.e. no "fail"
39+
AC_MSG_RESULT([yes])
40+
41+
AC_MSG_CHECKING([if we can link against libgap])
42+
# That was all for the CLI. Now we check for libgap,
43+
# too. There's a long list of headers we need in
44+
# src/sage/libs/gap/gap_includes.pxd, but libgap-api.h
45+
# combined with the version test above should be
46+
# sufficient even on systems where the headers are
47+
# packaged separately.
48+
_old_libs=$LIBS
49+
LIBS="${LIBS} -lgap"
50+
AC_LANG_PUSH([C])
51+
AC_LINK_IFELSE([
52+
AC_LANG_PROGRAM(
53+
[[#include <gap/libgap-api.h>]],
54+
[[
55+
int main(int argc, char** argv) {
56+
GAP_Initialize(0, 0, 0, 0, 0);
57+
return 0;
58+
}
59+
]])
60+
],[
61+
AC_MSG_RESULT([yes])
62+
sage_spkg_install_gap=no
63+
],[
64+
AC_MSG_RESULT([no])
65+
])
66+
AC_LANG_POP
67+
LIBS="${_old_libs}"
68+
])
69+
], [
70+
# The gap command itself failed
71+
AC_MSG_RESULT([no (package check command failed)])
72+
])
73+
])
74+
],[
75+
# Version too old
76+
AC_MSG_RESULT([no])
77+
])
78+
])
79+
])
80+
81+
m4_popdef([GAP_MINVER])
82+
],[],[],[
83+
# This is the post-check phase, where we make sage-conf
84+
# substitutions, in this case of GAP_ROOT_PATHS. We begin with the
85+
# two root paths used by the sage distribution. The '${prefix}' is
86+
# a magic string that sage-conf will replace.
87+
GAP_ROOT_PATHS='${prefix}/lib/gap;${prefix}/share/gap';
88+
89+
AS_IF([test "${sage_spkg_install_gap}" = "no"],[
90+
# If we're using the system GAP, append the system root
91+
# paths to the existing two sage paths.
92+
GAP_ROOT_PATHS="${GAP_ROOT_PATHS};${SYS_GAP_ROOT_PATHS}"
93+
])
94+
95+
AC_SUBST(GAP_ROOT_PATHS, "${GAP_ROOT_PATHS}")
96+
])

build/pkgs/gap/spkg-install.in

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,43 @@ if [ "$SAGE_DEBUG" = yes ] ; then
1616
export CFLAGS="-O0 -g3 -DDEBUG_MASTERPOINTERS -DDEBUG_GLOBAL_BAGS -DDEBUG_FUNCTIONS_BAGS $CFLAGS"
1717
fi
1818

19-
# LDFLAGS hack below needed by Semigroups package
20-
sdh_configure $SAGE_CONFIGURE_GMP LDFLAGS="-pthread" --prefix=$SAGE_LOCAL
19+
sdh_configure $SAGE_CONFIGURE_GMP --prefix=$SAGE_LOCAL
2120
sdh_make
22-
2321
sdh_make_install
24-
# sdh_make install-headers install-libgap
25-
# The 'packagemanager' package expects this https://github.com/gap-packages/PackageManager/issues/105
26-
mkdir -p "$SAGE_LOCAL/lib/gap/bin"
2722

2823
# Install only the minimal packages GAP needs to run
2924
sdh_install pkg/gapdoc pkg/primgrp pkg/smallgrp pkg/transgrp "$GAP_ROOT"/pkg
3025

31-
# Install additional packages that are not strictly required, but that are
32-
# typically "expected" to be loaded: These are the default packages that are
33-
# autoloaded at GAP startup (via the PackagesToLoad UserPreference) with an
34-
# out-of-the-box GAP installation; see
35-
# https://github.com/sagemath/sage/issues/22626#comment:393 for discussion on this
36-
#
37-
# Also include atlasrep which is a dependency of tomlib
26+
# Install additional packages that are automatically loaded in the
27+
# default GAP configuration. The list can be found in lib/package.gi
28+
# as part of the "PackagesToLoad" user preference. Also include
29+
# atlasrep because it is a dependency of tomlib.
3830
sdh_install \
31+
pkg/alnuth \
3932
pkg/atlasrep \
40-
pkg/autodoc \
4133
pkg/autpgrp \
42-
pkg/alnuth \
4334
pkg/crisp \
4435
pkg/ctbllib \
4536
pkg/factint \
4637
pkg/fga \
4738
pkg/irredsol \
4839
pkg/laguna \
49-
pkg/packagemanager \
5040
pkg/polenta \
5141
pkg/polycyclic \
52-
pkg/radiroot \
5342
pkg/resclasses \
5443
pkg/sophus \
5544
pkg/tomlib \
56-
pkg/utils \
5745
"$GAP_ROOT"/pkg
5846

47+
# Finally, install packagemanager for the people who reject both
48+
# sage's and their system's package managers. We have to create
49+
# the local bin directory first:
50+
#
51+
# https://github.com/gap-packages/PackageManager/issues/105
52+
#
53+
mkdir -p "$SAGE_LOCAL/lib/gap/bin"
54+
sdh_install pkg/packagemanager "$GAP_ROOT"/pkg
55+
5956
# TODO: This seems unnecessary--we are already installing all of doc/ to
6057
# GAP_ROOT, which is necessary for some functionality in GAP to work. Do
6158
# we need this? Maybe doc/gap could just be a symlink to gap/doc??

build/pkgs/gap_packages/SPKG.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@ Description
77
Several "official" and "undeposited" GAP packages available from
88
https://www.gap-system.org/Packages/packages.html
99

10+
Installing this SPKG will install the corresponding GAP packages, but
11+
before you can use them in Sage, they still have to be loaded into
12+
either the GAP interface or libgap::
13+
14+
sage: gap.eval('LoadPackage("Grape")') # optional - gap_packages
15+
'true'
16+
sage: libgap.LoadPackage("Grape") # optional - gap_packages
17+
true
18+
19+
Those correspond to::
20+
21+
gap> LoadPackage("Grape");
22+
23+
within the GAP interface and libgap, respectively.
1024

1125
Upstream Contact
1226
----------------

build/pkgs/gap_packages/spkg-install.in

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,34 @@
1-
GAP_ROOT="$SAGE_LOCAL/lib/gap"
2-
PKG_DIR="$GAP_ROOT/pkg"
1+
# Ask GAP for the directory where sysinfo.gap lives. This is to
2+
# support system GAP installations. This root-path gathering
3+
# command is borrowed from gap's spkg-configure.m4 and modified
4+
# to separate the paths with spaces.
5+
GAPRUN="gap -r -q --bare --nointeract -c"
6+
_cmd='Display(JoinStringsWithSeparator(GAPInfo.RootPaths," "));'
7+
GAP_ROOT_PATHS=$(${GAPRUN} "${_cmd}")
8+
9+
# Loop though GAP_ROOT_PATHS looking for sysinfo.gap
10+
GAP_ROOT=""
11+
for grp in $GAP_ROOT_PATHS; do
12+
if [ -f "${grp}/sysinfo.gap" ]; then
13+
GAP_ROOT=$grp
14+
echo "found GAP root $GAP_ROOT"
15+
break
16+
fi
17+
done
18+
19+
# Try the old sage default if nothing else worked.
20+
if [ -z "$GAP_ROOT" ]; then
21+
GAP_ROOT="$SAGE_LOCAL/lib/gap"
22+
echo "falling back to GAP root $GAP_ROOT"
23+
fi
24+
25+
# And finally, throw an error ASAP if the build is going to fail anyway.
26+
if [ ! -f "${GAP_ROOT}/sysinfo.gap" ]; then
27+
sdh_die "no sysinfo.gap in your gap root"
28+
fi
29+
30+
# Where to install these packages
31+
PKG_DIR="$SAGE_LOCAL/lib/gap/pkg"
332

433
PKG_SRC_DIR="$(pwd)/src/pkg"
534
cd "$PKG_SRC_DIR"
@@ -12,6 +41,7 @@ cd "$PKG_SRC_DIR"
1241

1342
sdh_install \
1443
aclib \
44+
autodoc \
1545
corelg \
1646
crime \
1747
cryst \
@@ -31,11 +61,13 @@ sdh_install \
3161
polymaking \
3262
qpa \
3363
quagroup \
64+
radiroot \
3465
repsn \
3566
singular \
3667
sla \
3768
sonata \
3869
toric \
70+
utils \
3971
"$PKG_DIR"
4072

4173
install_compiled_pkg()

pkgs/sage-conf/_sage_conf/_conf.py.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ VERSION = "@PACKAGE_VERSION@"
99
SAGE_LOCAL = "@prefix@"
1010
SAGE_ROOT = "@SAGE_ROOT@"
1111

12+
# The semicolon-separated list of GAP root paths. This is the list of
13+
# locations that are searched for GAP packages. This is passed directly
14+
# to GAP via the -l flag.
15+
GAP_ROOT_PATHS = "@GAP_ROOT_PATHS@".replace('${prefix}', SAGE_LOCAL)
16+
1217
# The path to the standalone maxima executable.
1318
MAXIMA = "@SAGE_MAXIMA@".replace('${prefix}', SAGE_LOCAL)
1419

src/bin/sage

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,9 @@ fi
628628

629629
if [ "$1" = '-gap' -o "$1" = '--gap' ]; then
630630
shift
631-
exec gap "$@"
631+
# Use "-A" to avoid warnings about missing packages. The gap
632+
# interface and libgap within sage both already do this.
633+
exec gap -A "$@"
632634
fi
633635

634636
if [ "$1" = '-gap3' -o "$1" = '--gap3' ]; then

src/doc/en/constructions/groups.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,8 @@ Here's another way, working more directly with GAP::
180180
sage: print(gap.eval("normal := NormalSubgroups( G )"))
181181
[ Alt( [ 1 .. 5 ] ), Group(()) ]
182182
sage: G = gap.new("DihedralGroup( 10 )")
183-
sage: G.NormalSubgroups()
184-
[ Group( [ f1, f2 ] ), Group( [ f2 ] ), Group( <identity> of ... ) ]
183+
sage: G.NormalSubgroups().SortedList()
184+
[ Group( <identity> of ... ), Group( [ f2 ] ), Group( [ f1, f2 ] ) ]
185185
sage: print(gap.eval("G := SymmetricGroup( 4 )"))
186186
Sym( [ 1 .. 4 ] )
187187
sage: print(gap.eval("normal := NormalSubgroups( G );"))

src/doc/en/prep/Quickstarts/Abstract-Algebra.rst

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,13 @@ rather than just a list of numbers. This can be very powerful.
8383

8484
::
8585

86-
sage: for K in D.normal_subgroups():
86+
sage: len(D.normal_subgroups())
87+
7
88+
sage: for K in sorted(D.normal_subgroups()):
8789
....: print(K)
88-
Subgroup generated by [(1,2,3,4,5,6,7,8), (1,8)(2,7)(3,6)(4,5)] of (Dihedral group of order 16 as a permutation group)
89-
Subgroup generated by [(1,2,3,4,5,6,7,8), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group)
90-
Subgroup generated by [(1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8), (1,8)(2,7)(3,6)(4,5)] of (Dihedral group of order 16 as a permutation group)
91-
Subgroup generated by [(2,8)(3,7)(4,6), (1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group)
92-
Subgroup generated by [(1,3,5,7)(2,4,6,8), (1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group)
93-
Subgroup generated by [(1,5)(2,6)(3,7)(4,8)] of (Dihedral group of order 16 as a permutation group)
9490
Subgroup generated by [()] of (Dihedral group of order 16 as a permutation group)
91+
...
92+
Subgroup generated by [(1,2,3,4,5,6,7,8), (1,8)(2,7)(3,6)(4,5)] of (Dihedral group of order 16 as a permutation group)
9593

9694
We can access specific subgroups if we know the generators as a
9795
permutation group.

0 commit comments

Comments
 (0)