summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Caruso <xavier.caruso@univ-rennes1.fr>2018-01-17 15:45:43 +0100
committerXavier Caruso <xavier.caruso@univ-rennes1.fr>2018-01-17 15:45:43 +0100
commit8d68a69e4b2e0a562c991e0e7be80a70d74193b6 (patch)
treee7234e4611f094cccf7114a9e91af7ac3dda2bdb
parentFix small bug (diff)
Implementation of ZpLF
-rw-r--r--src/sage/categories/pushout.py2
-rw-r--r--src/sage/rings/padics/all.py4
-rw-r--r--src/sage/rings/padics/factory.py77
-rw-r--r--src/sage/rings/padics/lattice_precision.py1301
-rw-r--r--src/sage/rings/padics/padic_base_leaves.py164
-rw-r--r--src/sage/rings/padics/padic_lattice_element.py101
6 files changed, 989 insertions, 660 deletions
diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py
index 0488899..a969a4c 100644
--- a/src/sage/categories/pushout.py
+++ b/src/sage/categories/pushout.py
@@ -2471,7 +2471,7 @@ class CompletionFunctor(ConstructionFunctor):
return not (self == other)
_real_types = ['Interval','Ball','MPFR','RDF','RLF']
- _dvr_types = [None, 'fixed-mod','floating-point','capped-abs','capped-rel','lazy','lattice-cap']
+ _dvr_types = [None, 'fixed-mod','floating-point','capped-abs','capped-rel','lazy','lattice-cap','lattice-float']
def merge(self, other):
"""
diff --git a/src/sage/rings/padics/all.py b/src/sage/rings/padics/all.py
index cf9be74..8b6d85e 100644
--- a/src/sage/rings/padics/all.py
+++ b/src/sage/rings/padics/all.py
@@ -1,7 +1,7 @@
from __future__ import absolute_import
from .generic_nodes import is_pAdicField, is_pAdicRing
-from .factory import Zp, Zq, Zp as pAdicRing, ZpCR, ZpCA, ZpFM, ZpFP, ZpLC, ZqCR, ZqCA, ZqFM, ZqFP #, ZpL, ZqL
-from .factory import Qp, Qq, Qp as pAdicField, QpCR, QpFP, QpLC, QqCR, QqFP #, QpL, QqL
+from .factory import Zp, Zq, Zp as pAdicRing, ZpCR, ZpCA, ZpFM, ZpFP, ZpLC, ZpLF, ZqCR, ZqCA, ZqFM, ZqFP #, ZpL, ZqL
+from .factory import Qp, Qq, Qp as pAdicField, QpCR, QpFP, QpLC, QpLF, QqCR, QqFP #, QpL, QqL
from .factory import pAdicExtension
from .padic_generic import local_print_mode
from .pow_computer import PowComputer
diff --git a/src/sage/rings/padics/factory.py b/src/sage/rings/padics/factory.py
index 792bc48..0b38892 100644
--- a/src/sage/rings/padics/factory.py
+++ b/src/sage/rings/padics/factory.py
@@ -78,7 +78,8 @@ def _default_show_prec(type, print_mode):
INPUT:
- - ``type`` -- a string: ``'capped-rel'``, ``'capped-abs'``, ``'fixed-mod'``, ``'floating-point'`` or ``'lattice-cap'``
+ - ``type`` -- a string: ``'capped-rel'``, ``'capped-abs'``, ``'fixed-mod'``, ``'floating-point'``,
+ ``'lattice-cap'`` or ``'lattice-float'``
- ``print_mode`` -- a string: ``'series'``, ``'terse'``, ``'val-unit'``, ``'digits'``, ``'bars'``
EXAMPLES::
@@ -272,8 +273,9 @@ class Qp_class(UniqueFactory):
TYPES and PRECISION below.
- ``type`` -- string (default: ``'capped-rel'``) Valid types are
- ``'capped-rel'``, ``'floating-point'`` and ``'lazy'`` (though ``'lazy'`` currently
- doesn't work). See TYPES and PRECISION below
+ ``'capped-rel'``, ``'floating-point'``, ``'lattice-cap'``, ``'lattice-float'``
+ and ``'lazy'`` (though ``'lazy'`` currently doesn't work).
+ See TYPES and PRECISION below
- ``print_mode`` -- string (default: ``None``). Valid modes are 'series',
'val-unit', 'terse', 'digits', and 'bars'. See PRINTING below
@@ -612,7 +614,7 @@ class Qp_class(UniqueFactory):
print_alphabet = print_max_terms
print_max_terms = check
check = True
- return get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_sep, print_alphabet, print_max_terms, show_prec, check, ['capped-rel', 'floating-point', 'lattice-cap'], label, relprec, absprec)
+ return get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_sep, print_alphabet, print_max_terms, show_prec, check, ['capped-rel', 'floating-point', 'lattice-cap', 'lattice-float'], label, relprec, absprec)
def create_object(self, version, key):
"""
@@ -665,13 +667,14 @@ class Qp_class(UniqueFactory):
else:
return pAdicFieldFloatingPoint(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet,
'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name)
- elif type == 'lattice-cap':
+ elif type[:8] == 'lattice-':
+ subtype = type[8:]
if print_mode == 'terse':
- return pAdicFieldLattice(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet,
- 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, label)
+ return pAdicFieldLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet,
+ 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, label)
else:
- return pAdicFieldLattice(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet,
- 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, label)
+ return pAdicFieldLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet,
+ 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, label)
else:
raise ValueError("unexpected type")
@@ -1254,21 +1257,6 @@ def QpFP(p, prec = None, *args, **kwds):
# EXAMPLES::
-def QpLC(p, prec = None, *args, **kwds):
- """
- A shortcut function to create `p`-adic fields with lattice precision.
-
- See :func:`ZpLC` for more information about this model of precision.
-
- EXAMPLES::
-
- sage: R = QpLC(2)
- sage: R
- 2-adic Field with lattice precision
-
- """
- return Qp(p, prec, 'lattice-cap', *args, **kwds)
-
def QqCR(q, prec = None, *args, **kwds):
"""
A shortcut function to create capped relative unramified `p`-adic
@@ -1314,6 +1302,9 @@ def QpLC(p, prec = None, *args, **kwds):
"""
return Qp(p, prec, 'lattice-cap', *args, **kwds)
+def QpLF(p, prec = None, *args, **kwds):
+ return Qp(p, prec, 'lattice-float', *args, **kwds)
+
#######################################################################################################
#
@@ -1341,7 +1332,7 @@ class Zp_class(UniqueFactory):
- ``type`` -- string (default: ``'capped-rel'``) Valid types are
``'capped-rel'``, ``'capped-abs'``, ``'fixed-mod'``,
- ``'floating-point'`` and ``'lattice-cap'``.
+ ``'floating-point'``, ``'lattice-cap'``, ``'lattice-float'``
See TYPES and PRECISION below
- ``print_mode`` -- string (default: ``None``). Valid modes are
@@ -1400,7 +1391,7 @@ class Zp_class(UniqueFactory):
sage: R = ZpLC(17)
sage: x = R(1,10); y = R(1,5)
sage: R.precision()
- Precision Lattice on 2 objects
+ Precision lattice on 2 objects
sage: R.precision().precision_lattice()
[2015993900449 0]
[ 0 1419857]
@@ -1410,11 +1401,12 @@ class Zp_class(UniqueFactory):
::
- There are six types of `p`-adic rings: capped relative rings
+ There are seven types of `p`-adic rings: capped relative rings
(type= ``'capped-rel'``), capped absolute rings
(type= ``'capped-abs'``), fixed modulus rings (type= ``'fixed-mod'``),
- floating point rings (type=``'floating-point'``), lattice capped
- rings (type=``'lattice-cap'``) and lazy rings (type= ``'lazy'``).
+ floating point rings (type=``'floating-point'``), lattice capped rings
+ (type=``'lattice-cap'``), lattice float rings (type=``'lattice-float'``)
+ and lazy rings (type= ``'lazy'``).
In the capped relative case, the relative precision of an element
is restricted to be at most a certain value, specified at the
@@ -1766,7 +1758,8 @@ class Zp_class(UniqueFactory):
print_max_terms = check
check = True
return get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_sep, print_alphabet,
- print_max_terms, show_prec, check, ['capped-rel', 'fixed-mod', 'capped-abs', 'floating-point', 'lattice-cap'],
+ print_max_terms, show_prec, check,
+ ['capped-rel', 'fixed-mod', 'capped-abs', 'floating-point', 'lattice-cap', 'lattice-float'],
label=label, relprec=relprec, absprec=absprec)
def create_object(self, version, key):
@@ -1798,7 +1791,7 @@ class Zp_class(UniqueFactory):
# keys changed in order to reduce irrelevant duplications: e.g. two Zps with print_mode 'series'
# that are identical except for different 'print_alphabet' now return the same object.
key = get_key_base(p, prec, type, print_mode, name, None, print_pos, print_sep, print_alphabet,
- print_max_terms, None, False, ['capped-rel', 'fixed-mod', 'capped-abs', 'lattice-cap'])
+ print_max_terms, None, False, ['capped-rel', 'fixed-mod', 'capped-abs', 'lattice-cap', 'lattice-float'])
try:
obj = self._cache[version, key]()
if obj is not None:
@@ -1818,9 +1811,10 @@ class Zp_class(UniqueFactory):
elif type == 'floating-point':
return pAdicRingFloatingPoint(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet,
'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name)
- elif type == 'lattice-cap':
- return pAdicRingLattice(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet,
- 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, label)
+ elif type[:8] == 'lattice-':
+ subtype = type[8:]
+ return pAdicRingLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet,
+ 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, label)
else:
raise ValueError("unexpected type")
@@ -2646,7 +2640,7 @@ def ZpLC(p, prec=None, *args, **kwds):
sage: R = ZpLC(5, print_mode='terse')
sage: prec = R.precision()
sage: prec
- Precision Lattice on 0 object
+ Precision lattice on 0 object
This instance knows about all elements of the parent, it is
automatically updated when a new element (of this parent) is
@@ -2654,13 +2648,13 @@ def ZpLC(p, prec=None, *args, **kwds):
sage: x = R(3513,10)
sage: prec
- Precision Lattice on 1 object
+ Precision lattice on 1 object
sage: y = R(176,5)
sage: prec
- Precision Lattice on 2 objects
+ Precision lattice on 2 objects
sage: z = R.random_element()
sage: prec
- Precision Lattice on 3 objects
+ Precision lattice on 3 objects
The method :meth:`tracked_elements` provides the list of all
tracked elements::
@@ -2674,10 +2668,10 @@ def ZpLC(p, prec=None, *args, **kwds):
sage: z = 0
sage: prec
- Precision Lattice on 3 objects
+ Precision lattice on 3 objects
sage: prec.del_elements()
sage: prec
- Precision Lattice on 2 objects
+ Precision lattice on 2 objects
The method :meth:`precision_lattice` returns (a matrix defining)
the lattice that models the precision. Here we have::
@@ -2792,6 +2786,9 @@ def ZpLC(p, prec=None, *args, **kwds):
"""
return Zp(p, prec, 'lattice-cap', *args, **kwds)
+def ZpLF(p, prec=None, *args, **kwds):
+ return Zp(p, prec, 'lattice-float', *args, **kwds)
+
#def ZpL(p, prec = DEFAULT_PREC, print_mode = None, halt = DEFAULT_HALT, names = None, print_pos = None,
# print_sep = None, print_alphabet = None, print_max_terms = None, check=True):
# """
diff --git a/src/sage/rings/padics/lattice_precision.py b/src/sage/rings/padics/lattice_precision.py
index afba9a2..e7762cc 100644
--- a/src/sage/rings/padics/lattice_precision.py
+++ b/src/sage/rings/padics/lattice_precision.py
@@ -8,6 +8,8 @@ from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
from sage.rings.infinity import Infinity
+from sage.rings.padics.precision_error import PrecisionError
+
# Class pRational
#################
@@ -58,6 +60,12 @@ class pRational:
val = self._valuation
return self.__class__(self.p, x, exp, valuation=val)
+ def reduce_relative(self, prec):
+ v = self.valuation()
+ if v is Infinity:
+ return self
+ return self.reduce(prec+v)
+
def normalize(self):
if self.x == 0:
self.exponent = 0
@@ -190,8 +198,8 @@ class pRational:
return l
-# Class PrecisionLattice
-########################
+# Helper function
+#################
def list_of_padics(elements):
"""
@@ -206,10 +214,10 @@ def list_of_padics(elements):
sage: R = ZpLC(2)
sage: M = random_matrix(R,2,2)
sage: list_of_padics(M)
- [<weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; to 'pAdicLatticeElement' at 0x...>]
+ [<weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>]
"""
from sage.rings.padics.padic_lattice_element import pAdicLatticeElement
if isinstance(elements, pAdicLatticeElement):
@@ -256,32 +264,18 @@ def format_history(tme, status, timings):
else:
return status
-class PrecisionLattice(UniqueRepresentation, SageObject):
- """
- A class for handling precision lattices which are used to
- track precision in the ZpLC model.
- The precision lattice is stored as a triangular matrix whose
- rows are generators of the lattice.
+class DifferentialPrecisionGeneric(UniqueRepresentation, SageObject):
"""
- # Internal variables:
- # . self._cap
- # a cap for the (working) precision
- # meaning that the precision lattice always contains p^(self._cap)
- # . self._elements
- # list of weak references of elements in this parent
- # . self._lattice
- # an upper triangular matrix over ZZ representing the
- # lattice of precision
- # (its columns are indexed by self._elements)
- # . self._absolute_precisions
- def __init__(self, p, label):
+ A generic class for precision objects obtained by automatic
+ differentiation
+ """
+ def __init__(self, p, type, label):
self._p = p
self._label = label
- self._elements = [ ]
- self._capped = { }
- self._lattice = { }
- self._absolute_precisions = { }
+ self._type = type
+ self._elements = [ ] # Probably better to use a double chained list
+ self._matrix = { }
self._marked_for_deletion = [ ]
self._approx_zero = pRational(p, ZZ(0))
# History
@@ -309,25 +303,25 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
sage: R = ZpLC(2)
sage: R.precision()
- Precision Lattice on ... objects
+ Precision lattice on ... objects
If a label has been specified, it is included in the representation
sage: R = ZpLC(2, label="mylabel")
sage: R.precision()
- Precision Lattice on 0 object (label: mylabel)
+ Precision lattice on 0 object (label: mylabel)
"""
n = len(self._elements)
if self._label is None:
if n > 1:
- return "Precision Lattice on %s objects" % len(self._elements)
+ return "Precision %s on %s objects" % (self._type, len(self._elements))
else:
- return "Precision Lattice on %s object" % len(self._elements)
+ return "Precision %s on %s object" % (self._type, len(self._elements))
else:
if n > 1:
- return "Precision Lattice on %s objects (label: %s)" % (len(self._elements), self._label)
+ return "Precision %s on %s objects (label: %s)" % (self._type, len(self._elements), self._label)
else:
- return "Precision Lattice on %s object (label: %s)" % (len(self._elements), self._label)
+ return "Precision %s on %s object (label: %s)" % (self._type, len(self._elements), self._label)
def prime(self):
"""
@@ -341,6 +335,539 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
"""
return self._p
+ def _index(self, ref):
+ """
+ Return the index of the element whose reference is ``ref``
+ """
+ return self._elements.index(ref)
+
+ def new_element(self):
+ raise NotImplementedError("implement this function is subclasses")
+
+ def mark_for_deletion(self, ref):
+ raise NotImplementedError("implement this function is subclasses")
+
+ def del_elements(self, thresold=None):
+ raise NotImplementedError("implement this function in subclasses")
+
+ def precision_absolute(self, x):
+ raise NotImplementedError("implement this function in subclasses")
+
+ def precision_lattice(self, elements=None):
+ raise NotImplementedError("implement this function in subclasses")
+
+ def number_of_diffused_digits(self, elements=None):
+ """
+ Return the number of diffused digits of precision within a
+ subset of elements.
+
+ NOTE:
+
+ A diffused digit of precision is a known digit which is not
+ located on a single variable but only atppears on a suitable
+ linear combinaison of variables.
+
+ The number of diffused digits of precision quantifies the
+ quality of the approximation of the lattice precision by a
+ jagged precision (that is a precision which is split over
+ all variables).
+
+ We refer to [] for a detail exposition of the notion of
+ diffused digits.
+
+ EXAMPLES::
+
+ sage: R = ZpLC(2)
+ sage: prec = R.precision()
+ sage: x = R(1,10); y = R(1,5)
+ sage: u = x + y
+ sage: v = x - y
+
+ sage: prec.number_of_diffused_digits([x,y])
+ 0
+ sage: prec.number_of_diffused_digits([u,v])
+ 6
+
+ The elements `u` and `v` are known at absolute precision `O(2^5)`.
+ However, the sum `u + v = 2x` is known at precision `O(2^11)`, that
+ is with `6` more digits.
+ That is where the `6` diffused digits of precision comes from.
+
+ Here is another example with matrices::
+
+ sage: M = matrix(R, 2, 2, [R(3,5),R(7,5),R(1,5),R(11,1)])
+ sage: N = M^10
+
+ The next syntax provides as easy way to select an interesting
+ subset of variables (the selected subset consists of the four
+ entries of the matrix ``N``)::
+
+ sage: prec.number_of_diffused_digits(N)
+ 17
+ """
+ M = self.precision_lattice(elements)
+ n = M.nrows()
+ if M.ncols() > n:
+ return Infinity
+ p = self._p
+ diffused = 0
+ for j in range(n):
+ val = minval = M[j,j].valuation(p)
+ for i in range(j):
+ v = M[i,j].valuation(p)
+ if v < minval: minval = v
+ diffused += val - minval
+ return diffused
+
+ def number_of_tracked_elements(self, dead=True):
+ """
+ Return the number of tracked elements through this precision
+ lattice
+
+ INPUT:
+
+ - ``dead`` -- a boolean (default: ``True``); whether dead
+ elements for which the corresponding column is still not
+ erased should be counted or not
+
+ EXAMPLES::
+
+ sage: R = ZpLC(2, label='count')
+ sage: prec = R.precision()
+ sage: x = R(1,10); y = R(1,5)
+ sage: prec.number_of_tracked_elements()
+ 2
+
+ sage: u = x + y
+ sage: v = x - y
+ sage: prec.number_of_tracked_elements()
+ 4
+
+ sage: del x; del y
+ sage: prec.number_of_tracked_elements()
+ 4
+ sage: prec.number_of_tracked_elements(dead=False)
+ 2
+
+ sage: prec.del_elements()
+ sage: prec.number_of_tracked_elements()
+ 2
+ """
+ if dead:
+ return len(self._elements)
+ else:
+ count = 0
+ for x_ref in self._elements:
+ if x_ref() is not None: count += 1
+ return count
+
+ def tracked_elements(self, values=True, dead=True):
+ """
+ Return the list of tracked elements
+
+ INPUT:
+
+ - ``values`` -- a boolean (default: ``True``); if false,
+ the method returns a list of weak references on tracked
+ elements instead
+
+ - ``dead`` -- a boolean (default: ``True``); whether dead
+ elements for which the corresponding column is still not
+ erased should be listed or not
+
+ EXAMPLES::
+
+ sage: R = ZpLC(2, label='tracked')
+ sage: prec = R.precision()
+ sage: x = R(1,10); y = R(1,5)
+ sage: prec.tracked_elements()
+ [1 + O(2^10), 1 + O(2^5)]
+ sage: prec.tracked_elements(values=False)
+ [<weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; dead>]
+ sage: prec.tracked_elements(values=False, dead=False)
+ [<weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>]
+
+ sage: u = x + y
+ sage: v = x - y
+ sage: prec.tracked_elements()
+ [1 + O(2^10), 1 + O(2^5), 2 + O(2^5), O(2^5)]
+ sage: prec.tracked_elements(values=False)
+ [<weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; dead>]
+
+ sage: del x; del y
+ sage: prec.tracked_elements()
+ [None, None, 2 + O(2^5), O(2^5), None]
+ sage: prec.tracked_elements(values=False)
+ [<weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; to 'pAdicLatticeCapElement' at 0x...>,
+ <weakref at 0x...; dead>]
+ """
+ if values:
+ if dead:
+ return [ ref() for ref in self._elements ]
+ else:
+ return [ ref() for ref in self._elements if ref() is not None ]
+ else:
+ if dead:
+ return list(self._elements)
+ else:
+ return [ ref for ref in self._elements if ref() is not None ]
+
+
+ # History
+
+ def history_enable(self):
+ """
+ Enable history.
+
+ We refer to the documentation of the method :meth:`history` for
+ a complete documentation (including examples) about history.
+
+ TESTS::
+
+ sage: R = ZpLC(2, label='history_en')
+ sage: prec = R.precision()
+
+ sage: print(prec.history()) # history is disabled by default
+ Traceback (most recent call last):
+ ...
+ ValueError: History is not tracked
+
+ sage: prec.history_enable()
+ sage: print(prec.history())
+ Timings
+ ---
+
+ .. SEEALSO::
+
+ :meth:`history`, :meth:`history_disable`, :meth:`history_clear`
+ """
+ if self._history is None:
+ self._history_init = ( len(self._elements), list(self._marked_for_deletion) )
+ self._history = [ ]
+
+ def history_disable(self):
+ """
+ Disable history.
+
+ We refer to the documentation of the method :meth:`history` for
+ a complete documentation (including examples) about history.
+
+ TESTS::
+
+ sage: R = ZpLC(2, label='history_dis')
+ sage: prec = R.precision()
+
+ sage: print(prec.history()) # history is disabled by default
+ Traceback (most recent call last):
+ ...
+ ValueError: History is not tracked
+
+ sage: prec.history_enable()
+ sage: print(prec.history())
+ Timings
+ ---
+
+ sage: prec.history_disable()
+ sage: print(prec.history())
+ Traceback (most recent call last):
+ ...
+ ValueError: History is not tracked
+
+ .. SEEALSO::
+
+ :meth:`history`, :meth:`history_enable`, :meth:`history_clear`
+ """
+ self._history = self._history_init = None
+
+ def history_clear(self):
+ """
+ Clear history
+
+ We refer to the documentation of the method :meth:`history` for
+ a complete documentation (including examples) about history.
+
+ TESTS::
+
+ sage: R = ZpLC(2, label='history_clear')
+ sage: prec = R.precision()
+ sage: prec.history_enable()
+
+ sage: x = R(1,10); y = R(1,5)
+ sage: x,y = x+y, x-y
+ sage: print(prec.history())
+ Timings
+ ... oooo
+ ... ~~oo
+
+ When we clear history, only the last line is kept::
+
+ sage: prec.history_clear()
+ sage: print(prec.history())
+ Timings ~~oo
+ --- ~~oo
+
+ sage: del x;
+
+ sage: print(prec.history())
+ Timings ~~oo
+ ... ~~~o
+
+ .. SEEALSO::
+
+ :meth:`history`, :meth:`history_enable`, :meth:`history_disable`
+ """
+ if self._history is None:
+ raise ValueError("History is not tracked")
+ self._history_init = ( len(self._elements), list(self._marked_for_deletion) )
+ self._history = [ ]
+
+ def history(self, compact=True, separate_reduce=False, timings=True, output_type='asciiart'):
+ """
+ Show history
+
+ The history records creations and deletions of elements attached
+ to this precision lattice, together with many timings.
+
+ INPUT:
+
+ - ``compact`` -- a boolean (default: ``True``); if true, all
+ consecutive operations of the same type appear on a single row
+
+ - ``separate_reduce`` -- a boolean (default: ``False``); specify
+ whether partial/full Hermite reduction should be displayed
+ separatedly
+
+ - ``timings`` -- a boolean (default: ``True``); specify whether
+ timings should be displayed
+
+ - ``output_type`` -- only ``asciiart`` is implemented for now.
+
+ IMPORTANT NOTE:
+
+ History is disabled by default.
+ It should then be enabled (through a call to the method :meth:`history_enable`)
+ before use.
+
+ EXAMPLES::
+
+ sage: R = ZpLC(2, label='history_en')
+ sage: prec = R.precision()
+
+ We first enable history::
+
+ sage: prec.history_enable()
+
+ At the beginning, the history is of course empty::
+
+ sage: print(prec.history())
+ Timings
+ ---
+
+ Now we start creating and deleting elements::
+
+ sage: L = [ R.random_element() for _ in range(20) ]
+ sage: for p in range(20):
+ ....: if is_prime(p): L[p] = None
+ sage: prec.del_elements()
+
+ sage: print(prec.history())
+ Timings
+ ... oooooooooooooooooooo
+ ... oo~~o~o~ooo~o~ooo~o~
+ ... oooooooooooo
+
+ The legend is the following::
+ - the symbol ``o`` represents a tracked element
+ - the symbol ``~`` represents an element which is marked for deletion
+
+ On the history, we see:
+ - 1st line: twenty new elements were created
+ (this corresponds to the affectation of the list ``L``)
+ - 2nd line: elements at prime positions were marked for deletion
+ (this corresponds to the ``for`` loop)
+ - 3rd line: the above elements are indeed deleted
+ (this corresponds to the call of the method :meth:`del_elements`
+
+ Here are some variants::
+
+ sage: print(prec.history(timings=False))
+ oooooooooooooooooooo
+ oo~~o~o~ooo~o~ooo~o~
+ oooooooooooo
+
+ sage: print(prec.history(separate_reduce=True))
+ Timings
+ ... oooooooooooooooooooo
+ ... oo~~o~o~ooo~o~ooo~o~
+ ... oo~~o~o~ooo~ooooo
+ ... oo~~o~o~ooo~orrrr
+ ... oo~~o~o~oooooooo
+ ... oo~~o~o~ooorrrrr
+ ... oo~~o~ooooooooo
+ ... oo~~o~orrrrrrrr
+ ... oo~~oooooooooo
+ ... oo~~orrrrrrrrr
+ ... oo~oooooooooo
+ ... oo~rrrrrrrrrr
+ ... oooooooooooo
+ ... oorrrrrrrrrr
+ --- oooooooooooo
+
+ The symbol ``r`` represents a column of the precision matrix which is
+ currently under partial Hermite reduction
+
+ Timings for automatic reduction do not appear because they are included
+ in the timings for deletion.
+
+ The symbol ``R`` is used to symbolize a column which is under full
+ Hermite reduction. Note that full Hermite reduction are never performed
+ automatically but needs to be called by hand::
+
+ sage: prec.reduce()
+ sage: print(prec.history(separate_reduce=True))
+ Timings
+ ...
+ ... RRRRRRRRRRRR
+ --- oooooooooooo
+
+ .. SEEALSO::
+
+ :meth:`history_enable`, :meth:`history_disable`, :meth:`history_clear`
+ """
+ if self._history is None:
+ raise ValueError("History is not tracked")
+ total_time = 0
+ if output_type == 'asciiart':
+ # Legend:
+ # o : tracked element
+ # ~ : element marked for deletion
+ # r : partial reduction
+ # R : full Hermite reduction
+ (n, mark) = self._history_init
+ status = n*['o']
+ for index in mark:
+ status[index] = '~'
+ hist = [ format_history(-1, status, timings) ]
+ oldevent = ''; total_time = 0
+ for (event, index, tme) in self._history:
+ if event == 'partial reduce' or event == 'full reduce':
+ if separate_reduce:
+ if total_time > 0:
+ hist.append(format_history(total_time, status, timings))
+ if event == 'partial reduce': code = 'r'
+ else: code = 'R'
+ status_red = status[:index] + (len(status) - index) * [code]
+ hist.append(format_history(tme, status_red, timings))
+ total_time = 0
+ oldevent = ''
+ else:
+ total_time += tme
+ continue
+ if not compact or event != oldevent:
+ if total_time > 0:
+ hist.append(format_history(total_time, status, timings))
+ total_time = 0
+ oldevent = event
+ total_time += tme
+ if event == 'add':
+ if index is None:
+ status.append('o')
+ else:
+ status = status[:index] + ['o'] + status[index:]
+ elif event == 'mark':
+ status[index] = '~'
+ elif event == 'del':
+ del status[index]
+ if total_time > 0 or oldevent == '':
+ hist.append(format_history(total_time, status, timings))
+ return '\n'.join(hist)
+ else:
+ raise NotImplementedError
+
+ def timings(self, action=None):
+ """
+ Return cumulated timings (grouped by actions) since the last
+ time history has been cleared.
+
+ INPUT:
+
+ - ``action`` -- ``None`` (the default), ``add``, ``mark``, ``del``,
+ ``partial reduce`` or ``full reduce``; if not None, return the
+ cumulated timing corresponding to this action; otherwise, return
+ a dictionary
+
+ Here are the meanings of the keywords above:
+ - ``add``: time spent in adding new colunmns to the precision matrix
+ (corresponding to the creation of new elements)
+ - ``mark``: time spent in marking elements for deletion
+ - ``del``: time spent in deleting columns of the precision matrix
+ and re-echelonizing the matrix
+ - ``partial reduce``: time spent in partial Hermite reduction
+ - ``full reduce``: time spent in full Hermite reduction
+
+ EXAMPLES::
+
+ sage: R = ZpLC(2, label='timings')
+ sage: prec = R.precision()
+ sage: prec.history_enable()
+ sage: M = random_matrix(R,5,5)
+ sage: N = M^10
+ sage: prec.timings() # somewhat random
+ {'add': 1.0530245304107666,
+ 'del': 0.24358701705932617,
+ 'mark': 0.0013289451599121094,
+ 'partial reduce': 0.21604204177856445
+ 'full reduce': 0}
+
+ TESTS::
+
+ sage: prec.history_clear()
+ sage: prec.timings()
+ {'add': 0, 'del': 0, 'full reduce': 0, 'mark': 0, 'partial reduce': 0}
+ """
+ if self._history is None:
+ raise ValueError("History is not tracked")
+ tme_by_event = { 'add': 0, 'del': 0, 'mark': 0, 'partial reduce': 0, 'full reduce': 0 }
+ for (event, _, tme) in self._history:
+ tme_by_event[event] += tme
+ if action is None:
+ return tme_by_event
+ if tme_by_event.has_key(action):
+ return tme_by_event[action]
+ else:
+ raise ValueError("invalid event")
+
+
+# class PrecisionLattice
+########################
+
+class PrecisionLattice(DifferentialPrecisionGeneric):
+ """
+ A class for handling precision lattices which are used to
+ track precision in the ZpLC model.
+
+ The precision lattice is stored as a triangular matrix whose
+ rows are generators of the lattice.
+ """
+ def __init__(self, p, label):
+ DifferentialPrecisionGeneric.__init__(self, p, 'lattice', label)
+ self._absolute_precisions = { }
+ self._capped = { }
+
+ def _index(self, ref):
+ """
+ Return the index of the element whose reference is ``ref``
+ """
+ return len(self._matrix[ref]) - 1
+
def reduce(self, index=0, partial=False):
"""
Reduce the size of the entries above the diagonal of the precision matrix
@@ -384,7 +911,7 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
tme = walltime()
diffval = (n-index) * [0]
for j in range(n-1, index, -1):
- col = self._lattice[self._elements[j]]
+ col = self._matrix[self._elements[j]]
prec = col[j].valuation() - diffval[j-index]
for i in range(index,j):
col[i] = col[i].reduce(prec)
@@ -401,7 +928,7 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
tme = walltime()
for j in range(index+1, n):
# In what follows, we assume that col[j] is a power of p
- col = self._lattice[self._elements[j]]
+ col = self._matrix[self._elements[j]]
valpivot = col[j].valuation()
for i in range(index, j):
reduced = col[i].reduce(valpivot)
@@ -410,7 +937,7 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
col[i] = reduced
col[i].normalize()
for j2 in range(j+1, n):
- col2 = self._lattice[self._elements[j2]]
+ col2 = self._matrix[self._elements[j2]]
col2[i] -= scalar*col2[i]
col2[i].normalize()
# We update history
@@ -432,7 +959,7 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
- ``dx`` -- a dictionary representing the differential of ``x``
- ``dx_mode`` -- a string, either ``linear_combinaison`` (the default)
- or `values`
+ or ``values``
- ``capped`` -- a boolean, whether this element has been capped
according to the parent's cap
@@ -477,7 +1004,7 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
ref = weakref.ref(elt)
if not isinstance(scalar, pRational):
scalar = pRational(p, scalar)
- c = self._lattice[ref]
+ c = self._matrix[ref]
for i in range(len(c)):
col[i] += scalar * c[i]
elif dx_mode == 'values':
@@ -485,29 +1012,20 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
ref = weakref.ref(elt)
if not isinstance(scalar, pRational):
scalar = pRational(p, scalar)
- i = len(self._lattice[ref]) - 1
+ i = self._index(ref)
col[i] = scalar
else:
raise ValueError("dx_mode must be either 'linear_combinaison' or 'values'")
for i in range(n):
col[i] = col[i].reduce(bigoh)
col.append(pRational(p, ZZ(1), bigoh))
- self._lattice[x_ref] = col
+ self._matrix[x_ref] = col
self._capped[x_ref] = capped
# We update history
if self._history is not None:
self._history.append(('add', None, walltime(tme)))
- #def _set_precision(self, x, column={}):
- # p = self._p
- # x_ref = weakref.ref(x)
- # index = len(self._lattice[x_ref]) - 1
- # n = len(self._elements)
- # col = n * [self._approx_zero]
- # self._lattice[x_ref] = col
- # self._absolute_precisions[x_ref] = min([ c.valuation() for c in col ])
-
def mark_for_deletion(self, ref):
"""
Mark an element for deletion.
@@ -533,17 +1051,17 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
sage: prec = R.precision()
sage: x = R(1,10)
sage: prec
- Precision Lattice on 1 object (label: markdel)
+ Precision lattice on 1 object (label: markdel)
sage: del x # indirect doctest: x is here marked for deletion
sage: prec
- Precision Lattice on 1 object (label: markdel)
+ Precision lattice on 1 object (label: markdel)
sage: prec.del_elements() # x is indeed deleted
sage: prec
- Precision Lattice on 0 object (label: markdel)
+ Precision lattice on 0 object (label: markdel)
"""
tme = walltime()
try:
- index = len(self._lattice[ref]) - 1
+ index = self._index(ref)
except (IndexError, KeyError):
return
self._marked_for_deletion.append(index)
@@ -569,19 +1087,19 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
sage: x = R(1,10)
sage: prec
- Precision Lattice on 1 object (label: delelts)
+ Precision lattice on 1 object (label: delelts)
sage: prec.precision_lattice()
[1024]
sage: del x
sage: prec
- Precision Lattice on 1 object (label: delelts)
+ Precision lattice on 1 object (label: delelts)
sage: prec.precision_lattice()
[1024]
sage: prec.del_elements()
sage: prec
- Precision Lattice on 0 object (label: delelts)
+ Precision lattice on 0 object (label: delelts)
sage: prec.precision_lattice()
[]
"""
@@ -595,20 +1113,18 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
n -= 1; count += 1
tme = walltime()
- del self._lattice[self._elements[index]]
+ del self._matrix[self._elements[index]]
del self._elements[index]
# Now, we echelonize
for i in range(index,n):
- col = self._lattice[self._elements[i]]
- vali = col[i].valuation()
- valj = col[i+1].valuation()
+ col = self._matrix[self._elements[i]]
d, u, v = col[i].xgcd(col[i+1])
up, vp = col[i+1]/d, col[i]/d
col[i] = d
del col[i+1]
for j in range(i+1,n):
- col = self._lattice[self._elements[j]]
+ col = self._matrix[self._elements[j]]
col[i], col[i+1] = u*col[i] + v*col[i+1], up*col[i] - vp*col[i+1]
# We update history
@@ -667,7 +1183,7 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
1 + O(2^10)
"""
ref = weakref.ref(x)
- col = self._lattice[ref]
+ col = self._matrix[ref]
n = len(self._elements)
rows_by_val = { }
@@ -692,11 +1208,11 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
# We clear the entry on the i-th line
beta = col[i].unit_part()
for j in range(piv,n):
- col_cur = self._lattice[self._elements[j]]
+ col_cur = self._matrix[self._elements[j]]
col_cur[i] = alpha*col_cur[i] - beta*col_cur[piv]
# We rescale the piv-th line
for j in range(piv,n):
- col_cur = self._lattice[self._elements[j]]
+ col_cur = self._matrix[self._elements[j]]
col_cur[piv] = col_cur[piv] << (w-v)
# Now the entry on the piv-th line has valuation w
# We update the dictionary accordingly
@@ -706,14 +1222,13 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
# We clear the cached absolute precisions
self._absolute_precisions = { }
-
def _compute_precision_absolute(self, ref):
"""
Compute the absolute precision of the given element and cache it
For internal use.
"""
- col = self._lattice[ref]
+ col = self._matrix[ref]
absprec = Infinity
capped = False
for i in range(len(col)):
@@ -792,7 +1307,7 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
self._compute_precision_absolute(ref)
return self._absolute_precisions[ref][1]
- def precision_lattice(self, elements=None, echelon=True):
+ def precision_lattice(self, elements=None):
"""
Return a matrix representing the precision lattice on a
subset of elements.
@@ -856,7 +1371,7 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
n = len(self._elements)
rows = [ ]; val = 0
for ref in elements:
- col = self._lattice[ref]
+ col = self._matrix[ref]
row = [ x.value() for x in col ]
valcol = min([ x.valuation() for x in col ])
if valcol < val: val = valcol
@@ -866,497 +1381,233 @@ class PrecisionLattice(UniqueRepresentation, SageObject):
M = matrix(rows).transpose()
if val < 0:
M *= self._p ** (-val)
- if echelon:
- M = M.change_ring(ZZ)
- M.echelonize()
- n = len(elements)
- M = M.submatrix(0,0,n,n)
+ M = M.change_ring(ZZ)
+ M.echelonize()
+ n = len(elements)
+ M = M.submatrix(0,0,n,n)
if val < 0:
M *= self._p ** val
return M
- def number_of_diffused_digits(self, elements=None):
- """
- Return the number of diffused digits of precision within a
- subset of elements.
- NOTE:
+# class PrecisionModule
+#######################
- A diffused digit of precision is a known digit which is not
- located on a single variable but only atppears on a suitable
- linear combinaison of variables.
+STARTING_ADDITIONAL_PREC = 5
- The number of diffused digits of precision quantifies the
- quality of the approximation of the lattice precision by a
- jagged precision (that is a precision which is split over
- all variables).
+class PrecisionModule(DifferentialPrecisionGeneric):
+ """
+ A class for handling precision modules which are used to
+ track precision in the ZpLF model.
- We refer to [] for a detail exposition of the notion of
- diffused digits.
+ The precision module (which is not necessarily a lattice)
+ is stored as a matrix whose rows are generators.
+ """
+ def __init__(self, p, label, prec):
+ DifferentialPrecisionGeneric.__init__(self, p, 'module', label)
+ self._absolute_precisions = { }
+ self._zero_cap = prec
+ self._internal_prec = prec + STARTING_ADDITIONAL_PREC
+ self._count = 0
+ self._thresold = 1
- EXAMPLES::
+ def internal_prec(self):
+ return self._internal_prec
- sage: R = ZpLC(2)
- sage: prec = R.precision()
- sage: x = R(1,10); y = R(1,5)
- sage: u = x + y
- sage: v = x - y
+ def dimension(self):
+ if len(self._elements) == 0:
+ return 0
+ return len(self._matrix[self._elements[-1]])
- sage: prec.number_of_diffused_digits([x,y])
- 0
- sage: prec.number_of_diffused_digits([u,v])
- 6
+ def is_lattice(self):
+ return self.dimension() == len(self._elements)
- The elements `u` and `v` are known at absolute precision `O(2^5)`.
- However, the sum `u + v = 2x` is known at precision `O(2^11)`, that
- is with `6` more digits.
- That is where the `6` diffused digits of precision comes from.
+ def new_element(self, x, dx, bigoh, dx_mode='linear_combinaison'):
+ self.del_elements()
- Here is another example with matrices::
+ # We first increase the internal prec
+ self._count += 1
+ if self._count > self._thresold:
+ self._internal_prec += 2
+ self._thresold *= self._p
- sage: M = matrix(R, 2, 2, [R(3,5),R(7,5),R(1,5),R(11,1)])
- sage: N = M^10
-
- The next syntax provides as easy way to select an interesting
- subset of variables (the selected subset consists of the four
- entries of the matrix ``N``)::
-
- sage: prec.number_of_diffused_digits(N)
- 17
- """
- M = self.precision_lattice(elements)
- n = M.nrows()
+ tme = walltime()
p = self._p
- diffused = 0
- for j in range(n):
- val = minval = M[j,j].valuation(p)
- for i in range(j):
- v = M[i,j].valuation(p)
- if v < minval: minval = v
- diffused += val - minval
- return diffused
-
- def number_of_tracked_elements(self, dead=True):
- """
- Return the number of tracked elements through this precision
- lattice
-
- INPUT:
-
- - ``dead`` -- a boolean (default: ``True``); whether dead
- elements for which the corresponding column is still not
- erased should be counted or not
-
- EXAMPLES::
-
- sage: R = ZpLC(2, label='count')
- sage: prec = R.precision()
- sage: x = R(1,10); y = R(1,5)
- sage: prec.number_of_tracked_elements()
- 2
-
- sage: u = x + y
- sage: v = x - y
- sage: prec.number_of_tracked_elements()
- 4
-
- sage: del x; del y
- sage: prec.number_of_tracked_elements()
- 4
- sage: prec.number_of_tracked_elements(dead=False)
- 2
-
- sage: prec.del_elements()
- sage: prec.number_of_tracked_elements()
- 2
- """
- if dead:
- return len(self._elements)
+ n = self.dimension()
+ x_ref = weakref.ref(x, self.mark_for_deletion)
+ col = n * [self._approx_zero]
+ if dx_mode == 'linear_combinaison':
+ expected_vals = n * [ Infinity ]
+ for elt,scalar in dx:
+ ref = weakref.ref(elt)
+ if not isinstance(scalar, pRational):
+ scalar = pRational(p, scalar)
+ c = self._matrix[ref]
+ for i in range(len(c)):
+ summand = scalar * c[i]
+ expected_vals[i] = min(expected_vals[i], summand.valuation())
+ col[i] += summand
+ for i in range(n):
+ if col[i].valuation() >= expected_vals[i] + self._zero_cap:
+ col[i] = self._approx_zero
+ elif dx_mode == 'values':
+ for elt,scalar in dx:
+ ref = weakref.ref(elt)
+ if not isinstance(scalar, pRational):
+ scalar = pRational(p, scalar)
+ i = self._index(ref)
+ col[i] = scalar
else:
- count = 0
- for x_ref in self._elements:
- if x_ref() is not None: count += 1
- return count
-
-
- def tracked_elements(self, values=True, dead=True):
- """
- Return the list of tracked elements
-
- INPUT:
-
- - ``values`` -- a boolean (default: ``True``); if false,
- the method returns a list of weak references on tracked
- elements instead
+ raise ValueError("dx_mode must be either 'linear_combinaison' or 'values'")
- - ``dead`` -- a boolean (default: ``True``); whether dead
- elements for which the corresponding column is still not
- erased should be listed or not
+ for i in range(n):
+ col[i] = col[i].reduce_relative(self._internal_prec)
+ if bigoh is not None:
+ col.append(pRational(p, ZZ(1), bigoh))
- EXAMPLES::
+ self._elements.append(x_ref)
+ self._matrix[x_ref] = col
- sage: R = ZpLC(2, label='tracked')
- sage: prec = R.precision()
- sage: x = R(1,10); y = R(1,5)
- sage: prec.tracked_elements()
- [1 + O(2^10), 1 + O(2^5)]
- sage: prec.tracked_elements(values=False)
- [<weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; dead>]
- sage: prec.tracked_elements(values=False, dead=False)
- [<weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; to 'pAdicLatticeElement' at 0x...>]
+ # We update history
+ if self._history is not None:
+ self._history.append(('add', None, walltime(tme)))
- sage: u = x + y
- sage: v = x - y
- sage: prec.tracked_elements()
- [1 + O(2^10), 1 + O(2^5), 2 + O(2^5), O(2^5)]
- sage: prec.tracked_elements(values=False)
- [<weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; dead>]
- sage: del x; del y
- sage: prec.tracked_elements()
- [None, None, 2 + O(2^5), O(2^5), None]
- sage: prec.tracked_elements(values=False)
- [<weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; to 'pAdicLatticeElement' at 0x...>,
- <weakref at 0x...; dead>]
- """
- if values:
- if dead:
- return [ ref() for ref in self._elements ]
- else:
- return [ ref() for ref in self._elements if ref() is not None ]
+ def mark_for_deletion(self, ref):
+ tme = walltime()
+ try:
+ index = self._index(ref)
+ except (IndexError, KeyError):
+ return
+ if index == 0:
+ length_before = 0
else:
- if dead:
- return list(self._elements)
- else:
- return [ ref for ref in self._elements if ref() is not None ]
-
-
- # History
-
- def history_enable(self):
- """
- Enable history.
-
- We refer to the documentation of the method :meth:`history` for
- a complete documentation (including examples) about history.
-
- TESTS::
-
- sage: R = ZpLC(2, label='history_en')
- sage: prec = R.precision()
-
- sage: print(prec.history()) # history is disabled by default
- Traceback (most recent call last):
- ...
- ValueError: History is not tracked
-
- sage: prec.history_enable()
- sage: print(prec.history())
- Timings
- ---
-
- .. SEEALSO::
-
- :meth:`history`, :meth:`history_disable`, :meth:`history_clear`
- """
- if self._history is None:
- self._history_init = ( len(self._elements), list(self._marked_for_deletion) )
- self._history = [ ]
-
- def history_disable(self):
- """
- Disable history.
-
- We refer to the documentation of the method :meth:`history` for
- a complete documentation (including examples