Ticket #11339: trac_11339_refcount_singular_rings.patch

File trac_11339_refcount_singular_rings.patch, 11.7 KB (added by vbraun, 10 years ago)

Updated patch

  • sage/libs/singular/groebner_strategy.pxd

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1308487956 -3600
    # Node ID dca107e84dc194d9dae39c5e7e5e24c684dcda34
    # Parent  a48af224839e4eb2555175d15d703ecd81d0b4c1
    Trac #11339: Refcount singular rings
    
    This patch introduces the necessary framework to refcount Singular rings.
    
    diff --git a/sage/libs/singular/groebner_strategy.pxd b/sage/libs/singular/groebner_strategy.pxd
    a b  
    1 from sage.libs.singular.decl cimport skStrategy
     1from sage.libs.singular.decl cimport skStrategy, ring
    22
    3 from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular, MPolynomial_libsingular
     3from sage.rings.polynomial.multi_polynomial_libsingular cimport \
     4    MPolynomialRing_libsingular, MPolynomial_libsingular
    45from sage.structure.sage_object cimport SageObject
    56
    67
    78cdef class GroebnerStrategy(SageObject):
    89    cdef skStrategy *_strat
     10    cdef ring *_parent_ring
    911    cdef MPolynomialRing_libsingular _parent
    1012    cdef object _ideal
    1113
  • sage/libs/singular/groebner_strategy.pyx

    diff --git a/sage/libs/singular/groebner_strategy.pyx b/sage/libs/singular/groebner_strategy.pyx
    a b  
    2727from sage.libs.singular.decl cimport initEcartBBA, enterSBba, initBuchMoraCrit, initS, pNorm, id_Delete, kTest
    2828from sage.libs.singular.decl cimport omfree, redNF, p_Copy, redtailBba
    2929
     30from sage.libs.singular.ring cimport singular_ring_reference, singular_ring_delete
     31
    3032from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal
    3133from sage.rings.polynomial.multi_polynomial_ideal_libsingular cimport sage_ideal_to_singular_ideal
    3234from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular, MPolynomialRing_libsingular, new_MP
     
    4244
    4345    Uses Singular via libSINGULAR
    4446    """
    45     def __init__(self, L):
     47    def __cinit__(self, L):
    4648        """
    4749        Create a new :class:`GroebnerStrategy` object for the
    4850        generators of the ideal ``L``.
     
    100102
    101103        cdef MPolynomialRing_libsingular R = <MPolynomialRing_libsingular>L.ring()
    102104        self._parent = R
     105        self._parent_ring = singular_ring_reference(R._ring)
    103106
    104107        if not R.term_order().is_global():
    105108            raise NotImplementedError("The local case is not implemented yet.")
     
    141144            sage: strat = GroebnerStrategy(I)
    142145            sage: del strat
    143146        """
     147        # WARNING: the Cython class self._parent is no longer accessible!
     148        # see http://trac.sagemath.org/sage_trac/ticket/11339
    144149        cdef ring *oldRing = NULL
    145150        if self._strat:
    146151            omfree(self._strat.sevS)
     
    152157            omfree(self._strat.L)
    153158            omfree(self._strat.B)
    154159            omfree(self._strat.fromQ)
    155             id_Delete(&self._strat.Shdl, self._parent._ring)
     160            id_Delete(&self._strat.Shdl, self._parent_ring)
    156161
    157             if self._parent._ring != currRing:
     162            if self._parent_ring != currRing:
    158163                oldRing = currRing
    159                 rChangeCurrRing(self._parent._ring)
     164                rChangeCurrRing(self._parent_ring)
    160165                delete_skStrategy(self._strat)
    161166                rChangeCurrRing(oldRing)
    162167            else:
    163168                delete_skStrategy(self._strat)
     169        singular_ring_delete(self._parent_ring)
    164170
    165171    def _repr_(self):
    166172        """
  • sage/libs/singular/ring.pxd

    diff --git a/sage/libs/singular/ring.pxd b/sage/libs/singular/ring.pxd
    a b  
    1414
    1515from sage.libs.singular.decl cimport ring
    1616
     17
     18# To work with singular rings, you need to balance singular_ring_new with
     19# singular_ring_delete or singular_ring_reference with
     20# singular_ring_delete. That is, either use one of the two patterns:
     21#
     22# cdef class myclass_new():
     23#     cdef ring* myring;
     24#     cdef __cinit__():
     25#         self.myring = singular_ring_new(...)
     26#     cdef __dealloc__():
     27#         singular_ring_delete(self.myring)
     28#
     29# cdef class myclass_reference():
     30#     cdef ring* refring;
     31#     cdef __cinit__(ring* some_ring):
     32#         self.refring = singular_ring_reference(some_ring)
     33#     cdef __dealloc__():
     34#         singular_ring_delete(self.refring)
     35#
     36# You must not refer to Python/Cython classes in the Cython
     37# destructor, the following is INVALID:
     38#
     39# cdef class myclass_invalid():
     40#     cdef Parent parent;
     41#     cdef __cinit__(Parent p):
     42#         self.parent = p
     43#     cdef __dealloc__():
     44#         do_something_with(self.parent.ring)   # segfault
     45
     46
     47
    1748# create a new singular ring
    1849cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL
    1950
    20 # carefully delete a ring
    21 cdef void singular_ring_delete(ring *ring)
     51# reference an existing ring
     52cdef ring *singular_ring_reference(ring *existing_ring) except NULL
     53
     54# carefully delete a ring once its refcount is zero
     55cdef void singular_ring_delete(ring *doomed)
  • sage/libs/singular/ring.pyx

    diff --git a/sage/libs/singular/ring.pyx b/sage/libs/singular/ring.pyx
    a b  
    5555    "Ws": ringorder_Ws,
    5656}
    5757
     58
     59#############################################################################
    5860cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL:
    5961    """
    6062    Create a new Singular ring over the ``base_ring`` in ``n``
     
    292294    _ring.ShortOut = 0
    293295
    294296    rChangeCurrRing(_ring)
     297   
     298    wrapped_ring = wrap_ring(_ring)
     299    if wrapped_ring in ring_refcount_dict:
     300        raise ValueError('newly created ring already in dictionary??')
     301    ring_refcount_dict[wrapped_ring] = 1
    295302    return _ring
    296303
     304
     305#############################################################################
     306ring_refcount_dict = {}
     307
     308
     309cdef class ring_wrapper_Py(object):
     310    r"""
     311    Python object wrapping the ring pointer.
     312
     313    This is useful to store ring pointers in Python containers.
     314
     315    You must not construct instances of this class yourself, use
     316    :func:`wrap_ring` instead.
     317
     318    EXAMPLES::
     319
     320        sage: from sage.libs.singular.ring import ring_wrapper_Py
     321        sage: ring_wrapper_Py
     322        <type 'sage.libs.singular.ring.ring_wrapper_Py'>
     323    """
     324
     325    cdef ring* _ring
     326
     327    def __cinit__(self):
     328        """
     329        The Cython constructor.
     330       
     331        EXAMPLES::
     332       
     333            sage: from sage.libs.singular.ring import ring_wrapper_Py
     334            sage: t = ring_wrapper_Py(); t
     335            The ring pointer 0x0
     336            sage: TestSuite(t).run()
     337        """
     338        self._ring = NULL
     339
     340    def __hash__(self):
     341        """
     342        Return a hash value so that instances can be used as dictionary keys.
     343
     344        OUTPUT:
     345       
     346        Integer.
     347       
     348        EXAMPLES::
     349
     350            sage: from sage.libs.singular.ring import ring_wrapper_Py
     351            sage: t = ring_wrapper_Py()
     352            sage: t.__hash__()
     353            0
     354        """
     355        return <long>(self._ring)
     356
     357    def __repr__(self):
     358        """
     359        Return a string representation.
     360
     361        OUTPUT:
     362
     363        String.
     364
     365        EXAMPLES::
     366
     367            sage: from sage.libs.singular.ring import ring_wrapper_Py
     368            sage: t = ring_wrapper_Py()
     369            sage: t
     370            The ring pointer 0x0
     371            sage: t.__repr__()
     372            'The ring pointer 0x0'
     373        """
     374        return 'The ring pointer '+hex(self.__hash__())
     375
     376    def __cmp__(ring_wrapper_Py left, ring_wrapper_Py right):
     377        """
     378        Compare ``left`` and ``right`` so that instances can be used as dictionary keys.
     379       
     380        INPUT:
     381
     382        - ``right`` -- a :class:`ring_wrapper_Py`
     383       
     384        OUTPUT:
     385
     386        -1, 0, or +1 depending on whether ``left`` and ``right`` are
     387         less than, equal, or greather than.
     388
     389        EXAMPLES::
     390
     391            sage: from sage.libs.singular.ring import ring_wrapper_Py
     392            sage: t = ring_wrapper_Py()
     393            sage: t.__cmp__(t)
     394            0
     395        """
     396        if left._ring < right._ring:
     397            return -1
     398        if left._ring > right._ring:
     399            return +1
     400        return 0
     401
     402
     403cdef wrap_ring(ring* R):
     404    """
     405    Wrap a C ring pointer into a Python object.
     406
     407    INPUT:
     408
     409    - ``R`` -- a singular ring (a C datastructure).
     410
     411    OUTPUT:
     412
     413    A Python object :class:`ring_wrapper_Py` wrapping the C pointer.
     414    """
     415    cdef ring_wrapper_Py W = ring_wrapper_Py()
     416    W._ring = R
     417    return W
     418
     419
     420cdef ring *singular_ring_reference(ring *existing_ring) except NULL:
     421    """
     422    Refcount the ring ``existing_ring``.
     423
     424    INPUT:
     425
     426    - ``existing_ring`` -- an existing Singular ring.
     427   
     428    OUTPUT:
     429
     430    The same ring with its refcount increased. After calling this
     431    function `n` times, you need to call :func:`singular_ring_delete`
     432    `n+1` times to actually deallocate the ring.
     433
     434    EXAMPLE::
     435
     436        sage: import gc
     437        sage: from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular
     438        sage: from sage.libs.singular.groebner_strategy import GroebnerStrategy
     439        sage: from sage.libs.singular.ring import ring_refcount_dict
     440        sage: n = len(ring_refcount_dict)
     441        sage: prev_rings = set(ring_refcount_dict.keys())
     442        sage: P = MPolynomialRing_libsingular(GF(541), 2, ('x', 'y'), TermOrder('degrevlex', 2))
     443        sage: ring_ptr = set(ring_refcount_dict.keys()).difference(prev_rings).pop()
     444        sage: ring_ptr  # random output
     445        The ring pointer 0x7f78a646b8d0
     446        sage: ring_refcount_dict[ring_ptr]
     447        4
     448
     449        sage: strat = GroebnerStrategy(Ideal([P.gen(0) + P.gen(1)]))
     450        sage: ring_refcount_dict[ring_ptr]
     451        6
     452       
     453        sage: del strat
     454        sage: _ = gc.collect()
     455        sage: ring_refcount_dict[ring_ptr]
     456        4
     457
     458        sage: del P
     459        sage: _ = gc.collect()
     460        sage: ring_ptr in ring_refcount_dict
     461        False
     462    """
     463    if existing_ring==NULL:
     464        raise ValueError('singular_ring_reference(ring*) called with NULL pointer.')
     465    cdef object r = wrap_ring(existing_ring)
     466    refcount = ring_refcount_dict.pop(r)
     467    ring_refcount_dict[r] = refcount+1
     468    return existing_ring
     469
     470
     471#############################################################################
    297472cdef void singular_ring_delete(ring *doomed):
    298473    """
    299474    Carefully deallocate the ring, without changing "currRing" (since
     
    320495        sage: del R3
    321496        sage: _ = gc.collect()
    322497    """
    323     cdef ring *oldRing = NULL
    324     if currRing != doomed:
    325         oldRing = currRing
     498    if doomed==NULL:
     499        print 'singular_ring_delete(ring*) called with NULL pointer.'
     500        # this function is typically called in __deallocate__, so we can't raise an exception
     501        import traceback
     502        traceback.print_stack()
     503
     504    if not ring_refcount_dict:  # arbitrary finalization order when we shut Sage down
     505        return
     506
     507    cdef ring_wrapper_Py r = wrap_ring(doomed)
     508    refcount = ring_refcount_dict.pop(r)
     509    if refcount > 1:
     510        ring_refcount_dict[r] = refcount-1
     511        return
     512
     513    cdef ring *oldRing = currRing
     514    if currRing == doomed:
     515        rDelete(doomed)
     516        currRing = <ring*>NULL
     517    else:
    326518        rChangeCurrRing(doomed)
    327519        rDelete(doomed)
    328520        rChangeCurrRing(oldRing)
    329     else:
    330         (&currRing)[0] = NULL
    331         rDelete(doomed)
    332521   
  • sage/libs/singular/singular-cdefs.pxi

    diff --git a/sage/libs/singular/singular-cdefs.pxi b/sage/libs/singular/singular-cdefs.pxi
    a b  
    716716   
    717717    number *nlInit2(int i, int j)
    718718
     719    # simplify rational number (cancel common factors)
     720   
     721    number *nlNormalize(number *)
     722
    719723    # copy a number
    720724
    721725    number *nlCopy(number *)