owned this note
owned this note
Published
Linked with GitHub
# List of gap symbols currently used by Sage
```
<sage_root>/src/sage/libs/gap/*.pyx
Header:
<sage_root>/src/sage/libs/gap/*.pxd
sage: import glob, io, re
....: for s in sorted(set(match
....: for file in glob.glob(os.environ['SAGE_ROOT']+"/src/sage/libs/gap/*.pyx")
....: for line in io.open(file)
....: for match in re.findall(r'libGAP_\w+', line) )):
....: print(s)
....:
```
## On parsing GAP commands from SageMath
Currently, the SageMath interface to GAP directly calls into the GAP parser/scanner code; this code has recently been modified quite a bit, breaking this interaction. It would be much better to provide higher level API on the GAP side, which are more robust against future changes. For JupyterGAP, this is also beneficial.
In fact, in GAP 4.10, there is a new kernel function `READ_ALL_COMMANDS` which was added for JuptyerGAP, and which may be useful for SageMath, too; we could also add features you need to it, and/or create another function(s) specifically for SageMath. On the long run, we plan to expose the scanner/parser/executor code with a clear API (also for our own internal use in GAP, e.g. to be able to implement syntax highlighting on the REPL), but that's not a something I'd wait for, so let's be pragmatic on this and at something that's "good enough" now, and replace it with the proper solution once that's ready.
This affects `gap_eval` and `command` in SageMath, and also `src/sage/libs/gap/test/main.c`. There, the following "low-level" GAP symbols are used, which ideally should all be avoided in the final version of the code:
```
libGAP_ExecStatus # ok; typedef; basically alias for size_t
libGAP_ReadEvalResult # does not exist anymore; instead, pass a pointer to ReadEvalCommand / ReadEvalFile; then GAP stores
# the eval result in that location
libGAP_Symbol # now is STATE(Symbol); best to hide it in libgap API (see Match, S_EOF, etc.)
libGAP_STATUS_END # ok; equals 0; return code for ReadEvalCommand
libGAP_S_EOF # ok; but perhaps better to hide it (together with GetSymbol/Match, and Symbol, on the libgap side)
libGAP_S_SEMICOLON
libGAP_BottomLVars # internal
libGAP_GetSymbol # renamed to NextSymbol and made static ; could call Match() instead;
# but would be better to wrap in the libgap API
libGAP_ReadEvalCommand # OK, but signature changed
```
## low level / memory manager
These are used by SageMath's `memory_usage` from `util.pyx`, and, more importantly, for GAP object reference counting (see below).
We'd like to hide them on the GAP side, though,
as we are moving to supporting other garbage
collectors than GASMAN.
What is this really for? ~~General debugging?~~
> [name=Dima] *Sage does ref-counting of all the GAP objects*
> *Namely, it has to prevent GCing of such objects.* > Thus, it sets up a GC callback, and before each GC call it calls `MARK_BAG` to prevent these objects from being GCed. (in `libgap.pyx`)
To accompish this, Sage keeps a refcount dict for all the GAP objects it created, and updates refcount for newly created/deleted objects. (in `element.pyx`)
> > [name=Max Horn][time=Wed, Sep 19, 2018 10:03 AM] Of course, that's clear -- and it can keep using `MARK_BAG` (though it'd be better if the modern name `MarkBag` was used instead; the old is just `#defined` to be an alias). That API is high-level and supported by all garbage collectors. Unlike the *low-level* APIs discussed in this section.
GAP could provide a GAP library API which returns
a list or record with the actual desired
information, to encapsulate use of these
```
libGAP_AllocBags # low level
libGAP_EndBags # low level for memory usage
libGAP_MptrBags
libGAP_OldBags
libGAP_StopBags
libGAP_YoungBags
```
In addition, `print_gasman_objects` uses `libGAP_CallbackForAllBags`.
That is a super low level function, and GAP will never export it as a public API; it is also not available with alternate GC implementations.
This SageMath functions seems to be intended for debugging only. Note that there is a GAP function to do just that: `BagStats` (which could be changed to print the TNAM). Perhaps SageMath could just call that (with some improvements applied, if you like) for your debugging needs?
Finally, `DEBUG_CHECK` calls `libGAP_CheckMasterPointers` which again is internal and won't be part of any public GAP API. But we could provide a general `GAP_CheckInternalState` or whatever function to the GAP library API.
## Enums / TNUMs
A bunch of enums from GAP are used by SageMath, mostly to perform actions based on the the type / tnum of a GAP object. This is in principle OK, though there is one clash between GAP and Python headers, namely `T_INT` (but that can be worked around with some preprocessor trickery).
But in many cases, it is probably better to use GAP functions to perform the tests:
* in `decode_type_number`, just use GAP's `TNAM_OBJ` to cover all TNUMs
* in `make_any_gap_element`, the following can be done in the big if/elif/elif/... construct:
* use `IS_INT()` (new in GAP 4.9) to check for integers
* replace `libGAP_FIRST_RECORD_TNUM <= num <= libGAP_LAST_RECORD_TNUM` by a call to `IS_PREC()`
* remove the `libGAP_FIRST_LIST_TNUM <= num <= libGAP_LAST_LIST_TNUM and libGAP_LEN_PLIST(obj) == 0:`
case, resp. merge it with the `libGAP_IsStringConv` and `libGAP_IS_LIST` cases to handle the length 0 situation, roughly like this (untested; note that I replaced `libGAP_LEN_PLIST` by `libGAP_LEN_LIST`; using the former was actually incorrect here and could lead to undefined behaviour)
```
elif libGAP_IS_LIST(obj):
# GAP strings are lists, too
if libGAP_IS_STRING_REP(obj):
return make_GapElement_String(parent, obj)
# The following check converts GAP lists-of-characters into strings,
# except for empty lists
elif libGAP_LEN_LIST(obj) > 0 and libGAP_IsStringConv(obj)
return make_GapElement_String(parent, obj)
else:
return make_GapElement_List(parent, obj)
```
* all `libGAP_T_FOOBAR` symbols not used by `make_any_gap_element` probably are not needed and can be removed from `gap_includes.pxd`
## Calling GAP functions from SageMath
The following symbols are used by `GapElement_Function.__call__` in `element.pyx`.
```
libGAP_CALL_0ARGS
libGAP_CALL_1ARGS
libGAP_CALL_2ARGS
libGAP_CALL_3ARGS
libGAP_CALL_4ARGS
libGAP_CALL_5ARGS
libGAP_CALL_6ARGS
libGAP_CALL_XARGS
```
I'd avoid all of them, and use GAP's `CallFuncList()` instead (already present in GAP 4.8). That causes a small overhead for calls with less than 6 args, but that hopefully shouldn't matter. But if it does, we can discuss alternatives
* libgap-api now has `GAP_CallFuncList` and `GAP_CallFuncArray` to hopefully help with this
## Other symbols used by SageMath
### global variables
```
libGAP_False # ok
libGAP_True # ok
libGAP_Last
libGAP_Last2
libGAP_Last3
```
### Typedefs
```
libGAP_UInt # ok
libGAP_Obj # ok; more or less a void pointer
```
### functions which are probably OK for the API
... although we still may want to wrap them on the GAP side suitably.
```
libGAP_AssGVar
libGAP_AssPRec
libGAP_ASS_LIST
libGAP_CSTR_STRING
libGAP_C_NEW_STRING # helper function ; ok; could get a better name in the API
libGAP_ClearError
libGAP_CollectBags
libGAP_CopyObj
libGAP_DIFF
libGAP_ELM_LIST
libGAP_ELM_REC
libGAP_EQ
libGAP_GET_ELM_PREC
libGAP_GET_RNAM_PREC
libGAP_GVarName
libGAP_INTOBJ_INT
libGAP_INT_INTOBJ
libGAP_IS_FUNC
libGAP_IS_INTOBJ
libGAP_IS_LIST
libGAP_IS_MUTABLE_OBJ
libGAP_IS_REC
libGAP_IS_STRING
libGAP_IsStringConv
libGAP_LEN_LIST
libGAP_LEN_PREC
libGAP_LT
libGAP_MARK_BAG # use MarkBag instead (MARK_BAG is an alias for MarkBag for backwards compatibility)
libGAP_MOD
libGAP_NAME_RNAM
libGAP_NEW_PREC
libGAP_POW
libGAP_PROD
libGAP_QUO
libGAP_RNamName
libGAP_SHALLOW_COPY_OBJ
libGAP_SIZE_BAG # use SIZE_OBJ instead
libGAP_SUM
libGAP_TNAM_OBJ
libGAP_TNUM_BAG # use TNUM_OBJ instead
libGAP_TNUM_OBJ
libGAP_VAL_GVAR
libGAP_VAL_MACFLOAT # OK for converting GAP *machine* floats (of tnum T_MACFLOAT); but note that GAP also supports e.g. mpfr floats
libGAP_ViewObjHandler
```
# Changes from old libGAP
I am told that `libgap_enter()` and `libgap_exit()` guards are not needed. It would be good to get clarity on this. One should try removing them from the old libGAP and see if this flies. (Unless, of course, this is only true for the GAP 4.9 and/or newer).