Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Utility functions for libGAP """
#***************************************************************************** # Copyright (C) 2012 Volker Braun <vbraun.name@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #*****************************************************************************
from __future__ import print_function, absolute_import
from cpython.exc cimport PyErr_SetObject from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE from cysignals.signals cimport sig_on, sig_off, sig_error
from sage.interfaces.gap_workspace import prepare_workspace_dir from sage.env import SAGE_LOCAL, GAP_ROOT_DIR from .element cimport *
############################################################################ ### Hooking into the GAP memory management ################################# ############################################################################
cdef class ObjWrapper(object): """ Wrapper for GAP master pointers
EXAMPLES::
sage: from sage.libs.gap.util import ObjWrapper sage: x = ObjWrapper() sage: y = ObjWrapper() sage: x == y True """
def __richcmp__(ObjWrapper self, ObjWrapper other, int op): r""" Comparison wrapped libGAP_Obj.
INPUT:
- ``lhs``, ``rhs`` -- :class:`ObjWrapper`.
- ``op`` -- integer. The comparison operation to be performed.
OUTPUT:
Boolean.
EXAMPLES::
sage: from sage.libs.gap.util import ObjWrapper sage: x = ObjWrapper() sage: y = ObjWrapper() sage: x == y True """ cdef result return self_value < other_value return self_value <= other_value elif op == Py_GT: return self_value > other_value elif op == Py_GE: return self_value >= other_value elif op == Py_NE: return self_value != other_value else: assert False # unreachable
def __hash__(self): """ Return a hash value
EXAMPLES::
sage: from sage.libs.gap.util import ObjWrapper sage: x = ObjWrapper() sage: hash(x) 0 """
cdef ObjWrapper wrap_obj(libGAP_Obj obj): """ Constructor function for :class:`ObjWrapper` """
owned_objects_refcount = dict()
cpdef get_owned_objects(): """ Helper to access the refcount dictionary from Python code """
cdef void reference_obj(libGAP_Obj obj): """ Reference ``obj`` """ global owned_objects_refcount else:
cdef void dereference_obj(libGAP_Obj obj): """ Reference ``obj`` """ global owned_objects_refcount
cdef void gasman_callback(): """ Callback before each GAP garbage collection """ global owned_objects_refcount
############################################################################ ### Initialization of libGAP ############################################### ############################################################################
def gap_root(): """ Find the location of the GAP root install which is stored in the gap startup script.
EXAMPLES::
sage: from sage.libs.gap.util import gap_root sage: gap_root() # random output '/home/vbraun/opt/sage-5.3.rc0/local/gap/latest' """ print('The gap-4.5.5.spkg (or later) seems to be not installed!') gap_sh = open(os.path.join(SAGE_LOCAL, 'bin', 'gap')).read().splitlines() gapdir = filter(lambda dir:dir.strip().startswith('GAP_DIR'), gap_sh)[0] gapdir = gapdir.split('"')[1] gapdir = gapdir.replace('$SAGE_LOCAL', SAGE_LOCAL) return gapdir
cdef initialize(): """ Initialize the GAP library, if it hasn't already been initialized. It is safe to call this multiple times.
TESTS::
sage: libgap(123) # indirect doctest 123 """ global _gap_is_initialized
# Define argv and environ variables, which we will pass in to # initialize GAP. Note that we must pass define the memory pool # size! cdef char* argv[14]
# Initialize GAP and capture any error messages # The initialization just prints error and does not use the error handler raise RuntimeError('libGAP initialization failed\n' + gap_error_msg)
# The error handler is called if a GAP evaluation fails, e.g. 1/0
# Prepare global GAP variable to hold temporary GAP objects global reference_holder
# Finished!
# Save a new workspace if necessary prepare_workspace_dir() from sage.misc.temporary_file import atomic_write with atomic_write(workspace) as f: f.close() gap_eval('SaveWorkspace("{0}")'.format(f.name))
############################################################################ ### Evaluate string in GAP ################################################# ############################################################################
cdef libGAP_Obj gap_eval(str gap_string) except? NULL: r""" Evaluate a string in GAP.
INPUT:
- ``gap_string`` -- string. A valid statement in GAP.
OUTPUT:
The resulting GAP object or NULL+Python Exception in case of error.
EXAMPLES::
sage: libgap.eval('if 4>3 then\nPrint("hi");\nfi') NULL sage: libgap.eval('1+1') # testing that we have successfully recovered 2
sage: libgap.eval('if 4>3 thenPrint("hi");\nfi') Traceback (most recent call last): ... ValueError: libGAP: Syntax error: then expected if 4>3 thenPrint("hi"); fi; ^ sage: libgap.eval('1+1') # testing that we have successfully recovered 2
TESTS:
Check that we fail gracefully if this is called within ``libgap_enter()``::
sage: cython(''' ....: # distutils: libraries = gap ....: from sage.libs.gap.gap_includes cimport libgap_enter ....: libgap_enter() ....: ''') sage: libgap.eval('1+1') Traceback (most recent call last): ... ValueError: libGAP: Entered a critical block twice """ cdef libGAP_ExecStatus status
raise ValueError('did not end with semicolon')
finally:
############################################################################ ### Helper to protect temporary objects from deletion ###################### ############################################################################
cdef void hold_reference(libGAP_Obj obj): """ Hold a reference (inside the GAP kernel) to obj
This ensures that the GAP garbage collector does not delete ``obj``. This works by assigning it to a global variable. This is very simple, but you can't use it to keep two objects alive. Be careful. """ libgap_enter() global reference_holder libGAP_AssGVar(reference_holder, obj) libgap_exit()
############################################################################ ### Error handler ########################################################## ############################################################################
cdef void error_handler(char* msg): """ The libgap error handler
We call ``sig_error()`` which causes us to jump back to the Sage signal handler. Since we wrap libGAP C calls in ``sig_on`` / ``sig_off`` blocks, this then jumps back to the ``sig_on`` where the ``RuntimeError`` we raise here will be seen. """
############################################################################ ### Debug functions ######################################################## ############################################################################
cdef inline void DEBUG_CHECK(libGAP_Obj obj): """ Check that ``obj`` is valid.
This function is only useful for debugging. """ print('DEBUG_CHECK: Null pointer!')
cpdef memory_usage(): """ Return information about the memory usage.
See :meth:`~sage.libs.gap.libgap.Gap.mem` for details. """
cpdef error_enter_libgap_block_twice(): """ Demonstrate that we catch errors from entering a block twice.
EXAMPLES::
sage: from sage.libs.gap.util import error_enter_libgap_block_twice sage: error_enter_libgap_block_twice() Traceback (most recent call last): ... RuntimeError: Entered a critical block twice """ # The exception will be seen by this sig_on() after being # raised by the second libgap_enter(). sig_off() finally: libgap_exit()
cpdef error_exit_libgap_block_without_enter(): """ Demonstrate that we catch errors from omitting libgap_enter.
EXAMPLES::
sage: from sage.libs.gap.util import error_exit_libgap_block_without_enter sage: error_exit_libgap_block_without_enter() Traceback (most recent call last): ... RuntimeError: Called libgap_exit without previous libgap_enter """ sig_off()
############################################################################ ### Auxilliary functions ################################################### ############################################################################
def command(command_string): """ Playground for accessing Gap via libGap.
You should not use this function in your own programs. This is just here for convenience if you want to play with the libgap libray code.
EXAMPLES::
sage: from sage.libs.gap.util import command sage: command('1') Output follows... 1
sage: command('1/0') Traceback (most recent call last): ... ValueError: libGAP: Error, Rational operations: <divisor> must not be zero
sage: command('NormalSubgroups') Output follows... <Attribute "NormalSubgroups">
sage: command('rec(a:=1, b:=2)') Output follows... rec( a := 1, b := 2 ) """ cdef libGAP_ExecStatus status
libgap_call_error_handler()
raise ValueError('command() expects a single statement.')
else: print('No output.')
finally:
|