From abb9f998469824499d2ac1c26234363c6b6a2a72 Mon Sep 17 00:00:00 2001 From: Malcolm Rupert Date: Mon, 25 May 2015 14:19:43 -0700 Subject: [PATCH 001/126] 18430: Fixes self.is_hyperbolic(2) and various cleanups Adds functionality for infinite place and points to these changes in in quadratic_form__local_field_invariants.py. There are still some inconsitancies with naming the infinite place because hilber_symbol uses (-1) while is_hyperbolic uses "infinty". --- .../quadratic_form__local_field_invariants.py | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py index efcdc77d384..0998df728d3 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py +++ b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py @@ -256,7 +256,7 @@ def signature(self): def hasse_invariant(self, p): """ - Computes the Hasse invariant at a prime `p`, as given on p55 of + Computes the Hasse invariant at a prime `p` or at infinity, as given on p55 of Cassels's book. If Q is diagonal with coefficients `a_i`, then the (Cassels) Hasse invariant is given by @@ -277,7 +277,7 @@ def hasse_invariant(self, p): INPUT: - `p` -- a prime number > 0 + `p` -- a prime number > 0 or `-1` for the infinite place. OUTPUT: 1 or -1 @@ -361,7 +361,7 @@ def hasse_invariant__OMeara(self, p): INPUT: - `p` -- a prime number > 0 + `p` -- a prime number > 0 or `-1` for the infinite place. OUTPUT: 1 or -1 @@ -431,7 +431,7 @@ def hasse_invariant__OMeara(self, p): def is_hyperbolic(self, p): """ Checks if the quadratic form is a sum of hyperbolic planes over - the p-adic numbers Q_p. + the p-adic numbers Q_p or over the real numbers. REFERENCES: This criteria follows from Cassels's "Rational Quadratic Forms": @@ -439,7 +439,7 @@ def is_hyperbolic(self, p): - direct sum formulas (Lemma 2.3 on p58) INPUT: - `p` -- a prime number > 0 + `p` -- a prime number > 0 or "infinity" for the real place. OUTPUT: boolean @@ -477,7 +477,7 @@ def is_hyperbolic(self, p): return (self.signature() == 0) elif p == 2: - return QQ(self.det() * (-1)**m).is_padic_square(p) and (self.hasse_invariant(p) == (-1)**m) ## Actually, this -1 is the Hilbert symbol (-1,-1)_p + return QQ(self.det() * (-1)**m).is_padic_square(p) and (self.hasse_invariant(p) == (-1)**(m*(m-1)/2)) ## Actually, this -1 is the Hilbert symbol (-1,-1)_p else: return QQ(self.det() * (-1)**m).is_padic_square(p) and (self.hasse_invariant(p) == 1) @@ -486,10 +486,10 @@ def is_hyperbolic(self, p): def is_anisotropic(self, p): """ - Checks if the quadratic form is anisotropic over the p-adic numbers `Q_p`. + Checks if the quadratic form is anisotropic over the p-adic numbers `Q_p` or `RR`. INPUT: - `p` -- a prime number > 0 + `p` -- a prime number > 0 or "infinity" OUTPUT: boolean @@ -529,31 +529,34 @@ def is_anisotropic(self, p): D = self.det() ## TO DO: Should check that p is prime + if p == "infinity": + return self.is_definite() - if (n >= 5): - return False; + else: + if (n >= 5): + return False; - if (n == 4): - return ( QQ(D).is_padic_square(p) and (self.hasse_invariant(p) == - hilbert_symbol(-1,-1,p)) ) + if (n == 4): + return ( QQ(D).is_padic_square(p) and (self.hasse_invariant(p) == - hilbert_symbol(-1,-1,p)) ) - if (n == 3): - return (self.hasse_invariant(p) != hilbert_symbol(-1, -D, p)) + if (n == 3): + return (self.hasse_invariant(p) != hilbert_symbol(-1, -D, p)) - if (n == 2): - return (not QQ(-D).is_padic_square(p)) + if (n == 2): + return (not QQ(-D).is_padic_square(p)) - if (n == 1): - return (self[0,0] != 0) + if (n == 1): + return (self[0,0] != 0) raise NotImplementedError("Oops! We haven't established a convention for 0-dim'l quadratic forms... =(") def is_isotropic(self, p): """ - Checks if Q is isotropic over the p-adic numbers `Q_p`. + Checks if Q is isotropic over the p-adic numbers `Q_p` or `RR`. INPUT: - `p` -- a prime number > 0 + `p` -- a prime number > 0 or "infinity" OUTPUT: boolean @@ -624,7 +627,7 @@ def anisotropic_primes(self): """ ## Look at all prime divisors of 2 * Det(Q) to find the anisotropic primes... - possible_primes = prime_divisors(2 * self.det()) + possible_primes = prime_divisors(2 * self.det()) + ["infinity"] AnisoPrimes = [] ## DIAGNSOTIC From 56123809b3792ca37835c33fb6f85d68de5edc77 Mon Sep 17 00:00:00 2001 From: David Roe Date: Tue, 29 Nov 2016 17:15:47 -0500 Subject: [PATCH 002/126] Working on a floating point p-adic type --- src/sage/rings/padics/FP_template.pxi | 1535 +++++++++++++++++++++++++ 1 file changed, 1535 insertions(+) create mode 100644 src/sage/rings/padics/FP_template.pxi diff --git a/src/sage/rings/padics/FP_template.pxi b/src/sage/rings/padics/FP_template.pxi new file mode 100644 index 00000000000..ac40ea3799a --- /dev/null +++ b/src/sage/rings/padics/FP_template.pxi @@ -0,0 +1,1535 @@ +""" +Floating point template for complete discrete valuation rings. + +In order to use this template you need to write a linkage file and +gluing file. For an example see mpz_linkage.pxi (linkage file) and +padic_floating_point_element.pyx (gluing file). + +The linkage file implements a common API that is then used in the +class FPElement defined here. See sage/libs/linkages/padics/API.pxi +for the functions needed. + +The gluing file does the following: + +- ctypedef's celement to be the appropriate type (e.g. mpz_t) +- includes the linkage file +- includes this template +- defines a concrete class inheriting from FPElement, and implements + any desired extra methods + +AUTHORS: + +- David Roe (2016-03-21) -- initial version +""" + +#***************************************************************************** +# Copyright (C) 2007-2016 David Roe +# William Stein +# +# Distributed under the terms of the GNU General Public License (GPL) +# 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 sage.ext.stdsage cimport PY_NEW +include "padic_template_element.pxi" +from cpython.int cimport * + +from sage.structure.element cimport Element +from sage.rings.padics.common_conversion cimport comb_prec, _process_args_and_kwds +from sage.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ +from sage.categories.sets_cat import Sets +from sage.categories.sets_with_partial_maps import SetsWithPartialMaps +from sage.categories.homset import Hom + +cdef inline bint overunderflow(long* ordp, celement unit, PowComputer_class prime_pow): + """ + Check for over and underflow. If detected, sets ordp and unit + appropriately, and returns True. If not, returns False. + """ + if ordp[0] >= maxordp: + ordp[0] = maxordp + csetzero(unit, prime_pow) + elif ordp[0] <= minusmaxordp: + ordp[0] = minusmaxordp + csetone(unit, prime_pow) + else: + return False + return True + +cdef inline bint overunderlow_mpz(long* ordp, mpz_t ordp_mpz, celement unit, PowComputer_class prime_pow): + """ + Check for over and underflow with an mpz_t ordp. If detected, sets ordp and unit + appropriately, and returns True. If not, returns False. + """ + if mpz_fits_slong_p(ordp_mpz) == 0 or mpz_cmp_si(ordp_mpz, maxordp) >= 0 or mpz_cmp_si(ordp_mpz, minusmaxordp) <= 0: + if mpz_sgn(ordp_mpz) > 0: + ordp[0] = maxordp + csetzero(unit, prime_pow) + else: + ordp[0] = minusmaxordp + csetone(unit, prime_pow) + return True + return False + +cdef inline bint very_pos_val(long ordp): + return ordp >= maxordp + +cdef inline bint very_neg_val(long ordp): + return ordp <= minusmaxordp + +cdef inline bint huge_val(long ordp): + return very_pos_val(ordp) or very_neg_val(ordp) + +cdef class FPElement(pAdicTemplateElement): + cdef int _set(self, x, long val, long xprec, absprec, relprec) except -1: + """ + Sets the value of this element from given defining data. + + This function is intended for use in conversion, and should + not be called on an element created with :meth:`_new_c`. + + INPUT: + + - ``x`` -- data defining a `p`-adic element: int, long, + Integer, Rational, other `p`-adic element... + + - ``val`` -- the valuation of the resulting element (unused; + for compatibility with other `p`-adic precision modes) + + - ``xprec -- an inherent precision of ``x`` (unused; for + compatibility with other `p`-adic precision modes) + + - ``absprec`` -- an absolute precision cap for this element + (unused; for compatibility with other `p`-adic precision + modes) + + - ``relprec`` -- a relative precision cap for this element + (unused; for compatibility with other `p`-adic precision + modes) + + TESTS:: + + sage: R = ZpFP(5) + sage: a = R(17,5); a #indirect doctest + 2 + 3*5 + sage: R(15) #indirect doctest + 3*5 + + sage: R = ZpFP(5,5) + sage: a = R(25/9); a #indirect doctest + 4*5^2 + 2*5^3 + 5^5 + 2*5^6 + sage: R(ZpCR(5)(25/9)) == a + True + sage: R(5) - R(5) + 0 + """ + cconstruct(self.unit, self.prime_pow) + if exactzero(val): + self.ordp = maxordp + csetzero(self.unit) + else: + self.ordp = val + if isinstance(x,FPElement) and x.parent() is self.parent(): + ccopy(self.unit, (x).unit, self.prime_pow) + else: + cconv(self.unit, x, self.prime_pow.prec_cap, val, self.prime_pow) + + cdef int _set_exact_zero(self) except -1: + """ + Sets this element to zero. + + TESTS:: + + sage: R = Zp(5); R(0) #indirect doctest + 0 + """ + csetzero(self.unit, self.prime_pow) + self.ordp = maxordp + + cdef int _set_infinity(self) except -1: + """ + Sets this element to zero. + + TESTS:: + + sage: R = Zp(5); R(0) #indirect doctest + 0 + """ + csetone(self.unit, self.prime_pow) + self.ordp = minusmaxordp + + cdef FPElement _new_c(self): + """ + Creates a new element with the same basic info. + + TESTS:: + + sage: R = ZpFP(5); R(6) * R(7) #indirect doctest + 2 + 3*5 + 5^2 + """ + cdef type t = type(self) + cdef FPElement ans = t.__new__(t) + ans._parent = self._parent + ans.prime_pow = self.prime_pow + cconstruct(ans.unit, ans.prime_pow) + return ans + + cdef int check_preccap(self) except -1: + """ + Check that the precision of this element does not exceed the + precision cap. Does nothing for floating point elements. + + TESTS:: + + sage: ZpFP(5)(1).lift_to_precision(30) # indirect doctest + 1 + O(5^20) + """ + pass + + def __copy__(self): + """ + Return a copy of this element. + + EXAMPLES:: + + sage: a = ZpFP(5,6)(17); b = copy(a) + sage: a == b + True + sage: a is b + False + """ + cdef FPElement ans = self._new_c() + ans.ordp = self.ordp + ccopy(ans.unit, self.unit, ans.prime_pow) + return ans + + def __dealloc__(self): + """ + Deallocate the underlying data structure. + + TESTS:: + + sage: R = ZpFP(5) + sage: a = R(17) + sage: del(a) + """ + cdestruct(self.unit, self.prime_pow) + + def __reduce__(self): + """ + Return a tuple of a function and data that can be used to unpickle this + element. + + EXAMPLES:: + + sage: a = ZpFP(5)(-3) + sage: type(a) + + sage: loads(dumps(a)) == a + True + """ + return unpickle_fpe_v2, (self.__class__, self.parent(), cpickle(self.unit, self.prime_pow), self.ordp) + + def __richcmp__(self, right, int op): + """ + Compare this element to ``right`` using the comparison operator ``op``. + + TESTS:: + + sage: R = ZpFP(5) + sage: a = R(17) + sage: b = R(21) + sage: a == b + False + sage: a < b + True + """ + return (self)._richcmp(right, op) + + cpdef ModuleElement _neg_(self): + r""" + Return the additive inverse of this element. + + EXAMPLES:: + + sage: R = Zp(7, 4, 'floating-point', 'series') + sage: -R(7) #indirect doctest + 6*7 + 6*7^2 + 6*7^3 + O(7^4) + """ + cdef FPElement ans = self._new_c() + ans.ordp = self.ordp + if huge_val(self.ordp): # zero or infinity + ccopy(ans.unit, self.unit, ans.prime_pow) + else: + cneg(ans.unit, self.unit, ans.prime_pow.prec_cap, ans.prime_pow) + creduce_small(ans.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) + return ans + + cpdef ModuleElement _add_(self, ModuleElement _right): + r""" + Return the sum of this element and ``_right``. + + EXAMPLES:: + + sage: R = Zp(7, 4, 'floating-point', 'series') + sage: x = R(1721); x + 6 + 5*7^3 + O(7^4) + sage: y = R(1373); y + 1 + 4*7^3 + O(7^4) + sage: x + y #indirect doctest + 7 + 2*7^3 + O(7^4) + """ + cdef FPElement ans + cdef FPElement right = _right + cdef long tmpL + if self.ordp == right.ordp: + ans = self._new_c() + ans.ordp = self.ordp + if huge_val(ans.ordp): + ccopy(ans.unit, self.unit, ans.prime_pow) + else: + cadd(ans.unit, self.unit, right.unit, ans.prime_pow.prec_cap, ans.prime_pow) + ans._normalize() # safer than trying to leave unnormalized + else: + if self.ordp > right.ordp: + # Addition is commutative, swap so self.ordp < right.ordp + ans = right; right = self; self = ans + tmpL = right.ordp - self.ordp + if tmpL > self.prime_pow.prec_cap: + return self + ans = self._new_c() + ans.ordp = self.ordp + if huge_val(ans.ordp): + ccopy(ans.unit, self.unit, ans.prime_pow) + else: + cshift(ans.unit, right.unit, tmpL, ans.prime_pow.prec_cap, ans.prime_pow, False) + cadd(ans.unit, ans.unit, self.unit, ans.prime_pow.prec_cap, ans.prime_pow) + creduce(ans.unit, ans.unit, ans.relprec, ans.prime_pow) + return ans + + cpdef ModuleElement _sub_(self, ModuleElement _right): + r""" + Return the difference of this element and ``_right``. + + EXAMPLES:: + + sage: R = Zp(7, 4, 'floating-point', 'series') + sage: x = R(1721); x + 6 + 5*7^3 + O(7^4) + sage: y = R(1373); y + 1 + 4*7^3 + O(7^4) + sage: x - y #indirect doctest + 5 + 7^3 + O(7^4) + """ + cdef FPElement ans + cdef FPElement right = _right + cdef long tmpL + if self.ordp == right.ordp: + ans = self._new_c() + ans.ordp = self.ordp + if huge_val(ans.ordp): + ccopy(ans.unit, self.unit, ans.prime_pow) + else: + csub(ans.unit, self.unit, right.unit, ans.prime_pow.prec_cap, ans.prime_pow) + ans._normalize() # safer than trying to leave unnormalized + elif self.ordp < right.ordp: + tmpL = right.ordp - self.ordp + if tmpL > self.prime_pow.prec_cap: + return self + ans = self._new_c() + ans.ordp = self.ordp + if huge_val(ans.ordp): + ccopy(ans.unit, self.unit, ans.prime_pow) + else: + cshift(ans.unit, right.unit, tmpL, ans.prime_pow.prec_cap, ans.prime_pow, False) + csub(ans.unit, self.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) + creduce(ans.unit, ans.unit, ans.relprec, ans.prime_pow) + else: + tmpL = self.ordp - right.ordp + if tmpL > self.prime_pow.prec_cap: + return right._neg_() + ans = self._new_c() + ans.ordp = right.ordp + if huge_val(ans.ordp): + ccopy(ans.unit, self.unit, ans.prime_pow) + else: + cshift(ans.unit, self.unit, tmpL, ans.prime_pow.prec_cap, ans.prime_pow, False) + csub(ans.unit, ans.unit, right.unit, ans.prime_pow.prec_cap, ans.prime_pow) + creduce(ans.unit, ans.unit, ans.relprec, ans.prime_pow) + return ans + + def __invert__(self): + r""" + Returns multiplicative inverse of this element. + + EXAMPLES:: + + sage: R = Zp(7, 4, 'floating-point', 'series') + sage: ~R(2) + 4 + 3*7 + 3*7^2 + 3*7^3 + O(7^4) + sage: ~R(0) + Traceback (most recent call last): + ... + ValueError: cannot invert non-unit + sage: ~R(7) + Traceback (most recent call last): + ... + ValueError: cannot invert non-unit + """ + # Input should be normalized! + cdef FPElement ans = self._new_c() + if ans.prime_pow.in_field == 0: + ans._parent = self._parent.fraction_field() + ans.prime_pow = ans._parent.prime_pow + ans.ordp = -self.ordp + if very_pos_val(ans.ordp): + csetone(ans.unit, ans.prime_pow) + elif very_neg_val(ans.ordp): + csetzero(ans.unit, ans.prime_pow) + else: + cinvert(ans.unit, self.unit, ans.prime_pow.prec_cap, ans.prime_pow) + return ans + + cpdef RingElement _mul_(self, RingElement _right): + r""" + Return the product of this element and ``_right``. + + EXAMPLES:: + + sage: R = Zp(7, 4, 'floating-point', 'series') + sage: R(3) * R(2) #indirect doctest + 6 + O(7^4) + sage: R(1/2) * R(2) + 1 + O(7^4) + """ + cdef FPElement right = _right + if very_pos_val(self.ordp): + if very_neg_val(right.ordp): + raise ZeroDivisionError("Cannot multipy 0 by infinity") + return self + elif very_pos_val(right.ordp): + if very_neg_val(self.ordp): + raise ZeroDivisionError("Cannot multiply 0 by infinity") + return right + elif very_neg_val(self.ordp): + return self + elif very_neg_val(right.ordp): + return right + cdef FPElement ans = self._new_c() + ans.ordp = self.ordp + right.ordp + if overunderflow(&ans.ordp, ans.unit, ans.prime_pow): + return ans + cmul(ans.unit, self.unit, right.unit, ans.prime_pow.prec_cap, ans.prime_pow) + creduce(ans.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) + return ans + + cpdef RingElement _div_(self, RingElement _right): + r""" + Return the quotient of this element and ``right``. ``right`` must have + valuation zero. + + EXAMPLES:: + + sage: R = Zp(7, 4, 'floating-point', 'series') + sage: R(3) / R(2) #indirect doctest + 5 + 3*7 + 3*7^2 + 3*7^3 + O(7^4) + sage: R(5) / R(0) + Traceback (most recent call last): + ... + ValueError: cannot invert non-unit + sage: R(7) / R(49) + Traceback (most recent call last): + ... + ValueError: cannot invert non-unit + """ + # Input should be normalized! + cdef FPElement ans, right = _right + if very_pos_val(self.ordp): + if very_pos_val(right.ordp): + raise ZeroDivisionError("Cannot divide 0 by 0") + return self + elif very_neg_val(right.ordp): + if very_neg_val(self.ordp): + raise ZeroDivisionError("Cannot divide infinity by infinity") + ans = self._new_c() + ans._set_exact_zero() + return ans + elif very_neg_val(self.ordp): + return self + elif very_pos_val(right.ordp): + ans = self._new_c() + ans._set_infinity() + return ans + ans = self._new_c() + ans.ordp = self.ordp - right.ordp + if overunderflow(&ans.ordp, ans.unit, ans.prime_pow): + return ans + cdivunit(ans.unit, self.unit, right.unit, ans.prime_pow.prec_cap, ans.prime_pow) + creduce(ans.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) + return ans + + def __pow__(FPElement self, _right, dummy): # NOTE: dummy ignored, always use self.prime_pow.prec_cap + """ + Exponentiation by an integer + + EXAMPLES:: + + sage: R = ZpFP(11, 5) + sage: R(1/2)^5 + 10 + 7*11 + 11^2 + 5*11^3 + 4*11^4 + O(11^5) + sage: R(1/32) + 10 + 7*11 + 11^2 + 5*11^3 + 4*11^4 + O(11^5) + sage: R(1/2)^5 == R(1/32) + True + sage: R(3)^1000 #indirect doctest + 1 + 4*11^2 + 3*11^3 + 7*11^4 + O(11^5) + + TESTS: + + We check that :trac:`15640` is resolved:: + + sage: R(11)^-1 + Traceback (most recent call last): + ... + ValueError: cannot invert non-unit + """ + cdef long dummyL + cdef mpz_t tmp + cdef Integer right + cdef FPElement base, pright, ans + cdef bint exact_exp + if isinstance(_right, (Integer, int, long, Rational)): + if _right < 0: + self = ~self + _right = -right + exact_exp = True + elif self.parent() is _right.parent(): + ## For extension elements, we need to switch to the + ## fraction field sometimes in highly ramified extensions. + exact_exp = False + pright = _right + else: + self, _right = canonical_coercion(self, _right) + return self.__pow__(_right, dummy) + if exact_exp and _right == 0: + ans = self._new_c() + ans.ordp = 0 + csetone(ans.unit, ans.prime_pow) + return ans + if huge_val(self.ordp): + if exact_exp: + # We may assume from above that right > 0 + return self + else: + # log(0) and log(infinity) not defined + raise ValueError("0^x and inf^x not defined for p-adic x") + ans = self._new_c() + if exact_exp: + # exact_pow_helper is defined in padic_template_element.pxi + right = exact_pow_helper(&dummyL, self.prime_pow.prec_cap, _right, self.prime_pow) + mpz_init(tmp) + try: + mpz_mul_si(tmp, right.value, self.ordp) + if overunderflow_mpz(&ans.ordp, tmp, ans.unit, ans.prime_pow): + return ans + else: + ans.ordp = mpz_get_si(tmp) + finally: + mpz_clear(tmp) + cpow(ans.unit, self.unit, right.value, ans.prime_pow.prec_cap, ans.prime_pow) + else: + # padic_pow_helper is defined in padic_template_element.pxi + dummyL = padic_pow_helper(ans.unit, self.unit, self.ordp, self.prime_pow.prec_cap, + pright.unit, pright.ordp, pright.prime_pow.prec_cap, self.prime_pow) + ans.ordp = 0 + return ans + + cdef pAdicTemplateElement _lshift_c(self, long shift): + """ + Multiplies self by `\pi^{shift}`. + + Negative shifts may truncate the result if the parent is not a + field. + + EXAMPLES: + + We create a floating point ring:: + + sage: R = ZpFP(5, 20); a = R(1000); a + 3*5^3 + 5^4 + + Shifting to the right is the same as dividing by a power of + the uniformizer `\pi` of the `p`-adic ring.:: + + sage: a >> 1 + 3*5^2 + 5^3 + + Shifting to the left is the same as multiplying by a power of + `\pi`:: + + sage: a << 2 + 3*5^5 + 5^6 + sage: a*5^2 + 3*5^5 + 5^6 + + Shifting by a negative integer to the left is the same as + right shifting by the absolute value:: + + sage: a << -3 + 3 + 5 + sage: a >> 3 + 3 + 5 + """ + if shift < 0: + return self._rshift_c(-shift) + elif shift == 0: + return self + cdef FPElement ans = self._new_c() + # check both in case of overflow in sum; this case also includes self.ordp = maxordp + if very_pos_val(shift) or very_pos_val(self.ordp + shift): + # need to check that we're not shifting infinity + if very_neg_val(self.ordp): + raise ZeroDivisionError("Cannot multiply zero by infinity") + ans.ordp = maxordp + csetzero(ans.unit, ans.prime_pow) + else: + ans.ordp = self.ordp + shift + ccopy(ans.unit, self.unit, ans.prime_pow) + return ans + + cdef pAdicTemplateElement _rshift_c(self, long shift): + """ + Divides by `\pi^{shift}`. + + Positive shifts may truncate the result if the parent is not a + field. + + EXAMPLES:: + + sage: R = ZpFP(997, 7); a = R(123456878908); a + 964*997 + 572*997^2 + 124*997^3 + + Shifting to the right divides by a power of `\pi`, but + dropping terms with negative valuation:: + + sage: a >> 3 + 124 + + A negative shift multiplies by that power of `\pi`:: + + sage: a >> -3 + 964*997^4 + 572*997^5 + 124*997^6 + """ + if shift == 0: + return self + elif very_pos_val(self.ordp): + if very_pos_val(shift): + raise ZeroDivisionError("Cannot divide zero by zero") + return self + elif very_neg_val(self.ordp): + if very_neg_val(shift): + raise ZeroDivisionError("Cannot divide infinity by infinity") + return self + cdef FPElement ans = self._new_c() + cdef long diff + if self.prime_pow.in_field == 1 or shift <= self.ordp: + if very_pos_val(shift): + ans._set_infinity() + elif very_neg_val(shift): + ans._set_exact_zero() + else: + ans.ordp = self.ordp - shift + ccopy(ans.unit, self.unit, ans.prime_pow) + else: + diff = shift - self.ordp + if diff >= self.prime_pow.prec_cap: + ans._set_exact_zero() + else: + ans.ordp = 0 + cshift(ans.unit, self.unit, -diff, ans.prime_pow.prec_cap, ans.prime_pow, False) + ans._normalize() + return ans + + def add_bigoh(self, absprec): + """ + Returns a new element truncated modulo `\pi^{\mbox{absprec}}`. + + INPUT: + + - ``absprec`` -- an integer + + OUTPUT: + + - a new element truncated modulo `\pi^{\mbox{absprec}}`. + + EXAMPLES:: + + sage: R = Zp(7,4,'floating-point','series'); a = R(8); a.add_bigoh(1) + 1 + """ + cdef long aprec, newprec + if absprec is inifinity or very_neg_val(self.ordp): + return self + elif isinstance(absprec, int): + aprec = absprec + else: + if not isinstance(absprec, Integer): + absprec = Integer(absprec) + if mpz_fits_slong_p((absprec).value) == 0: + if mpz_sgn((absprec).value) > 0: + return self + aprec = minusmaxordp + else: + aprec = mpz_get_si((absprec).value) + if aprec >= self.ordp + self.prime_pow.prec_cap: + return self + cdef FPElement ans = self._new_c() + if aprec <= self.ordp: + ans._set_exact_zero() + else: + ans.ordp = self.ordp + creduce(ans.unit, self.unit, aprec - self.ordp, ans.prime_pow) + return ans + + cpdef bint _is_exact_zero(self) except -1: + """ + Tests whether this element is exactly zero. + + EXAMPLES:: + + sage: R = Zp(7,4,'floating-point','series'); a = R(8); a._is_exact_zero() + False + sage: b = R(0); a._is_exact_zero() + True + """ + return very_pos_val(self.ordp) + + cpdef bint _is_inexact_zero(self) except -1: + """ + Returns True if self is indistinguishable from zero. + + EXAMPLES:: + + sage: R = ZpFP(7, 5) + sage: R(14)._is_inexact_zero() + False + sage: R(0)._is_inexact_zero() + True + """ + return very_pos_val(self.ordp) + + def is_zero(self, absprec = None): + r""" + Returns whether self is zero modulo `\pi^{\mbox{absprec}}`. + + INPUT: + + - ``absprec`` -- an integer + + EXAMPLES:: + + sage: R = ZpFP(17, 6) + sage: R(0).is_zero() + True + sage: R(17^6).is_zero() + True + sage: R(17^2).is_zero(absprec=2) + True + """ + if absprec is None: + return very_pos_val(self.ordp) + if very_pos_val(self.ordp): + return True + if absprec is infinity: + return False + if isinstance(absprec, int): + return self.ordp >= absprec + if not isinstance(absprec, Integer): + absprec = Integer(absprec) + return mpz_cmp_si((absprec).value, self.ordp) <= 0 + + def __nonzero__(self): + """ + Returns True if this element is distinguishable from zero. + + For most applications, explicitly specifying the power of p + modulo which the element is supposed to be nonzero is + preferrable. + + EXAMPLES:: + + sage: R = ZpFP(5); a = R(0); b = R(75) + sage: bool(a), bool(b) # indirect doctest + (False, True) + """ + return not very_pos_val(self.ordp) + + def is_equal_to(self, _right, absprec=None): + r""" + Returns whether this element is equal to ``right`` modulo `p^{\mbox{absprec}}`. + + If ``absprec`` is ``None``, determines whether self and right + have the same value. + + INPUT: + + - ``right`` -- a p-adic element with the same parent + - ``absprec`` -- a positive integer or ``None`` (default: ``None``) + + EXAMPLES:: + + sage: R = ZpFP(2, 6) + sage: R(13).is_equal_to(R(13)) + True + sage: R(13).is_equal_to(R(13+2^10)) + True + sage: R(13).is_equal_to(R(17), 2) + True + sage: R(13).is_equal_to(R(17), 5) + False + """ + cdef FPElement right + cdef long aprec, rprec + if self.parent() is _right.parent(): + right = _right + else: + right = self.parent().coerce(_right) + if very_neg_val(self.ordp): + if very_neg_val(right.ordp): + return True + return False + elif very_neg_val(right.ordp): + return False + if absprec is None: + return ((self.ordp == right.ordp) and + (ccmp(self.unit, right.unit, self.prime_pow.prec_cap, False, False, self.prime_pow) == 0)) + if not isinstance(absprec, Integer): + absprec = Integer(absprec) + if mpz_cmp_si((absprec).value, self.ordp) <= 0: + if mpz_cmp_si((absprec).value, right.ordp) <= 0: + return True + return False + elif mpz_cmp_si((absprec).value, right.ordp) <= 0: + return False + if self.ordp != right.ordp: + return False + if mpz_cmp_si((absprec).value, maxordp) >= 0: + return ccmp(self.unit, right.unit, self.prime_pow.prec_cap, False, False, self.prime_pow) == 0 + aprec = mpz_get_si((absprec).value) + rprec = aprec - self.ordp + if rprec > self.prime_pow.prec_cap: + rprec = self.prime_pow.prec_cap + return ccmp(self.unit, + right.unit, + rprec, + rprec < self.prime_pow.prec_cap, + rprec < right.prime_pow.prec_cap, + self.prime_pow) == 0 + + cdef int _cmp_units(self, pAdicGenericElement _right) except -2: + """ + Comparison of units, used in equality testing. + + EXAMPLES:: + + sage: R = ZpFP(5) + sage: a = R(17); b = R(0,3); c = R(85,7); d = R(2, 1) + sage: any([a == b, a == c, b == c, b == d, c == d, a == d]) # indirect doctest + False + sage: all([a == a, b == b, c == c, d == d]) + True + """ + cdef FPElement right = _right + return ccmp(self.unit, right.unit, self.prime_pow.prec_cap, False, False, self.prime_pow) + + cdef pAdicTemplateElement lift_to_precision_c(self, long absprec): + """ + Lifts this element to another with precision at least absprec. + + Since floating point elements don't track precision, this + function just returns the same element. + + EXAMPLES:: + + sage: R = ZpFP(5); + sage: a = R(77, 2); a + 2 + 3*5^2 + O(5^20) + sage: a.lift_to_precision(17) # indirect doctest + 2 + 3*5^2 + O(5^20) + """ + return self + + def list(self, lift_mode = 'simple', start_val = None): + r""" + Returns a list of coefficients in a power series expansion of + this element in terms of `\pi`. If this is a field element, + they start at `\pi^{\mbox{valuation}}`, if a ring element at `\pi^0`. + + For each lift mode, this function returns a list of `a_i` so + that this element can be expressed as + + .. MATH:: + + \pi^v \cdot \sum_{i=0}^\infty a_i \pi^i + + where `v` is the valuation of this element when the parent is + a field, and `v = 0` otherwise. + + Different lift modes affect the choice of `a_i`. When + ``lift_mode`` is ``'simple'``, the resulting `a_i` will be + non-negative: if the residue field is `\mathbb{F}_p` then they + will be integers with `0 \le a_i < p`; otherwise they will be + a list of integers in the same range giving the coefficients + of a polynomial in the indeterminant representing the maximal + unramified subextension. + + Choosing ``lift_mode`` as ``'smallest'`` is similar to + ``'simple'``, but uses a balanced representation `-p/2 < a_i + \le p/2`. + + Finally, setting ``lift_mode = 'teichmuller'`` will yield + Teichmuller representatives for the `a_i`: `a_i^q = a_i`. In + this case the `a_i` will also be `p`-adic elements. + + INPUT: + + - ``lift_mode`` -- ``'simple'``, ``'smallest'`` or + ``'teichmuller'`` (default: ``'simple'``) + + - ``start_val`` -- start at this valuation rather than the + default (`0` or the valuation of this element). If + ``start_val`` is larger than the valuation of this element + a ``ValueError`` is raised. + + OUTPUT: + + - the list of coefficients of this element. For base elements + these will be integers if ``lift_mode`` is ``'simple'`` or + ``'smallest'``, and elements of ``self.parent()`` if + ``lift_mode`` is ``'teichmuller'``. + + .. NOTE:: + + Use slice operators to get a particular range. + + EXAMPLES:: + + sage: R = ZpFP(7,6); a = R(12837162817); a + 3 + 4*7 + 4*7^2 + 4*7^4 + O(7^6) + sage: L = a.list(); L + [3, 4, 4, 0, 4] + sage: sum([L[i] * 7^i for i in range(len(L))]) == a + True + sage: L = a.list('smallest'); L + [3, -3, -2, 1, -3, 1] + sage: sum([L[i] * 7^i for i in range(len(L))]) == a + True + sage: L = a.list('teichmuller'); L + [3 + 4*7 + 6*7^2 + 3*7^3 + 2*7^5, + 0, + 5 + 2*7 + 3*7^3 + 6*7^4 + 4*7^5, + 1, + 3 + 4*7 + 6*7^2 + 3*7^3 + 2*7^5, + 5 + 2*7 + 3*7^3 + 6*7^4 + 4*7^5] + sage: sum([L[i] * 7^i for i in range(len(L))]) + 3 + 4*7 + 4*7^2 + 4*7^4 + + sage: R(0).list() + [] + + sage: R = QpFP(7,4); a = R(6*7+7**2); a.list() + [6, 1] + sage: a.list('smallest') + [-1, 2] + sage: a.list('teichmuller') + [6 + 6*7 + 6*7^2 + 6*7^3, + 2 + 4*7 + 6*7^2 + 3*7^3, + 3 + 4*7 + 6*7^2 + 3*7^3, + 3 + 4*7 + 6*7^2 + 3*7^3] + """ + R = self.parent() + if start_val is not None and start_val > self.ordp: + raise ValueError("starting valuation must be smaller than the element's valuation. See slice()") + if very_pos_val(self.ordp): + return [] + elif very_neg_val(self.ordp): + if lift_mode == 'teichmuller': + return [R(1)] + elif R.f() == 1: + return [ZZ(1)] + else: + return [[ZZ(1)]] + if lift_mode == 'teichmuller': + ulist = self.teichmuller_list() + elif lift_mode == 'simple': + ulist = clist(self.unit, self.prime_pow.prec_cap, True, self.prime_pow) + elif lift_mode == 'smallest': + ulist = clist(self.unit, self.prime_pow.prec_cap, False, self.prime_pow) + else: + raise ValueError("unknown lift_mode") + if (self.prime_pow.in_field and self.ordp > 0) or start_val is not None: + if lift_mode = 'teichmuller': + zero = R(0) + else: + # needs to be defined in the linkage file. + zero = _list_zero + if start_val is None: + v = self.ordp + else: + v = self.ordp - start_val + ulist = [zero] * v + ulist + return ulist + + def teichmuller_list(self): + r""" + Returns a list [`a_0`, `a_1`,..., `a_n`] such that + + - `a_i^q = a_i` + + - self.unit_part() = `\sum_{i = 0}^n a_i \pi^i` + + EXAMPLES:: + + sage: R = ZpFP(5,5); R(14).list('teichmuller') #indirect doctest + [4 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5), + 3 + 3*5 + 2*5^2 + 3*5^3 + 5^4 + O(5^5), + 2 + 5 + 2*5^2 + 5^3 + 3*5^4 + O(5^5), + 1 + O(5^5), + 4 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)] + """ + cdef FPElement list_elt + ans = PyList_New(0) + if very_pos_val(self.ordp): + return ans + if very_neg_val(self.ordp): + csetone(list_elt.unit, self.prime_pow) + PyList_Append(ans, list_elt) + return ans + cdef long prec_cap = self.prime_pow.prec_cap + cdef long curpower = prec_cap + cdef FPElement tmp = self._new_c() + ccopy(tmp.unit, self.unit, self.prime_pow) + while not ciszero(tmp.unit, tmp.prime_pow) and curpower > 0: + list_elt = self._new_c() + cteichmuller(list_elt.unit, tmp.unit, prec_cap, self.prime_pow) + if ciszero(list_elt.unit, self.prime_pow): + list_elt.ordp = maxordp + cshift_notrunc(tmp.unit, tmp.unit, -1, prec_cap, self.prime_pow) + else: + list_elt.ordp = 0 + csub(tmp.unit, tmp.unit, list_elt.unit, prec_cap, self.prime_pow) + cshift_notrunc(tmp.unit, tmp.unit, -1, prec_cap, self.prime_pow) + creduce(tmp.unit, tmp.unit, prec_cap, self.prime_pow) + curpower -= 1 + PyList_Append(ans, list_elt) + return ans + + def _teichmuller_set_unsafe(self): + """ + Sets this element to the Teichmuller representative with the + same residue. + + .. WARNING:: + + This function modifies the element, which is not safe. + Elements are supposed to be immutable. + + EXAMPLES:: + + sage: R = ZpFP(17,5); a = R(11) + sage: a + 11 + O(17^5) + sage: a._teichmuller_set_unsafe(); a + 11 + 14*17 + 2*17^2 + 12*17^3 + 15*17^4 + O(17^5) + sage: a.list('teichmuller') + [11 + 14*17 + 2*17^2 + 12*17^3 + 15*17^4 + O(17^5)] + + Note that if you set an element which is congruent to 0 you + get 0 to maximum precision:: + + sage: b = R(17*5); b + 5*17 + O(17^5) + sage: b._teichmuller_set_unsafe(); b + O(17^5) + """ + if self.ordp > 0: + self._set_exact_zero() + elif self.ordp < 0: + raise ValueError("cannot set negative valuation element to Teichmuller representative.") + else: + cteichmuller(self.unit, self.unit, self.prime_pow.prec_cap, self.prime_pow) + + def precision_absolute(self): + """ + The absolute precision of this element. + + EXAMPLES:: + + sage: R = Zp(7,4,'floating-point'); a = R(7); a.precision_absolute() + 5 + sage: R(0).precision_absolute() + infinity + sage: (~R(0)).precision_absolute() + -infinity + """ + if very_pos_val(self.ordp): + return infinity + elif very_neg_val(self.ordp): + return -infinity + cdef Integer ans = PY_NEW(Integer) + mpz_set_si(ans.value, self.ordp + self.prime_pow.prec_cap) + return ans + + def precision_relative(self): + r""" + The relative precision of this element. + + EXAMPLES:: + + sage: R = Zp(7,4,'floating-point'); a = R(7); a.precision_relative() + 4 + sage: R(0).precision_relative() + 0 + sage: (~R(0)).precision_relative() + 0 + """ + cdef Integer ans = PY_NEW(Integer) + if huge_val(self.ordp): + mpz_set_si(ans.value, 0) + else: + mpz_set_si(ans.value, self.prime_pow.prec_cap) + return ans + + cpdef pAdicTemplateElement unit_part(FPElement self): + r""" + Returns the unit part of self. + + If the valuation of self is positive, then the high digits of the + result will be zero. + + EXAMPLES:: + + sage: R = Zp(17, 4, 'floating-point') + sage: R(5).unit_part() + 5 + O(17^4) + sage: R(18*17).unit_part() + 1 + 17 + O(17^4) + sage: R(0).unit_part() + O(17^4) + sage: type(R(5).unit_part()) + + sage: R = ZpFP(5, 5); a = R(75); a.unit_part() + 3 + O(5^5) + """ + if huge_val(self.ordp): + raise ValueError("unit part of 0 and infinitynot defined") + cdef FPElement ans = (self)._new_c() + ans.ordp = 0 + ccopy(ans.unit, (self).unit, ans.prime_pow) + return ans + + cdef long valuation_c(self): + """ + Returns the valuation of this element. + + If this element is an exact zero, returns ``maxordp``, which is defined as + ``(1L << (sizeof(long) * 8 - 2))-1``. + + If this element is infinity, returns ``-maxordp``. + + TESTS:: + + sage: R = ZpFP(5, 5); R(1).valuation() #indirect doctest + 0 + sage: R = Zp(17, 4,'floating-point') + sage: a = R(2*17^2) + sage: a.valuation() + 2 + sage: R = Zp(5, 4,'floating-point') + sage: R(0).valuation() + infinity + sage: R(1).valuation() + 0 + sage: R(2).valuation() + 0 + sage: R(5).valuation() + 1 + sage: R(10).valuation() + 1 + sage: R(25).valuation() + 2 + sage: R(50).valuation() + 2 + """ + return self.ordp + + cpdef val_unit(self, p=None): + """ + Returns a 2-tuple, the first element set to the valuation of + this element, and the second to the unit part. + + If this element is either zero or infinity, raises an error. + + EXAMPLES:: + + sage: R = ZpFP(5,5) + sage: a = R(75); b = a - a + sage: a.val_unit() + (2, 3) + sage: b.val_unit() + (5, O(5^5)) + """ + if p is not None and p != self.parent().prime(): + raise ValueError('Ring (%s) residue field of the wrong characteristic.'%self.parent()) + if huge_val(self.ordp): + raise ValueError("unit part of 0 and infinity not defined") + cdef Integer valuation = PY_NEW(Integer) + mpz_set_si(valuation.value, self.ordp) + cdef FPElement unit = self._new_c() + unit.ordp = 0 + ccopy(unit.unit, self.unit, unit.prime_pow) + return valuation, unit + + def __hash__(self): + """ + Hashing. + + EXAMPLES:: + + sage: R = ZpFP(11, 5) + sage: hash(R(3)) == hash(3) + True + """ + if very_pos_val(self.ordp): + return 0 + if very_neg_val(self.ordp): + return 314159 + return chash(self.unit, self.ordp, self.prime_pow.prec_cap, self.prime_pow) ^ self.ordp + +cdef class pAdicCoercion_ZZ_FP(RingHomomorphism_coercion): + """ + The canonical inclusion from the integer ring to a floating point ring. + + EXAMPLES:: + + sage: f = ZpFP(5).coerce_map_from(ZZ); f + Ring Coercion morphism: + From: Integer Ring + To: 5-adic Ring with floating precision 20 + """ + def __init__(self, R): + """ + Initialization. + + EXAMPLES:: + + sage: f = ZpFP(5).coerce_map_from(ZZ); type(f) + + """ + RingHomomorphism_coercion.__init__(self, ZZ.Hom(R), check=False) + self._zero = R._element_constructor(R, 0) + self._section = pAdicConvert_FP_ZZ(R) + + cdef dict _extra_slots(self, dict _slots): + """ + Helper for copying and pickling. + + EXAMPLES:: + + sage: f = ZpFP(5).coerce_map_from(ZZ) + sage: g = copy(f) # indirect doctest + sage: g == f + True + sage: g(6) + 1 + 5 + O(5^20) + sage: g(6) == f(6) + True + """ + _slots['_zero'] = self._zero + _slots['_section'] = self._section + return RingHomomorphism_coercion._extra_slots(self, _slots) + + cdef _update_slots(self, dict _slots): + """ + Helper for copying and pickling. + + EXAMPLES:: + + sage: f = ZpFP(5).coerce_map_from(ZZ) + sage: g = copy(f) # indirect doctest + sage: g == f + True + sage: g(6) + 1 + 5 + O(5^20) + sage: g(6) == f(6) + True + """ + self._zero = _slots['_zero'] + self._section = _slots['_section'] + RingHomomorphism_coercion._update_slots(self, _slots) + + cpdef Element _call_(self, x): + """ + Evaluation. + + EXAMPLES:: + + sage: f = ZpFP(5).coerce_map_from(ZZ) + sage: f(0).parent() + 5-adic Ring of floating point 5^20 + sage: f(5) + 5 + O(5^20) + """ + if mpz_sgn((x).value) == 0: + return self._zero + cdef FPElement ans = self._zero._new_c() + ans.ordp = cconv_mpz_t(ans.unit, (x).value, ans.prime_pow.prec_cap, False, ans.prime_pow) + return ans + + cpdef Element _call_with_args(self, x, args=(), kwds={}): + """ + This function is used when some precision cap is passed in (relative or absolute or both). + + INPUT: + + - ``x`` -- an Integer + + - ``absprec``, or the first positional argument -- the maximum + absolute precision (unused for floating point elements). + + - ``relprec``, or the second positional argument -- the + maximum relative precision (unused for floating point + elements) + + EXAMPLES:: + + sage: R = ZpFP(5,4) + sage: type(R(10,2)) + + sage: R(30,2) + 5 + 5^2 + O(5^4) + sage: R(30,3,1) + 5 + 5^2 + O(5^4) + sage: R(30,absprec=2) + 5 + 5^2 + O(5^4) + sage: R(30,relprec=2) + 5 + 5^2 + O(5^4) + sage: R(30,absprec=1) + 5 + 5^2 + O(5^4) + sage: R(30,empty=True) + 5 + 5^2 + O(5^4) + """ + cdef long val, aprec, rprec + if mpz_sgn((x).value) == 0: + return self._zero + _process_args_and_kwds(&aprec, &rprec, args, kwds, False, self._zero.prime_pow) + val = get_ordp(x, self._zero.prime_pow) + if aprec - val < rprec: + rprec = aprec - val + if rprec <= 0: + return self._zero + cdef FPElement ans = self._zero._new_c() + ans.ordp = cconv_mpz_t(ans.unit, (x).value, rprec, False, ans.prime_pow) + return ans + + def section(self): + """ + Returns a map back to ZZ that approximates an element of this + `p`-adic ring by an integer. + + EXAMPLES:: + + sage: f = ZpFP(5).coerce_map_from(ZZ).section() + sage: f(ZpFP(5)(-1)) - 5^20 + -1 + """ + return self._section + +cdef class pAdicConvert_FP_ZZ(RingMap): + """ + The map from a floating point ring back to ZZ that returns the the smallest + non-negative integer approximation to its input which is accurate up to the precision. + + If the input is not in the closure of the image of ZZ, raises a ValueError. + + EXAMPLES:: + + sage: f = ZpFP(5).coerce_map_from(ZZ).section(); f + Set-theoretic ring morphism: + From: 5-adic Ring of floating point 5^20 + To: Integer Ring + """ + def __init__(self, R): + """ + Initialization. + + EXAMPLES:: + + sage: f = ZpFP(5).coerce_map_from(ZZ).section(); type(f) + + sage: f.category() + Category of homsets of sets + """ + if R.degree() > 1 or R.characteristic() != 0 or R.residue_characteristic() == 0: + RingMap.__init__(self, Hom(R, ZZ, SetsWithPartialMaps())) + else: + RingMap.__init__(self, Hom(R, ZZ, Sets())) + + cpdef Element _call_(self, _x): + """ + Evaluation. + + EXAMPLES:: + + sage: f = ZpFP(5).coerce_map_from(ZZ).section() + sage: f(ZpFP(5)(-1)) - 5^20 + -1 + sage: f(ZpFP(5)(0)) + 0 + """ + cdef Integer ans = PY_NEW(Integer) + cdef FPElement x = _x + cconv_mpz_t_out(ans.unit, x.unit, 0, x.prime_pow.prec_cap, x.prime_pow) + return ans + +cdef class pAdicConvert_QQ_FP(Morphism): + """ + The inclusion map from QQ to a floating point ring that is defined + on all elements with non-negative p-adic valuation. + + EXAMPLES:: + + sage: f = ZpFP(5).convert_map_from(QQ); f + Generic morphism: + From: Rational Field + To: 5-adic Ring of fixed modulus 5^20 + """ + def __init__(self, R): + """ + Initialization. + + EXAMPLES:: + + sage: f = ZpFP(5).convert_map_from(QQ); type(f) + + """ + Morphism.__init__(self, Hom(QQ, R, SetsWithPartialMaps())) + self._zero = R._element_constructor(R, 0) + + cdef dict _extra_slots(self, dict _slots): + """ + Helper for copying and pickling. + + EXAMPLES:: + + sage: f = ZpFP(5).convert_map_from(QQ) + sage: g = copy(f) # indirect doctest + sage: g == f # todo: comparison not implemented + True + sage: g(1/6) + 1 + 4*5 + 4*5^3 + 4*5^5 + 4*5^7 + 4*5^9 + 4*5^11 + 4*5^13 + 4*5^15 + 4*5^17 + 4*5^19 + O(5^20) + sage: g(1/6) == f(1/6) + True + """ + _slots['_zero'] = self._zero + return Morphism._extra_slots(self, _slots) + + cdef _update_slots(self, dict _slots): + """ + Helper for copying and pickling. + + EXAMPLES:: + + sage: f = ZpFP(5).convert_map_from(QQ) + sage: g = copy(f) # indirect doctest + sage: g == f # todo: comparison not implemented + True + sage: g(1/6) + 1 + 4*5 + 4*5^3 + 4*5^5 + 4*5^7 + 4*5^9 + 4*5^11 + 4*5^13 + 4*5^15 + 4*5^17 + 4*5^19 + O(5^20) + sage: g(1/6) == f(1/6) + True + """ + self._zero = _slots['_zero'] + Morphism._update_slots(self, _slots) + + cpdef Element _call_(self, x): + """ + Evaluation. + + EXAMPLES:: + + sage: f = ZpFP(5,4).convert_map_from(QQ) + sage: f(1/7) + 3 + 3*5 + 2*5^3 + O(5^4) + sage: f(0) + O(5^4) + """ + if mpq_sgn((x).unit) == 0: + return self._zero + cdef FPElement ans = self._zero._new_c() + cconv_mpq_t(ans.unit, (x).unit, ans.prime_pow.prec_cap, True, ans.prime_pow) + return ans + + cpdef Element _call_with_args(self, x, args=(), kwds={}): + """ + This function is used when some precision cap is passed in (relative or absolute or both). + + INPUT: + + - ``x`` -- a Rational + + - ``absprec``, or the first positional argument -- the maximum + absolute precision (unused for floating point elements). + + - ``relprec``, or the second positional argument -- the + maximum relative precision (unused for floating point + elements) + + EXAMPLES:: + + sage: R = ZpFP(5,4) + sage: type(R(1/7,2)) + + sage: R(1/7,2) + 3 + 3*5 + 2*5^3 + O(5^4) + sage: R(1/7,3,1) + 3 + 3*5 + 2*5^3 + O(5^4) + sage: R(1/7,absprec=2) + 3 + 3*5 + 2*5^3 + O(5^4) + sage: R(1/7,relprec=2) + 3 + 3*5 + 2*5^3 + O(5^4) + sage: R(1/7,absprec=1) + 3 + 3*5 + 2*5^3 + O(5^4) + sage: R(1/7,empty=True) + 3 + 3*5 + 2*5^3 + O(5^4) + """ + if mpq_sgn((x).unit) == 0: + return self._zero + cdef FPElement ans = self._zero._new_c() + cconv_mpq_t(ans.unit, (x).unit, ans.prime_pow.prec_cap, True, ans.prime_pow) + return ans + +def unpickle_fpe_v2(cls, parent, unit, ordp): + """ + Unpickles a capped relative element. + + EXAMPLES:: + + sage: from sage.rings.padics.padic_floating_point_element import pAdicFloatingPointElement, unpickle_fpe_v2 + sage: R = ZpFP(5) + sage: a = unpickle_fpe_v2(pAdicFloatingPointElement, R, 17*25); a + 2*5^2 + 3*5^3 + O(5^20) + sage: a.parent() is R + True + """ + cdef FPElement ans = cls.__new__(cls) + ans._parent = parent + ans.prime_pow = parent.prime_pow + cconstruct(ans.unit, ans.prime_pow) + cunpickle(ans.unit, unit, ans.prime_pow) + ans.ordp = ordp + return ans From 695b2932587b4cafcbe886116913866ac39f574c Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 23 Dec 2016 23:01:08 -0800 Subject: [PATCH 003/126] Making lots of changes for floating point p-adics. --- src/module_list.py | 7 + src/sage/rings/padics/FP_template.pxi | 537 +++++++++++++----- src/sage/rings/padics/FP_template_header.pxi | 55 ++ src/sage/rings/padics/all.py | 4 +- src/sage/rings/padics/factory.py | 154 ++++- src/sage/rings/padics/generic_nodes.py | 44 ++ src/sage/rings/padics/local_generic.py | 25 + src/sage/rings/padics/padic_base_generic.py | 18 +- src/sage/rings/padics/padic_base_leaves.py | 183 +++++- .../rings/padics/padic_extension_leaves.py | 116 +++- .../padics/padic_floating_point_element.pxd | 13 + .../padics/padic_floating_point_element.pyx | 304 ++++++++++ .../rings/padics/padic_generic_element.pyx | 4 +- src/sage/rings/padics/padic_printing.pxd | 1 + src/sage/rings/padics/padic_printing.pyx | 78 ++- src/sage/rings/padics/pow_computer.pyx | 2 + src/sage/rings/padics/pow_computer_flint.pyx | 2 + src/sage/rings/padics/qadic_flint_FP.pxd | 11 + src/sage/rings/padics/qadic_flint_FP.pyx | 124 ++++ 19 files changed, 1490 insertions(+), 192 deletions(-) create mode 100644 src/sage/rings/padics/FP_template_header.pxi create mode 100644 src/sage/rings/padics/padic_floating_point_element.pxd create mode 100644 src/sage/rings/padics/padic_floating_point_element.pyx create mode 100644 src/sage/rings/padics/qadic_flint_FP.pxd create mode 100644 src/sage/rings/padics/qadic_flint_FP.pyx diff --git a/src/module_list.py b/src/module_list.py index 0dee41b9fa4..7f997e36849 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1485,6 +1485,9 @@ def uname_specific(name, value, alternative): Extension('sage.rings.padics.padic_capped_relative_element', sources = ['sage/rings/padics/padic_capped_relative_element.pyx']), + Extension('sage.rings.padics.padic_floating_point_element', + sources = ['sage/rings/padics/padic_floating_point_element.pyx']), + Extension('sage.rings.padics.padic_ext_element', sources = ['sage/rings/padics/padic_ext_element.pyx'], libraries=['ntl', 'gmp', 'gmpxx', 'm'], @@ -1548,6 +1551,10 @@ def uname_specific(name, value, alternative): sources = ['sage/rings/padics/qadic_flint_FM.pyx'], libraries = ["flint"]), + Extension('sage.rings.padics.qadic_flint_FP', + sources = ['sage/rings/padics/qadic_flint_FP.pyx'], + libraries = ["flint"]), + ################################ ## ## sage.rings.polynomial diff --git a/src/sage/rings/padics/FP_template.pxi b/src/sage/rings/padics/FP_template.pxi index ac40ea3799a..7c08103e94a 100644 --- a/src/sage/rings/padics/FP_template.pxi +++ b/src/sage/rings/padics/FP_template.pxi @@ -45,7 +45,7 @@ from sage.categories.sets_cat import Sets from sage.categories.sets_with_partial_maps import SetsWithPartialMaps from sage.categories.homset import Hom -cdef inline bint overunderflow(long* ordp, celement unit, PowComputer_class prime_pow): +cdef inline bint overunderflow(long* ordp, celement unit, PowComputer_ prime_pow): """ Check for over and underflow. If detected, sets ordp and unit appropriately, and returns True. If not, returns False. @@ -60,7 +60,7 @@ cdef inline bint overunderflow(long* ordp, celement unit, PowComputer_class prim return False return True -cdef inline bint overunderlow_mpz(long* ordp, mpz_t ordp_mpz, celement unit, PowComputer_class prime_pow): +cdef inline bint overunderflow_mpz(long* ordp, mpz_t ordp_mpz, celement unit, PowComputer_ prime_pow): """ Check for over and underflow with an mpz_t ordp. If detected, sets ordp and unit appropriately, and returns True. If not, returns False. @@ -128,9 +128,10 @@ cdef class FPElement(pAdicTemplateElement): 0 """ cconstruct(self.unit, self.prime_pow) - if exactzero(val): - self.ordp = maxordp - csetzero(self.unit) + if very_pos_val(val): + self._set_exact_zero() + elif very_neg_val(val): + self._set_infinity() else: self.ordp = val if isinstance(x,FPElement) and x.parent() is self.parent(): @@ -186,7 +187,7 @@ cdef class FPElement(pAdicTemplateElement): TESTS:: sage: ZpFP(5)(1).lift_to_precision(30) # indirect doctest - 1 + O(5^20) + 1 """ pass @@ -207,6 +208,32 @@ cdef class FPElement(pAdicTemplateElement): ccopy(ans.unit, self.unit, ans.prime_pow) return ans + cdef int _normalize(self) except -1: + """ + Normalizes this element, so that ``self.ordp`` is correct. + + TESTS:: + + sage: R = ZpFP(5) + sage: R(6) + R(4) #indirect doctest + 2*5 + """ + cdef long diff + cdef bint is_zero + if very_pos_val(self.ordp): + self._set_exact_zero() + elif very_neg_val(self.ordp): + self._set_infinity() + else: + is_zero = creduce(self.unit, self.unit, self.prime_pow.prec_cap, self.prime_pow) + if is_zero: + self.ordp = maxordp + else: + diff = cremove(self.unit, self.unit, self.prime_pow.prec_cap, self.prime_pow) + self.ordp += diff + if very_pos_val(self.ordp): + self._set_exact_zero() + def __dealloc__(self): """ Deallocate the underlying data structure. @@ -234,23 +261,23 @@ cdef class FPElement(pAdicTemplateElement): """ return unpickle_fpe_v2, (self.__class__, self.parent(), cpickle(self.unit, self.prime_pow), self.ordp) - def __richcmp__(self, right, int op): - """ - Compare this element to ``right`` using the comparison operator ``op``. - - TESTS:: - - sage: R = ZpFP(5) - sage: a = R(17) - sage: b = R(21) - sage: a == b - False - sage: a < b - True - """ - return (self)._richcmp(right, op) - - cpdef ModuleElement _neg_(self): +# def __richcmp__(self, right, int op): +# """ +# Compare this element to ``right`` using the comparison operator ``op``. +# +# TESTS:: +# +# sage: R = ZpFP(5) +# sage: a = R(17) +# sage: b = R(21) +# sage: a == b +# False +# sage: a < b +# True +# """ +# return (self)._richcmp(right, op) + + cpdef _neg_(self): r""" Return the additive inverse of this element. @@ -258,7 +285,7 @@ cdef class FPElement(pAdicTemplateElement): sage: R = Zp(7, 4, 'floating-point', 'series') sage: -R(7) #indirect doctest - 6*7 + 6*7^2 + 6*7^3 + O(7^4) + 6*7 + 6*7^2 + 6*7^3 + 6*7^4 """ cdef FPElement ans = self._new_c() ans.ordp = self.ordp @@ -269,7 +296,7 @@ cdef class FPElement(pAdicTemplateElement): creduce_small(ans.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) return ans - cpdef ModuleElement _add_(self, ModuleElement _right): + cpdef _add_(self, _right): r""" Return the sum of this element and ``_right``. @@ -277,11 +304,11 @@ cdef class FPElement(pAdicTemplateElement): sage: R = Zp(7, 4, 'floating-point', 'series') sage: x = R(1721); x - 6 + 5*7^3 + O(7^4) + 6 + 5*7^3 sage: y = R(1373); y - 1 + 4*7^3 + O(7^4) + 1 + 4*7^3 sage: x + y #indirect doctest - 7 + 2*7^3 + O(7^4) + 7 + 2*7^3 """ cdef FPElement ans cdef FPElement right = _right @@ -308,10 +335,10 @@ cdef class FPElement(pAdicTemplateElement): else: cshift(ans.unit, right.unit, tmpL, ans.prime_pow.prec_cap, ans.prime_pow, False) cadd(ans.unit, ans.unit, self.unit, ans.prime_pow.prec_cap, ans.prime_pow) - creduce(ans.unit, ans.unit, ans.relprec, ans.prime_pow) + creduce(ans.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) return ans - cpdef ModuleElement _sub_(self, ModuleElement _right): + cpdef _sub_(self, _right): r""" Return the difference of this element and ``_right``. @@ -319,11 +346,11 @@ cdef class FPElement(pAdicTemplateElement): sage: R = Zp(7, 4, 'floating-point', 'series') sage: x = R(1721); x - 6 + 5*7^3 + O(7^4) + 6 + 5*7^3 sage: y = R(1373); y - 1 + 4*7^3 + O(7^4) + 1 + 4*7^3 sage: x - y #indirect doctest - 5 + 7^3 + O(7^4) + 5 + 7^3 """ cdef FPElement ans cdef FPElement right = _right @@ -347,7 +374,7 @@ cdef class FPElement(pAdicTemplateElement): else: cshift(ans.unit, right.unit, tmpL, ans.prime_pow.prec_cap, ans.prime_pow, False) csub(ans.unit, self.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) - creduce(ans.unit, ans.unit, ans.relprec, ans.prime_pow) + creduce(ans.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) else: tmpL = self.ordp - right.ordp if tmpL > self.prime_pow.prec_cap: @@ -359,7 +386,7 @@ cdef class FPElement(pAdicTemplateElement): else: cshift(ans.unit, self.unit, tmpL, ans.prime_pow.prec_cap, ans.prime_pow, False) csub(ans.unit, ans.unit, right.unit, ans.prime_pow.prec_cap, ans.prime_pow) - creduce(ans.unit, ans.unit, ans.relprec, ans.prime_pow) + creduce(ans.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) return ans def __invert__(self): @@ -370,15 +397,11 @@ cdef class FPElement(pAdicTemplateElement): sage: R = Zp(7, 4, 'floating-point', 'series') sage: ~R(2) - 4 + 3*7 + 3*7^2 + 3*7^3 + O(7^4) + 4 + 3*7 + 3*7^2 + 3*7^3 sage: ~R(0) - Traceback (most recent call last): - ... - ValueError: cannot invert non-unit + infinity sage: ~R(7) - Traceback (most recent call last): - ... - ValueError: cannot invert non-unit + 7^-1 """ # Input should be normalized! cdef FPElement ans = self._new_c() @@ -394,7 +417,7 @@ cdef class FPElement(pAdicTemplateElement): cinvert(ans.unit, self.unit, ans.prime_pow.prec_cap, ans.prime_pow) return ans - cpdef RingElement _mul_(self, RingElement _right): + cpdef _mul_(self, _right): r""" Return the product of this element and ``_right``. @@ -402,9 +425,9 @@ cdef class FPElement(pAdicTemplateElement): sage: R = Zp(7, 4, 'floating-point', 'series') sage: R(3) * R(2) #indirect doctest - 6 + O(7^4) + 6 sage: R(1/2) * R(2) - 1 + O(7^4) + 1 """ cdef FPElement right = _right if very_pos_val(self.ordp): @@ -427,24 +450,19 @@ cdef class FPElement(pAdicTemplateElement): creduce(ans.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) return ans - cpdef RingElement _div_(self, RingElement _right): + cpdef _div_(self, _right): r""" - Return the quotient of this element and ``right``. ``right`` must have - valuation zero. + Return the quotient of this element and ``right``. EXAMPLES:: sage: R = Zp(7, 4, 'floating-point', 'series') sage: R(3) / R(2) #indirect doctest - 5 + 3*7 + 3*7^2 + 3*7^3 + O(7^4) + 5 + 3*7 + 3*7^2 + 3*7^3 sage: R(5) / R(0) - Traceback (most recent call last): - ... - ValueError: cannot invert non-unit + infinity sage: R(7) / R(49) - Traceback (most recent call last): - ... - ValueError: cannot invert non-unit + 7^-1 """ # Input should be normalized! cdef FPElement ans, right = _right @@ -480,22 +498,15 @@ cdef class FPElement(pAdicTemplateElement): sage: R = ZpFP(11, 5) sage: R(1/2)^5 - 10 + 7*11 + 11^2 + 5*11^3 + 4*11^4 + O(11^5) + 10 + 7*11 + 11^2 + 5*11^3 + 4*11^4 sage: R(1/32) - 10 + 7*11 + 11^2 + 5*11^3 + 4*11^4 + O(11^5) + 10 + 7*11 + 11^2 + 5*11^3 + 4*11^4 sage: R(1/2)^5 == R(1/32) True sage: R(3)^1000 #indirect doctest - 1 + 4*11^2 + 3*11^3 + 7*11^4 + O(11^5) - - TESTS: - - We check that :trac:`15640` is resolved:: - + 1 + 4*11^2 + 3*11^3 + 7*11^4 sage: R(11)^-1 - Traceback (most recent call last): - ... - ValueError: cannot invert non-unit + 11^-1 """ cdef long dummyL cdef mpz_t tmp @@ -505,7 +516,7 @@ cdef class FPElement(pAdicTemplateElement): if isinstance(_right, (Integer, int, long, Rational)): if _right < 0: self = ~self - _right = -right + _right = -_right exact_exp = True elif self.parent() is _right.parent(): ## For extension elements, we need to switch to the @@ -654,6 +665,29 @@ cdef class FPElement(pAdicTemplateElement): ans._normalize() return ans + def _repr_(self, mode=None, do_latex=False): + """ + Returns a string representation of this element. + + INPUT: + + - ``mode`` -- allows one to override the default print mode of + the parent (default: ``None``). + + - ``do_latex`` -- whether to return a latex representation or + a normal one. + + EXAMPLES:: + + sage: ZpFP(5,5)(1/3) # indirect doctest + 2 + 3*5 + 5^2 + 3*5^3 + 5^4 + sage: ~QpFP(5,5)(0) + infinity + """ + if very_neg_val(self.ordp): + return "infinity" + return self.parent()._printer.repr_gen(self, do_latex, mode=mode) + def add_bigoh(self, absprec): """ Returns a new element truncated modulo `\pi^{\mbox{absprec}}`. @@ -672,7 +706,7 @@ cdef class FPElement(pAdicTemplateElement): 1 """ cdef long aprec, newprec - if absprec is inifinity or very_neg_val(self.ordp): + if absprec is infinity or very_neg_val(self.ordp): return self elif isinstance(absprec, int): aprec = absprec @@ -703,7 +737,7 @@ cdef class FPElement(pAdicTemplateElement): sage: R = Zp(7,4,'floating-point','series'); a = R(8); a._is_exact_zero() False - sage: b = R(0); a._is_exact_zero() + sage: b = R(0); b._is_exact_zero() True """ return very_pos_val(self.ordp) @@ -736,7 +770,7 @@ cdef class FPElement(pAdicTemplateElement): sage: R(0).is_zero() True sage: R(17^6).is_zero() - True + False sage: R(17^2).is_zero(absprec=2) True """ @@ -857,9 +891,9 @@ cdef class FPElement(pAdicTemplateElement): sage: R = ZpFP(5); sage: a = R(77, 2); a - 2 + 3*5^2 + O(5^20) + 2 sage: a.lift_to_precision(17) # indirect doctest - 2 + 3*5^2 + O(5^20) + 2 """ return self @@ -919,7 +953,7 @@ cdef class FPElement(pAdicTemplateElement): EXAMPLES:: sage: R = ZpFP(7,6); a = R(12837162817); a - 3 + 4*7 + 4*7^2 + 4*7^4 + O(7^6) + 3 + 4*7 + 4*7^2 + 4*7^4 sage: L = a.list(); L [3, 4, 4, 0, 4] sage: sum([L[i] * 7^i for i in range(len(L))]) == a @@ -971,8 +1005,8 @@ cdef class FPElement(pAdicTemplateElement): ulist = clist(self.unit, self.prime_pow.prec_cap, False, self.prime_pow) else: raise ValueError("unknown lift_mode") - if (self.prime_pow.in_field and self.ordp > 0) or start_val is not None: - if lift_mode = 'teichmuller': + if (self.prime_pow.in_field == 0 and self.ordp > 0) or start_val is not None: + if lift_mode == 'teichmuller': zero = R(0) else: # needs to be defined in the linkage file. @@ -995,18 +1029,20 @@ cdef class FPElement(pAdicTemplateElement): EXAMPLES:: sage: R = ZpFP(5,5); R(14).list('teichmuller') #indirect doctest - [4 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5), - 3 + 3*5 + 2*5^2 + 3*5^3 + 5^4 + O(5^5), - 2 + 5 + 2*5^2 + 5^3 + 3*5^4 + O(5^5), - 1 + O(5^5), - 4 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5)] + [4 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4, + 3 + 3*5 + 2*5^2 + 3*5^3 + 5^4, + 2 + 5 + 2*5^2 + 5^3 + 3*5^4, + 1, + 4 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4] """ cdef FPElement list_elt ans = PyList_New(0) if very_pos_val(self.ordp): return ans if very_neg_val(self.ordp): + list_elt = self._new_c() csetone(list_elt.unit, self.prime_pow) + list_elt.ordp = 0 PyList_Append(ans, list_elt) return ans cdef long prec_cap = self.prime_pow.prec_cap @@ -1042,19 +1078,19 @@ cdef class FPElement(pAdicTemplateElement): sage: R = ZpFP(17,5); a = R(11) sage: a - 11 + O(17^5) + 11 sage: a._teichmuller_set_unsafe(); a - 11 + 14*17 + 2*17^2 + 12*17^3 + 15*17^4 + O(17^5) + 11 + 14*17 + 2*17^2 + 12*17^3 + 15*17^4 sage: a.list('teichmuller') - [11 + 14*17 + 2*17^2 + 12*17^3 + 15*17^4 + O(17^5)] + [11 + 14*17 + 2*17^2 + 12*17^3 + 15*17^4] Note that if you set an element which is congruent to 0 you get 0 to maximum precision:: sage: b = R(17*5); b - 5*17 + O(17^5) + 5*17 sage: b._teichmuller_set_unsafe(); b - O(17^5) + 0 """ if self.ordp > 0: self._set_exact_zero() @@ -1072,9 +1108,9 @@ cdef class FPElement(pAdicTemplateElement): sage: R = Zp(7,4,'floating-point'); a = R(7); a.precision_absolute() 5 sage: R(0).precision_absolute() - infinity + +Infinity sage: (~R(0)).precision_absolute() - -infinity + -Infinity """ if very_pos_val(self.ordp): return infinity @@ -1106,27 +1142,29 @@ cdef class FPElement(pAdicTemplateElement): cpdef pAdicTemplateElement unit_part(FPElement self): r""" - Returns the unit part of self. + Returns the unit part of this element. - If the valuation of self is positive, then the high digits of the - result will be zero. + If the valuation of this element is positive, then the high + digits of the result will be zero. EXAMPLES:: sage: R = Zp(17, 4, 'floating-point') sage: R(5).unit_part() - 5 + O(17^4) + 5 sage: R(18*17).unit_part() - 1 + 17 + O(17^4) + 1 + 17 sage: R(0).unit_part() - O(17^4) + Traceback (most recent call last): + ... + ValueError: unit part of 0 and infinity not defined sage: type(R(5).unit_part()) sage: R = ZpFP(5, 5); a = R(75); a.unit_part() - 3 + O(5^5) + 3 """ if huge_val(self.ordp): - raise ValueError("unit part of 0 and infinitynot defined") + raise ValueError("unit part of 0 and infinity not defined") cdef FPElement ans = (self)._new_c() ans.ordp = 0 ccopy(ans.unit, (self).unit, ans.prime_pow) @@ -1151,7 +1189,9 @@ cdef class FPElement(pAdicTemplateElement): 2 sage: R = Zp(5, 4,'floating-point') sage: R(0).valuation() - infinity + +Infinity + sage: (~R(0)).valuation() + -Infinity sage: R(1).valuation() 0 sage: R(2).valuation() @@ -1181,7 +1221,9 @@ cdef class FPElement(pAdicTemplateElement): sage: a.val_unit() (2, 3) sage: b.val_unit() - (5, O(5^5)) + Traceback (most recent call last): + ... + ValueError: unit part of 0 and infinity not defined """ if p is not None and p != self.parent().prime(): raise ValueError('Ring (%s) residue field of the wrong characteristic.'%self.parent()) @@ -1245,7 +1287,7 @@ cdef class pAdicCoercion_ZZ_FP(RingHomomorphism_coercion): sage: g == f True sage: g(6) - 1 + 5 + O(5^20) + 1 + 5 sage: g(6) == f(6) True """ @@ -1264,7 +1306,7 @@ cdef class pAdicCoercion_ZZ_FP(RingHomomorphism_coercion): sage: g == f True sage: g(6) - 1 + 5 + O(5^20) + 1 + 5 sage: g(6) == f(6) True """ @@ -1280,9 +1322,9 @@ cdef class pAdicCoercion_ZZ_FP(RingHomomorphism_coercion): sage: f = ZpFP(5).coerce_map_from(ZZ) sage: f(0).parent() - 5-adic Ring of floating point 5^20 + 5-adic Ring with floating precision 20 sage: f(5) - 5 + O(5^20) + 5 """ if mpz_sgn((x).value) == 0: return self._zero @@ -1311,17 +1353,17 @@ cdef class pAdicCoercion_ZZ_FP(RingHomomorphism_coercion): sage: type(R(10,2)) sage: R(30,2) - 5 + 5^2 + O(5^4) - sage: R(30,3,1) - 5 + 5^2 + O(5^4) + 5 + sage: R(30,3,2) + 5 + 5^2 sage: R(30,absprec=2) - 5 + 5^2 + O(5^4) + 5 sage: R(30,relprec=2) - 5 + 5^2 + O(5^4) + 5 + 5^2 sage: R(30,absprec=1) - 5 + 5^2 + O(5^4) + 0 sage: R(30,empty=True) - 5 + 5^2 + O(5^4) + 0 """ cdef long val, aprec, rprec if mpz_sgn((x).value) == 0: @@ -1360,7 +1402,7 @@ cdef class pAdicConvert_FP_ZZ(RingMap): sage: f = ZpFP(5).coerce_map_from(ZZ).section(); f Set-theoretic ring morphism: - From: 5-adic Ring of floating point 5^20 + From: 5-adic Ring with floating precision 20 To: Integer Ring """ def __init__(self, R): @@ -1385,28 +1427,241 @@ cdef class pAdicConvert_FP_ZZ(RingMap): EXAMPLES:: - sage: f = ZpFP(5).coerce_map_from(ZZ).section() - sage: f(ZpFP(5)(-1)) - 5^20 + sage: f = QpFP(5).coerce_map_from(ZZ).section() + sage: f(QpFP(5)(-1)) - 5^20 -1 - sage: f(ZpFP(5)(0)) + sage: f(QpFP(5)(5)) + 5 + sage: f(QpFP(5)(0)) 0 + sage: f(~QpFP(5)(5)) + Traceback (most recent call last): + ... + ValueError: negative valuation + sage: f(~QpFP(5)(0)) + Traceback (most recent call last): + ... + ValueError: Infinity cannot be converted to a rational """ cdef Integer ans = PY_NEW(Integer) cdef FPElement x = _x - cconv_mpz_t_out(ans.unit, x.unit, 0, x.prime_pow.prec_cap, x.prime_pow) + if very_pos_val(x.ordp): + mpz_set_ui(ans.value, 0) + elif very_neg_val(x.ordp): + raise ValueError("Infinity cannot be converted to a rational") + else: + cconv_mpz_t_out(ans.value, x.unit, x.ordp, x.prime_pow.prec_cap, x.prime_pow) + return ans + +cdef class pAdicCoercion_QQ_FP(RingHomomorphism_coercion): + """ + The canonical inclusion from the rationals to a floating point field. + + EXAMPLES:: + + sage: f = QpFP(5).coerce_map_from(QQ); f + Ring Coercion morphism: + From: Rational Field + To: 5-adic Field with floating precision 20 + """ + def __init__(self, R): + """ + Initialization. + + EXAMPLES:: + + sage: f = QpFP(5).coerce_map_from(QQ); type(f) + + """ + RingHomomorphism_coercion.__init__(self, QQ.Hom(R), check=False) + self._zero = R._element_constructor(R, 0) + self._section = pAdicConvert_FP_QQ(R) + + cdef dict _extra_slots(self, dict _slots): + """ + Helper for copying and pickling. + + EXAMPLES:: + + sage: f = QpFP(5).coerce_map_from(QQ) + sage: g = copy(f) # indirect doctest + sage: g + Ring Coercion morphism: + From: Rational Field + To: 5-adic Field with floating precision 20 + sage: g == f + True + sage: g is f + False + sage: g(6) + 1 + 5 + sage: g(6) == f(6) + True + """ + _slots['_zero'] = self._zero + _slots['_section'] = self._section + return RingHomomorphism_coercion._extra_slots(self, _slots) + + cdef _update_slots(self, dict _slots): + """ + Helper for copying and pickling. + + EXAMPLES:: + + sage: f = QpFP(5).coerce_map_from(QQ) + sage: g = copy(f) # indirect doctest + sage: g + Ring Coercion morphism: + From: Rational Field + To: 5-adic Field with floating precision 20 + sage: g == f + True + sage: g is f + False + sage: g(6) + 1 + 5 + sage: g(6) == f(6) + True + """ + self._zero = _slots['_zero'] + self._section = _slots['_section'] + RingHomomorphism_coercion._update_slots(self, _slots) + + cpdef Element _call_(self, x): + """ + Evaluation. + + EXAMPLES:: + + sage: f = QpFP(5).coerce_map_from(QQ) + sage: f(0).parent() + 5-adic Field with floating precision 20 + sage: f(1/5) + 5^-1 + sage: f(1/4) + 4 + 3*5 + 3*5^2 + 3*5^3 + 3*5^4 + 3*5^5 + 3*5^6 + 3*5^7 + 3*5^8 + 3*5^9 + 3*5^10 + 3*5^11 + 3*5^12 + 3*5^13 + 3*5^14 + 3*5^15 + 3*5^16 + 3*5^17 + 3*5^18 + 3*5^19 + sage: f(1/4, 5) + 4 + 3*5 + 3*5^2 + 3*5^3 + 3*5^4 + """ + if mpq_sgn((x).value) == 0: + return self._zero + cdef FPElement ans = self._zero._new_c() + ans.ordp = cconv_mpq_t(ans.unit, (x).value, ans.prime_pow.prec_cap, False, self._zero.prime_pow) + return ans + + cpdef Element _call_with_args(self, x, args=(), kwds={}): + """ + This function is used when some precision cap is passed in + (relative or absolute or both). + + See the documentation for + :meth:`pAdicCappedRelativeElement.__init__` for more details. + + EXAMPLES:: + + sage: R = QpFP(5,4) + sage: type(R(10/3,2)) + + sage: R(10/3,2) + 4*5 + sage: R(10/3,3,1) + 4*5 + sage: R(10/3,absprec=2) + 4*5 + sage: R(10/3,relprec=2) + 4*5 + 5^2 + sage: R(10/3,absprec=1) + 0 + sage: R(3/100,absprec=-1) + 2*5^-2 + """ + cdef long val, aprec, rprec + cdef FPElement ans + _process_args_and_kwds(&aprec, &rprec, args, kwds, False, self._zero.prime_pow) + if mpq_sgn((x).value) == 0: + return self._zero + val = get_ordp(x, self._zero.prime_pow) + if aprec <= val: + return self._zero + ans = self._zero._new_c() + rprec = min(rprec, aprec - val) + ans.ordp = cconv_mpq_t(ans.unit, (x).value, rprec, False, self._zero.prime_pow) + return ans + + def section(self): + """ + Returns a map back to the rationals that approximates an element by + a rational number. + + EXAMPLES:: + + sage: f = QpFP(5).coerce_map_from(QQ).section() + sage: f(QpFP(5)(1/4)) + 1/4 + sage: f(QpFP(5)(1/5)) + 1/5 + """ + return self._section + +cdef class pAdicConvert_FP_QQ(RingMap): + """ + The map from the floating point ring back to the rationals that returns a + rational approximation of its input. + + EXAMPLES:: + + sage: f = QpFP(5).coerce_map_from(QQ).section(); f + Set-theoretic ring morphism: + From: 5-adic Field with floating precision 20 + To: Rational Field + """ + def __init__(self, R): + """ + Initialization. + + EXAMPLES:: + + sage: f = QpFP(5).coerce_map_from(QQ).section(); type(f) + + sage: f.category() + Category of homsets of sets with partial maps + """ + RingMap.__init__(self, Hom(R, QQ, SetsWithPartialMaps())) + + cpdef Element _call_(self, _x): + """ + Evaluation. + + EXAMPLES:: + + sage: f = QpFP(5).coerce_map_from(QQ).section() + sage: f(QpFP(5)(-1)) + -1 + sage: f(QpFP(5)(0)) + 0 + sage: f(QpFP(5)(1/5)) + 1/5 + """ + cdef Rational ans = Rational.__new__(Rational) + cdef FPElement x = _x + if very_pos_val(x.ordp): + mpq_set_ui(ans.value, 0, 1) + elif very_neg_val(x.ordp): + raise ValueError("Infinity cannot be converted to a rational") + else: + cconv_mpq_t_out(ans.value, x.unit, x.ordp, x.prime_pow.prec_cap, x.prime_pow) return ans cdef class pAdicConvert_QQ_FP(Morphism): """ - The inclusion map from QQ to a floating point ring that is defined - on all elements with non-negative p-adic valuation. + The inclusion map from QQ to a floating point ring. EXAMPLES:: sage: f = ZpFP(5).convert_map_from(QQ); f Generic morphism: From: Rational Field - To: 5-adic Ring of fixed modulus 5^20 + To: 5-adic Ring with floating precision 20 """ def __init__(self, R): """ @@ -1431,7 +1686,7 @@ cdef class pAdicConvert_QQ_FP(Morphism): sage: g == f # todo: comparison not implemented True sage: g(1/6) - 1 + 4*5 + 4*5^3 + 4*5^5 + 4*5^7 + 4*5^9 + 4*5^11 + 4*5^13 + 4*5^15 + 4*5^17 + 4*5^19 + O(5^20) + 1 + 4*5 + 4*5^3 + 4*5^5 + 4*5^7 + 4*5^9 + 4*5^11 + 4*5^13 + 4*5^15 + 4*5^17 + 4*5^19 sage: g(1/6) == f(1/6) True """ @@ -1449,7 +1704,7 @@ cdef class pAdicConvert_QQ_FP(Morphism): sage: g == f # todo: comparison not implemented True sage: g(1/6) - 1 + 4*5 + 4*5^3 + 4*5^5 + 4*5^7 + 4*5^9 + 4*5^11 + 4*5^13 + 4*5^15 + 4*5^17 + 4*5^19 + O(5^20) + 1 + 4*5 + 4*5^3 + 4*5^5 + 4*5^7 + 4*5^9 + 4*5^11 + 4*5^13 + 4*5^15 + 4*5^17 + 4*5^19 sage: g(1/6) == f(1/6) True """ @@ -1464,14 +1719,16 @@ cdef class pAdicConvert_QQ_FP(Morphism): sage: f = ZpFP(5,4).convert_map_from(QQ) sage: f(1/7) - 3 + 3*5 + 2*5^3 + O(5^4) - sage: f(0) - O(5^4) + 3 + 3*5 + 2*5^3 + sage: f(0/1) + 0 """ - if mpq_sgn((x).unit) == 0: + if mpq_sgn((x).value) == 0: return self._zero cdef FPElement ans = self._zero._new_c() - cconv_mpq_t(ans.unit, (x).unit, ans.prime_pow.prec_cap, True, ans.prime_pow) + ans.ordp = cconv_mpq_t(ans.unit, (x).value, ans.prime_pow.prec_cap, False, ans.prime_pow) + if ans.ordp < 0: + raise ValueError("p divides the denominator") return ans cpdef Element _call_with_args(self, x, args=(), kwds={}): @@ -1495,34 +1752,42 @@ cdef class pAdicConvert_QQ_FP(Morphism): sage: type(R(1/7,2)) sage: R(1/7,2) - 3 + 3*5 + 2*5^3 + O(5^4) - sage: R(1/7,3,1) - 3 + 3*5 + 2*5^3 + O(5^4) + 3 + 3*5 + sage: R(1/7,3,2) + 3 + 3*5 sage: R(1/7,absprec=2) - 3 + 3*5 + 2*5^3 + O(5^4) - sage: R(1/7,relprec=2) - 3 + 3*5 + 2*5^3 + O(5^4) + 3 + 3*5 + sage: R(5/7,relprec=2) + 3*5 + 3*5^2 sage: R(1/7,absprec=1) - 3 + 3*5 + 2*5^3 + O(5^4) + 3 sage: R(1/7,empty=True) - 3 + 3*5 + 2*5^3 + O(5^4) + 0 """ - if mpq_sgn((x).unit) == 0: + cdef long val, aprec, rprec + if mpq_sgn((x).value) == 0: + return self._zero + _process_args_and_kwds(&aprec, &rprec, args, kwds, False, self._zero.prime_pow) + val = get_ordp(x, self._zero.prime_pow) + rprec = min(rprec, aprec - val) + if rprec <= 0: return self._zero cdef FPElement ans = self._zero._new_c() - cconv_mpq_t(ans.unit, (x).unit, ans.prime_pow.prec_cap, True, ans.prime_pow) + ans.ordp = cconv_mpq_t(ans.unit, (x).value, rprec, False, ans.prime_pow) + if ans.ordp < 0: + raise ValueError("p divides the denominator") return ans def unpickle_fpe_v2(cls, parent, unit, ordp): """ - Unpickles a capped relative element. + Unpickles a floating point element. EXAMPLES:: sage: from sage.rings.padics.padic_floating_point_element import pAdicFloatingPointElement, unpickle_fpe_v2 sage: R = ZpFP(5) - sage: a = unpickle_fpe_v2(pAdicFloatingPointElement, R, 17*25); a - 2*5^2 + 3*5^3 + O(5^20) + sage: a = unpickle_fpe_v2(pAdicFloatingPointElement, R, 17, 2); a + 2*5^2 + 3*5^3 sage: a.parent() is R True """ diff --git a/src/sage/rings/padics/FP_template_header.pxi b/src/sage/rings/padics/FP_template_header.pxi new file mode 100644 index 00000000000..6a991d3c85a --- /dev/null +++ b/src/sage/rings/padics/FP_template_header.pxi @@ -0,0 +1,55 @@ +""" +This file provides the declaration for ``FPElement`` and the morphisms +to and from the integers and rationals. + +It is included in the .pxd files associated to gluing files, such as +padic_floating_point_element.pxd. + +AUTHORS: + +- David Roe (2012-03-01) -- initial version +""" + +#***************************************************************************** +# Copyright (C) 2012 David Roe +# William Stein +# +# Distributed under the terms of the GNU General Public License (GPL) +# 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/ +#***************************************************************************** + +# includes the header for pAdicTemplateElement +include "padic_template_element_header.pxi" + +from sage.categories.morphism cimport Morphism +from sage.rings.morphism cimport RingHomomorphism_coercion, RingMap + +cdef class FPElement(pAdicTemplateElement): + cdef celement unit + cdef long ordp + + cdef FPElement _new_c(self) + cdef int _normalize(self) except -1 + cdef int _set_infinity(self) except -1 + +cdef class pAdicCoercion_ZZ_FP(RingHomomorphism_coercion): + cdef FPElement _zero + cdef RingMap _section +cdef class pAdicConvert_FP_ZZ(RingMap): + pass +cdef class pAdicCoercion_QQ_FP(RingHomomorphism_coercion): + cdef FPElement _zero + cdef RingMap _section +cdef class pAdicConvert_FP_QQ(RingMap): + pass +cdef class pAdicConvert_QQ_FP(Morphism): + cdef FPElement _zero + cdef RingMap _section +cdef class pAdicCoercion_FP_frac_field(RingHomomorphism_coercion): + cdef FPElement _zero + cdef Morphism _section +cdef class pAdicConvert_FP_frac_field(Morphism): + cdef FPElement _zero diff --git a/src/sage/rings/padics/all.py b/src/sage/rings/padics/all.py index 7fe2a73483d..809b4aafe9f 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, ZqCR, ZqCA, ZqFM #, ZpL, ZqL -from .factory import Qp, Qq, Qp as pAdicField, QpCR, QqCR #, QpL, QqL +from .factory import Zp, Zq, Zp as pAdicRing, ZpCR, ZpCA, ZpFM, ZpFP, ZqCR, ZqCA, ZqFM, ZqFP #, ZpL, ZqL +from .factory import Qp, Qq, Qp as pAdicField, QpCR, QpFP, 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 79688be9d0a..3bbef03ee3c 100644 --- a/src/sage/rings/padics/factory.py +++ b/src/sage/rings/padics/factory.py @@ -30,7 +30,9 @@ from .padic_base_leaves import (pAdicRingCappedRelative, pAdicRingCappedAbsolute, pAdicRingFixedMod, - pAdicFieldCappedRelative) + pAdicRingFloatingPoint, + pAdicFieldCappedRelative, + pAdicFieldFloatingPoint) from . import padic_printing ###################################################### @@ -49,6 +51,8 @@ ext_table['e', pAdicRingCappedAbsolute] = EisensteinExtensionRingCappedAbsolute ext_table['e', pAdicRingCappedRelative] = EisensteinExtensionRingCappedRelative ext_table['e', pAdicRingFixedMod] = EisensteinExtensionRingFixedMod +#ext_table['e', pAdicRingFloatingPoint] = EisensteinExtensionRingFloatingPoint +#ext_table['e', pAdicFieldFloatingPoint] = EisensteinExtensionFieldFloatingPoint #ext_table['e', pAdicRingLazy] = EisensteinExtensionRingLazy #ext_table['p', pAdicFieldCappedRelative] = pAdicGeneralExtensionFieldCappedRelative #ext_table['p', pAdicFieldLazy] = pAdicGeneralExtensionFieldLazy @@ -61,6 +65,8 @@ ext_table['u', pAdicRingCappedAbsolute] = UnramifiedExtensionRingCappedAbsolute ext_table['u', pAdicRingCappedRelative] = UnramifiedExtensionRingCappedRelative ext_table['u', pAdicRingFixedMod] = UnramifiedExtensionRingFixedMod +ext_table['u', pAdicRingFloatingPoint] = UnramifiedExtensionRingFloatingPoint +ext_table['u', pAdicFieldFloatingPoint] = UnramifiedExtensionFieldFloatingPoint #ext_table['u', pAdicRingLazy] = UnramifiedExtensionRingLazy @@ -185,7 +191,7 @@ class Qp_class(UniqueFactory): TYPES and PRECISION below. - ``type`` -- string (default: ``'capped-rel'``) Valid types are - ``'capped-rel'`` and ``'lazy'`` (though ``'lazy'`` currently + ``'capped-rel'``, ``'floating-point'`` and ``'lazy'`` (though ``'lazy'`` currently doesn't work). See TYPES and PRECISION below - ``print_mode`` -- string (default: ``None``). Valid modes are 'series', @@ -236,8 +242,8 @@ class Qp_class(UniqueFactory): sage: a.precision_absolute() 22 - There are two types of `p`-adic fields: capped relative fields and - lazy fields. + There are three types of `p`-adic fields: capped relative fields, + floating point fields and lazy fields. In the capped relative case, the relative precision of an element is restricted to be at most a certain value, specified at the @@ -254,6 +260,10 @@ class Qp_class(UniqueFactory): sage: a + b 1 + 5 + 5^2 + 4*5^3 + 2*5^4 + O(5^5) + In the floating point case, elements do not track their + precision, but the relative precision of elements is truncated + during arithmetic to the precision cap of the field. + The lazy case will eventually support elements that can increase their precision upon request. It is not currently implemented. @@ -472,7 +482,7 @@ def create_key(self, p, prec = DEFAULT_PREC, type = 'capped-rel', print_mode = N sage: Qp.create_key(5,40) (5, 40, 'capped-rel', 'series', '5', True, '|', (), -1) """ - return get_key_base(p, prec, type, print_mode, halt, names, ram_name, print_pos, print_sep, print_alphabet, print_max_terms, check, ['capped-rel']) + return get_key_base(p, prec, type, print_mode, halt, names, ram_name, print_pos, print_sep, print_alphabet, print_max_terms, check, ['capped-rel', 'floating-point']) def create_object(self, version, key): """ @@ -514,6 +524,13 @@ def create_object(self, version, key): else: return pAdicFieldCappedRelative(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms}, name) + elif type == 'floating-point': + if print_mode == 'terse': + return pAdicFieldFloatingPoint(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': False}, name) + 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': False}, name) else: raise ValueError("unexpected type") @@ -545,8 +562,8 @@ def Qq(q, prec = DEFAULT_PREC, type = 'capped-rel', modulus = None, names=None, TYPES and PRECISION below. - ``type`` -- string (default: ``'capped-rel'``) Valid types are - ``'capped-rel'`` and ``'lazy'`` (though ``'lazy'`` doesn't currently work). - See TYPES and PRECISION below + ``'capped-rel'``, ``'floating-point'`` and ``'lazy'`` (though ``'lazy'`` + doesn't currently work). See TYPES and PRECISION below - ``modulus`` -- polynomial (default ``None``) A polynomial defining an unramified extension of `\mathbb{Q}_p`. See MODULUS below. @@ -608,8 +625,8 @@ def Qq(q, prec = DEFAULT_PREC, type = 'capped-rel', modulus = None, names=None, sage: b.precision_absolute() 22 - There are two types of unramified `p`-adic fields: capped relative - fields and lazy fields. + There are three types of unramified `p`-adic fields: capped relative + fields, floating point fields and lazy fields. In the capped relative case, the relative precision of an element is restricted to be at most a certain value, specified at the @@ -626,6 +643,10 @@ def Qq(q, prec = DEFAULT_PREC, type = 'capped-rel', modulus = None, names=None, sage: b + c 2 + (2*a + 2)*3 + (2*a + 2)*3^2 + 3^4 + O(3^5) + In the floating point case, elements do not track their + precision, but the relative precision of elements is truncated + during arithmetic to the precision cap of the field. + The lazy case will eventually support elements that can increase their precision upon request. It is not currently implemented. @@ -1043,6 +1064,23 @@ def QpCR(p, prec = DEFAULT_PREC, print_mode = None, halt = DEFAULT_HALT, names = print_pos=print_pos, print_sep=print_sep, print_alphabet=print_alphabet, print_max_terms=print_max_terms, type = 'capped-rel') +def QpFP(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): + """ + A shortcut function to create floating point `p`-adic fields. + + Same functionality as ``Qp``. See documentation for ``Qp`` for a + description of the input parameters. + + EXAMPLES:: + + sage: QpFP(5, 40) + 5-adic Field with floating precision 40 + """ + return Qp(p=p, prec=prec, print_mode=print_mode, halt=halt, check=check, names=names, + print_pos=print_pos, print_sep=print_sep, print_alphabet=print_alphabet, print_max_terms=print_max_terms, + type = 'floating-point') + #def QpL(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): # """ @@ -1079,6 +1117,27 @@ def QqCR(q, prec = DEFAULT_PREC, modulus = None, names=None, print_max_unram_terms=print_max_unram_terms, print_max_terse_terms=print_max_terse_terms, check=check, implementation=implementation, type = 'capped-rel') +def QqFP(q, prec = DEFAULT_PREC, modulus = None, names=None, + print_mode=None, halt = DEFAULT_HALT, ram_name = None, print_pos = None, + print_sep = None, print_alphabet = None, print_max_ram_terms = None, + print_max_unram_terms = None, print_max_terse_terms = None, check = True, implementation = 'FLINT'): + """ + A shortcut function to create floating point unramified `p`-adic + fields. + + Same functionality as ``Qq``. See documentation for ``Qq`` for a + description of the input parameters. + + EXAMPLES:: + + sage: R. = QqFP(25, 40); R + Unramified Extension of 5-adic Field with floating precision 40 in a defined by x^2 + 4*x + 2 + """ + return Qq(q, prec=prec, modulus=modulus, names=names, print_mode=print_mode, + halt=halt, ram_name=ram_name, print_pos=print_pos, print_max_ram_terms=print_max_ram_terms, + print_max_unram_terms=print_max_unram_terms, print_max_terse_terms=print_max_terse_terms, + check=check, implementation=implementation, type = 'floating-point') + #def QqL(q, prec = DEFAULT_PREC, modulus = None, names=None, # print_mode=None, halt = DEFAULT_HALT, ram_name = None, print_pos = None, # print_sep = None, print_alphabet = None, print_max_ram_terms = None, @@ -1119,9 +1178,9 @@ class Zp_class(UniqueFactory): below. - ``type`` -- string (default: ``'capped-rel'``) Valid types are - ``'capped-rel'``, ``'capped-abs'``, ``'fixed-mod'`` and - ``'lazy'`` (though lazy is not yet implemented). See TYPES and - PRECISION below + ``'capped-rel'``, ``'capped-abs'``, ``'fixed-mod'``, + ``'floating-point'`` and ``'lazy'`` (though lazy is not yet + implemented). See TYPES and PRECISION below - ``print_mode`` -- string (default: ``None``). Valid modes are ``'series'``, ``'val-unit'``, ``'terse'``, ``'digits'``, and @@ -1170,9 +1229,10 @@ class Zp_class(UniqueFactory): sage: a.precision_absolute() 22 - There are four types of `p`-adic rings: capped relative rings + There are five types of `p`-adic rings: capped relative rings (type= ``'capped-rel'``), capped absolute rings - (type= ``'capped-abs'``), fixed modulus ring (type= ``'fixed-mod'``) + (type= ``'capped-abs'``), fixed modulus rings (type= ``'fixed-mod'``), + floating point rings (type=``'floating-point'``), and lazy rings (type= ``'lazy'``). In the capped relative case, the relative precision of an element @@ -1216,6 +1276,10 @@ class Zp_class(UniqueFactory): sage: a // 5 1 + 2*5^2 + 5^3 + O(5^5) + The floating point case is similar to the fixed modulus type + in that elements do not trac their own precision. However, relative + precision is truncated with each operation rather than absolute precision. + The lazy case will eventually support elements that can increase their precision upon request. It is not currently implemented. @@ -1471,7 +1535,7 @@ def create_key(self, p, prec = DEFAULT_PREC, type = 'capped-rel', print_mode = N (5, 40, 'capped-rel', 'digits', '5', True, '|', ('0', '1', '2', '3', '4'), -1) """ return get_key_base(p, prec, type, print_mode, halt, names, ram_name, print_pos, print_sep, print_alphabet, - print_max_terms, check, ['capped-rel', 'fixed-mod', 'capped-abs']) + print_max_terms, check, ['capped-rel', 'fixed-mod', 'capped-abs', 'floating-point']) def create_object(self, version, key): """ @@ -1515,6 +1579,9 @@ def create_object(self, version, key): elif type == 'capped-abs': return pAdicRingCappedAbsolute(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, 'ram_name': name, 'max_ram_terms': print_max_terms}, name) + 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': False}, name) else: raise ValueError("unexpected type") @@ -1543,8 +1610,9 @@ def Zq(q, prec = DEFAULT_PREC, type = 'capped-abs', modulus = None, names=None, field. Individual elements keep track of their own precision. See TYPES and PRECISION below. - - ``type`` -- string (default: ``'capped-rel'``) Valid types are - ``'capped-rel'`` and ``'lazy'`` (though ``'lazy'`` doesn't + - ``type`` -- string (default: ``'capped-abs'``) Valid types are + ``'capped-abs'``, ``'capped-rel'``, ``'fixed-mod'``, + ``'floating-point'`` and ``'lazy'`` (though ``'lazy'`` doesn't currently work). See TYPES and PRECISION below - modulus -- polynomial (default None) A polynomial defining an @@ -1611,8 +1679,11 @@ def Zq(q, prec = DEFAULT_PREC, type = 'capped-abs', modulus = None, names=None, sage: b.precision_absolute() 22 - There are four types of unramified `p`-adic rings: capped relative - rings, capped absolute rings, fixed modulus rings, and lazy rings. + There are five 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'``), + 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 @@ -1661,6 +1732,10 @@ def Zq(q, prec = DEFAULT_PREC, type = 'capped-abs', modulus = None, names=None, sage: b*c >> 1 2*3^2 + (2*a + 2)*3^3 + O(3^5) + The floating point case is similar to the fixed modulus type + in that elements do not trac their own precision. However, relative + precision is truncated with each operation rather than absolute precision. + The lazy case will eventually support elements that can increase their precision upon request. It is not currently implemented. @@ -1984,6 +2059,7 @@ def Zq(q, prec = DEFAULT_PREC, type = 'capped-abs', modulus = None, names=None, True sage: Zq(125.factor(), names="alpha") is R True + """ if check: if isinstance(q, Factorization) or isinstance(q, (list, tuple)): @@ -2095,6 +2171,23 @@ def ZpFM(p, prec = DEFAULT_PREC, print_mode = None, halt = DEFAULT_HALT, names = print_pos=print_pos, print_sep=print_sep, print_alphabet=print_alphabet, print_max_terms=print_max_terms, type = 'fixed-mod') +def ZpFP(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): + """ + A shortcut function to create floating point `p`-adic rings. + + Same functionality as ``Zp``. See documentation for ``Zp`` for a + description of the input parameters. + + EXAMPLES:: + + sage: ZpFP(5, 40) + 5-adic Ring with floating precision 40 + """ + return Zp(p=p, prec=prec, print_mode=print_mode, halt=halt, check=check, names=names, + print_pos=print_pos, print_sep=print_sep, print_alphabet=print_alphabet, print_max_terms=print_max_terms, + type = 'floating-point') + #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): # """ @@ -2167,6 +2260,26 @@ def ZqFM(q, prec = DEFAULT_PREC, modulus = None, names=None, print_max_unram_terms=print_max_unram_terms, print_max_terse_terms=print_max_terse_terms, check=check, implementation=implementation, type = 'fixed-mod') +def ZqFP(q, prec = DEFAULT_PREC, modulus = None, names=None, + print_mode=None, halt = DEFAULT_HALT, ram_name = None, print_pos = None, + print_sep = None, print_alphabet = None, print_max_ram_terms = None, + print_max_unram_terms = None, print_max_terse_terms = None, check = True, implementation = 'FLINT'): + """ + A shortcut function to create floating point unramified `p`-adic rings. + + Same functionality as ``Zq``. See documentation for ``Zq`` for a + description of the input parameters. + + EXAMPLES:: + + sage: R. = ZqFP(25, 40); R + Unramified Extension of 5-adic Ring with floating precision 40 in a defined by x^2 + 4*x + 2 + """ + return Zq(q, prec=prec, modulus=modulus, names=names, print_mode=print_mode, + halt=halt, ram_name=ram_name, print_pos=print_pos, print_max_ram_terms=print_max_ram_terms, + print_max_unram_terms=print_max_unram_terms, print_max_terse_terms=print_max_terse_terms, + check=check, implementation=implementation, type = 'floating-point') + #def ZqL(q, prec = DEFAULT_PREC, modulus = None, names=None, # print_mode=None, halt = DEFAULT_HALT, ram_name = None, print_pos = None, # print_sep = None, print_alphabet = None, print_max_ram_terms = None, @@ -2392,10 +2505,11 @@ def create_object(self, version, key, shift_seed): if polytype == 'u' or polytype == 'e': (polytype, base, premodulus, modulus, names, prec, halt, print_mode, print_pos, print_sep, print_alphabet, print_max_ram_terms, print_max_unram_terms, print_max_terse_terms, implementation) = key + show_prec = base._printer._show_prec() T = ext_table[polytype, type(base.ground_ring_of_tower()).__base__] return T(premodulus, modulus, prec, halt, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'max_ram_terms': print_max_ram_terms, 'max_unram_terms': print_max_unram_terms, 'max_terse_terms': print_max_terse_terms}, + 'max_ram_terms': print_max_ram_terms, 'max_unram_terms': print_max_unram_terms, 'max_terse_terms': print_max_terse_terms, 'show_prec': show_prec}, shift_seed, names, implementation) elif polytype == 'p': (polytype, base, premodulus, upoly, epoly, names, prec, halt, print_mode, print_pos, print_sep, diff --git a/src/sage/rings/padics/generic_nodes.py b/src/sage/rings/padics/generic_nodes.py index a464120ac81..c0e4ee95984 100644 --- a/src/sage/rings/padics/generic_nodes.py +++ b/src/sage/rings/padics/generic_nodes.py @@ -140,6 +140,46 @@ def _prec_type(self): """ return 'fixed-mod' +class FloatingPointGeneric(LocalGeneric): + def is_floating_point(self): + """ + Returns whether this `p`-adic ring uses a floating point precision model. + + Elements in the floating point model are stored by giving a + valuation and a unit part. Arithmetic is done where the unit + part is truncated modulo a fixed power of the uniformizer, + stored in the precision cap of the parent. + + EXAMPLES:: + + sage: R = ZpFP(5,15) + sage: R.is_floating_point() + True + sage: R(5^7,absprec=9) + 5^7 + sage: S = ZpCR(5,15) + sage: S.is_floating_point() + False + sage: S(5^7,absprec=9) + 5^7 + O(5^9) + """ + return True + + def _prec_type(self): + """ + Returns the precision handling type. + + EXAMPLES:: + + sage: ZpFP(5)._prec_type() + 'floating-point' + """ + return 'floating-point' + +class FloatingPointRingGeneric(FloatingPointGeneric): + pass +class FloatingPointFieldGeneric(FloatingPointGeneric):#, sage.rings.ring.Field): + pass class CappedRelativeRingGeneric(CappedRelativeGeneric): pass class CappedRelativeFieldGeneric(CappedRelativeGeneric):#, sage.rings.ring.Field): @@ -247,6 +287,10 @@ class pAdicCappedRelativeRingGeneric(pAdicRingGeneric, CappedRelativeRingGeneric pass class pAdicCappedRelativeFieldGeneric(pAdicFieldGeneric, CappedRelativeFieldGeneric): pass +class pAdicFloatingPointRingGeneric(pAdicRingGeneric, FloatingPointRingGeneric): + pass +class pAdicFloatingPointFieldGeneric(pAdicFieldGeneric, FloatingPointFieldGeneric): + pass class pAdicRingBaseGeneric(pAdicBaseGeneric, pAdicRingGeneric): def construction(self): diff --git a/src/sage/rings/padics/local_generic.py b/src/sage/rings/padics/local_generic.py index 8fbaef3d9d0..cd9cfb749c4 100644 --- a/src/sage/rings/padics/local_generic.py +++ b/src/sage/rings/padics/local_generic.py @@ -138,6 +138,31 @@ def is_fixed_mod(self): """ return False + def is_floating_point(self): + """ + Returns whether this `p`-adic ring bounds precision in a floating + point fashion. + + The relative precision of an element is the power of `p` + modulo which the unit part of that element is defined. In a + floating point ring, elements do not store precision, but arithmetic + operations truncate to a relative precision depending on the ring. + + EXAMPLES:: + + sage: R = ZpCR(5, 15) + sage: R.is_floating_point() + False + sage: R(5^7) + 5^7 + O(5^22) + sage: S = ZpFP(5, 15) + sage: S.is_floating_point() + True + sage: S(5^7) + 5^7 + """ + return False + def is_lazy(self): """ Returns whether this `p`-adic ring bounds precision in a lazy diff --git a/src/sage/rings/padics/padic_base_generic.py b/src/sage/rings/padics/padic_base_generic.py index 8b14d3931a8..2aee170a4dc 100644 --- a/src/sage/rings/padics/padic_base_generic.py +++ b/src/sage/rings/padics/padic_base_generic.py @@ -25,6 +25,7 @@ from sage.rings.padics.padic_capped_relative_element import pAdicCoercion_ZZ_CR, pAdicCoercion_QQ_CR, pAdicConvert_QQ_CR from sage.rings.padics.padic_capped_absolute_element import pAdicCoercion_ZZ_CA, pAdicConvert_QQ_CA from sage.rings.padics.padic_fixed_mod_element import pAdicCoercion_ZZ_FM, pAdicConvert_QQ_FM +from sage.rings.padics.padic_floating_point_element import pAdicCoercion_ZZ_FP, pAdicCoercion_QQ_FP, pAdicConvert_QQ_FP class pAdicBaseGeneric(pAdicGeneric): _implementation = 'GMP' @@ -39,8 +40,12 @@ def __init__(self, p, prec, print_mode, names, element_class): self.prime_pow = PowComputer(p, max(min(prec - 1, 30), 1), prec, self.is_field(), self._prec_type()) pAdicGeneric.__init__(self, self, p, prec, print_mode, names, element_class) if self.is_field(): - coerce_list = [pAdicCoercion_ZZ_CR(self), pAdicCoercion_QQ_CR(self)] - convert_list = [] + if self.is_capped_relative(): + coerce_list = [pAdicCoercion_ZZ_CR(self), pAdicCoercion_QQ_CR(self)] + convert_list = [] + else: + coerce_list = [pAdicCoercion_ZZ_FP(self), pAdicCoercion_QQ_FP(self)] + convert_list = [] elif self.is_capped_relative(): coerce_list = [pAdicCoercion_ZZ_CR(self)] convert_list = [pAdicConvert_QQ_CR(self)] @@ -50,6 +55,9 @@ def __init__(self, p, prec, print_mode, names, element_class): elif self.is_fixed_mod(): coerce_list = [pAdicCoercion_ZZ_FM(self)] convert_list = [pAdicConvert_QQ_FM(self)] + elif self.is_floating_point(): + coerce_list = [pAdicCoercion_ZZ_FP(self)] + convert_list = [pAdicConvert_QQ_FP(self)] else: raise RuntimeError self._populate_coercion_lists_(coerce_list=coerce_list, convert_list=convert_list, element_constructor=element_class) @@ -78,7 +86,11 @@ def fraction_field(self, print_mode=None): if self.is_field() and print_mode is None: return self from sage.rings.padics.factory import Qp - return Qp(self.prime(), self.precision_cap(), 'capped-rel', print_mode=self._modified_print_mode(print_mode), names=self._uniformizer_print()) + if self.is_floating_point(): + mode = 'floating-point' + else: + mode = 'capped-rel' + return Qp(self.prime(), self.precision_cap(), mode, print_mode=self._modified_print_mode(print_mode), names=self._uniformizer_print()) def integer_ring(self, print_mode=None): r""" diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index bee21f5c0e5..56c47382502 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -194,10 +194,13 @@ class names.:: pAdicRingBaseGeneric, \ pAdicCappedRelativeRingGeneric, \ pAdicFixedModRingGeneric, \ - pAdicCappedAbsoluteRingGeneric + pAdicCappedAbsoluteRingGeneric, \ + pAdicFloatingPointRingGeneric, \ + pAdicFloatingPointFieldGeneric from .padic_capped_relative_element import pAdicCappedRelativeElement from .padic_capped_absolute_element import pAdicCappedAbsoluteElement from .padic_fixed_mod_element import pAdicFixedModElement +from .padic_floating_point_element import pAdicFloatingPointElement from sage.rings.integer_ring import ZZ class pAdicRingCappedRelative(pAdicRingBaseGeneric, pAdicCappedRelativeRingGeneric): @@ -381,6 +384,94 @@ def _coerce_map_from_(self, R): if R.precision_cap() == self.precision_cap() and self._printer.cmp_modes(R._printer) <= 0: return True +class pAdicRingFloatingPoint(pAdicRingBaseGeneric, pAdicFloatingPointRingGeneric): + r""" + An implementation of the `p`-adic integers with floating point + precision. + """ + def __init__(self, p, prec, print_mode, names): + """ + Initialization. + + INPUT: + + - ``p`` -- prime + - ``prec`` -- precision cap + - ``print_mode`` -- dictionary with print options. + - ``names`` -- how to print the prime. + + EXAMPLES:: + + sage: R = ZpFP(next_prime(10^60)) #indirect doctest + sage: type(R) + + + TESTS:: + + sage: R = ZpFP(2) + sage: TestSuite(R).run() + sage: TestSuite(R).run(elements = [R.random_element() for i in range(2^10)], max_runs = 2^12) # long time + + sage: R = ZpFP(3, 1) + sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^3)]) + + sage: R = ZpFP(3, 2) + sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^6)]) # long time + + sage: R = ZpFP(next_prime(10^60)) + sage: TestSuite(R).run() + sage: TestSuite(R).run(elements = [R.random_element() for i in range(2^4)], max_runs = 2^6) # long time + + """ + pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicFloatingPointElement) + + def _coerce_map_from_(self, R): + """ + Returns ``True`` if there is a coerce map from ``R`` to ``self``. + + EXAMPLES:: + + sage: K = ZpFP(17) + sage: K(1) + 1 #indirect doctest + 2 + sage: K.has_coerce_map_from(ZZ) + True + sage: K.has_coerce_map_from(int) + True + sage: K.has_coerce_map_from(QQ) + False + sage: K.has_coerce_map_from(RR) + False + sage: K.has_coerce_map_from(Qp(7)) + False + sage: K.has_coerce_map_from(Zp(17,40)) + False + sage: K.has_coerce_map_from(Zp(17,10)) + False + sage: K.has_coerce_map_from(ZpCA(17,40)) + False + """ + if isinstance(R, pAdicRingFloatingPoint) and R.prime() == self.prime(): + if R.precision_cap() > self.precision_cap(): + return True + elif R.precision_cap() == self.precision_cap() and self._printer.cmp_modes(R._printer) <= 0: + return True + + def _repr_(self, do_latex=False): + r""" + Print representation. + + EXAMPLES:: + + sage: K = ZpFP(17); K #indirect doctest + 17-adic Ring with floating precision 20 + sage: latex(K) + \ZZ_{17} + """ + if do_latex: + return "\\ZZ_{%s}" % self.prime() + return "%s-adic Ring with floating precision %s"%(self.prime(), self.precision_cap()) + class pAdicRingFixedMod(pAdicRingBaseGeneric, pAdicFixedModRingGeneric): r""" An implementation of the `p`-adic integers using fixed modulus. @@ -615,3 +706,93 @@ def random_element(self, algorithm='default'): return self(self.prime()**k * a, absprec = k + self.precision_cap()) else: raise NotImplementedError("Don't know %s algorithm"%algorithm) + +class pAdicFieldFloatingPoint(pAdicFieldBaseGeneric, pAdicFloatingPointFieldGeneric): + r""" + An implementation of the `p`-adic rationals with floating point + precision. + """ + def __init__(self, p, prec, print_mode, names): + """ + Initialization. + + INPUT: + + - ``p`` -- prime + - ``prec`` -- precision cap + - ``print_mode`` -- dictionary with print options. + - ``names`` -- how to print the prime. + + EXAMPLES:: + + sage: R = QpFP(next_prime(10^60)) #indirect doctest + sage: type(R) + + + TESTS:: + + sage: R = QpFP(2) + sage: TestSuite(R).run() + sage: TestSuite(R).run(elements = [R.random_element() for i in range(2^10)], max_runs = 2^12) # long time + + sage: R = QpFP(3, 1) + sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^3)]) + + sage: R = QpFP(3, 2) + sage: TestSuite(R).run(elements = [R.random_element() for i in range(3^6)]) # long time + + sage: R = QpFP(next_prime(10^60)) + sage: TestSuite(R).run() + sage: TestSuite(R).run(elements = [R.random_element() for i in range(2^4)], max_runs = 2^6) # long time + + """ + pAdicFieldBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicFloatingPointElement) + + def _coerce_map_from_(self, R): + """ + Returns ``True`` if there is a coerce map from ``R`` to ``self``. + + EXAMPLES:: + + sage: K = QpFP(17) + sage: K(1) + 1 #indirect doctest + 2 + sage: K.has_coerce_map_from(ZZ) + True + sage: K.has_coerce_map_from(int) + True + sage: K.has_coerce_map_from(QQ) + True + sage: K.has_coerce_map_from(RR) + False + sage: K.has_coerce_map_from(Qp(7)) + False + sage: K.has_coerce_map_from(Zp(17,40)) + False + sage: K.has_coerce_map_from(Qp(17,10)) + False + sage: K.has_coerce_map_from(ZpFP(17)) + True + sage: K.has_coerce_map_from(ZpCA(17,40)) + False + """ + if isinstance(R, (pAdicRingFloatingPoint, pAdicFieldFloatingPoint)) and R.prime() == self.prime(): + if R.precision_cap() > self.precision_cap(): + return True + elif R.precision_cap() == self.precision_cap() and self._printer.cmp_modes(R._printer) <= 0: + return True + + def _repr_(self, do_latex=False): + r""" + Print representation. + + EXAMPLES:: + + sage: K = QpFP(17); K #indirect doctest + 17-adic Field with floating precision 20 + sage: latex(K) + \QQ_{17} + """ + if do_latex: + return "\\QQ_{%s}" % self.prime() + return "%s-adic Field with floating precision %s"%(self.prime(), self.precision_cap()) diff --git a/src/sage/rings/padics/padic_extension_leaves.py b/src/sage/rings/padics/padic_extension_leaves.py index 063da34c3ca..8b7d837e2d6 100644 --- a/src/sage/rings/padics/padic_extension_leaves.py +++ b/src/sage/rings/padics/padic_extension_leaves.py @@ -35,7 +35,9 @@ from .generic_nodes import pAdicCappedRelativeRingGeneric, \ pAdicCappedRelativeFieldGeneric, \ pAdicCappedAbsoluteRingGeneric, \ - pAdicFixedModRingGeneric + pAdicFixedModRingGeneric, \ + pAdicFloatingPointRingGeneric, \ + pAdicFloatingPointFieldGeneric #from unramified_extension_absolute_element import UnramifiedExtensionAbsoluteElement #from unramified_extension_capped_relative_element import UnramifiedExtensionCappedRelativeElement @@ -53,6 +55,7 @@ from .qadic_flint_CR import qAdicCappedRelativeElement from .qadic_flint_CA import qAdicCappedAbsoluteElement from .qadic_flint_FM import qAdicFixedModElement +from .qadic_flint_FP import qAdicFloatingPointElement def _make_integral_poly(prepoly, p, prec): """ @@ -97,7 +100,7 @@ class UnramifiedExtensionRingCappedRelative(UnramifiedExtensionGeneric, pAdicCap sage: R. = ZqCR(27,10000); R == loads(dumps(R)) True """ - def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): + def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='FLINT'): """ A capped relative representation of Zq. @@ -157,7 +160,7 @@ class UnramifiedExtensionFieldCappedRelative(UnramifiedExtensionGeneric, pAdicCa sage: R. = QqCR(27,10000); R == loads(dumps(R)) True """ - def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): + def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='FLINT'): """ A representation of Qq. @@ -228,7 +231,7 @@ class UnramifiedExtensionRingCappedAbsolute(UnramifiedExtensionGeneric, pAdicCap sage: R. = ZqCA(27,10000); R == loads(dumps(R)) True """ - def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): + def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='FLINT'): """ A capped absolute representation of Zq. @@ -289,7 +292,7 @@ class UnramifiedExtensionRingFixedMod(UnramifiedExtensionGeneric, pAdicFixedModR sage: R. = ZqFM(27,10000); R == loads(dumps(R)) True """ - def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): + def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='FLINT'): """ A fixed modulus representation of Zq. @@ -347,6 +350,109 @@ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, imp # return Morphism_ZpFM_UnrFM(S, self) # return None +class UnramifiedExtensionRingFloatingPoint(UnramifiedExtensionGeneric, pAdicFloatingPointRingGeneric): + """ + TESTS:: + + sage: R. = ZqFP(27,10000); R == loads(dumps(R)) + True + """ + def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='FLINT'): + """ + A floating point representation of Zq. + + INPUT: + + - prepoly -- The original polynomial defining the + extension. This could be a polynomial with integer + coefficients, for example, while poly has coefficients + in Zp. + + - poly -- The polynomial with coefficients in + self.base_ring() defining this extension. + + - prec -- The precision cap of this ring. + + - halt -- unused + + - print_mode -- A dictionary of print options. + + - shift_seed -- unused + + - names -- a 4-tuple, (variable_name, residue_name, unramified_subextension_variable_name, uniformizer_name) + + EXAMPLES:: + + sage: R. = ZqFP(27,10000); R #indirect doctest + Unramified Extension of 3-adic Ring with floating precision 10000 in a defined by x^3 + 2*x + 1 + sage: R. = ZqFP(next_prime(10^30)^3, 3); R.prime() + 1000000000000000000000000000057 + """ + self._shift_seed = None + self._pre_poly = prepoly + self._implementation = implementation + if implementation == 'NTL': + raise NotImplementedError + Zpoly = _make_integral_poly(prepoly, poly.base_ring().prime(), prec) + cache_limit = min(prec, 30) + self.prime_pow = PowComputer_flint_maker(poly.base_ring().prime(), cache_limit, prec, prec, True, Zpoly, prec_type='floating-point') + UnramifiedExtensionGeneric.__init__(self, poly, prec, print_mode, names, qAdicFloatingPointElement) + from .qadic_flint_FP import pAdicCoercion_ZZ_FP, pAdicConvert_QQ_FP + self.register_coercion(pAdicCoercion_ZZ_FP(self)) + self.register_conversion(pAdicConvert_QQ_FP(self)) + +class UnramifiedExtensionFieldFloatingPoint(UnramifiedExtensionGeneric, pAdicFloatingPointFieldGeneric): + """ + TESTS:: + + sage: R. = QqFP(27,10000); R == loads(dumps(R)) + True + """ + def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='FLINT'): + """ + A representation of Qq. + + INPUT: + + - prepoly -- The original polynomial defining the + extension. This could be a polynomial with integer + coefficients, for example, while poly has coefficients + in Qp. + + - poly -- The polynomial with coefficients in + self.base_ring() defining this extension. + + - prec -- The precision cap of this ring. + + - halt -- unused + + - print_mode -- A dictionary of print options. + + - shift_seed -- unused + + - names -- a 4-tuple, (variable_name, residue_name, unramified_subextension_variable_name, uniformizer_name) + + EXAMPLES:: + + sage: R. = QqFP(27,10000); R #indirect doctest + Unramified Extension of 3-adic Field with floating precision 10000 in a defined by x^3 + 2*x + 1 + sage: R. = Qq(next_prime(10^30)^3, 3); R.prime() + 1000000000000000000000000000057 + """ + # Currently doesn't support polynomials with non-integral coefficients + self._shift_seed = None + self._pre_poly = prepoly + self._implementation = implementation + if implementation == 'NTL': + raise NotImplementedError + Zpoly = _make_integral_poly(prepoly, poly.base_ring().prime(), prec) + cache_limit = min(prec, 30) + self.prime_pow = PowComputer_flint_maker(poly.base_ring().prime(), cache_limit, prec, prec, True, Zpoly, prec_type='floating-point') + UnramifiedExtensionGeneric.__init__(self, poly, prec, print_mode, names, qAdicFloatingPointElement) + from .qadic_flint_FP import pAdicCoercion_ZZ_FP, pAdicCoercion_QQ_FP + self.register_coercion(pAdicCoercion_ZZ_FP(self)) + self.register_coercion(pAdicCoercion_QQ_FP(self)) + class EisensteinExtensionRingCappedRelative(EisensteinExtensionGeneric, pAdicCappedRelativeRingGeneric): """ TESTS:: diff --git a/src/sage/rings/padics/padic_floating_point_element.pxd b/src/sage/rings/padics/padic_floating_point_element.pxd new file mode 100644 index 00000000000..9c9bf17e51b --- /dev/null +++ b/src/sage/rings/padics/padic_floating_point_element.pxd @@ -0,0 +1,13 @@ +from sage.libs.gmp.types cimport mpz_t +from sage.libs.pari.gen cimport gen as pari_gen + +ctypedef mpz_t celement +include "FP_template_header.pxi" + +cdef class pAdicFloatingPointElement(FPElement): + cdef lift_c(self) + cdef pari_gen _to_gen(self) + +from sage.rings.padics.pow_computer cimport PowComputer_base +cdef class PowComputer_(PowComputer_base): + pass diff --git a/src/sage/rings/padics/padic_floating_point_element.pyx b/src/sage/rings/padics/padic_floating_point_element.pyx new file mode 100644 index 00000000000..9036b30034f --- /dev/null +++ b/src/sage/rings/padics/padic_floating_point_element.pyx @@ -0,0 +1,304 @@ +""" +`p`-Adic Floating Point Elements + +Elements of `p`-Adic Rings with Floating Point Precision + +AUTHORS: + +- David Roe: initial version (2016-12-6) +""" + +#***************************************************************************** +# Copyright (C) 2016 David Roe +# +# Distributed under the terms of the GNU General Public License (GPL) +# 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/ +#***************************************************************************** + +include "sage/libs/linkages/padics/mpz.pxi" +include "FP_template.pxi" + +from sage.libs.pari.pari_instance cimport PariInstance +cdef PariInstance P = sage.libs.pari.pari_instance.pari +from sage.rings.finite_rings.integer_mod import Mod + +cdef class PowComputer_(PowComputer_base): + """ + A PowComputer for a floating-point padic ring or field. + """ + def __init__(self, Integer prime, long cache_limit, long prec_cap, long ram_prec_cap, bint in_field): + """ + Initialization. + + EXAMPLES:: + + sage: R = ZpFP(5) + sage: type(R.prime_pow) + + sage: R.prime_pow._prec_type + 'floating-point' + """ + self._prec_type = 'floating-point' + PowComputer_base.__init__(self, prime, cache_limit, prec_cap, ram_prec_cap, in_field) + +cdef class pAdicFloatingPointElement(FPElement): + """ + Constructs new element with given parent and value. + + INPUT: + + - ``x`` -- value to coerce into a floating point ring or field + + - ``absprec`` -- maximum number of digits of absolute precision + + - ``relprec`` -- maximum number of digits of relative precision + + EXAMPLES:: + + sage: R = Zp(5, 10, 'floating-point') + + Construct from integers:: + + sage: R(3) + 3 + sage: R(75) + 3*5^2 + sage: R(0) + 0 + sage: R(-1) + 4 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + 4*5^5 + 4*5^6 + 4*5^7 + 4*5^8 + 4*5^9 + sage: R(-5) + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + 4*5^5 + 4*5^6 + 4*5^7 + 4*5^8 + 4*5^9 + 4*5^10 + sage: R(-7*25) + 3*5^2 + 3*5^3 + 4*5^4 + 4*5^5 + 4*5^6 + 4*5^7 + 4*5^8 + 4*5^9 + 4*5^10 + 4*5^11 + + Construct from rationals:: + + sage: R(1/2) + 3 + 2*5 + 2*5^2 + 2*5^3 + 2*5^4 + 2*5^5 + 2*5^6 + 2*5^7 + 2*5^8 + 2*5^9 + sage: R(-7875/874) + 3*5^3 + 2*5^4 + 2*5^5 + 5^6 + 3*5^7 + 2*5^8 + 3*5^10 + 3*5^11 + 3*5^12 + sage: R(15/425) + Traceback (most recent call last): + ... + ValueError: p divides the denominator + + Construct from IntegerMod:: + + sage: R(Integers(125)(3)) + 3 + sage: R(Integers(5)(3)) + 3 + sage: R(Integers(5^30)(3)) + 3 + sage: R(Integers(5^30)(1+5^23)) + 1 + sage: R(Integers(49)(3)) + Traceback (most recent call last): + ... + TypeError: p does not divide modulus 49 + + :: + + sage: R(Integers(48)(3)) + Traceback (most recent call last): + ... + TypeError: p does not divide modulus 48 + + Some other conversions:: + + sage: R(R(5)) + 5 + + Construct from Pari objects:: + + sage: R = ZpFP(5) + sage: x = pari(123123) ; R(x) + 3 + 4*5 + 4*5^2 + 4*5^3 + 5^4 + 4*5^5 + 2*5^6 + 5^7 + sage: R(pari(R(5252))) + 2 + 2*5^3 + 3*5^4 + 5^5 + sage: R = ZpFP(5,prec=5) + sage: R(pari(-1)) + 4 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + sage: pari(R(-1)) + 4 + 4*5 + 4*5^2 + 4*5^3 + 4*5^4 + O(5^5) + sage: pari(R(0)) + 0 + sage: R(pari(R(0,5))) + 0 + + # todo: doctests for converting from other types of p-adic rings + + """ + def lift(self): + """ + Return an integer or rational congruent to ``self`` modulo ``self``'s + precision. If a rational is returned, its denominator will equal + ``p^ordp(self)``. + + This method will raise a ValueError when this element is infinity. + + EXAMPLES:: + + sage: R = Zp(7,4,'floating-point'); a = R(8); a.lift() + 8 + sage: R = QpFP(7,4); a = R(8); a.lift() + 8 + sage: R = QpFP(7,4); a = R(8/7); a.lift() + 8/7 + """ + return self.lift_c() + + cdef lift_c(self): + """ + Implementation of lift. + + TESTS:: + + sage: ZpFP(5)(0).lift() #indirect doctest + 0 + sage: R = QpFP(5); R(0).lift() + 0 + sage: R(5/9).lift() + 264909532335070 + sage: R(9/5).lift() + 9/5 + """ + cdef Integer ans + cdef Rational ansr + if self.ordp >= 0: + ans = PY_NEW(Integer) + if very_pos_val(self.ordp): + mpz_set_ui(ans.value, 0) + else: + mpz_set(ans.value, self.unit) + mpz_mul(ans.value, ans.value, self.prime_pow.pow_mpz_t_tmp(self.ordp)) + return ans + else: + ansr = Rational.__new__(Rational) + if very_neg_val(self.ordp): + raise ValueError("infinity cannot be lifted to an integer or rational") + mpz_set(mpq_numref(ansr.value), self.unit) + mpz_set(mpq_denref(ansr.value), self.prime_pow.pow_mpz_t_tmp(-self.ordp)) + return ansr + + def _pari_(self): + """ + Converts this element to an equivalent pari element. + + EXAMPLES:: + + sage: R = ZpFP(17, 10); a = ~R(14); pari(a) #indirect doctest + 11 + 3*17 + 17^2 + 6*17^3 + 13*17^4 + 15*17^5 + 10*17^6 + 3*17^7 + 17^8 + 6*17^9 + O(17^10) + sage: pari(R(0)) + 0 + """ + return self._to_gen() + + cdef pari_gen _to_gen(self): + """ + Converts this element to an equivalent pari element. + + EXAMPLES:: + + sage: R = ZpFP(5, 10); a = R(17); pari(a) #indirect doctest + 2 + 3*5 + O(5^10) + sage: pari(R(0)) + 0 + """ + if very_pos_val(self.ordp): + return P.new_gen_from_int(0) + elif very_neg_val(self.ordp): + raise ValueError("no analogue of p-adic infinity in pari") + else: + return P.new_gen_from_padic(self.ordp, self.prime_pow.prec_cap, + self.prime_pow.prime.value, + self.prime_pow.pow_mpz_t_top(), + self.unit) + def _integer_(self, Z=None): + """ + Returns an integer congruent to this element modulo + ``p^self.absolute_precision()``. + + EXAMPLES:: + + sage: R = ZpFP(5); a = R(-1); a._integer_() + 95367431640624 + """ + if self.ordp < 0: + raise ValueError("Cannot form an integer out of a p-adic field element with negative valuation") + return self.lift_c() + + def residue(self, absprec=1): + """ + Reduces this element modulo `p^{\mathrm{absprec}}`. + + INPUT: + + - ``absprec`` - a non-negative integer (default: ``1``) + + OUTPUT: + + This element reduced modulo `p^\mathrm{absprec}` as an element of + `\ZZ/p^\mathrm{absprec}\ZZ` + + EXAMPLES:: + + sage: R = ZpFP(7,4) + sage: a = R(8) + sage: a.residue(1) + 1 + sage: a.residue(2) + 8 + + sage: K = QpFP(7,4) + sage: a = K(8) + sage: a.residue(1) + 1 + sage: a.residue(2) + 8 + sage: b = K(1/7) + sage: b.residue() + Traceback (most recent call last): + ... + ValueError: element must have non-negative valuation in order to compute residue. + + TESTS:: + + sage: R = ZpFP(7,4) + sage: a = R(8) + sage: a.residue(0) + 0 + sage: a.residue(-1) + Traceback (most recent call last): + ... + ValueError: cannot reduce modulo a negative power of p. + sage: a.residue(5) + Traceback (most recent call last): + ... + PrecisionError: not enough precision known in order to compute residue. + + """ + cdef Integer selfvalue, modulus + cdef long aprec + if not isinstance(absprec, Integer): + absprec = Integer(absprec) + if mpz_cmp_ui((absprec).value, self.prime_pow.prec_cap) > 0: + raise PrecisionError("not enough precision known in order to compute residue.") + elif mpz_sgn((absprec).value) < 0: + raise ValueError("cannot reduce modulo a negative power of p.") + aprec = mpz_get_ui((absprec).value) + if self.ordp < 0: + raise ValueError("element must have non-negative valuation in order to compute residue.") + modulus = PY_NEW(Integer) + mpz_set(modulus.value, self.prime_pow.pow_mpz_t_tmp(aprec)) + selfvalue = PY_NEW(Integer) + if very_pos_val(self.ordp): + mpz_set_ui(selfvalue.value, 0) + else: + # Need to do this better. + mpz_mul(selfvalue.value, self.prime_pow.pow_mpz_t_tmp(self.ordp), self.unit) + return Mod(selfvalue, modulus) diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index a4a73d4db40..a812bf29a1e 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -497,7 +497,7 @@ cdef class pAdicGenericElement(LocalGenericElement): def _repr_(self, mode=None, do_latex=False): """ - Returns a string representation of self. + Returns a string representation of this element. INPUT: @@ -1430,6 +1430,8 @@ cdef class pAdicGenericElement(LocalGenericElement): cdef long v = self.valuation_c() if v == maxordp: return infinity + if v == -maxordp: + return -infinity cdef Integer ans = PY_NEW(Integer) mpz_set_si(ans.value, v) return ans diff --git a/src/sage/rings/padics/padic_printing.pxd b/src/sage/rings/padics/padic_printing.pxd index b3f02ef006d..d7f22b372e8 100644 --- a/src/sage/rings/padics/padic_printing.pxd +++ b/src/sage/rings/padics/padic_printing.pxd @@ -17,6 +17,7 @@ cdef class pAdicPrinter_class(SageObject): cdef long max_ram_terms cdef long max_unram_terms cdef long max_terse_terms + cdef object show_prec cdef base_p_list(self, value, bint pos) cdef _repr_gen(self, pAdicGenericElement elt, bint do_latex, bint pos, int mode, pname) diff --git a/src/sage/rings/padics/padic_printing.pyx b/src/sage/rings/padics/padic_printing.pyx index 983e7744f8c..195772159b0 100644 --- a/src/sage/rings/padics/padic_printing.pyx +++ b/src/sage/rings/padics/padic_printing.pyx @@ -59,7 +59,7 @@ def pAdicPrinter(ring, options={}): sage: pAdicPrinter(R, {'sep': '&'}) series printer for 5-adic Ring with capped relative precision 20 """ - for option in ['mode', 'pos', 'ram_name', 'unram_name', 'var_name', 'max_ram_terms', 'max_unram_terms', 'max_terse_terms', 'sep', 'alphabet']: + for option in ['mode', 'pos', 'ram_name', 'unram_name', 'var_name', 'max_ram_terms', 'max_unram_terms', 'max_terse_terms', 'sep', 'alphabet', 'show_prec']: if option not in options: options[option] = None return pAdicPrinter_class(ring, **options) @@ -296,7 +296,7 @@ cdef class pAdicPrinter_class(SageObject): or field, and uses these to compute the representations of elements. """ - def __init__(self, ring, mode, pos, ram_name, unram_name, var_name, max_ram_terms, max_unram_terms, max_terse_terms, sep, alphabet): + def __init__(self, ring, mode, pos, ram_name, unram_name, var_name, max_ram_terms, max_unram_terms, max_terse_terms, sep, alphabet, show_prec): """ Initializes a pAdicPrinter. @@ -366,6 +366,9 @@ cdef class pAdicPrinter_class(SageObject): p-adic digits into strings (so that no separator need be used in 'digits' mode). + - show_prec -- Determines whether `` + O(p^prec)`` is added. + If None, uses defaults determined by print mode. + TESTS:: sage: R = Qp(7, print_mode='bars', print_sep='&') #indirect doctest @@ -436,6 +439,7 @@ cdef class pAdicPrinter_class(SageObject): raise ValueError("max_terse_terms must be positive and fit in a long") else: self.max_terse_terms = _printer_defaults._max_terse_terms + self.show_prec = show_prec def __reduce__(self): """ @@ -452,15 +456,16 @@ cdef class pAdicPrinter_class(SageObject): return pAdicPrinter, (self.ring, \ {'mode': self._print_mode(), \ - 'pos': self.pos, \ - 'ram_name': self.ram_name, \ - 'unram_name': self.unram_name, \ - 'var_name': self.var_name, \ - 'max_ram_terms': self.max_ram_terms, \ - 'max_unram_terms': self.max_unram_terms, \ - 'max_terse_terms': self.max_terse_terms, \ - 'sep':self.sep, \ - 'alphabet': self.alphabet}) + 'pos': self.pos, \ + 'ram_name': self.ram_name, \ + 'unram_name': self.unram_name, \ + 'var_name': self.var_name, \ + 'max_ram_terms': self.max_ram_terms, \ + 'max_unram_terms': self.max_unram_terms, \ + 'max_terse_terms': self.max_terse_terms, \ + 'sep':self.sep, \ + 'alphabet': self.alphabet, \ + 'show_prec': self.show_prec}) def __cmp__(self, other): """ @@ -549,7 +554,7 @@ cdef class pAdicPrinter_class(SageObject): c = cmp(self.max_terse_terms, other.max_terse_terms) if c != 0: return c - return 0 + return cmp(self.show_prec, other.show_prec) def _repr_(self): """ @@ -586,7 +591,7 @@ cdef class pAdicPrinter_class(SageObject): sage: D = Zp(5)._printer.dict(); D['sep'] '|' """ - return {'mode': self._print_mode(), 'pos': self.pos, 'ram_name': self.ram_name, 'unram_name': self.unram_name, 'var_name': self.var_name, 'max_ram_terms': self.max_ram_terms, 'max_unram_terms': self.max_unram_terms, 'max_terse_terms': self.max_terse_terms, 'sep': self.sep, 'alphabet': self.alphabet} + return {'mode': self._print_mode(), 'pos': self.pos, 'ram_name': self.ram_name, 'unram_name': self.unram_name, 'var_name': self.var_name, 'max_ram_terms': self.max_ram_terms, 'max_unram_terms': self.max_unram_terms, 'max_terse_terms': self.max_terse_terms, 'sep': self.sep, 'alphabet': self.alphabet, 'show_prec': self.show_prec} def __exit__(self, type, value, traceback): """ @@ -670,6 +675,17 @@ cdef class pAdicPrinter_class(SageObject): """ return self.max_terse_terms + def _show_prec(self): + """ + Accesses self.show_prec. + + EXAMPLES:: + + sage: R = ZpFP(5); R._printer._show_prec() + False + """ + return self.show_prec + def _ring(self): """ Accesses self.ring. @@ -851,27 +867,34 @@ cdef class pAdicPrinter_class(SageObject): if elt._is_exact_zero(): return "0" if elt._is_inexact_zero(): + if self.show_prec is False: + return "0" if mode == val_unit or mode == series: s = "O(%s"%(ram_name) elif mode == terse: s = "0 + O(%s"%(ram_name) else: # mode == digits or bars - s = "..." + if self.show_prec is True: + s = "O(%s"%(ram_name) + else: + s = "..." elif mode == val_unit: if do_latex: if elt.valuation() == 0: - s = "%s + O(%s"%(self._repr_spec(elt, do_latex, pos, terse, 0, ram_name), ram_name) + s = self._repr_spec(elt, do_latex, pos, terse, 0, ram_name) elif elt.valuation() == 1: - s = "%s \\cdot %s + O(%s"%(ram_name, self._repr_spec(elt.unit_part(), do_latex, pos, terse, 1, ram_name), ram_name) + s = "%s \\cdot %s"%(ram_name, self._repr_spec(elt.unit_part(), do_latex, pos, terse, 1, ram_name)) else: - s = "%s^{%s} \\cdot %s + O(%s"%(ram_name, elt.valuation(), self._repr_spec(elt.unit_part(), do_latex, pos, terse, 1, ram_name), ram_name) + s = "%s^{%s} \\cdot %s"%(ram_name, elt.valuation(), self._repr_spec(elt.unit_part(), do_latex, pos, terse, 1, ram_name)) else: if elt.valuation() == 0: - s = "%s + O(%s"%(self._repr_spec(elt, do_latex, pos, terse, 0, ram_name), ram_name) + s = self._repr_spec(elt, do_latex, pos, terse, 0, ram_name) elif elt.valuation() == 1: - s = "%s * %s + O(%s"%(ram_name, self._repr_spec(elt.unit_part(), do_latex, pos, terse, 1, ram_name), ram_name) + s = "%s * %s"%(ram_name, self._repr_spec(elt.unit_part(), do_latex, pos, terse, 1, ram_name)) else: - s = "%s^%s * %s + O(%s"%(ram_name, elt.valuation(), self._repr_spec(elt.unit_part(), do_latex, pos, terse, 1, ram_name), ram_name) + s = "%s^%s * %s"%(ram_name, elt.valuation(), self._repr_spec(elt.unit_part(), do_latex, pos, terse, 1, ram_name)) + if not (self.show_prec is False): + s += " + O(%s"%(ram_name) elif mode == digits: n = elt.valuation() if self.base: @@ -890,7 +913,10 @@ cdef class pAdicPrinter_class(SageObject): L = ['?']*(1 - n - len(L)) + L L = L[:n] + ['.'] + L[n:] s = "".join(L) - s = "..." + s + if self.show_prec: + s += " + O(%s"%(ram_name) + else: + s = "..." + s elif mode == bars: n = elt.valuation() if self.base: @@ -918,13 +944,17 @@ cdef class pAdicPrinter_class(SageObject): L = ['0']*(min(-n, elt.precision_relative()) - len(L)) + L L = ['?']*(-n - len(L)) + L L = L[:n] + ['.'] + L[n:] - if L[0] == '.': + if self.show_prec: + s = "%s + O(%s"%(self.sep.join(L), ram_name) + elif L[0] == '.': s = "..." + self.sep + self.sep.join(L) else: s = "..." + self.sep.join(L) else: # mode == terse or series - s = "%s + O(%s"%(self._repr_spec(elt, do_latex, pos, mode, 0, ram_name), ram_name) - if mode != bars and mode != digits: + s = self._repr_spec(elt, do_latex, pos, mode, 0, ram_name) + if not (self.show_prec is False): + s += " + O(%s"%(ram_name) + if (mode == bars or mode == digits) and self.show_prec or (mode == terse or mode == series or mode == val_unit) and not (self.show_prec is False): if elt.precision_absolute() == 1: s += ")" else: diff --git a/src/sage/rings/padics/pow_computer.pyx b/src/sage/rings/padics/pow_computer.pyx index a91f338d02e..308b43d3896 100644 --- a/src/sage/rings/padics/pow_computer.pyx +++ b/src/sage/rings/padics/pow_computer.pyx @@ -575,6 +575,8 @@ cdef PowComputer_base PowComputer_c(Integer m, Integer cache_limit, Integer prec from padic_capped_absolute_element import PowComputer_ as PC_class elif prec_type == 'fixed-mod': from padic_fixed_mod_element import PowComputer_ as PC_class + elif prec_type == 'floating-point': + from padic_floating_point_element import PowComputer_ as PC_class else: PC_class = PowComputer_base PC = PC_class(m, mpz_get_ui(cache_limit.value), mpz_get_ui(prec_cap.value), mpz_get_ui(prec_cap.value), in_field) diff --git a/src/sage/rings/padics/pow_computer_flint.pyx b/src/sage/rings/padics/pow_computer_flint.pyx index 1696e78d069..d2c2a000496 100644 --- a/src/sage/rings/padics/pow_computer_flint.pyx +++ b/src/sage/rings/padics/pow_computer_flint.pyx @@ -595,6 +595,8 @@ def PowComputer_flint_maker(prime, cache_limit, prec_cap, ram_prec_cap, in_field from qadic_flint_CA import PowComputer_ elif prec_type == 'fixed-mod': from qadic_flint_FM import PowComputer_ + elif prec_type == 'floating-point': + from qadic_flint_FP import PowComputer_ else: raise ValueError("unknown prec_type `%s`"%prec_type) return PowComputer_(prime, cache_limit, prec_cap, ram_prec_cap, in_field, poly) diff --git a/src/sage/rings/padics/qadic_flint_FP.pxd b/src/sage/rings/padics/qadic_flint_FP.pxd new file mode 100644 index 00000000000..5ddfaf0313e --- /dev/null +++ b/src/sage/rings/padics/qadic_flint_FP.pxd @@ -0,0 +1,11 @@ +from sage.libs.pari.gen cimport gen as pari_gen +from sage.libs.flint.fmpz_poly cimport fmpz_poly_t +from sage.rings.padics.pow_computer_flint cimport PowComputer_flint_unram +cdef class PowComputer_(PowComputer_flint_unram): + pass +ctypedef fmpz_poly_t celement + +include "FP_template_header.pxi" + +cdef class qAdicFloatingPointElement(FPElement): + pass diff --git a/src/sage/rings/padics/qadic_flint_FP.pyx b/src/sage/rings/padics/qadic_flint_FP.pyx new file mode 100644 index 00000000000..0137a9f2da6 --- /dev/null +++ b/src/sage/rings/padics/qadic_flint_FP.pyx @@ -0,0 +1,124 @@ +from types import MethodType + +include "sage/libs/linkages/padics/fmpz_poly_unram.pxi" +include "sage/libs/linkages/padics/unram_shared.pxi" +include "FP_template.pxi" + +cdef class PowComputer_(PowComputer_flint_unram): + """ + A PowComputer for a floating-point unramified ring or field. + """ + def __init__(self, Integer prime, long cache_limit, long prec_cap, long ram_prec_cap, bint in_field, poly=None): + """ + Initialization. + + EXAMPLES:: + + sage: R. = ZqFP(125) + sage: type(R.prime_pow) + + sage: R.prime_pow._prec_type + 'floating-point' + """ + self._prec_type = 'floating-point' + PowComputer_flint_unram.__init__(self, prime, cache_limit, prec_cap, ram_prec_cap, in_field, poly) + +cdef class qAdicFloatingPointElement(FPElement): + frobenius = MethodType(frobenius_unram, None, qAdicFloatingPointElement) + trace = MethodType(trace_unram, None, qAdicFloatingPointElement) + norm = MethodType(norm_unram, None, qAdicFloatingPointElement) + + def matrix_mod_pn(self): + """ + Returns the matrix of right multiplication by the element on + the power basis `1, x, x^2, \ldots, x^{d-1}` for this + extension field. Thus the *rows* of this matrix give the + images of each of the `x^i`. The entries of the matrices are + IntegerMod elements, defined modulo ``p^(self.absprec() / e)``. + + Raises an error if ``self`` has negative valuation. + + EXAMPLES:: + + sage: R. = QqFP(5^5,5) + sage: b = (5 + 15*a)^3 + sage: b.matrix_mod_pn() + [ 125 1125 3375 3375 0] + [ 0 125 1125 3375 3375] + [380500 377125 125 1125 3375] + [380500 367000 377125 125 1125] + [387250 376000 367000 377125 125] + + sage: M = R(0,3).matrix_mod_pn(); M == 0 + True + sage: M.base_ring() + Integer Ring + + Check that :trac:`13617` has been fixed:: + + sage: R(0).matrix_mod_pn() + [0 0 0 0 0] + [0 0 0 0 0] + [0 0 0 0 0] + [0 0 0 0 0] + [0 0 0 0 0] + """ + if self.ordp < 0: + raise ValueError("self must be integral") + if very_pos_val(self.ordp): + from sage.matrix.all import matrix + return matrix(ZZ, self.prime_pow.deg, self.prime_pow.deg) + else: + return cmatrix_mod_pn(self.unit, self.ordp + self.prime_pow.prec_cap, self.ordp, self.prime_pow) + + def _flint_rep(self, var='x'): + """ + Replacement for _ntl_rep for use in printing and debugging. + + EXAMPLES:: + + sage: R. = QqFP(27, 4) + sage: (~(1+a))._flint_rep() + 41*x^2 + 40*x + 42 + sage: (1+a)*(41*a^2+40*a+42) + 1 + """ + return self.prime_pow._new_fmpz_poly(self.unit, var) + + def _flint_rep_abs(self, var='x'): + """ + Replacement for _ntl_rep_abs for use in printing and debugging. + + EXAMPLES:: + + sage: R. = QqFP(27, 4) + sage: (~(3+3*a))._flint_rep_abs() + (41*x^2 + 40*x + 42, -1) + sage: (3+3*a)*(41*a^2+40*a+42) + 3 + sage: (3+3*a)._flint_rep_abs() + (3*x + 3, 0) + """ + if self.ordp < 0: + return self._flint_rep(var), Integer(self.ordp) + cshift(self.prime_pow.poly_flint_rep, self.unit, self.ordp, self.ordp + self.prime_pow.prec_cap, self.prime_pow, False) + return self.prime_pow._new_fmpz_poly(self.prime_pow.poly_flint_rep, var), Integer(0) + + def __hash__(self): + r""" + Raise a ``TypeError`` since this element is not hashable + (:trac:`11895`.) + + TESTS:: + + sage: K. = QqFP(9) + sage: hash(a) + Traceback (most recent call last): + ... + TypeError: unhashable type: 'sage.rings.padics.qadic_flint_FP.qAdicFloatingPointElement' + + """ + # Eventually, hashing will be disabled for all (non-fixed-mod) p-adic + # elements (#11895), until then, we only to this for types which did + # not support hashing before we switched some elements to FLINT + raise TypeError("unhashable type: 'sage.rings.padics.qadic_flint_FP.qAdicFloatingPointElement'") From 53d0c22c1c22b43e9f3c45de3ed6d8b51162932f Mon Sep 17 00:00:00 2001 From: David Roe Date: Tue, 27 Dec 2016 15:58:15 -0800 Subject: [PATCH 004/126] Fixing TestSuite for p-adic floats --- src/sage/rings/padics/FP_template.pxi | 30 +++++----- src/sage/rings/padics/generic_nodes.py | 77 ++++++++++++++++++++++++++ src/sage/rings/padics/padic_generic.py | 52 +++++++++++------ 3 files changed, 125 insertions(+), 34 deletions(-) diff --git a/src/sage/rings/padics/FP_template.pxi b/src/sage/rings/padics/FP_template.pxi index 7c08103e94a..022638e17a2 100644 --- a/src/sage/rings/padics/FP_template.pxi +++ b/src/sage/rings/padics/FP_template.pxi @@ -465,29 +465,27 @@ cdef class FPElement(pAdicTemplateElement): 7^-1 """ # Input should be normalized! - cdef FPElement ans, right = _right + cdef FPElement right = _right + cdef FPElement ans = self._new_c() + if ans.prime_pow.in_field == 0: + ans._parent = self._parent.fraction_field() + ans.prime_pow = ans._parent.prime_pow if very_pos_val(self.ordp): if very_pos_val(right.ordp): raise ZeroDivisionError("Cannot divide 0 by 0") - return self + ans._set_exact_zero() elif very_neg_val(right.ordp): if very_neg_val(self.ordp): raise ZeroDivisionError("Cannot divide infinity by infinity") - ans = self._new_c() ans._set_exact_zero() - return ans - elif very_neg_val(self.ordp): - return self - elif very_pos_val(right.ordp): - ans = self._new_c() + elif very_neg_val(self.ordp) or very_pos_val(right.ordp): ans._set_infinity() - return ans - ans = self._new_c() - ans.ordp = self.ordp - right.ordp - if overunderflow(&ans.ordp, ans.unit, ans.prime_pow): - return ans - cdivunit(ans.unit, self.unit, right.unit, ans.prime_pow.prec_cap, ans.prime_pow) - creduce(ans.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) + else: + ans.ordp = self.ordp - right.ordp + if overunderflow(&ans.ordp, ans.unit, ans.prime_pow): + return ans + cdivunit(ans.unit, self.unit, right.unit, ans.prime_pow.prec_cap, ans.prime_pow) + creduce(ans.unit, ans.unit, ans.prime_pow.prec_cap, ans.prime_pow) return ans def __pow__(FPElement self, _right, dummy): # NOTE: dummy ignored, always use self.prime_pow.prec_cap @@ -838,7 +836,7 @@ cdef class FPElement(pAdicTemplateElement): return False elif very_neg_val(right.ordp): return False - if absprec is None: + if absprec is None or absprec is infinity: return ((self.ordp == right.ordp) and (ccmp(self.unit, right.unit, self.prime_pow.prec_cap, False, False, self.prime_pow) == 0)) if not isinstance(absprec, Integer): diff --git a/src/sage/rings/padics/generic_nodes.py b/src/sage/rings/padics/generic_nodes.py index c0e4ee95984..f528ee68c6d 100644 --- a/src/sage/rings/padics/generic_nodes.py +++ b/src/sage/rings/padics/generic_nodes.py @@ -27,6 +27,7 @@ from sage.rings.padics.padic_base_generic import pAdicBaseGeneric from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ +from sage.rings.infinity import infinity, SignError class CappedAbsoluteGeneric(LocalGeneric): def is_capped_absolute(self): @@ -176,6 +177,82 @@ def _prec_type(self): """ return 'floating-point' + def _test_distributivity(self, **options): + r""" + Test the distributivity of `*` on `+` on (not necessarily + all) elements of this set. + + p-adic floating point rings only satisfy distributivity + up to a precision that depends on the elements. + + INPUT: + + - ``options`` -- any keyword arguments accepted by :meth:`_tester` + + EXAMPLES: + + By default, this method runs the tests only on the + elements returned by ``self.some_elements()``:: + + sage: R = ZpFP(5,3) + sage: R.some_elements() + [0, 1, 5, 1 + 3*5 + 3*5^2, 5 + 4*5^2 + 4*5^3] + sage: R._test_distributivity() + + However, the elements tested can be customized with the + ``elements`` keyword argument:: + + sage: R._test_distributivity(elements=[R(0),~R(0),R(42)]) + + See the documentation for :class:`TestSuite` for more information. + """ + tester = self._tester(**options) + S = tester.some_elements() + from sage.misc.misc import some_tuples + for x,y,z in some_tuples(S, 3, tester._max_runs): + yz_prec = min(y.precision_absolute(), z.precision_absolute()) + yz_val = (y + z).valuation() + try: + prec = min(x.valuation() + yz_val + min(x.precision_relative(), yz_prec - yz_val), + x.valuation() + y.valuation() + (x * y).precision_relative(), + x.valuation() + z.valuation() + (x * z).precision_relative()) + except SignError: + pass + else: + if prec > -infinity: + # only check left distributivity, since multiplication commutative + tester.assert_((x * (y + z)).is_equal_to((x * y) + (x * z),prec)) + + def _test_additive_associativity(self, **options): + r""" + Test associativity for (not necessarily all) elements of this + additive semigroup. + + INPUT: + + - ``options`` -- any keyword arguments accepted by :meth:`_tester` + + EXAMPLES: + + By default, this method tests only the elements returned by + ``self.some_elements()``:: + + sage: R = QpFP(7,3) + sage: R._test_additive_associativity() + + However, the elements tested can be customized with the + ``elements`` keyword argument:: + + sage: R._test_additive_associativity(elements = [R(0), ~R(0), R(42)]) + + See the documentation for :class:`TestSuite` for more information. + """ + tester = self._tester(**options) + S = tester.some_elements() + from sage.misc.misc import some_tuples + for x,y,z in some_tuples(S, 3, tester._max_runs): + tester.assert_(((x + y) + z).is_equal_to(x + (y + z), min(x.precision_absolute(), y.precision_absolute(), z.precision_absolute()))) + class FloatingPointRingGeneric(FloatingPointGeneric): pass class FloatingPointFieldGeneric(FloatingPointGeneric):#, sage.rings.ring.Field): diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 6941c1c06f0..7c341f87359 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -539,12 +539,14 @@ def _test_add(self, **options): for x,y in some_tuples(elements, 2, tester._max_runs): z = x + y tester.assertIs(z.parent(), self) - tester.assertEqual(z.precision_absolute(), min(x.precision_absolute(), y.precision_absolute())) + zprec = min(x.precision_absolute(), y.precision_absolute()) + if not self.is_floating_point(): + tester.assertEqual(z.precision_absolute(), zprec) tester.assertGreaterEqual(z.valuation(), min(x.valuation(),y.valuation())) if x.valuation() != y.valuation(): tester.assertEqual(z.valuation(), min(x.valuation(),y.valuation())) - tester.assertEqual(z - x, y) - tester.assertEqual(z - y, x) + tester.assert_(y.is_equal_to(z-x,zprec)) + tester.assert_(x.is_equal_to(z-y,zprec)) def _test_sub(self, **options): """ @@ -575,12 +577,14 @@ def _test_sub(self, **options): for x,y in some_tuples(elements, 2, tester._max_runs): z = x - y tester.assertIs(z.parent(), self) - tester.assertEqual(z.precision_absolute(), min(x.precision_absolute(), y.precision_absolute())) + zprec = min(x.precision_absolute(), y.precision_absolute()) + if not self.is_floating_point(): + tester.assertEqual(z.precision_absolute(), zprec) tester.assertGreaterEqual(z.valuation(), min(x.valuation(),y.valuation())) if x.valuation() != y.valuation(): tester.assertEqual(z.valuation(), min(x.valuation(),y.valuation())) - tester.assertEqual(z - x, -y) - tester.assertEqual(z + y, x) + tester.assert_((-y).is_equal_to(z - x,zprec)) + tester.assert_(x.is_equal_to(z + y,zprec)) def _test_invert(self, **options): """ @@ -609,13 +613,16 @@ def _test_invert(self, **options): tester.assertFalse(x.is_unit()) if not self.is_fixed_mod(): tester.assertTrue(x.is_zero()) else: - e = y * x - - tester.assertFalse(x.is_zero()) - tester.assertIs(y.parent(), self if self.is_fixed_mod() else self.fraction_field()) - tester.assertTrue(e.is_one()) - tester.assertEqual(e.precision_relative(), x.precision_relative()) - tester.assertEqual(y.valuation(), -x.valuation()) + try: + e = y * x + except ZeroDivisionError: + tester.assertTrue(self.is_floating_point() and (x.is_zero() or y.is_zero())) + else: + tester.assertFalse(x.is_zero()) + tester.assertIs(y.parent(), self if self.is_fixed_mod() else self.fraction_field()) + tester.assertTrue(e.is_one()) + tester.assertEqual(e.precision_relative(), x.precision_relative()) + tester.assertEqual(y.valuation(), -x.valuation()) def _test_mul(self, **options): """ @@ -640,7 +647,10 @@ def _test_mul(self, **options): for x,y in some_tuples(elements, 2, tester._max_runs): z = x * y tester.assertIs(z.parent(), self) - tester.assertLessEqual(z.precision_relative(), min(x.precision_relative(), y.precision_relative())) + if self.is_capped_relative() or self.is_floating_point(): + tester.assertEqual(z.precision_relative(), min(x.precision_relative(), y.precision_relative())) + else: + tester.assertLessEqual(z.precision_relative(), min(x.precision_relative(), y.precision_relative())) if not z.is_zero(): tester.assertEqual(z.valuation(), x.valuation() + y.valuation()) @@ -671,10 +681,16 @@ def _test_div(self, **options): if self.is_fixed_mod(): tester.assertFalse(y.is_unit()) else: tester.assertTrue(y.is_zero()) else: - tester.assertFalse(y.is_zero()) - tester.assertIs(z.parent(), self if self.is_fixed_mod() else self.fraction_field()) - tester.assertEqual(z.precision_relative(), min(x.precision_relative(), y.precision_relative())) - tester.assertEqual(z.valuation(), x.valuation() - y.valuation()) + try: + xx = z*y + except ZeroDivisionError: + tester.assertTrue(self.is_floating_point() and (z.is_zero() or y.is_zero())) + else: + tester.assertFalse(y.is_zero()) + tester.assertIs(z.parent(), self if self.is_fixed_mod() else self.fraction_field()) + tester.assertEqual(z.precision_relative(), min(x.precision_relative(), y.precision_relative())) + tester.assertEqual(z.valuation(), x.valuation() - y.valuation()) + tester.assertEqual(xx, x) def _test_neg(self, **options): """ From 6350602c728147d509d073c35cb76d9f830f2111 Mon Sep 17 00:00:00 2001 From: David Roe Date: Thu, 29 Dec 2016 15:54:14 -0800 Subject: [PATCH 005/126] Accomodating changes to pari in Sage 7.5 --- .../rings/padics/padic_floating_point_element.pxd | 2 +- .../rings/padics/padic_floating_point_element.pyx | 14 +++++++------- src/sage/rings/padics/qadic_flint_FP.pxd | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/padics/padic_floating_point_element.pxd b/src/sage/rings/padics/padic_floating_point_element.pxd index 9c9bf17e51b..534d6a5fa6c 100644 --- a/src/sage/rings/padics/padic_floating_point_element.pxd +++ b/src/sage/rings/padics/padic_floating_point_element.pxd @@ -1,5 +1,5 @@ from sage.libs.gmp.types cimport mpz_t -from sage.libs.pari.gen cimport gen as pari_gen +from sage.libs.cypari2.gen cimport gen as pari_gen ctypedef mpz_t celement include "FP_template_header.pxi" diff --git a/src/sage/rings/padics/padic_floating_point_element.pyx b/src/sage/rings/padics/padic_floating_point_element.pyx index 9036b30034f..5a652602bac 100644 --- a/src/sage/rings/padics/padic_floating_point_element.pyx +++ b/src/sage/rings/padics/padic_floating_point_element.pyx @@ -21,8 +21,8 @@ AUTHORS: include "sage/libs/linkages/padics/mpz.pxi" include "FP_template.pxi" -from sage.libs.pari.pari_instance cimport PariInstance -cdef PariInstance P = sage.libs.pari.pari_instance.pari +from sage.libs.cypari2.pari_instance cimport pari_instance as pari +from sage.libs.pari.convert_gmp cimport new_gen_from_padic from sage.rings.finite_rings.integer_mod import Mod cdef class PowComputer_(PowComputer_base): @@ -210,14 +210,14 @@ cdef class pAdicFloatingPointElement(FPElement): 0 """ if very_pos_val(self.ordp): - return P.new_gen_from_int(0) + return pari.zero() elif very_neg_val(self.ordp): raise ValueError("no analogue of p-adic infinity in pari") else: - return P.new_gen_from_padic(self.ordp, self.prime_pow.prec_cap, - self.prime_pow.prime.value, - self.prime_pow.pow_mpz_t_top(), - self.unit) + return new_gen_from_padic(self.ordp, self.prime_pow.prec_cap, + self.prime_pow.prime.value, + self.prime_pow.pow_mpz_t_top(), + self.unit) def _integer_(self, Z=None): """ Returns an integer congruent to this element modulo diff --git a/src/sage/rings/padics/qadic_flint_FP.pxd b/src/sage/rings/padics/qadic_flint_FP.pxd index 5ddfaf0313e..91ce7441f83 100644 --- a/src/sage/rings/padics/qadic_flint_FP.pxd +++ b/src/sage/rings/padics/qadic_flint_FP.pxd @@ -1,4 +1,4 @@ -from sage.libs.pari.gen cimport gen as pari_gen +from sage.libs.cypari2.gen cimport gen as pari_gen from sage.libs.flint.fmpz_poly cimport fmpz_poly_t from sage.rings.padics.pow_computer_flint cimport PowComputer_flint_unram cdef class PowComputer_(PowComputer_flint_unram): From 234ef6efb9cd4003441c56790944a4fdf9735f0f Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Sat, 21 Jan 2017 18:30:54 +0100 Subject: [PATCH 006/126] Fix warning when converting number field elements from pari... ...triggered by some computations with algebraic numbers --- src/sage/rings/number_field/number_field.py | 3 ++- src/sage/rings/qqbar.py | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 9ec161c163c..191604c98a8 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -1643,7 +1643,8 @@ def _element_constructor_(self, x, check=True): if x.type() in ["t_INT", "t_FRAC"]: pass elif x.type() == "t_POL": - if check and self.pari_polynomial() != self.absolute_polynomial().monic(): + var = self.absolute_polynomial().variable_name() + if check and self.pari_polynomial(var) != self.absolute_polynomial().monic(): from warnings import warn warn("interpreting PARI polynomial %s relative to the defining polynomial %s of the PARI number field" % (x, self.pari_polynomial())) diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index f43e8bdeeda..fec71681350 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -498,6 +498,14 @@ sage: P = 1/(1+x^4) sage: P.partial_fraction_decomposition() (0, [(-0.3535533905932738?*x + 1/2)/(x^2 - 1.414213562373095?*x + 1), (0.3535533905932738?*x + 1/2)/(x^2 + 1.414213562373095?*x + 1)]) + +Check that :trac:`22202` is fixed:: + + sage: R1. = AA[]; R2. = QQbar[] + sage: v = QQbar.polynomial_root(x^2 - x + 1, CIF(0.5, RIF(-0.87, -0.85))) + sage: a = QQbar.polynomial_root((-4*v + 2)*s + (v - 1/2), CIF(RIF(0.24, 0.26), RIF(0))) + sage: QQ(a) + 1/4 """ from __future__ import absolute_import, print_function From 2fc32f8d39de2009a1bbf0717ff6a11602a8a12c Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Tue, 7 Feb 2017 09:24:38 +0100 Subject: [PATCH 007/126] #22202: add simpler test provided by Manuel Kauers --- src/sage/rings/number_field/number_field.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 191604c98a8..bd632f16e1d 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -1617,6 +1617,12 @@ def _element_constructor_(self, x, check=True): sage: L(gap(tau)^3) # indirect doctest 2 + Check that :trac:`22202` is fixed:: + + sage: y = QQ['y'].gen() + sage: R = QQ.extension(y^2-2,'a')['x'] + sage: R("a*x").factor() + (a) * x """ if isinstance(x, number_field_element.NumberFieldElement): K = x.parent() From baedc4131640d4c18aaa0cf2a68aa1de64f25941 Mon Sep 17 00:00:00 2001 From: David Roe Date: Wed, 1 Mar 2017 00:20:34 -0500 Subject: [PATCH 008/126] Fixing build and doctest errors --- src/sage/misc/session.pyx | 3 ++- src/sage/rings/padics/padic_base_leaves.py | 4 ++-- src/sage/rings/padics/padic_floating_point_element.pxd | 2 +- src/sage/rings/padics/padic_floating_point_element.pyx | 2 +- src/sage/rings/padics/qadic_flint_FP.pxd | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/sage/misc/session.pyx b/src/sage/misc/session.pyx index 856aa73095e..fe70a1b3de0 100644 --- a/src/sage/misc/session.pyx +++ b/src/sage/misc/session.pyx @@ -215,7 +215,7 @@ def show_identifiers(hidden=False): ['__', '_i', '_6', '_4', '_3', '_1', '_ii', '__doc__', '__builtins__', '___', '_9', '__name__', '_', 'a', '_i12', '_i14', 'factor', '__file__', '_hello', '_i13', '_i11', '_i10', '_i15', '_i5', '_13', '_10', '_iii', '_i9', '_i8', '_i7', '_i6', '_i4', '_i3', '_i2', '_i1', '_init_cmdline', '_14'] """ state = caller_locals() - return [x for x, v in state.iteritems() if _is_new_var(x, v, hidden)] + return sorted([x for x, v in state.iteritems() if _is_new_var(x, v, hidden)]) def save_session(name='sage_session', verbose=False): r""" @@ -288,6 +288,7 @@ def save_session(name='sage_session', verbose=False): sage: g = cython_lambda('double x', 'x*x + 1.5') sage: save_session(tmp_f, verbose=True) + Saving... Not saving g: g is a function, method, class or type ... """ diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index c3316000bbf..cfe76dbe739 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -457,7 +457,7 @@ def _coerce_map_from_(self, R): if isinstance(R, pAdicRingFloatingPoint) and R.prime() == self.prime(): if R.precision_cap() > self.precision_cap(): return True - elif R.precision_cap() == self.precision_cap() and self._printer.cmp_modes(R._printer) <= 0: + elif R.precision_cap() == self.precision_cap() and self._printer.richcmp_modes(R._printer, op_LE): return True def _repr_(self, do_latex=False): @@ -784,7 +784,7 @@ def _coerce_map_from_(self, R): if isinstance(R, (pAdicRingFloatingPoint, pAdicFieldFloatingPoint)) and R.prime() == self.prime(): if R.precision_cap() > self.precision_cap(): return True - elif R.precision_cap() == self.precision_cap() and self._printer.cmp_modes(R._printer) <= 0: + elif R.precision_cap() == self.precision_cap() and self._printer.richcmp_modes(R._printer, op_LE): return True def _repr_(self, do_latex=False): diff --git a/src/sage/rings/padics/padic_floating_point_element.pxd b/src/sage/rings/padics/padic_floating_point_element.pxd index 534d6a5fa6c..6e59e55b8c1 100644 --- a/src/sage/rings/padics/padic_floating_point_element.pxd +++ b/src/sage/rings/padics/padic_floating_point_element.pxd @@ -1,5 +1,5 @@ from sage.libs.gmp.types cimport mpz_t -from sage.libs.cypari2.gen cimport gen as pari_gen +from sage.libs.cypari2.gen cimport Gen as pari_gen ctypedef mpz_t celement include "FP_template_header.pxi" diff --git a/src/sage/rings/padics/padic_floating_point_element.pyx b/src/sage/rings/padics/padic_floating_point_element.pyx index 5a652602bac..8466f35637e 100644 --- a/src/sage/rings/padics/padic_floating_point_element.pyx +++ b/src/sage/rings/padics/padic_floating_point_element.pyx @@ -21,7 +21,7 @@ AUTHORS: include "sage/libs/linkages/padics/mpz.pxi" include "FP_template.pxi" -from sage.libs.cypari2.pari_instance cimport pari_instance as pari +from sage.libs.pari.all import pari from sage.libs.pari.convert_gmp cimport new_gen_from_padic from sage.rings.finite_rings.integer_mod import Mod diff --git a/src/sage/rings/padics/qadic_flint_FP.pxd b/src/sage/rings/padics/qadic_flint_FP.pxd index 91ce7441f83..c0d0f58b991 100644 --- a/src/sage/rings/padics/qadic_flint_FP.pxd +++ b/src/sage/rings/padics/qadic_flint_FP.pxd @@ -1,4 +1,4 @@ -from sage.libs.cypari2.gen cimport gen as pari_gen +from sage.libs.cypari2.gen cimport Gen as pari_gen from sage.libs.flint.fmpz_poly cimport fmpz_poly_t from sage.rings.padics.pow_computer_flint cimport PowComputer_flint_unram cdef class PowComputer_(PowComputer_flint_unram): From c069fc27fa7933bc2cf353e65729849b63f825d7 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Fri, 17 Mar 2017 01:39:56 +0100 Subject: [PATCH 009/126] Fix the SINGULAR_SO location on Cygwin so that it can be dlopened --- src/sage/env.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 68758245a1d..963a77f29f9 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -17,6 +17,7 @@ ######################################################################## from __future__ import absolute_import +import glob import os import socket import site @@ -142,13 +143,15 @@ def _add_variable_or_fallback(key, fallback, force=False): # locate singular shared object if UNAME[:6] == "CYGWIN": - extension = "dll" -elif UNAME == "Darwin": - extension = "dylib" + SINGULAR_SO = ([None] + glob.glob(os.path.join( + SAGE_LOCAL, "bin", "cygSingular-*.dll")))[-1] else: - extension = "so" -# library name changed from libsingular to libSingular btw 3.x and 4.x -SINGULAR_SO = SAGE_LOCAL+"/lib/libSingular."+extension + if UNAME == "Darwin": + extension = "dylib" + else: + extension = "so" + # library name changed from libsingular to libSingular btw 3.x and 4.x + SINGULAR_SO = SAGE_LOCAL+"/lib/libSingular."+extension _add_variable_or_fallback('SINGULAR_SO', SINGULAR_SO) # post process From 33233d1788b3d030169c1e65ba83aa3de09cdec3 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Wed, 22 Mar 2017 16:12:40 +0100 Subject: [PATCH 010/126] Better library cleanup for Singular on Cygwin --- build/pkgs/singular/spkg-install | 34 ++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/build/pkgs/singular/spkg-install b/build/pkgs/singular/spkg-install index 373bd0852b2..716ea9ca3d0 100755 --- a/build/pkgs/singular/spkg-install +++ b/build/pkgs/singular/spkg-install @@ -61,17 +61,31 @@ remove_old_version() rm -f "$SAGE_LOCAL/include/omlimits.h" # 3.x only rm -rf "$SAGE_LOCAL/include/resources" #4.x only rm -rf "$SAGE_LOCAL/include/gfanlib" #4.x only - rm -f "$SAGE_LOCAL"/lib/libsingular* # 3.x with lower case - rm -f "$SAGE_LOCAL"/lib/libsingcf*.a # 3.x only additional archives - rm -f "$SAGE_LOCAL"/lib/libsingfac*.a # 3.x only additional archives - rm -f "$SAGE_LOCAL"/lib/libSingular* # 4.x with upper case + + # Clean up all Singular-related libraries + libs=( + singular # 3.x with lower case + singcf # 3.x only additional archives + singfac # 3.x only additional archives + Singular # 4.x with upper case + polys + factory + omalloc + resources + gfan + ) + if [ "$UNAME" = "CYGWIN" ]; then + for name in ${libs[*]}; do + rm -rf "$SAGE_LOCAL"/bin/cyg${name}*.dll + rm -rf "$SAGE_LOCAL"/lib/lib${name}*.a + done + else + for name in ${libs[*]}; do + rm -rf "$SAGE_LOCAL"/lib/lib${name}*.{so,a} + done + fi + rm -f "$SAGE_LOCAL"/lib/p_Procs_Field* # 3.x only - # a bunch of additional libraries for 4.x - rm -f "$SAGE_LOCAL"/lib/libpolys* - rm -f "$SAGE_LOCAL"/lib/libfactory* - rm -f "$SAGE_LOCAL"/lib/libomalloc* - rm -f "$SAGE_LOCAL"/lib/libresources* - rm -r "$SAGE_LOCAL"/lib/libgfan* rm -rf "$SAGE_LOCAL/share/singular" rm -f "$SAGE_LOCAL"/share/info/singular* } From 15e37fe1a10e35b6b40d2ba2bcd984e0517a6416 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Wed, 22 Mar 2017 16:21:10 +0100 Subject: [PATCH 011/126] 'libresources' was renamed 'libsingular_resources' in Singular 4.0 --- build/pkgs/singular/spkg-install | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/pkgs/singular/spkg-install b/build/pkgs/singular/spkg-install index 716ea9ca3d0..936efee4bed 100755 --- a/build/pkgs/singular/spkg-install +++ b/build/pkgs/singular/spkg-install @@ -71,7 +71,8 @@ remove_old_version() polys factory omalloc - resources + resources # 3.x + singular_resources # 4.x and up gfan ) if [ "$UNAME" = "CYGWIN" ]; then From 4f33a48f6fee31322f89916437cf8009f564df06 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Wed, 22 Mar 2017 16:24:55 +0100 Subject: [PATCH 012/126] Don't hard-code the extension on other platforms (e.g. to support OSX) --- build/pkgs/singular/spkg-install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/singular/spkg-install b/build/pkgs/singular/spkg-install index 936efee4bed..13488df3635 100755 --- a/build/pkgs/singular/spkg-install +++ b/build/pkgs/singular/spkg-install @@ -82,7 +82,7 @@ remove_old_version() done else for name in ${libs[*]}; do - rm -rf "$SAGE_LOCAL"/lib/lib${name}*.{so,a} + rm -rf "$SAGE_LOCAL"/lib/lib${name}* done fi From 48f1827d02ee6cc65756fe4a614057c751da2687 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 28 Mar 2017 12:23:44 +0200 Subject: [PATCH 013/126] Libraries are not directories, no need for rm -r --- build/pkgs/singular/spkg-install | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/singular/spkg-install b/build/pkgs/singular/spkg-install index 13488df3635..fcc680164da 100755 --- a/build/pkgs/singular/spkg-install +++ b/build/pkgs/singular/spkg-install @@ -77,12 +77,12 @@ remove_old_version() ) if [ "$UNAME" = "CYGWIN" ]; then for name in ${libs[*]}; do - rm -rf "$SAGE_LOCAL"/bin/cyg${name}*.dll - rm -rf "$SAGE_LOCAL"/lib/lib${name}*.a + rm -f "$SAGE_LOCAL"/bin/cyg${name}*.dll + rm -f "$SAGE_LOCAL"/lib/lib${name}*.a done else for name in ${libs[*]}; do - rm -rf "$SAGE_LOCAL"/lib/lib${name}* + rm -f "$SAGE_LOCAL"/lib/lib${name}* done fi From a5ddc0406a1ca806cf3d5159e1b135c95b7fb30d Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 28 Mar 2017 12:27:11 +0200 Subject: [PATCH 014/126] SINGULAR_SO should not be None --- src/sage/env.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 963a77f29f9..038ede03fd5 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -143,8 +143,8 @@ def _add_variable_or_fallback(key, fallback, force=False): # locate singular shared object if UNAME[:6] == "CYGWIN": - SINGULAR_SO = ([None] + glob.glob(os.path.join( - SAGE_LOCAL, "bin", "cygSingular-*.dll")))[-1] + SINGULAR_SO = glob.glob(os.path.join( + SAGE_LOCAL, "bin", "cygSingular-*.dll"))[-1] else: if UNAME == "Darwin": extension = "dylib" From 0e337ef83b79610a4bd0df64b9e7c88450f3e7b4 Mon Sep 17 00:00:00 2001 From: paulmasson Date: Sun, 2 Apr 2017 15:12:27 -0700 Subject: [PATCH 015/126] Add Giac conversions and cleanup --- src/sage/functions/airy.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/sage/functions/airy.py b/src/sage/functions/airy.py index a3e3aee4ef7..442a3a48f81 100644 --- a/src/sage/functions/airy.py +++ b/src/sage/functions/airy.py @@ -161,12 +161,13 @@ def __init__(self): sage: airy_ai_simple(x)._sympy_() airyai(x) """ - BuiltinFunction.__init__(self, "airy_ai", - latex_name=r'\operatorname{Ai}', + BuiltinFunction.__init__(self, 'airy_ai', + latex_name=r"\operatorname{Ai}", conversions=dict(mathematica='AiryAi', maxima='airy_ai', sympy='airyai', - fricas='airyAi')) + fricas='airyAi', + giac='Airy_Ai')) def _derivative_(self, x, diff_param=None): """ @@ -267,7 +268,7 @@ def __init__(self): sage: airy_ai_prime(x)._sympy_() airyaiprime(x) """ - BuiltinFunction.__init__(self, "airy_ai_prime", + BuiltinFunction.__init__(self, 'airy_ai_prime', latex_name=r"\operatorname{Ai}'", conversions=dict(mathematica='AiryAiPrime', maxima='airy_dai', @@ -590,12 +591,13 @@ def __init__(self): sage: f._sympy_() airybi(x) """ - BuiltinFunction.__init__(self, "airy_bi", - latex_name=r'\operatorname{Bi}', + BuiltinFunction.__init__(self, 'airy_bi', + latex_name=r"\operatorname{Bi}", conversions=dict(mathematica='AiryBi', maxima='airy_bi', sympy='airybi', - fricas='airyBi')) + fricas='airyBi', + giac='Airy_Bi')) def _derivative_(self, x, diff_param=None): """ @@ -698,7 +700,7 @@ def __init__(self): sage: airy_bi_prime(x)._sympy_() airybiprime(x) """ - BuiltinFunction.__init__(self, "airy_bi_prime", + BuiltinFunction.__init__(self, 'airy_bi_prime', latex_name=r"\operatorname{Bi}'", conversions=dict(mathematica='AiryBiPrime', maxima='airy_dbi', From ffba36a98cdf3a5a1de6480ded01711f034adc8d Mon Sep 17 00:00:00 2001 From: paulmasson Date: Sun, 2 Apr 2017 15:24:14 -0700 Subject: [PATCH 016/126] Add Giac conversions and cleanup --- src/sage/functions/bessel.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index 40dacbc337e..d2bab7c4ee1 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -341,11 +341,12 @@ def __init__(self): sage: bessel_J(x, x)._sympy_() besselj(x, x) """ - BuiltinFunction.__init__(self, "bessel_J", nargs=2, + BuiltinFunction.__init__(self, 'bessel_J', nargs=2, conversions=dict(mathematica='BesselJ', maxima='bessel_j', sympy='besselj', - fricas='besselJ')) + fricas='besselJ', + giac='BesselJ')) def _eval_(self, n, x): """ @@ -557,11 +558,12 @@ def __init__(self): sage: bessel_Y(x, x)._sympy_() bessely(x, x) """ - BuiltinFunction.__init__(self, "bessel_Y", nargs=2, + BuiltinFunction.__init__(self, 'bessel_Y', nargs=2, conversions=dict(mathematica='BesselY', maxima='bessel_y', sympy='bessely', - fricas='besselY')) + fricas='besselY', + giac='BesselY')) def _eval_(self, n, x): """ @@ -762,7 +764,7 @@ def __init__(self): sage: bessel_I(x, x)._sympy_() besseli(x, x) """ - BuiltinFunction.__init__(self, "bessel_I", nargs=2, + BuiltinFunction.__init__(self, 'bessel_I', nargs=2, conversions=dict(mathematica='BesselI', maxima='bessel_i', sympy='besseli', @@ -962,7 +964,7 @@ def __init__(self): sage: bessel_K(x, x)._sympy_() besselk(x, x) """ - BuiltinFunction.__init__(self, "bessel_K", nargs=2, + BuiltinFunction.__init__(self, 'bessel_K', nargs=2, conversions=dict(mathematica='BesselK', maxima='bessel_k', sympy='besselk', From e1a63edf85af5280aa74d9001bed6ce48328b34a Mon Sep 17 00:00:00 2001 From: paulmasson Date: Sun, 2 Apr 2017 15:53:33 -0700 Subject: [PATCH 017/126] Add Giac conversions and cleanup --- src/sage/functions/orthogonal_polys.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 931b247ba5f..b9634ddd561 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -574,9 +574,10 @@ def __init__(self): chebyshev_t(_SAGE_VAR_n,chebyshev_t(_SAGE_VAR_n,_SAGE_VAR_x)) """ ChebyshevFunction.__init__(self, 'chebyshev_T', nargs=2, - conversions=dict(maxima='chebyshev_t', - mathematica='ChebyshevT', - sympy='chebyshevt')) + conversions=dict(maxima='chebyshev_t', + mathematica='ChebyshevT', + sympy='chebyshevt', + giac='tchebyshev1')) def _latex_(self): r""" @@ -883,9 +884,10 @@ def __init__(self): chebyshev_u(_SAGE_VAR_n,_SAGE_VAR_x) """ ChebyshevFunction.__init__(self, 'chebyshev_U', nargs=2, - conversions=dict(maxima='chebyshev_u', - mathematica='ChebyshevU', - sympy='chebyshevu')) + conversions=dict(maxima='chebyshev_u', + mathematica='ChebyshevU', + sympy='chebyshevu', + giac='tchebyshev2')) def _latex_(self): r""" @@ -1142,9 +1144,11 @@ def __init__(self): sage: loads(dumps(legendre_P)) legendre_P """ - BuiltinFunction.__init__(self, "legendre_P", nargs=2, latex_name=r"P", - conversions={'maxima':'legendre_p', 'mathematica':'LegendreP', - 'maple':'LegendreP'}) + BuiltinFunction.__init__(self, 'legendre_P', nargs=2, latex_name=r"P", + conversions={'maxima':'legendre_p', + 'mathematica':'LegendreP', + 'maple':'LegendreP', + 'giac':'legendre'}) def _eval_(self, n, x, *args, **kwds): r""" From 3a3d0792d3a10a4b067231c3d1279c82fcafbb40 Mon Sep 17 00:00:00 2001 From: paulmasson Date: Sun, 2 Apr 2017 16:00:01 -0700 Subject: [PATCH 018/126] Add Giac conversion --- src/sage/functions/transcendental.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py index 2cc0904d7de..5f281cbe4d6 100644 --- a/src/sage/functions/transcendental.py +++ b/src/sage/functions/transcendental.py @@ -124,7 +124,7 @@ def __init__(self): sage: (zeta(x) * 1/(1 - exp(-x))).residue(x==2*pi*I) zeta(2*I*pi) """ - GinacFunction.__init__(self, "zeta") + GinacFunction.__init__(self, 'zeta', conversions={'giac':'Zeta'}) zeta = Function_zeta() From bdc2807934ce570c7a29547f3ff3fdff5a387beb Mon Sep 17 00:00:00 2001 From: paulmasson Date: Sun, 2 Apr 2017 16:28:09 -0700 Subject: [PATCH 019/126] Add Giac conversions and cleanup --- src/sage/functions/other.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index a1704120fcb..51fa663bbf9 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -908,12 +908,13 @@ def __init__(self): :meth:`sage.functions.other.gamma` """ - GinacFunction.__init__(self, "gamma", latex_name=r'\Gamma', - ginac_name='tgamma', - conversions={'mathematica':'Gamma', - 'maple':'GAMMA', - 'sympy':'gamma', - 'fricas':'Gamma'}) + GinacFunction.__init__(self, 'gamma', latex_name=r"\Gamma", + ginac_name='tgamma', + conversions={'mathematica':'Gamma', + 'maple':'GAMMA', + 'sympy':'gamma', + 'fricas':'Gamma', + 'giac':'Gamma'}) gamma1 = Function_gamma() @@ -2056,11 +2057,13 @@ def __init__(self): sage: beta(-1.3,-0.4) -4.92909641669610 """ - GinacFunction.__init__(self, "beta", nargs=2, - conversions=dict(maxima='beta', - mathematica='Beta', - sympy='beta', - fricas='Beta')) + GinacFunction.__init__(self, 'beta', nargs=2, + latex_name=r"\operatorname{B}", + conversions=dict(maxima='beta', + mathematica='Beta', + sympy='beta', + fricas='Beta', + giac='Beta')) beta = Function_beta() From 7690f842f00d3e84b2b6e32c94ee62d924dae09d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 3 Apr 2017 22:36:32 +0200 Subject: [PATCH 020/126] trac 18430 fixing doctests, plus little code cleanup --- .../quadratic_form__local_field_invariants.py | 42 ++++--------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py index 2f97c0b118f..7d46dcc307a 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py +++ b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py @@ -743,54 +743,28 @@ def is_isotropic(self, p): def anisotropic_primes(self): """ - Returns a list with all of the anisotropic primes of the quadratic form. + Return a list with all of the anisotropic primes of the quadratic form. - - INPUT: - - None - - OUTPUT: - - Returns a list of prime numbers >0. + The infinite prime is denoted by `-1`. EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.anisotropic_primes() - [2] - - :: + [2, -1] sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Q.anisotropic_primes() - [2] - - :: + [2, -1] sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1,1]) sage: Q.anisotropic_primes() - [] - + [-1] """ - - ## Look at all prime divisors of 2 * Det(Q) to find the anisotropic primes... + # Look at all prime divisors of 2 * Det(Q) to find the + # anisotropic primes... possible_primes = prime_divisors(2 * self.det()) + [-1] - AnisoPrimes = [] - - ## DIAGNSOTIC - #print " Possible anisotropic primes are: " + str(possible_primes) - - for p in possible_primes: - if (self.is_anisotropic(p)): - AnisoPrimes += [p] - - ## DIAGNSOTIC - #print " leaving anisotropic_primes..." - - return AnisoPrimes - - + return [p for p in possible_primes if self.is_anisotropic(p)] def compute_definiteness(self): From 3231a6ddc00a7a4049d39ba5a2eacf1d2fdc7529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 4 Apr 2017 21:02:41 +0200 Subject: [PATCH 021/126] trac 18430 details --- .../quadratic_form__local_field_invariants.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py index 7d46dcc307a..2350f1c0f15 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py +++ b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py @@ -621,7 +621,7 @@ def is_hyperbolic(self, p): if p == 2: return (QQ(self.det() * (-1) ** m).is_padic_square(p) and self.hasse_invariant(p) == - hilbert_symbol(-1, -1, p) ** m.binomial(2)) + (-1) ** m.binomial(2)) # here -1 is hilbert_symbol(-1,-1,2) return (QQ(self.det() * (-1) ** m).is_padic_square(p) and self.hasse_invariant(p) == 1) @@ -745,7 +745,7 @@ def anisotropic_primes(self): """ Return a list with all of the anisotropic primes of the quadratic form. - The infinite prime is denoted by `-1`. + The infinite place is denoted by `-1`. EXAMPLES:: @@ -837,13 +837,11 @@ def compute_definiteness(self): n = self.dim() M = self.matrix() - ## Deal with the zero-diml form if n == 0: self.__definiteness_string = "zero" return - sig_pos, sig_neg, sig_zer = self.signature_vector() ## Determine and cache the definiteness string From ab2c200efd0cdb07997fb528ca753067a428774a Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 23 Apr 2017 19:16:10 -0500 Subject: [PATCH 022/126] Fixing tensor product for 0 x m or m x 0 matrices. --- src/sage/matrix/matrix2.pyx | 23 ++++++++++++++++++++++- src/sage/matrix/matrix_cyclo_dense.pyx | 15 +++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index b0f98ca8011..29a0213c6de 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -8062,9 +8062,30 @@ cdef class Matrix(matrix1.Matrix): Traceback (most recent call last): ... TypeError: tensor product requires a second matrix, not junk + + TESTS: + + Check that `m \times 0` and `0 \times m` matrices work + (:trac:`22769`):: + + sage: m1 = matrix(QQ, 1, 0, []) + sage: m2 = matrix(QQ, 2, 2, [1, 2, 3, 4]) + sage: m1.tensor_product(m2).dimensions() + (2, 0) + sage: m2.tensor_product(m1).dimensions() + (2, 0) + sage: m3 = matrix(QQ, 0, 3, []) + sage: m3.tensor_product(m2).dimensions() + (0, 6) + sage: m2.tensor_product(m3).dimensions() + (0, 6) """ if not isinstance(A, Matrix): raise TypeError('tensor product requires a second matrix, not {0}'.format(A)) + # Special case when one of the matrices is 0 \times m or m \times 0 + if self.nrows() == 0 or self.ncols() == 0 or A.nrows() == 0 or A.ncols() == 0: + return sage.matrix.constructor.matrix(QQ, self.nrows()*A.nrows(), + self.ncols()*A.ncols(), []) return sage.matrix.constructor.block_matrix(self.nrows(),self.ncols(),[x*A for x in self.list()], subdivide=subdivide) def randomize(self, density=1, nonzero=False, *args, **kwds): @@ -15001,4 +15022,4 @@ def _matrix_power_symbolic(A, n): else: Pinv = ~P - return P * FJ * Pinv \ No newline at end of file + return P * FJ * Pinv diff --git a/src/sage/matrix/matrix_cyclo_dense.pyx b/src/sage/matrix/matrix_cyclo_dense.pyx index a5db5b69395..ae4228155b6 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pyx +++ b/src/sage/matrix/matrix_cyclo_dense.pyx @@ -1869,6 +1869,21 @@ cdef class Matrix_cyclo_dense(matrix_dense.Matrix_dense): sage: subdiv = super(type(Mp),Mp).tensor_product(Np).subdivisions() sage: Mp.tensor_product(Np).subdivisions() == subdiv True + + Check that `m \times 0` and `0 \times m` matrices work + (:trac:`22769`):: + + sage: m1 = matrix(C, 1, 0, []) + sage: m2 = matrix(C, 2, 2, [1, 2, 3, 4]) + sage: m1.tensor_product(m2).dimensions() + (2, 0) + sage: m2.tensor_product(m1).dimensions() + (2, 0) + sage: m3 = matrix(C, 0, 3, []) + sage: m3.tensor_product(m2).dimensions() + (0, 6) + sage: m2.tensor_product(m3).dimensions() + (0, 6) """ if not isinstance(A, Matrix): raise TypeError('tensor product requires a second matrix, not {0}'.format(A)) From 16120c8f7b62c7cc6dbaf828063d17c6997d05db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Honrubia=20Gonz=C3=A1lez?= Date: Tue, 25 Apr 2017 18:01:59 +0200 Subject: [PATCH 023/126] Introduction to 3d graphics rewritten to mimi 2d graphics introduction page --- src/doc/en/reference/plot3d/index.rst | 2 +- src/sage/plot/plot3d/examples.py | 13 --- src/sage/plot/plot3d/introduction.py | 129 ++++++++++++++++++++++++++ src/sage/plot/plot3d/plot3d.py | 35 +++++-- 4 files changed, 156 insertions(+), 23 deletions(-) delete mode 100644 src/sage/plot/plot3d/examples.py create mode 100644 src/sage/plot/plot3d/introduction.py diff --git a/src/doc/en/reference/plot3d/index.rst b/src/doc/en/reference/plot3d/index.rst index f314e640259..2cbabe1b75c 100644 --- a/src/doc/en/reference/plot3d/index.rst +++ b/src/doc/en/reference/plot3d/index.rst @@ -4,7 +4,7 @@ .. toctree:: :maxdepth: 2 - sage/plot/plot3d/examples + sage/plot/plot3d/introduction Function and Data Plots ----------------------- diff --git a/src/sage/plot/plot3d/examples.py b/src/sage/plot/plot3d/examples.py deleted file mode 100644 index 798fa8ad375..00000000000 --- a/src/sage/plot/plot3d/examples.py +++ /dev/null @@ -1,13 +0,0 @@ -r""" -Introduction - -EXAMPLES:: - - sage: x, y = var('x y') - sage: W = plot3d(sin(pi*((x)^2+(y)^2))/2,(x,-1,1),(y,-1,1), frame=False, color='purple', opacity=0.8) - sage: S = sphere((0,0,0),size=0.3, color='red', aspect_ratio=[1,1,1]) - sage: show(W + S, figsize=8) -""" - - - diff --git a/src/sage/plot/plot3d/introduction.py b/src/sage/plot/plot3d/introduction.py new file mode 100644 index 00000000000..65c31845406 --- /dev/null +++ b/src/sage/plot/plot3d/introduction.py @@ -0,0 +1,129 @@ +r""" +Introduction + +Sage has a wide support for 3D graphics, from basic shapes to implicit and +parametric plots. + +The following graphics functions are supported: + + +- :func:`~plot3d` - plot a 3d function + +- :func:`~sage.plot.plot3d.parametric_plot3d.parametric_plot3d` - a parametric three-dimensional space curve or surface + +- :func:`~sage.plot.plot3d.revolution_plot3d.revolution_plot3d` - a plot of a revolved curve + +- :func:`~sage.plot.plot3d.plot_field3d.plot_vector_field3d` - a plot of a 3d vector field + +- :func:`~sage.plot.plot3d.implicit_plot3d.implicit_plot3d` - a plot of an isosurface of a function + +- :func:`~sage.plot.plot3d.list_plot3d.list_plot3d`- a 3-dimensional plot of a surface defined by a list of points in 3-dimensional space + +- :func:`~sage.plot.plot3d.list_plot3d.list_plot3d_matrix` - a 3-dimensional plot of a surface defined by a matrix defining points in 3-dimensional space + +- :func:`~sage.plot.plot3d.list_plot3d.list_plot3d_array_of_arrays`- A 3-dimensional plot of a surface defined by a list of lists defining points in 3-dimensional space + +- :func:`~sage.plot.plot3d.list_plot3d.list_plot3d_tuples` - a 3-dimensional plot of a surface defined by a list of points in 3-dimensional space + +The following classes for basic shapes are supported: + + +- :class:`~sage.plot.plot3d.shapes.Box` - a box given its three magnitudes + +- :class:`~sage.plot.plot3d.shapes.Cone` - a cone, with base in the xy-plane pointing up the z-axis + +- :class:`~sage.plot.plot3d.shapes.Cylinder` - a cylinder, with base in the xy-plane pointing up the z-axis + +- :class:`~sage.plot.plot3d.shapes2.Line` - a 3d line joining a sequence of points + +- :class:`~sage.plot.plot3d.shapes.Sphere` - a sphere centered at the origin + +- :class:`~sage.plot.plot3d.shapes.Text` - a text label attached to a point in 3d space + +- :class:`~sage.plot.plot3d.shapes.Torus` - a 3d torus + +- :class:`~sage.plot.plot3d.shapes2.Point` - a position in 3d, represented by a sphere of fixed size + + +The following plotting funtions for basic shapes are supported + + +- :func:`~sage.plot.plot3d.shapes.ColorCube` - a cube with given size and sides with given colors + +- :func:`~sage.plot.plot3d.shapes.LineSegment` - a line segment, which is drawn as a cylinder from start to end with radius radius + +- :func:`~sage.plot.plot3d.shapes2.line3d` - a 3d line joining a sequence of points + +- :func:`~sage.plot.plot3d.shapes.arrow3d` - a 3d arrow + +- :func:`~sage.plot.plot3d.shapes2.point3d` - a point or list of points in 3d space + +- :func:`~sage.plot.plot3d.shapes2.bezier3d` - a 3d bezier path + +- :func:`~sage.plot.plot3d.shapes2.frame3d` - a frame in 3d + +- :func:`~sage.plot.plot3d.shapes2.frame_labels` - labels for a given frame in 3d + +- :func:`~sage.plot.plot3d.shapes2.polygon3d` - draw a polygon in 3d + +- :func:`~sage.plot.plot3d.shapes2.polygons3d` - draw the union of several polygons in 3d + +- :func:`~sage.plot.plot3d.shapes2.ruler` - draw a ruler in 3d, with major and minor ticks + +- :func:`~sage.plot.plot3d.shapes2.ruler_frame` - draw a frame made of 3d rulers, with major and minor ticks + +- :func:`~sage.plot.plot3d.shapes2.sphere` - plot of a sphere given center and radius + +- :func:`~sage.plot.plot3d.shapes2.text3d` - 3d text + +Sage also supports platonic solids with the following functions: + + +- :func:`~sage.plot.plot3d.platonic.tetrahedron` + +- :func:`~sage.plot.plot3d.platonic.cube` + +- :func:`~sage.plot.plot3d.platonic.octahedron` + +- :func:`~sage.plot.plot3d.platonic.dodecahedron` + +- :func:`~sage.plot.plot3d.platonic.icosahedron` + +Different viewers are supported other jmol, like a web-based interactive viewer +using the Three.js JavaScript library and accesible through the ``show(viewer='threejs')`` +method of any 3d graphic. A raytraced representation is accesible by typing +``show(viewer='tachyon')``: + +- :class:`~sage.plot.plot3d.tachyon.Tachyon` - create a scene the can be rendered using the Tachyon ray tracer + +- :class:`~sage.plot.plot3d.tachyon.Axis_aligned_box` - box with axis-aligned edges with the given min and max coordinates + +- :class:`~sage.plot.plot3d.tachyon.Cylinder` - an infinite cylinder + +- :class:`~sage.plot.plot3d.tachyon.FCylinder` - a finite cylinder + +- :class:`~sage.plot.plot3d.tachyon.FractalLandscape`- axis-aligned fractal landscape + +- :class:`~sage.plot.plot3d.tachyon.Light` - represents lighting objects + +- :class:`~sage.plot.plot3d.tachyon.ParametricPlot` - parametric plot routines + +- :class:`~sage.plot.plot3d.tachyon.Plane` - an infinite plane + +- :class:`~sage.plot.plot3d.tachyon.Ring` - an annulus of zero thickness + +- :class:`~sage.plot.plot3d.tachyon.Sphere`- a sphere + +- :class:`~sage.plot.plot3d.tachyon.TachyonSmoothTriangle` - a triangle along with a normal vector, which is used for smoothing + +- :class:`~sage.plot.plot3d.tachyon.TachyonTriangle` - basic triangle class + +- :class:`~sage.plot.plot3d.tachyon.TachyonTriangleFactory` - class to produce triangles of various rendering types + +- :class:`~sage.plot.plot3d.tachyon.Texfunc` - creates a texture function + +- :class:`~sage.plot.plot3d.tachyon.Texture` - stores texture information + +- :func:`~sage.plot.plot3d.tachyon.tostr` - converts vector information to a space-separated string + +""" diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 3b1e7aaa541..e818b85799d 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -1,19 +1,34 @@ r""" Plotting Functions + EXAMPLES:: + sage: x, y = var('x y') + sage: W = plot3d(sin(pi*((x)^2+(y)^2))/2,(x,-1,1),(y,-1,1), frame=False, color='purple', opacity=0.8) + sage: S = sphere((0,0,0),size=0.3, color='red', aspect_ratio=[1,1,1]) + sage: show(W + S, figsize=8) + +.. PLOT:: + + x, y = var('x y') + W = plot3d(sin(pi*((x)**2+(y)**2))/2,(x,-1,1),(y,-1,1), frame=False, color='purple', opacity=0.8) + S = sphere((0,0,0),size=0.3, color='red', aspect_ratio=[1,1,1]) + sphinx_plot(W + S) + +:: + sage: def f(x,y): - ....: return math.sin(y*y+x*x)/math.sqrt(x*x+y*y+.0001) + ....: return math.sin(y^2+x^2)/math.sqrt(x^2+y^2.0001) sage: P = plot3d(f,(-3,3),(-3,3), adaptive=True, color=rainbow(60, 'rgbtuple'), max_bend=.1, max_depth=15) sage: P.show() .. PLOT:: - + def f(x,y): return math.sin(y*y+x*x)/math.sqrt(x*x+y*y+.0001) P = plot3d(f,(-3,3),(-3,3), adaptive=True, color=rainbow(60, 'rgbtuple'), max_bend=.1, max_depth=15) sphinx_plot(P) - + :: sage: def f(x,y): @@ -260,10 +275,10 @@ def to_cartesian(self, func, params=None): sage: v_phi=array([ 0., 1.57079637, 3.14159274, 4.71238911, 6.28318548]) sage: v_theta=array([ 0., 0.78539819, 1.57079637, 2.35619456, 3.14159274]) sage: m_r=array([[ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422], - ....: [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422], - ....: [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422], - ....: [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422], - ....: [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422]]) + ... [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422], + ... [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422], + ... [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422], + ... [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422]]) sage: import scipy.interpolate sage: f=scipy.interpolate.RectBivariateSpline(v_phi,v_theta,m_r) sage: spherical_plot3d(f,(0,2*pi),(0,pi)) @@ -742,6 +757,8 @@ def smooth_triangle(self, a, b, c, da, db, dc, color = None): from . import parametric_plot3d def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): """ + Plots a function in 3d. + INPUT: @@ -965,7 +982,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): sage: D = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=cylindric_axial,plot_points=[100,100]) sage: E = plot3d(2,(u,-pi,pi),(v,-pi,pi),transformation=parabolic_cylindrical,plot_points=[100,100]) sage: @interact - ....: def _(which_plot=[A,B,C,D,E]): + ... def _(which_plot=[A,B,C,D,E]): ....: show(which_plot) ... @@ -978,7 +995,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): sage: I = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=cylindric_axial,plot_points=[100,100]) sage: J = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=parabolic_cylindrical,plot_points=[100,100]) sage: @interact - ....: def _(which_plot=[F, G, H, I, J]): + ... def _(which_plot=[F, G, H, I, J]): ....: show(which_plot) ... From 9143bd2c7f60e364f3864e862d0cf8d563bc6a60 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Thu, 27 Apr 2017 13:45:23 +0200 Subject: [PATCH 024/126] add more /functions conversions --- src/sage/functions/hyperbolic.py | 9 ++++++--- src/sage/functions/other.py | 29 +++++++++++++++++++---------- src/sage/functions/trig.py | 16 ++++++++-------- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/sage/functions/hyperbolic.py b/src/sage/functions/hyperbolic.py index 4de0da92b24..2e9ca64a7a0 100644 --- a/src/sage/functions/hyperbolic.py +++ b/src/sage/functions/hyperbolic.py @@ -435,7 +435,8 @@ def __init__(self): asinh(x) """ GinacFunction.__init__(self, "arcsinh", latex_name=r"{\rm arcsinh}", - conversions=dict(maxima='asinh', sympy='asinh', fricas='asinh')) + conversions=dict(maxima='asinh', sympy='asinh', fricas='asinh', + giac='asinh')) arcsinh = asinh = Function_arcsinh() @@ -519,7 +520,8 @@ def __init__(self): acosh(x) """ GinacFunction.__init__(self, "arccosh", latex_name=r"{\rm arccosh}", - conversions=dict(maxima='acosh', sympy='acosh', fricas='acosh')) + conversions=dict(maxima='acosh', sympy='acosh', fricas='acosh', + giac='acosh')) arccosh = acosh = Function_arccosh() @@ -577,7 +579,8 @@ def __init__(self): atanh(x) """ GinacFunction.__init__(self, "arctanh", latex_name=r"{\rm arctanh}", - conversions=dict(maxima='atanh', sympy='atanh', fricas='atanh')) + conversions=dict(maxima='atanh', sympy='atanh', fricas='atanh', + giac='atanh')) arctanh = atanh = Function_arctanh() diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 51fa663bbf9..b550b51582a 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -162,7 +162,8 @@ def __init__(self): BuiltinFunction.__init__(self, "erf", latex_name=r"\text{erf}", conversions=dict(maxima='erf', sympy='erf', - fricas='erf')) + fricas='erf', + giac='erf')) def _eval_(self, x): """ @@ -330,7 +331,8 @@ def __init__(self): (pi + e)*abs(x) """ GinacFunction.__init__(self, "abs", latex_name=r"\mathrm{abs}", - conversions=dict(sympy='Abs')) + conversions=dict(sympy='Abs', + giac='abs')) abs = abs_symbolic = Function_abs() @@ -419,7 +421,8 @@ def __init__(self): """ BuiltinFunction.__init__(self, "ceil", conversions=dict(maxima='ceiling', - sympy='ceiling')) + sympy='ceiling', + giac='ceil')) def _print_latex_(self, x): r""" @@ -575,7 +578,7 @@ def __init__(self): floor """ BuiltinFunction.__init__(self, "floor", - conversions=dict(sympy='floor')) + conversions=dict(sympy='floor', giac='floor')) def _print_latex_(self, x): r""" @@ -1727,7 +1730,8 @@ def __init__(self): conversions=dict(maxima='factorial', mathematica='Factorial', sympy='factorial', - fricas='factorial')) + fricas='factorial', + giac='factorial')) def _eval_(self, x): """ @@ -1859,7 +1863,8 @@ def __init__(self): conversions=dict(maxima='binomial', mathematica='Binomial', sympy='binomial', - fricas='binomial')) + fricas='binomial', + giac='comb')) def _binomial_sym(self, n, k): """ @@ -2281,7 +2286,8 @@ def __init__(self): BuiltinFunction.__init__(self, "arg", conversions=dict(maxima='carg', mathematica='Arg', - sympy='arg')) + sympy='arg', + giac='arg')) def _eval_(self, x): """ @@ -2432,7 +2438,8 @@ def __init__(self): """ GinacFunction.__init__(self, "real_part", conversions=dict(maxima='realpart', - sympy='re'), + sympy='re', + giac='re'), alt_name="real") def __call__(self, x, **kwargs): @@ -2491,7 +2498,8 @@ def __init__(self): """ GinacFunction.__init__(self, "imag_part", conversions=dict(maxima='imagpart', - sympy='im'), + sympy='im', + giac='im'), alt_name="imag") def __call__(self, x, **kwargs): @@ -2583,7 +2591,8 @@ def __init__(self): conjugate """ GinacFunction.__init__(self, "conjugate", - conversions=dict(sympy='conjugate')) + conversions=dict(sympy='conjugate', + giac='conj')) conjugate = Function_conjugate() diff --git a/src/sage/functions/trig.py b/src/sage/functions/trig.py index 1886831bf7b..d29ff41cabc 100644 --- a/src/sage/functions/trig.py +++ b/src/sage/functions/trig.py @@ -108,7 +108,7 @@ def __init__(self): sin(1/42*pi) """ GinacFunction.__init__(self, 'sin', latex_name=r"\sin", - conversions=dict(maxima='sin',mathematica='Sin')) + conversions=dict(maxima='sin',mathematica='Sin',giac='sin')) sin = Function_sin() @@ -158,7 +158,7 @@ def __init__(self): -cos(1/42*pi) """ GinacFunction.__init__(self, 'cos', latex_name=r"\cos", - conversions=dict(maxima='cos',mathematica='Cos')) + conversions=dict(maxima='cos',mathematica='Cos',giac='cos')) cos = Function_cos() @@ -499,7 +499,7 @@ def __init__(self): (0.6662394324925152+1.0612750619050357j) """ GinacFunction.__init__(self, 'arcsin', latex_name=r"\arcsin", - conversions=dict(maxima='asin', sympy='asin', fricas="asin")) + conversions=dict(maxima='asin', sympy='asin', fricas="asin", giac="asin")) arcsin = asin = Function_arcsin() @@ -558,7 +558,7 @@ def __init__(self): (0.9045568943023814-1.0612750619050357j) """ GinacFunction.__init__(self, 'arccos', latex_name=r"\arccos", - conversions=dict(maxima='acos', sympy='acos', fricas='acos')) + conversions=dict(maxima='acos', sympy='acos', fricas='acos', giac='acos')) arccos = acos = Function_arccos() @@ -626,7 +626,7 @@ def __init__(self): 1/2*pi """ GinacFunction.__init__(self, 'arctan', latex_name=r"\arctan", - conversions=dict(maxima='atan', sympy='atan', fricas='atan')) + conversions=dict(maxima='atan', sympy='atan', fricas='atan', giac='atan')) arctan = atan = Function_arctan() @@ -676,7 +676,7 @@ def __init__(self): """ GinacFunction.__init__(self, 'arccot', latex_name=r"\operatorname{arccot}", - conversions=dict(maxima='acot', sympy='acot', fricas='acot')) + conversions=dict(maxima='acot', sympy='acot', fricas='acot',giac='acot')) def _eval_numpy_(self, x): """ @@ -732,7 +732,7 @@ def __init__(self): (0.45227844715119064-0.5306375309525178j) """ GinacFunction.__init__(self, 'arccsc', latex_name=r"\operatorname{arccsc}", - conversions=dict(maxima='acsc', sympy='acsc', fricas='acsc')) + conversions=dict(maxima='acsc', sympy='acsc', fricas='acsc', giac='acsc')) def _eval_numpy_(self, x): """ @@ -790,7 +790,7 @@ def __init__(self): (1.118517879643706+0.5306375309525178j) """ GinacFunction.__init__(self, 'arcsec', latex_name=r"\operatorname{arcsec}", - conversions=dict(maxima='asec', sympy='asec', fricas='asec')) + conversions=dict(maxima='asec', sympy='asec', fricas='asec', giac='asec')) def _eval_numpy_(self, x): """ From 1d9a50e38a3babc53457d7001b717483abd21822 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 30 Apr 2017 12:15:51 +0200 Subject: [PATCH 025/126] trac #22908: generator of random block graphs --- src/sage/graphs/generators/random.py | 145 +++++++++++++++++++++++++++ src/sage/graphs/graph_generators.py | 2 + 2 files changed, 147 insertions(+) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index f64da2a46cf..165f8966a94 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -244,6 +244,151 @@ def RandomBipartite(n1, n2, p): return g +def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): + r""" + Return a Random Block Graph + + A block graph is a connected graph in which every biconnected component + (block) is a clique. See :wikipedia:`Block_graph` for more details. + + INPUT: + + - ``m`` -- number of blocks. + + - ``k`` -- minimum number of vertices of a block (at least two). + + - ``kmax`` -- (default: None) By default, each block has `k` vertices. When + the parameter `kmax` is specified (with `kmax \geq k`), the number of + vertices of each block is randomly chosen between `k` and `kmax`. + + - ``incidence_structure`` -- (default: False) when set to ``True``, the + incidence structure of the graphs is returned instead of the graph itself, + that is the list of the lists of vertices in each block. This is useful + for the creation of some hypergraphs. + + OUTPUT: + + A Graph when ``incidence_structure==False`` (default), and otherwise an + incidence structure. + + .. SEEALSO:: + + - :meth:`~sage.combinat.designs.incidence.IncidenceStructure` + + EXAMPLES: + + A block graph with only 1 block is a clique:: + + sage: B = graphs.RandomBlockGraph(1, 4) + sage: B.is_clique() + True + + A block graph with blocks of order 2 is a tree:: + + sage: B = graphs.RandomBlockGraph(10, 2) + sage: B.is_tree() + True + + Every biconnected components of a block graph are cliques:: + + sage: B = graphs.RandomBlockGraph(5, 3, kmax=6) + sage: blocks,cuts = B.blocks_and_cut_vertices() + sage: all(B.is_clique(block) for block in blocks) + True + + A block graph with blocks of order `k` has `m*(k-1)+1` vertices:: + + sage: m, k = 6, 4 + sage: B = graphs.RandomBlockGraph(m, k) + sage: B.order() == m*(k-1)+1 + True + + Asking for the incidence structure:: + + sage: m, k = 6, 4 + sage: IS = graphs.RandomBlockGraph(m, k, incidence_structure=True) + sage: from sage.combinat.designs.incidence_structures import IncidenceStructure + sage: IncidenceStructure(IS) + Incidence structure with 19 points and 6 blocks + sage: m*(k-1)+1 + 19 + + TESTS: + + A block graph has at least one block, so `m\geq 1`:: + + sage: B = graphs.RandomBlockGraph(0, 1) + Traceback (most recent call last): + ... + ValueError: the number `m` of blocks must be >= 1 + + A block has at least 2 vertices, so `k\geq 2`:: + + sage: B = graphs.RandomBlockGraph(1, 1) + Traceback (most recent call last): + ... + ValueError: the minimum number `k` of vertices in a block must be >= 2 + + The maximum size of a block is at least its minimum size, so `k\leq kmax`:: + + sage: B = graphs.RandomBlockGraph(1, 3, kmax=2) + Traceback (most recent call last): + ... + ValueError: the maximum number `kmax` of vertices in a block must be >= `k` + """ + import itertools + from sage.misc.prandom import choice + from sage.sets.disjoint_set import DisjointSet + + if m < 1: + raise ValueError("the number `m` of blocks must be >= 1") + if k < 2: + raise ValueError("the minimum number `k` of vertices in a block must be >= 2") + if kmax is None: + kmax = k + elif kmax < k: + raise ValueError("the maximum number `kmax` of vertices in a block must be >= `k`") + + if m == 1: + # A block graph with a single block is a clique + IS = [ list(range(randint(k, kmax))) ] + + elif kmax == 2: + # A block graph with blocks of order 2 is a tree + IS = [ list(e) for e in RandomTree(m+1).edges(labels=False) ] + + else: + # We start with a random tree of order m + T = RandomTree(m) + + # We create a block of order in range [k,kmax] per vertex of the tree + B = {u:[(u,i) for i in range(randint(k, kmax))] for u in T} + + # For each edge of the tree, we choose 1 vertex in each of the + # corresponding blocks and we merge them. We use a disjoint set data + # structure to keep a unique identifier per merged vertices + DS = DisjointSet([i for u in B for i in B[u]]) + for u,v in T.edges(labels=0): + DS.union(choice(B[u]), choice(B[v])) + + # We relabel vertices in the range [0, m*(k-1)] and build the incidence + # structure + new_label = {root:i for i,root in enumerate(DS.root_to_elements_dict())} + IS = [ [new_label[DS.find(v)] for v in B[u]] for u in B ] + + if incidence_structure: + return IS + + # We finally build the block graph + if k == kmax: + BG = Graph(name = "Random Block Graph with {} blocks of order {}".format(m, k)) + else: + BG = Graph(name = "Random Block Graph with {} blocks of order {} to {}".format(m, k, kmax)) + for block in IS: + BG.add_clique( block ) + return BG + + def RandomBoundedToleranceGraph(n): r""" Returns a random bounded tolerance graph. diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 85ae7c71b93..c8b5d468e2f 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -302,6 +302,7 @@ def __append_to_doc(methods): ["RandomBarabasiAlbert", "RandomBicubicPlanar", "RandomBipartite", + "RandomBlockGraph", "RandomBoundedToleranceGraph", "RandomGNM", "RandomGNP", @@ -2078,6 +2079,7 @@ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None RandomBarabasiAlbert = staticmethod(sage.graphs.generators.random.RandomBarabasiAlbert) RandomBipartite = staticmethod(sage.graphs.generators.random.RandomBipartite) RandomBicubicPlanar = staticmethod(sage.graphs.generators.random.RandomBicubicPlanar) + RandomBlockGraph = staticmethod(sage.graphs.generators.random.RandomBlockGraph) RandomBoundedToleranceGraph = staticmethod(sage.graphs.generators.random.RandomBoundedToleranceGraph) RandomGNM = staticmethod(sage.graphs.generators.random.RandomGNM) RandomGNP = staticmethod(sage.graphs.generators.random.RandomGNP) From 921e395206999036a864df1250c7b355fe7c6d72 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 30 Apr 2017 13:09:35 +0200 Subject: [PATCH 026/126] trac #22908: test if a graph is a block graphs --- src/sage/graphs/generators/random.py | 12 ++++++---- src/sage/graphs/graph.py | 36 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 165f8966a94..b20d36d94c1 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -249,7 +249,13 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): Return a Random Block Graph A block graph is a connected graph in which every biconnected component - (block) is a clique. See :wikipedia:`Block_graph` for more details. + (block) is a clique. + + .. SEEALSO:: + + - :wikipedia:`Block_graph` for more details on these graphs + - :meth:`~sage.graphs.graph.Graph.is_block_graph` -- test if a graph is a block graph + - :meth:`~sage.combinat.designs.incidence.IncidenceStructure` INPUT: @@ -271,10 +277,6 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): A Graph when ``incidence_structure==False`` (default), and otherwise an incidence structure. - .. SEEALSO:: - - - :meth:`~sage.combinat.designs.incidence.IncidenceStructure` - EXAMPLES: A block graph with only 1 block is a clique:: diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 0459a769833..9a5b1606dcc 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1819,6 +1819,42 @@ def is_biconnected(self): return False return True + @doc_index("Graph properties") + def is_block_graph(self): + r""" + Tests if the graph is a block graph + + A block graph is a connected graph in which every biconnected component + (block) is a clique. + + .. SEEALSO:: + + - :wikipedia:`Block_graph` for more details on these graphs + - :meth:`~sage.graphs.graph_generators.GraphGenerators.RandomBlockGraph` + -- generator of random block graphs + + EXAMPLES:: + + sage: G = graphs.RandomBlockGraph(6, 2, kmax=4) + sage: G.is_block_graph() + True + sage: graphs.CompleteGraph(4).is_block_graph() + True + sage: graphs.RandomTree(6).is_block_graph() + True + sage: graphs.PetersenGraph().is_block_graph() + False + sage: Graph(4).is_block_graph() + False + """ + if not self.is_connected(): + return False + if self.is_clique(): + return True + + B,C = self.blocks_and_cut_vertices() + return all(self.is_clique(vertices=block) for block in B) + @doc_index("Graph properties") def is_apex(self): """ From f6f2b39eaa26f78abe15d865c746ae2b696cc01b Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 30 Apr 2017 13:22:10 +0200 Subject: [PATCH 027/126] trac #22908: add methods to graph_classes --- src/sage/graphs/generators/random.py | 1 + src/sage/graphs/graph.py | 2 ++ src/sage/graphs/isgci.py | 6 ++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index b20d36d94c1..13e76e0c765 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -255,6 +255,7 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): - :wikipedia:`Block_graph` for more details on these graphs - :meth:`~sage.graphs.graph.Graph.is_block_graph` -- test if a graph is a block graph + - :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices` - :meth:`~sage.combinat.designs.incidence.IncidenceStructure` INPUT: diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 9a5b1606dcc..da630633b14 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1832,6 +1832,8 @@ def is_block_graph(self): - :wikipedia:`Block_graph` for more details on these graphs - :meth:`~sage.graphs.graph_generators.GraphGenerators.RandomBlockGraph` -- generator of random block graphs + - :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices` + EXAMPLES:: diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index 346f1d26464..80e66440603 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -161,7 +161,9 @@ * - Block - - :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices` + - :meth:`~sage.graphs.graph.Graph.is_block_graph`, + :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices`, + :meth:`~sage.graphs.graph_generators.GraphGenerators.RandomBlockGraph` * - Chordal @@ -1043,7 +1045,7 @@ def _XML_to_dict(root): graph_classes.Biconnected = GraphClass("Biconnected", "gc_771", recognition_function = lambda x:x.is_biconnected()) graph_classes.BinaryTrees = GraphClass("BinaryTrees", "gc_847") graph_classes.Bipartite = GraphClass("Bipartite", "gc_69", recognition_function = lambda x:x.is_bipartite()) -graph_classes.Block = GraphClass("Block", "gc_93") +graph_classes.Block = GraphClass("Block", "gc_93", recognition_function = lambda x:x.is_block_graph()) graph_classes.Chordal = GraphClass("Chordal", "gc_32", recognition_function = lambda x:x.is_chordal()) graph_classes.ClawFree = GraphClass("Claw-free", "gc_62") graph_classes.Comparability = GraphClass("Comparability", "gc_72", recognition_function = lambda x: __import__('sage').graphs.comparability.is_comparability) From 1f6453736b812d5976041e48e25ac1c618322346 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 30 Apr 2017 13:29:22 +0200 Subject: [PATCH 028/126] trac #22908: fix doc in isgci --- src/sage/graphs/isgci.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/sage/graphs/isgci.py b/src/sage/graphs/isgci.py index 80e66440603..bfdc53b34c7 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -149,6 +149,21 @@ * - Class - Related methods + * - Apex + + - :meth:`~Graph.is_apex()`, + :meth:`~Graph.apex_vertices()` + + * - AT_free + + - :meth:`~Graph.is_asteroidal_triple_free` + + * - Biconnected + + - :meth:`~Graph.is_biconnected`, + :meth:`~GenericGraph.blocks_and_cut_vertices`, + :meth:`~GenericGraph.blocks_and_cuts_tree` + * - BinaryTrees - :meth:`~sage.graphs.graph_generators.GraphGenerators.BalancedTree`, From 753c6906f1156956a94f78a26a258ef3f7473fc9 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 30 Apr 2017 13:40:40 +0200 Subject: [PATCH 029/126] trac #22908: add example using graph_classes --- src/sage/graphs/graph.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index da630633b14..f3e65a1edf2 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1840,6 +1840,9 @@ def is_block_graph(self): sage: G = graphs.RandomBlockGraph(6, 2, kmax=4) sage: G.is_block_graph() True + sage: from sage.graphs.isgci import graph_classes + sage: G in graph_classes.Block + True sage: graphs.CompleteGraph(4).is_block_graph() True sage: graphs.RandomTree(6).is_block_graph() From 452b64d6e5fc96e6ec615ac445f0985d7faabf85 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sun, 30 Apr 2017 22:05:41 +0200 Subject: [PATCH 030/126] trac #22908: implement reviewers comments --- src/sage/graphs/generators/random.py | 3 ++- src/sage/graphs/graph.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 13e76e0c765..25b86f9ecd7 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -246,7 +246,7 @@ def RandomBipartite(n1, n2, p): def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): r""" - Return a Random Block Graph + Return a Random Block Graph. A block graph is a connected graph in which every biconnected component (block) is a clique. @@ -256,6 +256,7 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): - :wikipedia:`Block_graph` for more details on these graphs - :meth:`~sage.graphs.graph.Graph.is_block_graph` -- test if a graph is a block graph - :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices` + - :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cuts_tree` - :meth:`~sage.combinat.designs.incidence.IncidenceStructure` INPUT: diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index f3e65a1edf2..b628af23540 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1822,7 +1822,7 @@ def is_biconnected(self): @doc_index("Graph properties") def is_block_graph(self): r""" - Tests if the graph is a block graph + Test if the graph is a block graph. A block graph is a connected graph in which every biconnected component (block) is a clique. @@ -1833,6 +1833,7 @@ def is_block_graph(self): - :meth:`~sage.graphs.graph_generators.GraphGenerators.RandomBlockGraph` -- generator of random block graphs - :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices` + - :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cuts_tree` EXAMPLES:: From 2e45504a577c8d72177cb526617b68358b9038c9 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Fri, 5 May 2017 16:45:22 +0200 Subject: [PATCH 031/126] raise an error very early in sage.env if SINGULAR_SO cannot be located --- src/sage/env.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 038ede03fd5..9582ba4fe1c 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -143,8 +143,8 @@ def _add_variable_or_fallback(key, fallback, force=False): # locate singular shared object if UNAME[:6] == "CYGWIN": - SINGULAR_SO = glob.glob(os.path.join( - SAGE_LOCAL, "bin", "cygSingular-*.dll"))[-1] + SINGULAR_SO = ([None] + glob.glob(os.path.join( + SAGE_LOCAL, "bin", "cygSingular-*.dll")))[-1] else: if UNAME == "Darwin": extension = "dylib" @@ -152,7 +152,13 @@ def _add_variable_or_fallback(key, fallback, force=False): extension = "so" # library name changed from libsingular to libSingular btw 3.x and 4.x SINGULAR_SO = SAGE_LOCAL+"/lib/libSingular."+extension -_add_variable_or_fallback('SINGULAR_SO', SINGULAR_SO) + +if not SINGULAR_SO or not os.path.exists(SINGULAR_SO): + raise RuntimeError( + "libSingular not found--a working Singular install in $SAGE_LOCAL " + "is required for Sage to work") +else: + _add_variable_or_fallback('SINGULAR_SO', SINGULAR_SO) # post process if ' ' in DOT_SAGE: From cb3dadf42350807cc7da3d9e6365ce5cfed78c39 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Fri, 5 May 2017 16:49:15 +0200 Subject: [PATCH 032/126] Still allow SINGULAR_SO to be read from the environment in case it's specified there --- src/sage/env.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/env.py b/src/sage/env.py index 9582ba4fe1c..aa43b16ca50 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -153,12 +153,12 @@ def _add_variable_or_fallback(key, fallback, force=False): # library name changed from libsingular to libSingular btw 3.x and 4.x SINGULAR_SO = SAGE_LOCAL+"/lib/libSingular."+extension +_add_variable_or_fallback('SINGULAR_SO', SINGULAR_SO) + if not SINGULAR_SO or not os.path.exists(SINGULAR_SO): raise RuntimeError( "libSingular not found--a working Singular install in $SAGE_LOCAL " "is required for Sage to work") -else: - _add_variable_or_fallback('SINGULAR_SO', SINGULAR_SO) # post process if ' ' in DOT_SAGE: From b19465feb1a1488934da6ee6da880534bba487c1 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Sat, 6 May 2017 10:36:50 +0200 Subject: [PATCH 033/126] trac #22908: fix seealso section and add recognition example --- src/sage/graphs/generators/random.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 25b86f9ecd7..a4f9faebf1d 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -257,7 +257,7 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): - :meth:`~sage.graphs.graph.Graph.is_block_graph` -- test if a graph is a block graph - :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices` - :meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cuts_tree` - - :meth:`~sage.combinat.designs.incidence.IncidenceStructure` + - :meth:`~sage.combinat.designs.incidence_structures.IncidenceStructure` INPUT: @@ -307,6 +307,14 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): sage: B.order() == m*(k-1)+1 True + Test recognition methods:: + + sage: B = graphs.RandomBlockGraph(6, 2, kmax=6) + sage: B.is_block_graph() + True + sage: B in graph_classes.Block + True + Asking for the incidence structure:: sage: m, k = 6, 4 From f530cafc0064680821e7ca7b657d6398130b05ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Honrubia=20Gonz=C3=A1lez?= Date: Sat, 6 May 2017 18:02:36 +0200 Subject: [PATCH 034/126] Reverted some changes and somw rewriting done --- src/sage/plot/plot3d/introduction.py | 10 ++++++---- src/sage/plot/plot3d/plot3d.py | 16 ++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/sage/plot/plot3d/introduction.py b/src/sage/plot/plot3d/introduction.py index 65c31845406..1222aec1684 100644 --- a/src/sage/plot/plot3d/introduction.py +++ b/src/sage/plot/plot3d/introduction.py @@ -89,10 +89,12 @@ - :func:`~sage.plot.plot3d.platonic.icosahedron` -Different viewers are supported other jmol, like a web-based interactive viewer -using the Three.js JavaScript library and accesible through the ``show(viewer='threejs')`` -method of any 3d graphic. A raytraced representation is accesible by typing -``show(viewer='tachyon')``: +Different viewers are supported: jmol, a web-based interactive viewer +using the Three.js JavaScript library and a raytraced representation. +The viewer is invoked by adding the keyword argument +``viewer='jmol'`` (respectively ``'tachyon'`` or ``'threejs'``) +to the command ``show()`` on any three-dimensional graphic + - :class:`~sage.plot.plot3d.tachyon.Tachyon` - create a scene the can be rendered using the Tachyon ray tracer diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index e818b85799d..8d51cd9d60f 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -19,13 +19,13 @@ :: sage: def f(x,y): - ....: return math.sin(y^2+x^2)/math.sqrt(x^2+y^2.0001) + ....: return math.sin(y^2+x^2)/math.sqrt(x^2+y^2+0.0001) sage: P = plot3d(f,(-3,3),(-3,3), adaptive=True, color=rainbow(60, 'rgbtuple'), max_bend=.1, max_depth=15) sage: P.show() .. PLOT:: - def f(x,y): return math.sin(y*y+x*x)/math.sqrt(x*x+y*y+.0001) + def f(x,y): return math.sin(y*y+x*x)/math.sqrt(x*x+y*y+0.0001) P = plot3d(f,(-3,3),(-3,3), adaptive=True, color=rainbow(60, 'rgbtuple'), max_bend=.1, max_depth=15) sphinx_plot(P) @@ -275,10 +275,10 @@ def to_cartesian(self, func, params=None): sage: v_phi=array([ 0., 1.57079637, 3.14159274, 4.71238911, 6.28318548]) sage: v_theta=array([ 0., 0.78539819, 1.57079637, 2.35619456, 3.14159274]) sage: m_r=array([[ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422], - ... [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422], - ... [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422], - ... [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422], - ... [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422]]) + ....: [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422], + ....: [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422], + ....: [ 0.16763356, 0.19993708, 0.31403568, 0.47359696, 0.55282422], + ....: [ 0.16763356, 0.25683223, 0.16649297, 0.10594339, 0.55282422]]) sage: import scipy.interpolate sage: f=scipy.interpolate.RectBivariateSpline(v_phi,v_theta,m_r) sage: spherical_plot3d(f,(0,2*pi),(0,pi)) @@ -982,7 +982,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): sage: D = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=cylindric_axial,plot_points=[100,100]) sage: E = plot3d(2,(u,-pi,pi),(v,-pi,pi),transformation=parabolic_cylindrical,plot_points=[100,100]) sage: @interact - ... def _(which_plot=[A,B,C,D,E]): + ....: def _(which_plot=[A,B,C,D,E]): ....: show(which_plot) ... @@ -995,7 +995,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): sage: I = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=cylindric_axial,plot_points=[100,100]) sage: J = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=parabolic_cylindrical,plot_points=[100,100]) sage: @interact - ... def _(which_plot=[F, G, H, I, J]): + ....: def _(which_plot=[F, G, H, I, J]): ....: show(which_plot) ... From 6a74951a2ffdd1b83cd0faffcbf89ae59d2fbf98 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Sat, 13 May 2017 01:35:43 +0200 Subject: [PATCH 035/126] Building issues fixed --- src/sage/rings/padics/padic_floating_point_element.pxd | 2 +- src/sage/rings/padics/qadic_flint_FP.pxd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/padics/padic_floating_point_element.pxd b/src/sage/rings/padics/padic_floating_point_element.pxd index 6e59e55b8c1..721c471d253 100644 --- a/src/sage/rings/padics/padic_floating_point_element.pxd +++ b/src/sage/rings/padics/padic_floating_point_element.pxd @@ -1,5 +1,5 @@ from sage.libs.gmp.types cimport mpz_t -from sage.libs.cypari2.gen cimport Gen as pari_gen +from cypari2.gen cimport Gen as pari_gen ctypedef mpz_t celement include "FP_template_header.pxi" diff --git a/src/sage/rings/padics/qadic_flint_FP.pxd b/src/sage/rings/padics/qadic_flint_FP.pxd index c0d0f58b991..1a25be2fc08 100644 --- a/src/sage/rings/padics/qadic_flint_FP.pxd +++ b/src/sage/rings/padics/qadic_flint_FP.pxd @@ -1,4 +1,4 @@ -from sage.libs.cypari2.gen cimport Gen as pari_gen +from cypari2.gen cimport Gen as pari_gen from sage.libs.flint.fmpz_poly cimport fmpz_poly_t from sage.rings.padics.pow_computer_flint cimport PowComputer_flint_unram cdef class PowComputer_(PowComputer_flint_unram): From 6e5e3e2af7f55105b5b85b5940dcbe916c3a35d9 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Wed, 17 May 2017 08:20:40 +0200 Subject: [PATCH 036/126] incomplete gamma conversions --- src/sage/functions/other.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 25c49bead45..3eeafab084c 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -1081,7 +1081,7 @@ def __init__(self): """ BuiltinFunction.__init__(self, "gamma", nargs=2, latex_name=r"\Gamma", conversions={'maxima':'gamma_incomplete', 'mathematica':'Gamma', - 'maple':'GAMMA', 'sympy':'uppergamma'}) + 'maple':'GAMMA', 'sympy':'uppergamma', 'giac':'ugamma'}) def _eval_(self, x, y): """ @@ -1230,7 +1230,7 @@ def __init__(self): """ BuiltinFunction.__init__(self, "gamma_inc_lower", nargs=2, latex_name=r"\gamma", conversions={'maxima':'gamma_greek', 'mathematica':'Gamma', - 'maple':'GAMMA', 'sympy':'lowergamma'}) + 'maple':'GAMMA', 'sympy':'lowergamma', 'giac':'igamma'}) def _eval_(self, x, y): """ From 1dbe4e6c2dfdc444c38a0df19b981b5ab619b8a6 Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 19 May 2017 15:44:29 -0400 Subject: [PATCH 037/126] Adapt to new __pari__ function --- src/sage/rings/padics/padic_floating_point_element.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/padics/padic_floating_point_element.pyx b/src/sage/rings/padics/padic_floating_point_element.pyx index 8466f35637e..7de6486c476 100644 --- a/src/sage/rings/padics/padic_floating_point_element.pyx +++ b/src/sage/rings/padics/padic_floating_point_element.pyx @@ -185,7 +185,7 @@ cdef class pAdicFloatingPointElement(FPElement): mpz_set(mpq_denref(ansr.value), self.prime_pow.pow_mpz_t_tmp(-self.ordp)) return ansr - def _pari_(self): + def __pari__(self): """ Converts this element to an equivalent pari element. From 999cdc0ecca7e4c088f12d9dfee238da57be23b7 Mon Sep 17 00:00:00 2001 From: Lokesh Jain Date: Sat, 20 May 2017 14:36:43 +0530 Subject: [PATCH 038/126] trac #7675: shortest path length functions optimized --- src/sage/graphs/base/c_graph.pyx | 73 +++++++++++++++------ src/sage/graphs/generic_graph.py | 105 +++++++++++++++++++++++++------ 2 files changed, 142 insertions(+), 36 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index e9a15c43e3b..c78e5f525ae 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -2075,9 +2075,9 @@ cdef class CGraphBackend(GenericGraphBackend): self.vertex_ints = new_vx_ints self.vertex_labels = new_vx_labels - def shortest_path(self, x, y): + def shortest_path(self, x, y, distance_flag=False): r""" - Returns the shortest path between ``x`` and ``y``. + Returns the shortest path or distance from ``x`` to ``y``. INPUT: @@ -2086,15 +2086,22 @@ cdef class CGraphBackend(GenericGraphBackend): - ``y`` -- the end vertex in the shortest path from ``x`` to ``y``. + - ``distance_flag`` -- flag to indicate whether shortest path or distance + from ``x`` to ``y`` is returned. If true, distance is returned. + OUTPUT: - - A list of vertices in the shortest path from ``x`` to ``y``. + - A list of vertices in the shortest path from ``x`` to ``y`` or + integer specifying the distance from ``x`` to ``y``. EXAMPLES:: sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph") sage: G.shortest_path(0, 1) [0, 1] + sage: G.shortest_path_length(0, 1) + 1 + """ if x == y: return 0 @@ -2166,13 +2173,16 @@ cdef class CGraphBackend(GenericGraphBackend): # to the list. if v not in dist_current: dist_current[v] = dist_current[u] + 1 - pred_current[v] = u + if not distance_flag: + pred_current[v] = u next_current.append(v) # If the new neighbor is already known by the other # side ... if v in dist_other: # build the shortest path and returns in. + if distance_flag: + return dist_other[v] + dist_current[v] w = v while w != x_int: @@ -2199,11 +2209,14 @@ cdef class CGraphBackend(GenericGraphBackend): next_current, next_other = next_other, next_current out = -out + if distance_flag: + from sage.rings.infinity import Infinity + return Infinity return [] - def bidirectional_dijkstra(self, x, y, weight_function=None): + def bidirectional_dijkstra(self, x, y, weight_function=None, distance_flag = False): r""" - Returns the shortest path between ``x`` and ``y`` using a + Returns the shortest path or distance from ``x`` to ``y`` using a bidirectional version of Dijkstra's algorithm. INPUT: @@ -2217,9 +2230,13 @@ cdef class CGraphBackend(GenericGraphBackend): ``(u, v, l)`` and outputs its weight. If ``None``, we use the edge label ``l`` as a weight. + - ``distance_flag`` -- flag to indicate whether shortest path or distance + from ``x`` to ``y`` is returned. If true, distance is returned. + OUTPUT: - - A list of vertices in the shortest path from ``x`` to ``y``. + - A list of vertices in the shortest path from ``x`` to ``y`` or + integer specifying the distance from ``x`` to ``y``. EXAMPLES:: @@ -2228,9 +2245,13 @@ cdef class CGraphBackend(GenericGraphBackend): ....: G.set_edge_label(u,v,1) sage: G.shortest_path(0, 1, by_weight=True) [0, 1] + sage: G.shortest_path_length(0, 1, by_weight=True) + 1.0 sage: G = DiGraph([(1,2,{'weight':1}), (1,3,{'weight':5}), (2,3,{'weight':1})]) sage: G.shortest_path(1, 3, weight_function=lambda e:e[2]['weight']) [1, 2, 3] + sage: G.shortest_path_length(1, 3, weight_function=lambda e:e[2]['weight']) + 2.0 TEST: @@ -2238,7 +2259,7 @@ cdef class CGraphBackend(GenericGraphBackend): sage: G = Graph([(0,1,9),(0,2,8),(1,2,7)]) sage: G.shortest_path_length(0,1,by_weight=True) - 9 + 9.0 """ if x == y: return 0 @@ -2308,7 +2329,8 @@ cdef class CGraphBackend(GenericGraphBackend): pred_current, pred_other = pred_y, pred_x if v not in dist_current: - pred_current[v] = pred + if not distance_flag: + pred_current[v] = pred dist_current[v] = distance if v in dist_other: @@ -2336,9 +2358,14 @@ cdef class CGraphBackend(GenericGraphBackend): # No meeting point has been found if meeting_vertex == -1: + if distance_flag: + from sage.rings.infinity import Infinity + return Infinity return [] else: # build the shortest path and returns it. + if distance_flag: + return shortest_path_length w = meeting_vertex while w != x_int: @@ -2359,9 +2386,10 @@ cdef class CGraphBackend(GenericGraphBackend): return shortest_path - def shortest_path_all_vertices(self, v, cutoff=None): + def shortest_path_all_vertices(self, v, cutoff=None, distance_flag = False): r""" - Returns for each vertex ``u`` a shortest ``v-u`` path. + Returns for each vertex ``u`` a shortest ``v-u`` path or distance from + ``v`` to ``u``. INPUT: @@ -2369,10 +2397,13 @@ cdef class CGraphBackend(GenericGraphBackend): - ``cutoff`` -- maximal distance. Longer paths will not be returned. + - ``distance_flag`` -- flag to indicate whether shortest path or distance + is returned for each vertex u. If true, distance is returned. + OUTPUT: - - A list which associates to each vertex ``u`` the shortest path - between ``u`` and ``v`` if there is one. + - A dictionary which associates to each vertex ``u`` the shortest path list + or distance from ``v`` to ``u`` if they are connected to each other. .. NOTE:: @@ -2390,6 +2421,8 @@ cdef class CGraphBackend(GenericGraphBackend): sage: paths = g._backend.shortest_path_all_vertices(0) sage: all([ len(paths[v]) == 0 or len(paths[v])-1 == g.distance(0,v) for v in g]) True + sage: g._backend.shortest_path_all_vertices(0, distance_flag=True) + {0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2} On a disconnected graph :: @@ -2410,8 +2443,8 @@ cdef class CGraphBackend(GenericGraphBackend): cdef bitset_t seen cdef int v_int cdef int u_int - cdef dict distances_int - cdef dict distance + cdef dict distances_int = {} + cdef dict distances cdef int d distances = {} @@ -2429,22 +2462,26 @@ cdef class CGraphBackend(GenericGraphBackend): for u_int in self._cg.out_neighbors(v_int)] next_layer = [] distances[v] = [v] + distances_int[v] = 0 while current_layer: if cutoff is not None and d >= cutoff: break + d += 1 while current_layer: v_int, u_int = current_layer.pop() if bitset_not_in(seen, v_int): bitset_add(seen, v_int) - distances[self.vertex_label(v_int)] = distances[self.vertex_label(u_int)] + [self.vertex_label(v_int)] + if distance_flag: + distances_int[self.vertex_label(v_int)] = d + else: + distances[self.vertex_label(v_int)] = distances[self.vertex_label(u_int)] + [self.vertex_label(v_int)] next_layer.extend([(u_int, v_int) for u_int in self._cg.out_neighbors(v_int)]) current_layer = next_layer next_layer = [] - d += 1 # If the graph is not connected, vertices which have not been # seen should be associated to the empty path @@ -2454,7 +2491,7 @@ cdef class CGraphBackend(GenericGraphBackend): # distances[vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)] = [] bitset_free(seen) - return distances + return distances_int if distance_flag else distances def depth_first_search(self, v, reverse=False, ignore_direction=False): r""" diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index dc5f8556d10..99b77246a3a 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -13410,7 +13410,7 @@ def distance(self, u, v, by_weight=False): sage: G.distance(0, 3) 2 sage: G.distance(0, 3, by_weight=True) - 3 + 3.0 """ return self.shortest_path_length(u, v, by_weight = by_weight) @@ -15202,7 +15202,7 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_Bid_NetworkX') 5 sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_Bid') - 5 + 5.0 sage: D.shortest_path_length(4, 9, algorithm='Bellman-Ford_Boost') 5 sage: D.shortest_path_length(5, 5) @@ -15215,7 +15215,7 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, sage: G.shortest_path_length(0, 3) 2 sage: G.shortest_path_length(0, 3, by_weight=True) - 3 + 3.0 sage: G.shortest_path_length(0, 3, by_weight=True, algorithm='Dijkstra_NetworkX') 3 sage: G.shortest_path_length(0, 3, by_weight=True, algorithm='Dijkstra_Bid_NetworkX') @@ -15237,18 +15237,53 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, sage: G.shortest_path_length(0, 2, by_weight=True, algorithm='Bellman-Ford_Boost') -1000 sage: G.shortest_path_length(0, 2, by_weight=True) - 2 + 2.0 """ if weight_sum is not None: deprecation(18938, "Now weight_sum is replaced by by_weight.") - path = self.shortest_path(u, v, by_weight=by_weight, - weight_function=weight_function, - algorithm=algorithm, - check_weight=check_weight, - bidirectional=bidirectional) - return self._path_length(path, by_weight, weight_function) + if u == v: # to avoid a NetworkX bug + return 0 + + if weight_function is not None: + by_weight = True + + if algorithm is None: + algorithm = 'Dijkstra_Bid' if by_weight else 'BFS_Bid' + + if weight_function is None and by_weight: + weight_function = lambda e:e[2] + + if algorithm in ['BFS', 'Dijkstra_NetworkX', 'Bellman-Ford_Boost']: + return self.shortest_path_lengths(u, by_weight, algorithm, weight_function, check_weight)[v] + + if bidirectional is not None: + deprecation(18938, "Variable 'bidirectional' is deprecated and " + + "replaced by 'algorithm'.") + + if by_weight: + if algorithm == 'BFS_Bid': + raise ValueError("The 'BFS_Bid' algorithm does not " + + "work on weighted graphs.") + if check_weight: + self._check_weight_function(weight_function) + else: + weight_function = lambda e:1 + if algorithm=="Dijkstra_Bid": + return self._backend.bidirectional_dijkstra(u, v, weight_function, distance_flag=True) + elif algorithm=="Dijkstra_Bid_NetworkX": + import networkx + if self.is_directed(): + G = networkx.DiGraph([(e[0], e[1], dict(weight=weight_function(e))) for e in self.edge_iterator()]) + else: + G = networkx.Graph([(e[0], e[1], dict(weight=weight_function(e))) for e in self.edge_iterator()]) + G.add_nodes_from(self.vertices()) + return networkx.bidirectional_dijkstra(G, u, v)[0] + elif algorithm=="BFS_Bid": + return self._backend.shortest_path(u, v, distance_flag=True) + else: + raise ValueError("Algorithm '" + algorithm + "' not yet implemented.") def _check_weight_function(self, weight_function=None): r""" @@ -15664,18 +15699,52 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, if weight_sums is not None: deprecation(18938, "Now weight_sums is replaced by by_weight.") - if algorithm in ['Dijkstra_Boost', 'Bellman-Ford_Boost'] or (algorithm is None and weight_function is None and by_weight): - if weight_function is None and not by_weight: - weight_function = lambda e:1 + if weight_function is not None: + by_weight = True + elif by_weight: + weight_function = lambda e:e[2] + else: + weight_function = lambda e:1 + + if algorithm is None and not by_weight: + algorithm = 'BFS' + + if by_weight and check_weight: + self._check_weight_function(weight_function) + + if algorithm=='BFS': + if by_weight: + raise ValueError("The 'BFS' algorithm does not work on " + + "weighted graphs.") + return self._backend.shortest_path_all_vertices(u, cutoff=None, distance_flag=True) + + elif algorithm=='Dijkstra_NetworkX': + import networkx + # If this is not present, an error might be raised by NetworkX + if self.num_verts()==1 and self.vertices()[0]==u: + return {u:[u]} + if by_weight: + if self.is_directed(): + G = networkx.DiGraph([(e[0], e[1], dict(weight=weight_function(e))) for e in self.edge_iterator()]) + else: + G = networkx.Graph([(e[0], e[1], dict(weight=weight_function(e))) for e in self.edge_iterator()]) + else: + # Needed to remove labels. + if self.is_directed(): + G = networkx.DiGraph(self.edges(labels=False)) + else: + G = networkx.Graph(self.edges(labels=False)) + G.add_nodes_from(self.vertices()) + return networkx.single_source_dijkstra_path_length(G, u) + + elif algorithm in ['Dijkstra_Boost', 'Bellman-Ford_Boost', None]: self.weighted(True) from sage.graphs.base.boost_graph import shortest_paths return shortest_paths(self, u, weight_function, algorithm)[0] - paths = self.shortest_paths(u, by_weight=by_weight, algorithm=algorithm, - weight_function=weight_function) - return {v:self._path_length(p, by_weight, weight_function) - for v,p in iteritems(paths)} - + else: + raise ValueError("Algorithm " + algorithm + " not yet " + + "implemented. Please, contribute!") def shortest_path_all_pairs(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True, From 662afab9e261bb077fb84446b29fe4cffc0cf13e Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Sun, 21 May 2017 17:05:28 +0200 Subject: [PATCH 039/126] Implementation of fast logarithm for capped relative padics --- .../padics/padic_capped_relative_element.pyx | 164 ++++++++++++++++++ src/sage/rings/padics/transcendantal.c | 139 +++++++++++++++ 2 files changed, 303 insertions(+) create mode 100644 src/sage/rings/padics/transcendantal.c diff --git a/src/sage/rings/padics/padic_capped_relative_element.pyx b/src/sage/rings/padics/padic_capped_relative_element.pyx index 60e8c5d0391..c8bd3159d63 100644 --- a/src/sage/rings/padics/padic_capped_relative_element.pyx +++ b/src/sage/rings/padics/padic_capped_relative_element.pyx @@ -29,6 +29,9 @@ from sage.libs.pari.convert_gmp cimport new_gen_from_padic from sage.rings.finite_rings.integer_mod import Mod from sage.rings.padics.pow_computer cimport PowComputer_class +cdef extern from "sage/rings/padics/transcendantal.c": + cdef void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, const mpz_t modulo) + cdef class PowComputer_(PowComputer_base): """ A PowComputer for a capped-relative padic ring or field. @@ -332,6 +335,167 @@ cdef class pAdicCappedRelativeElement(CRElement): mpz_mul(selfvalue.value, self.prime_pow.pow_mpz_t_tmp(self.ordp), self.unit) return Mod(selfvalue, modulus) + def log(self, p_branch=None, aprec=None, change_frac=False): + r""" + Compute the `p`-adic logarithm of this element. + + The usual power series for the logarithm with values in the additive + group of a `p`-adic ring only converges for 1-units (units congruent to + 1 modulo `p`). However, there is a unique extension of the logarithm + to a homomorphism defined on all the units: If `u = a \cdot v` is a + unit with `v \equiv 1 \pmod{p}` and `a` a Teichmuller representative, + then we define `log(u) = log(v)`. This is the correct extension + because the units `U` split as a product `U = V \times \langle w + \rangle`, where `V` is the subgroup of 1-units and `w` is a fundamental + root of unity. The `\langle w \rangle` factor is torsion, so must go + to 0 under any homomorphism to the fraction field, which is a torsion + free group. + + INPUT: + + - ``p_branch`` -- an element in the base ring or its fraction + field; the implementation will choose the branch of the + logarithm which sends `p` to ``branch``. + + - ``aprec`` -- an integer or ``None`` (default: ``None``) if not + ``None``, then the result will only be correct to precision + ``aprec``. + + - ``change_frac`` -- In general the codomain of the logarithm should be + in the `p`-adic field, however, for most neighborhoods of 1, it lies + in the ring of integers. This flag decides if the codomain should be + the same as the input (default) or if it should change to the + fraction field of the input. + + NOTES: + + What some other systems do: + + - PARI: Seems to define the logarithm for units not congruent + to 1 as we do. + + - MAGMA: Only implements logarithm for 1-units (as of version 2.19-2) + + ALGORITHM: + + 1. Take the unit part `u` of the input. + + 2. Raise `u` to `p-1` to obtain a 1-unit. + + 3. Write + + .. MATH:: + + u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{2^i}) + + with `0 \leq a_i < p^{2^i}` and compute `\log(1 - a_i p^{2^i})` + using the standard Taylor expansion + + .. MATH:: + + \log(1 - x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots + + together with a binary spliting method. + + 4. Divide the result by ``q-1`` and multiply by ``self.valuation()*log(p)`` + + The complexity of this algorithm is quasi-linear. + + EXAMPLES:: + + sage: Z13 = Zp(13, 10) + sage: a = Z13(14); a + 1 + 13 + O(13^10) + + Note that the relative precision decreases when we take log -- it is + the absolute precision that is preserved:: + + sage: a.log() + 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) + sage: Q13 = Qp(13, 10) + sage: a = Q13(14); a + 1 + 13 + O(13^10) + sage: a.log() + 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) + + The next few examples illustrate precision when computing `p`-adic + logarithms:: + + sage: R = Zp(5,10) + sage: e = R(389); e + 4 + 2*5 + 3*5^3 + O(5^10) + sage: e.log() + 2*5 + 2*5^2 + 4*5^3 + 3*5^4 + 5^5 + 3*5^7 + 2*5^8 + 4*5^9 + O(5^10) + sage: K = Qp(5,10) + sage: e = K(389); e + 4 + 2*5 + 3*5^3 + O(5^10) + sage: e.log() + 2*5 + 2*5^2 + 4*5^3 + 3*5^4 + 5^5 + 3*5^7 + 2*5^8 + 4*5^9 + O(5^10) + + The logarithm is not only defined for 1-units:: + + sage: R = Zp(5,10) + sage: a = R(2) + sage: a.log() + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + + If you want to take the logarithm of a non-unit you must specify either + ``p_branch`` or ``pi_branch``:: + + sage: b = R(5) + sage: b.log() + Traceback (most recent call last): + ... + ValueError: You must specify a branch of the logarithm for non-units + sage: b.log(p_branch=4) + 4 + O(5^10) + sage: c = R(10) + sage: c.log(p_branch=4) + 4 + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + + The branch parameters are only relevant for elements of non-zero + valuation:: + + sage: a.log(p_branch=0) + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + sage: a.log(p_branch=1) + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + + TESTS:: + + sage: Z17 = Zp(17, 2^20) + sage: a = Z17(18) + sage: b = a.log() # should be rather fast + """ + cdef unsigned long p = self.prime_pow.prime + cdef unsigned long prec + cdef pAdicCappedRelativeElement ans + + if self.is_zero(): + raise ValueError('logarithm is not defined at zero') + if aprec is None: + prec = self.relprec + else: + prec = min(aprec, self.relprec) + + ans = self._new_c() + ans.ordp = 0 + ans.relprec = prec + sig_on() + padiclog(ans.unit, self.unit, p, prec, self.prime_pow.pow_mpz_t_tmp(prec)) + sig_off() + ans._normalize() + + if self.valuation() != 0: + if p_branch is None: + raise ValueError("You must specify a branch of the logarithm for non-units") + ans += self.valuation() * p_branch + + if change_frac: + ans = self.parent().fraction_field()(ans) + + return ans + def unpickle_pcre_v1(R, unit, ordp, relprec): """ Unpickles a capped relative element. diff --git a/src/sage/rings/padics/transcendantal.c b/src/sage/rings/padics/transcendantal.c new file mode 100644 index 00000000000..39c1dc3beb6 --- /dev/null +++ b/src/sage/rings/padics/transcendantal.c @@ -0,0 +1,139 @@ +/* + * C helper functions for the computation + * of p-adic transcendantal functions + * + *********************************************/ + +#include +#include +#include +#include + +#include +#include + +/* p-adic logarithm */ +void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, const mpz_t modulo) { + /* Compute the p-adic logarithm of a, + which is supposed to be a unit + + Algorithm: If a = 1 (mod p), write a as a product + a = (1 - a_0*p) (1 - a_1*p^2) (1 - a_2*p^4) (1 - a_3*p^8) ... + with 0 <= a_i < p^(2^i). + Then compute each log(1 - a_i*p^(2^i)) using Taylor expansion + and a binary spliting strategy. + For general a, compute log(a^(p-1)) and then divide by p-1 */ + + char congruent_to_one; + unsigned long i, N, saveN, Np, tmp, trunc, step; + mpz_t f, arg, trunc_mod, h, hpow, mpz_tmp, d, inv; + mpz_t *num, *denom; + + mpz_init(mpz_tmp); + mpz_init(arg); + mpz_set_ui(ans, 0); + + mpz_fdiv_r_ui(mpz_tmp, a, p); + congruent_to_one = (mpz_cmp_ui(mpz_tmp, 1) == 0); + if (congruent_to_one) { + mpz_set(arg, a); + } else { + mpz_powm_ui(arg, a, p-1, modulo); + } + + /* Where do we need to truncate the Taylor expansion */ + N = prec; + while(1) { + tmp = prec + (unsigned long)(log(N)/log(p)); + if (tmp == N) break; + N = tmp; + } + saveN = N; + + /* We allocate memory and initialize variables */ + mpz_init(f); + mpz_init(h); mpz_init(hpow); + mpz_init(d); mpz_init(inv); + num = (mpz_t*)malloc(N*sizeof(mpz_t)); + denom = (mpz_t*)malloc(N*sizeof(mpz_t)); + for (i = 0; i < N; i++) { + mpz_init(num[i]); + mpz_init(denom[i]); + } + + trunc = 2; + mpz_init_set_ui(trunc_mod, p); + mpz_mul_ui(trunc_mod, trunc_mod, p); + while(1) { + /* We compute f = 1 + a_i*p^(2^i) + trunc_mod is p^(2^(i+1)) */ + mpz_fdiv_r(f, arg, trunc_mod); + mpz_ui_sub(f, 2, f); + mpz_mul(arg, arg, f); + + /* We compute the Taylor expansion of log(f) + For now, computations are carried out over the rationals */ + for (i = 0; i < N; i++) { + mpz_set_ui(num[i], 1); + mpz_set_ui(denom[i], i+1); + } + step = 1; + mpz_ui_sub(h, 1, f); // we write f = 1 + h, i.e. h = a_i*p^(2^i) + mpz_set(hpow, h); + while(step < N) { + for (i = 0; i < N - step; i += step << 1) { + mpz_mul(mpz_tmp, hpow, num[i+step]); + mpz_mul(mpz_tmp, mpz_tmp, denom[i]); + mpz_mul(num[i], num[i], denom[i+step]); + mpz_add(num[i], num[i], mpz_tmp); + mpz_mul(denom[i], denom[i], denom[i+step]); + } + step <<= 1; + mpz_mul(hpow, hpow, hpow); + } + + /* We compute the p-adic valuation of the denominateur (which is N!) */ + Np = N; tmp = 0; + while(Np > 0) { Np /= p; tmp += Np; } + mpz_ui_pow_ui(d, p, tmp); + mpz_divexact(mpz_tmp, num[0], d); + mpz_mul(mpz_tmp, h, mpz_tmp); + + /* We coerce the result from Q to Zp */ + mpz_divexact(denom[0], denom[0], d); + mpz_gcdext(d, inv, NULL, denom[0], modulo); + mpz_mul(mpz_tmp, mpz_tmp, inv); + + /* We add this contribution to log(f) */ + mpz_add(ans, ans, mpz_tmp); + + if (trunc > prec) break; + + /* We update the variables for the next step */ + mpz_mul(trunc_mod, trunc_mod, trunc_mod); + trunc <<= 1; + N >>= 1; + } + + if (! congruent_to_one) { + mpz_set_ui(mpz_tmp, p-1); + mpz_gcdext(d, inv, NULL, mpz_tmp, modulo); + mpz_mul(ans, ans, inv); + } + + mpz_fdiv_r(ans, ans, modulo); + + /* We clear memory */ + mpz_clear(f); + mpz_clear(trunc_mod); + mpz_clear(h); + mpz_clear(hpow); + mpz_clear(mpz_tmp); + mpz_clear(d); + mpz_clear(inv); + for (i = 0; i < saveN; i++) { + mpz_clear(num[i]); + mpz_clear(denom[i]); + } + +} From e83902f25c3fa2dd75f4b7180cd793f4245fb194 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Sun, 21 May 2017 17:52:58 +0200 Subject: [PATCH 040/126] Small fixes --- src/sage/rings/padics/transcendantal.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/padics/transcendantal.c b/src/sage/rings/padics/transcendantal.c index 39c1dc3beb6..97b40b40e2f 100644 --- a/src/sage/rings/padics/transcendantal.c +++ b/src/sage/rings/padics/transcendantal.c @@ -9,16 +9,13 @@ #include #include -#include -#include - /* p-adic logarithm */ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, const mpz_t modulo) { /* Compute the p-adic logarithm of a, which is supposed to be a unit Algorithm: If a = 1 (mod p), write a as a product - a = (1 - a_0*p) (1 - a_1*p^2) (1 - a_2*p^4) (1 - a_3*p^8) ... + 1/a = (1 - a_0*p) (1 - a_1*p^2) (1 - a_2*p^4) (1 - a_3*p^8) ... with 0 <= a_i < p^(2^i). Then compute each log(1 - a_i*p^(2^i)) using Taylor expansion and a binary spliting strategy. @@ -57,15 +54,15 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con num = (mpz_t*)malloc(N*sizeof(mpz_t)); denom = (mpz_t*)malloc(N*sizeof(mpz_t)); for (i = 0; i < N; i++) { - mpz_init(num[i]); - mpz_init(denom[i]); + mpz_init(num[i]); + mpz_init(denom[i]); } trunc = 2; mpz_init_set_ui(trunc_mod, p); mpz_mul_ui(trunc_mod, trunc_mod, p); while(1) { - /* We compute f = 1 + a_i*p^(2^i) + /* We compute f = 1 - a_i*p^(2^i) trunc_mod is p^(2^(i+1)) */ mpz_fdiv_r(f, arg, trunc_mod); mpz_ui_sub(f, 2, f); @@ -78,7 +75,7 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con mpz_set_ui(denom[i], i+1); } step = 1; - mpz_ui_sub(h, 1, f); // we write f = 1 + h, i.e. h = a_i*p^(2^i) + mpz_ui_sub(h, 1, f); // we write f = 1 - h, i.e. h = a_i*p^(2^i) mpz_set(hpow, h); while(step < N) { for (i = 0; i < N - step; i += step << 1) { From c29989b0113afe41a12bb5e73754734a41fc3be9 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Wed, 24 May 2017 01:04:57 +0100 Subject: [PATCH 041/126] update sagenb to 1.0 --- build/pkgs/sagenb/checksums.ini | 6 +++--- build/pkgs/sagenb/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sagenb/checksums.ini b/build/pkgs/sagenb/checksums.ini index 076dffc1a8f..8d216e36795 100644 --- a/build/pkgs/sagenb/checksums.ini +++ b/build/pkgs/sagenb/checksums.ini @@ -1,4 +1,4 @@ tarball=sagenb-VERSION.tar.bz2 -sha1=9fc8addff1c543521225acaf60a2336204e67d62 -md5=04ddd5a1ccf0764cd72dc0abcf322c1e -cksum=1784359449 +sha1=afc65abfd9441e6c9abc44ee611a27e79445e92b +md5=68b61671fcce495896ab26c431af6a77 +cksum=2787508638 diff --git a/build/pkgs/sagenb/package-version.txt b/build/pkgs/sagenb/package-version.txt index f3040840fd7..d3827e75a5c 100644 --- a/build/pkgs/sagenb/package-version.txt +++ b/build/pkgs/sagenb/package-version.txt @@ -1 +1 @@ -0.13 +1.0 From 52381bcedd9b3105062d2c70708f20ccd2d09176 Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 24 May 2017 10:10:19 +0200 Subject: [PATCH 042/126] trac #22908: improve INPUT blocks --- src/sage/graphs/generators/random.py | 19 ++++++++++--------- src/sage/graphs/graph.py | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index a4f9faebf1d..942825a96df 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -261,18 +261,19 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): INPUT: - - ``m`` -- number of blocks. + - ``m`` -- integer; number of blocks (at least one). - - ``k`` -- minimum number of vertices of a block (at least two). + - ``k`` -- integer; minimum number of vertices of a block (at least two). - - ``kmax`` -- (default: None) By default, each block has `k` vertices. When - the parameter `kmax` is specified (with `kmax \geq k`), the number of - vertices of each block is randomly chosen between `k` and `kmax`. + - ``kmax`` -- integer (default: ``None``) By default, each block has `k` + vertices. When the parameter `kmax` is specified (with `kmax \geq k`), the + number of vertices of each block is randomly chosen between `k` and + `kmax`. - - ``incidence_structure`` -- (default: False) when set to ``True``, the - incidence structure of the graphs is returned instead of the graph itself, - that is the list of the lists of vertices in each block. This is useful - for the creation of some hypergraphs. + - ``incidence_structure`` -- boolean (default: ``False``) when set to + ``True``, the incidence structure of the graphs is returned instead of the + graph itself, that is the list of the lists of vertices in each + block. This is useful for the creation of some hypergraphs. OUTPUT: diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index dbd85c5c877..59534103412 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -1835,7 +1835,7 @@ def is_biconnected(self): @doc_index("Graph properties") def is_block_graph(self): r""" - Test if the graph is a block graph. + Return whether this graph is a block graph. A block graph is a connected graph in which every biconnected component (block) is a clique. From a64f2a57af6dbfe09b74357707f8610f61c46ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Bissey?= Date: Thu, 25 May 2017 10:59:14 +1200 Subject: [PATCH 043/126] fix bug in tuned code which caused testsuite to fail with some compilers and hardware --- build/pkgs/gf2x/package-version.txt | 2 +- build/pkgs/gf2x/patches/0007-fix_tuning.patch | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 build/pkgs/gf2x/patches/0007-fix_tuning.patch diff --git a/build/pkgs/gf2x/package-version.txt b/build/pkgs/gf2x/package-version.txt index 07c205584e8..fb97a3ebb49 100644 --- a/build/pkgs/gf2x/package-version.txt +++ b/build/pkgs/gf2x/package-version.txt @@ -1 +1 @@ -1.1.p1 +1.1.p2 diff --git a/build/pkgs/gf2x/patches/0007-fix_tuning.patch b/build/pkgs/gf2x/patches/0007-fix_tuning.patch new file mode 100644 index 00000000000..764e8e53047 --- /dev/null +++ b/build/pkgs/gf2x/patches/0007-fix_tuning.patch @@ -0,0 +1,13 @@ +diff --git a/src/mul9clk2.c b/src/mul9clk2.c +index bf7ad4a..5c6b980 100644 +--- a/src/mul9clk2.c ++++ b/src/mul9clk2.c +@@ -149,7 +149,7 @@ void gf2x_mul9 (unsigned long *c, const unsigned long *a, const unsigned long *b + e = p2e[1]; h=l; l=p2o[1]; + _mm_storeu_si128((__v2di*)(c+14), e ^ _mm_slli_si128(l, 8) ^ _mm_srli_si128(h, 8)); + +- e = p2e[2]; ++ e = p2e[2]; h=l; + _mm_storeu_si128((__v2di*)(c+16), e ^ _mm_srli_si128(h, 8)); + + /* From adf17b5dd863867e4bf578b5053fbd5898080d15 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Thu, 25 May 2017 22:01:18 +0200 Subject: [PATCH 044/126] add is_exact method to SR --- src/sage/symbolic/expression.pyx | 55 ++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 8517128d815..0b418bc7f11 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -2293,6 +2293,61 @@ cdef class Expression(CommutativeRingElement): """ return is_a_relational(self._gobj) + def is_exact(self): + """ + Return True if this expression only contains exact numerical coefficients. + + EXAMPLES:: + + sage: x, y = var('x, y') + sage: (x+y-1).is_exact() + True + sage: (x+y-1.9).is_exact() + False + sage: x.is_exact() + True + sage: pi.is_exact() + True + sage: (sqrt(x-y) - 2*x + 1).is_exact() + True + sage: ((x-y)^0.5 - 2*x + 1).is_exact() + False + + TESTS:: + + sage: (sin(x*cos(2*x*pi)) - 10*y^3 - 1/(x+4)).is_exact() + True + sage: (sin(x*cos(2.0*x*pi)) - 10*y^3 - 1/(x+4)).is_exact() + False + sage: SR(42).is_exact() + True + sage: SR(42.01).is_exact() + False + sage: SR(I).is_exact() + True + sage: (x-I).is_exact() + True + sage: (x-CC(0,1)).is_exact() + False + """ + # generator over all numerical elements in the subexpression tree of expr + def numelems_gen(expr): + if expr.is_numeric(): + yield expr + elif expr.operator() is not None: + for op in expr.operands(): + if op.is_numeric(): + yield op + else: + for opp in numelems_gen(op): + yield opp + # stop at the first inexact number in the subexpression tree of self, + # and if there is no such element, then self is exact + for nelem in numelems_gen(self): + if not nelem.pyobject().base_ring().is_exact(): + return False + return True + cpdef bint is_infinity(self): """ Return True if self is an infinite expression. From 71bc33610a526043a93ff68f45964ed5b4b93660 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Thu, 25 May 2017 23:07:40 +0200 Subject: [PATCH 045/126] add error functions conversions --- src/sage/functions/error.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sage/functions/error.py b/src/sage/functions/error.py index db523fd85fb..83bfb79e9ce 100644 --- a/src/sage/functions/error.py +++ b/src/sage/functions/error.py @@ -182,7 +182,8 @@ def __init__(self): BuiltinFunction.__init__(self, "erf", latex_name=r"\operatorname{erf}", conversions=dict(maxima='erf', sympy='erf', - fricas='erf')) + fricas='erf', + giac='erf')) def _eval_(self, x): """ @@ -400,7 +401,8 @@ def __init__(self): latex_name=r"\operatorname{erfc}", conversions=dict(maxima='erfc', sympy='erfc', - fricas='erfc')) + fricas='erfc', + giac='erfc') def _eval_(self, x): """ From b2f426184bbd24ddc9b8d710ed937ff7b24eef0c Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Fri, 26 May 2017 00:05:22 +0200 Subject: [PATCH 046/126] fix missing ) in giac erfc --- src/sage/functions/error.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/functions/error.py b/src/sage/functions/error.py index 83bfb79e9ce..b2d6bc3307f 100644 --- a/src/sage/functions/error.py +++ b/src/sage/functions/error.py @@ -402,7 +402,7 @@ def __init__(self): conversions=dict(maxima='erfc', sympy='erfc', fricas='erfc', - giac='erfc') + giac='erfc')) def _eval_(self, x): """ From 6592c6197fbdb40307c6bad3e01e97116af448a3 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Fri, 26 May 2017 07:55:52 +0200 Subject: [PATCH 047/126] register swap psi --- src/sage/functions/other.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 5e68920539e..67ebcdb045f 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -1384,6 +1384,9 @@ def psi(x, *args, **kwds): # two functions with different number of arguments and the same name symbol_table['functions']['psi'] = psi +def _swap_psi(a, b): return psi(b, a) +register_symbol(_swap_psi, {'giac':'Psi'}) + class Function_factorial(GinacFunction): def __init__(self): r""" From 350316fe0bc69cb8c1fdebbd3363d3437661f28f Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Fri, 26 May 2017 10:08:01 +0200 Subject: [PATCH 048/126] add Psi conversion in psi2 --- src/sage/functions/other.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/functions/other.py b/src/sage/functions/other.py index 67ebcdb045f..37dafcf925d 100644 --- a/src/sage/functions/other.py +++ b/src/sage/functions/other.py @@ -1305,7 +1305,8 @@ def __init__(self): """ GinacFunction.__init__(self, "psi", nargs=2, latex_name='\psi', conversions=dict(mathematica='PolyGamma', - sympy='polygamma')) + sympy='polygamma', + giac='Psi')) def _maxima_init_evaled_(self, *args): """ From 70fa3f8da73a00053655f9e03e0e92d333f1b988 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Fri, 26 May 2017 12:19:13 +0100 Subject: [PATCH 049/126] updates to properly compare worksheets --- build/pkgs/sagenb/checksums.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/pkgs/sagenb/checksums.ini b/build/pkgs/sagenb/checksums.ini index 8d216e36795..2ed6a82d220 100644 --- a/build/pkgs/sagenb/checksums.ini +++ b/build/pkgs/sagenb/checksums.ini @@ -1,4 +1,4 @@ tarball=sagenb-VERSION.tar.bz2 -sha1=afc65abfd9441e6c9abc44ee611a27e79445e92b -md5=68b61671fcce495896ab26c431af6a77 -cksum=2787508638 +sha1=96ad0750cf953ac5d5f5d987f15bfad75f1dcb24 +md5=005a97641e8c5bc74f10d438d0056903 +cksum=1197603683 From f71bbeb09dc24480ce9308858a0566f89c4c06d1 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Sat, 27 May 2017 12:04:06 +0200 Subject: [PATCH 050/126] fix latex and docstring formatting in desolvers.py --- src/sage/calculus/desolvers.py | 212 ++++++++++++++++++--------------- 1 file changed, 118 insertions(+), 94 deletions(-) diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index 9ff89d9f749..ccd8aea1423 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -14,33 +14,41 @@ Commands: -- ``desolve`` - Compute the "general solution" to a 1st or 2nd order +- :func:`desolve` - Compute the "general solution" to a 1st or 2nd order ODE via Maxima. -- ``desolve_laplace`` - Solve an ODE using Laplace transforms via +- :func:`desolve_laplace` - Solve an ODE using Laplace transforms via Maxima. Initial conditions are optional. -- ``desolve_rk4`` - Solve numerically IVP for one first order +- :func:`desolve_rk4` - Solve numerically an IVP for one first order equation, return list of points or plot. -- ``desolve_system_rk4`` - Solve numerically IVP for system of first +- :func:`desolve_system_rk4` - Solve numerically an IVP for a system of first order equations, return list of points. -- ``desolve_odeint`` - Solve numerically a system of first-order ordinary - differential equations using ``odeint`` from scipy.integrate module. +- :func:`desolve_odeint` - Solve numerically a system of first-order ordinary + differential equations using ``odeint`` from `scipy.integrate module. + `_ -- ``desolve_system`` - Solve any size system of 1st order odes using +- :func:`desolve_system` - Solve a system of 1st order ODEs of any size using Maxima. Initial conditions are optional. -- ``eulers_method`` - Approximate solution to a 1st order DE, +- :func:`eulers_method` - Approximate solution to a 1st order DE, presented as a table. -- ``eulers_method_2x2`` - Approximate solution to a 1st order system +- :func:`eulers_method_2x2` - Approximate solution to a 1st order system of DEs, presented as a table. -- ``eulers_method_2x2_plot`` - Plot the sequence of points obtained +- :func:`eulers_method_2x2_plot` - Plot the sequence of points obtained from Euler's method. +The following functions require the optional package ``tides``: + +- :func:`desolve_mintides` - Numerical solution of a system of 1st order ODEs via + the Taylor series integrator method implemented in TIDES. + +- :func:`desolve_tides_mpfr` - Arbitrary precision Taylor series integrator implemented in TIDES. + AUTHORS: - David Joyner (3-2006) - Initial version of functions @@ -81,31 +89,29 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False): r""" - Solves a 1st or 2nd order linear ODE via maxima. Including IVP and BVP. - - *Use* ``desolve? `` *if the output in truncated in notebook.* + Solves a 1st or 2nd order linear ODE via Maxima, including IVP and BVP. INPUT: - ``de`` - an expression or equation representing the ODE - - ``dvar`` - the dependent variable (hereafter called ``y``) + - ``dvar`` - the dependent variable (hereafter called `y`) - ``ics`` - (optional) the initial or boundary conditions - - for a first-order equation, specify the initial ``x`` and ``y`` + - for a first-order equation, specify the initial `x` and `y` - - for a second-order equation, specify the initial ``x``, ``y``, - and ``dy/dx``, i.e. write `[x_0, y(x_0), y'(x_0)]` + - for a second-order equation, specify the initial `x`, `y`, + and `dy/dx`, i.e. write `[x_0, y(x_0), y'(x_0)]` - for a second-order boundary solution, specify initial and - final ``x`` and ``y`` boundary conditions, i.e. write `[x_0, y(x_0), x_1, y(x_1)]`. + final `x` and `y` boundary conditions, i.e. write `[x_0, y(x_0), x_1, y(x_1)]`. - gives an error if the solution is not SymbolicEquation (as happens for example for a Clairaut equation) - ``ivar`` - (optional) the independent variable (hereafter called - x), which must be specified if there is more than one + `x`), which must be specified if there is more than one independent variable in the equation. - ``show_method`` - (optional) if true, then Sage returns pair @@ -114,23 +120,26 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) following order for first order equations: linear, separable, exact (including exact with integrating factor), homogeneous, bernoulli, generalized homogeneous) - use carefully in class, - see below for the example of the equation which is separable but + see below the example of an equation which is separable but this property is not recognized by Maxima and the equation is solved as exact. - - ``contrib_ode`` - (optional) if true, desolve allows to solve + - ``contrib_ode`` - (optional) if true, ``desolve`` allows to solve Clairaut, Lagrange, Riccati and some other equations. This may take a long time and is thus turned off by default. Initial conditions can be used only if the result is one SymbolicEquation (does not - contain a singular solution, for example) + contain a singular solution, for example). OUTPUT: In most cases return a SymbolicEquation which defines the solution - implicitly. If the result is in the form y(x)=... (happens for - linear eqs.), return the right-hand side only. The possible - constant solutions of separable ODE's are omitted. + implicitly. If the result is in the form `y(x)=\ldots` (happens for + linear eqs.), return the right-hand side only. The possible + constant solutions of separable ODEs are omitted. + NOTES: + + Use ``desolve? `` if the output in the Sage notebook is truncated. EXAMPLES:: @@ -149,7 +158,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) sage: plot(f) Graphics object consisting of 1 graphics primitive - We can also solve second-order differential equations.:: + We can also solve second-order differential equations:: sage: x = var('x') sage: y = function('y')(x) @@ -260,8 +269,8 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) You can solve Bessel equations, also using initial conditions, but you cannot put (sometimes desired) the initial - condition at x=0, since this point is a singular point of the - equation. Anyway, if the solution should be bounded at x=0, then + condition at `x=0`, since this point is a singular point of the + equation. Anyway, if the solution should be bounded at `x=0`, then _K2=0.:: sage: desolve(x^2*diff(y,x,x)+x*diff(y,x)+(x^2-4)*y==0,y) @@ -278,7 +287,7 @@ def desolve(de, dvar, ics=None, ivar=None, show_method=False, contrib_ode=False) sage: desolve(sqrt(y)*diff(y,x)+e^(y)+cos(x)-sin(x+y)==0,y,contrib_ode=True) # not tested - Some more types of ODE's:: + Some more types of ODEs:: sage: desolve(x*diff(y,x)^2-(1+x*y)*diff(y,x)+y==0,y,contrib_ode=True,show_method=True) [[y(x) == _C + log(x), y(x) == _C*e^x], 'factor'] @@ -580,17 +589,17 @@ def desolve_laplace(de, dvar, ics=None, ivar=None): INPUT: - - ``de`` - a lambda expression representing the ODE (eg, de = - diff(y,x,2) == diff(y,x)+sin(x)) + - ``de`` - a lambda expression representing the ODE (e.g. ``de = + diff(y,x,2) == diff(y,x)+sin(x)``) - - ``dvar`` - the dependent variable (eg y) + - ``dvar`` - the dependent variable (e.g. ``y``) - ``ivar`` - (optional) the independent variable (hereafter called - x), which must be specified if there is more than one + `x`), which must be specified if there is more than one independent variable in the equation. - - ``ics`` - a list of numbers representing initial conditions, (eg, - f(0)=1, f'(0)=2 is ics = [0,1,2]) + - ``ics`` - a list of numbers representing initial conditions, (e.g. + ``f(0)=1``, ``f'(0)=2`` corresponds to ``ics = [0,1,2]``) OUTPUT: @@ -703,9 +712,9 @@ def sanitize_var(exprs): # 'y(x) -> y(x) def desolve_system(des, vars, ics=None, ivar=None): """ - Solve any size system of 1st order ODE's. Initial conditions are optional. + Solve a system of any size of 1st order ODEs. Initial conditions are optional. - Onedimensional systems are passed to :meth:`desolve_laplace`. + One dimensional systems are passed to :meth:`desolve_laplace`. INPUT: @@ -713,8 +722,8 @@ def desolve_system(des, vars, ics=None, ivar=None): - ``vars`` - list of dependent variables - - ``ics`` - (optional) list of initial values for ivar and vars. - If ics is defined, it should provide initial conditions for each variable, + - ``ics`` - (optional) list of initial values for ``ivar`` and ``vars``. + If ``ics`` is defined, it should provide initial conditions for each variable, otherwise an exception would be raised. - ``ivar`` - (optional) the independent variable, which must be @@ -777,7 +786,7 @@ def desolve_system(des, vars, ics=None, ivar=None): sage: P1 = plot([solx,soly], (0,1)) sage: P2 = parametric_plot((solx,soly), (0,1)) - Now type show(P1), show(P2) to view these plots. + Now type ``show(P1)``, ``show(P2)`` to view these plots. Check that :trac:`9824` is fixed:: @@ -837,13 +846,15 @@ def desolve_system(des, vars, ics=None, ivar=None): def eulers_method(f,x0,y0,h,x1,algorithm="table"): r""" This implements Euler's method for finding numerically the - solution of the 1st order ODE ``y' = f(x,y)``, ``y(a)=c``. The "x" - column of the table increments from ``x0`` to ``x1`` by ``h`` (so - ``(x1-x0)/h`` must be an integer). In the "y" column, the new - y-value equals the old y-value plus the corresponding entry in the + solution of the 1st order ODE `y' = f(x,y)`, `y(a)=c`. The ``x`` + column of the table increments from `x_0` to `x_1` by `h` (so + `(x_1-x_0)/h` must be an integer). In the ``y`` column, the new + `y`-value equals the old `y`-value plus the corresponding entry in the last column. - *For pedagogical purposes only.* + .. NOTE:: + + This function is for pedagogical purposes only. EXAMPLES:: @@ -924,18 +935,23 @@ def eulers_method_2x2(f,g, t0, x0, y0, h, t1,algorithm="table"): This implements Euler's method for finding numerically the solution of the 1st order system of two ODEs - ``x' = f(t, x, y), x(t0)=x0.`` + .. MATH:: - ``y' = g(t, x, y), y(t0)=y0.`` + \begin{align} + x' &= f(t, x, y), x(t_0)=x_0 \\ + y' &= g(t, x, y), y(t_0)=y_0. + \end{align} - The "t" column of the table increments from `t_0` to `t_1` by `h` - (so `\\frac{t_1-t_0}{h}` must be an integer). In the "x" column, - the new x-value equals the old x-value plus the corresponding - entry in the next (third) column. In the "y" column, the new - y-value equals the old y-value plus the corresponding entry in the + The ``t`` column of the table increments from `t_0` to `t_1` by `h` + (so `\frac{t_1-t_0}{h}` must be an integer). In the ``x`` column, + the new `x`-value equals the old `x`-value plus the corresponding + entry in the next (third) column. In the ``y`` column, the new + `y`-value equals the old `y`-value plus the corresponding entry in the next (last) column. - *For pedagogical purposes only.* + .. NOTE:: + + This function is for pedagogical purposes only. EXAMPLES:: @@ -969,7 +985,7 @@ def eulers_method_2x2(f,g, t0, x0, y0, h, t1,algorithm="table"): To numerically approximate `y(1)`, where `(1+t^2)y''+y'-y=0`, `y(0)=1`, `y'(0)=-1`, using 4 steps of Euler's method, first convert to a system: `y_1' = y_2`, `y_1(0)=1`; `y_2' = - \\frac{y_1-y_2}{1+t^2}`, `y_2(0)=-1`.:: + \frac{y_1-y_2}{1+t^2}`, `y_2(0)=-1`.:: sage: RR = RealField(sci_not=0, prec=4, rnd='RNDU') sage: t, x, y=PolynomialRing(RR,3,"txy").gens() @@ -982,7 +998,7 @@ def eulers_method_2x2(f,g, t0, x0, y0, h, t1,algorithm="table"): 3/4 0.63 -0.0078 -0.031 0.11 1 0.63 0.020 0.079 0.071 - To numerically approximate y(1), where `y''+ty'+y=0`, `y(0)=1`, `y'(0)=0`:: + To numerically approximate `y(1)`, where `y''+ty'+y=0`, `y(0)=1`, `y'(0)=0`:: sage: t,x,y=PolynomialRing(RR,3,"txy").gens() sage: f = y; g = -x-y*t @@ -1018,16 +1034,16 @@ def eulers_method_2x2_plot(f,g, t0, x0, y0, h, t1): r""" Plot solution of ODE. - This plots the soln in the rectangle ``(xrange[0],xrange[1]) - x (yrange[0],yrange[1])`` and plots using Euler's method the + This plots the solution in the rectangle with sides ``(xrange[0],xrange[1])`` and + ``(yrange[0],yrange[1])``, and plots using Euler's method the numerical solution of the 1st order ODEs `x' = f(t,x,y)`, `x(a)=x_0`, `y' = g(t,x,y)`, `y(a) = y_0`. - *For pedagogical purposes only.* + .. NOTE:: - EXAMPLES:: + This function is for pedagogical purposes only. - sage: from sage.calculus.desolvers import eulers_method_2x2_plot + EXAMPLES: The following example plots the solution to `\theta''+\sin(\theta)=0`, `\theta(0)=\frac 34`, `\theta'(0) = @@ -1035,6 +1051,7 @@ def eulers_method_2x2_plot(f,g, t0, x0, y0, h, t1): ``(P[0]+P[1]).show()`` to plot `(t,\theta(t))` and `(t,\theta'(t))`:: + sage: from sage.calculus.desolvers import eulers_method_2x2_plot sage: f = lambda z : z[2]; g = lambda z : -sin(z[1]) sage: P = eulers_method_2x2_plot(f,g, 0.0, 0.75, 0.0, 0.1, 1.0) """ @@ -1055,14 +1072,14 @@ def desolve_rk4_determine_bounds(ics,end_points=None): """ Used to determine bounds for numerical integration. - - If end_points is None, the interval for integration is from ics[0] - to ics[0]+10 + - If ``end_points`` is None, the interval for integration is from ``ics[0]`` + to ``ics[0]+10`` - - If end_points is a or [a], the interval for integration is from min(ics[0],a) - to max(ics[0],a) + - If ``end_points`` is ``a`` or ``[a]``, the interval for integration is from ``min(ics[0],a)`` + to ``max(ics[0],a)`` - - If end_points is [a,b], the interval for integration is from min(ics[0],a) - to max(ics[0],b) + - If ``end_points`` is ``[a,b]``, the interval for integration is from ``min(ics[0],a)`` + to ``max(ics[0],b)`` EXAMPLES:: @@ -1099,12 +1116,12 @@ def desolve_rk4_determine_bounds(ics,end_points=None): def desolve_rk4(de, dvar, ics=None, ivar=None, end_points=None, step=0.1, output='list', **kwds): """ Solve numerically one first-order ordinary differential - equation. See also ``ode_solver``. + equation. INPUT: - input is similar to ``desolve`` command. The differential equation can be - written in a form close to the plot_slope_field or desolve command + Input is similar to ``desolve`` command. The differential equation can be + written in a form close to the ``plot_slope_field`` or ``desolve`` command. - Variant 1 (function in two variables) @@ -1122,25 +1139,28 @@ def desolve_rk4(de, dvar, ics=None, ivar=None, end_points=None, step=0.1, output - ``ivar`` - should be specified, if there are more variables or if the equation is autonomous - - ``ics`` - initial conditions in the form [x0,y0] + - ``ics`` - initial conditions in the form ``[x0,y0]`` - ``end_points`` - the end points of the interval - - if end_points is a or [a], we integrate on between min(ics[0],a) and max(ics[0],a) - - if end_points is None, we use end_points=ics[0]+10 + - if ``end_points`` is a or [a], we integrate between ``min(ics[0],a)`` and ``max(ics[0],a)`` + - if ``end_points`` is None, we use ``end_points=ics[0]+10`` - - if end_points is [a,b] we integrate on between min(ics[0],a) and max(ics[0],b) + - if end_points is [a,b] we integrate between ``min(ics[0], a)`` and ``max(ics[0], b)`` - ``step`` - (optional, default:0.1) the length of the step (positive number) - - ``output`` - (optional, default: 'list') one of 'list', - 'plot', 'slope_field' (graph of the solution with slope field) + - ``output`` - (optional, default: ``'list'``) one of ``'list'``, + ``'plot'``, ``'slope_field'`` (graph of the solution with slope field) OUTPUT: - Return a list of points, or plot produced by list_plot, + Return a list of points, or plot produced by ``list_plot``, optionally with slope field. + .. SEEALSO:: + + :func:`ode_solver`. EXAMPLES:: @@ -1247,7 +1267,7 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1 r""" Solve numerically a system of first-order ordinary differential equations using the 4th order Runge-Kutta method. Wrapper for - Maxima command ``rk``. See also ``ode_solver``. + Maxima command ``rk``. INPUT: @@ -1261,14 +1281,14 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1 if the equation is autonomous and the independent variable is missing - - ``ics`` - initial conditions in the form [x0,y01,y02,y03,....] + - ``ics`` - initial conditions in the form ``[x0,y01,y02,y03,....]`` - ``end_points`` - the end points of the interval - - if end_points is a or [a], we integrate on between min(ics[0],a) and max(ics[0],a) - - if end_points is None, we use end_points=ics[0]+10 + - if ``end_points`` is a or [a], we integrate on between ``min(ics[0], a)`` and ``max(ics[0], a)`` + - if ``end_points`` is None, we use ``end_points=ics[0]+10`` - - if end_points is [a,b] we integrate on between min(ics[0],a) and max(ics[0],b) + - if ``end_points`` is [a,b] we integrate on between ``min(ics[0], a)`` and ``max(ics[0], b)`` - ``step`` -- (optional, default: 0.1) the length of the step @@ -1276,6 +1296,10 @@ def desolve_system_rk4(des, vars, ics=None, ivar=None, end_points=None, step=0.1 Return a list of points. + .. SEEALSO:: + + :func:`ode_solver`. + EXAMPLES:: sage: from sage.calculus.desolvers import desolve_system_rk4 @@ -1360,20 +1384,20 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() - ``times`` -- a sequence of time points in which the solution must be found - ``dvars`` -- dependent variables. ATTENTION: the order must be the same as - in des, that means: d(dvars[i])/dt=des[i] + in ``des``, that means: ``d(dvars[i])/dt=des[i]`` - ``ivar`` -- independent variable, optional. - ``compute_jac`` -- boolean. If True, the Jacobian of des is computed and used during the integration of Stiff Systems. Default value is False. - Other Parameters (taken from the documentation of odeint function from - scipy.integrate module) + Other Parameters (taken from the documentation of odeint function from `scipy.integrate module. + `_) - ``rtol``, ``atol`` : float - The input parameters rtol and atol determine the error + The input parameters ``rtol`` and ``atol`` determine the error control performed by the solver. The solver will control the - vector, e, of estimated local errors in y, according to an + vector, `e`, of estimated local errors in `y`, according to an inequality of the form: max-norm of (e / ewt) <= 1 @@ -1382,7 +1406,7 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() ewt = rtol * abs(y) + atol - rtol and atol can be either vectors the same length as y or scalars. + ``rtol`` and ``atol`` can be either vectors the same length as `y` or scalars. - ``tcrit`` : array Vector of critical points (e.g. singularities) where integration @@ -1415,7 +1439,7 @@ def desolve_odeint(des, ics, times, dvars, ivar=None, compute_jac=False, args=() OUTPUT: - Return a list with the solution of the system at each time in times. + Return a list with the solution of the system at each time in ``times``. EXAMPLES: @@ -1603,9 +1627,9 @@ def desolve_mintides(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-16) - A. Abad, R. Barrio, F. Blesa, M. Rodriguez. Algorithm 924. *ACM Transactions on Mathematical Software* , *39* (1), 1-28. - - (http://www.unizar.es/acz/05Publicaciones/Monografias/MonografiasPublicadas/Monografia36/IndMonogr36.htm) - A. Abad, R. Barrio, F. Blesa, M. Rodriguez. - TIDES tutorial: Integrating ODEs by using the Taylor Series Method. + - A. Abad, R. Barrio, F. Blesa, M. Rodriguez. + `TIDES tutorial: Integrating ODEs by using the Taylor Series Method. + `_ """ import subprocess if subprocess.call('command -v gcc', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE): @@ -1706,9 +1730,9 @@ def desolve_tides_mpfr(f, ics, initial, final, delta, tolrel=1e-16, tolabs=1e-1 .. A. Abad, R. Barrio, F. Blesa, M. Rodriguez. Algorithm 924. *ACM Transactions on Mathematical Software* , *39* (1), 1-28. - .. (http://www.unizar.es/acz/05Publicaciones/Monografias/MonografiasPublicadas/Monografia36/IndMonogr36.htm) - A. Abad, R. Barrio, F. Blesa, M. Rodriguez. - TIDES tutorial: Integrating ODEs by using the Taylor Series Method. + .. A. Abad, R. Barrio, F. Blesa, M. Rodriguez. + `TIDES tutorial: Integrating ODEs by using the Taylor Series Method. + `_ """ import subprocess From b266512b8f7c1815ca685bfc0ddabd8e5f5202ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 27 May 2017 22:36:00 +0200 Subject: [PATCH 051/126] trac 12562 remove obsolete tutorial on visualization, and add WARNING --- .../numerical_sage/index.rst | 24 +++-- .../numerical_sage/installation.rst | 8 -- .../numerical_sage/installation_linux.rst | 80 --------------- .../numerical_sage/installation_osx.rst | 38 -------- .../numerical_sage/plotting.rst | 97 ------------------- .../numerical_sage/visualization.rst | 22 ----- 6 files changed, 14 insertions(+), 255 deletions(-) delete mode 100644 src/doc/en/thematic_tutorials/numerical_sage/installation.rst delete mode 100644 src/doc/en/thematic_tutorials/numerical_sage/installation_linux.rst delete mode 100644 src/doc/en/thematic_tutorials/numerical_sage/installation_osx.rst delete mode 100644 src/doc/en/thematic_tutorials/numerical_sage/plotting.rst delete mode 100644 src/doc/en/thematic_tutorials/numerical_sage/visualization.rst diff --git a/src/doc/en/thematic_tutorials/numerical_sage/index.rst b/src/doc/en/thematic_tutorials/numerical_sage/index.rst index 985670a1908..babb3dd44e9 100644 --- a/src/doc/en/thematic_tutorials/numerical_sage/index.rst +++ b/src/doc/en/thematic_tutorials/numerical_sage/index.rst @@ -5,19 +5,24 @@ .. _numerical_computing: Numerical Computing with Sage -========================================== +============================= + +.. WARNING:: + + Beware that this document may be obsolete. + This document is designed to introduce the reader to the tools in Sage that are useful for doing numerical computation. By numerical computation we essentially mean machine precision floating point computations. In particular, things such as optimization, numerical -linear algebra, solving ODE's/PDE's numerically, etc. or the first -part of this document the reader is only assumed to be familiar with -Python/Sage. In the second section on using compiled code, the -computational prerequisites increase and I assume the reader is -comfortable with writing programs in C or Fortran. The third section -is on mpi and parallel programming and only requires knowledge of -Python, though familiarity with mpi would be helpful. -Finally the last section is about 3d visualization in Sage. +linear algebra, solving ODE's or PDE's numerically, etc. + +In the first part of this document the reader is only assumed to be +familiar with Python/Sage. In the second section on using compiled +code, the computational prerequisites increase and I assume the reader +is comfortable with writing programs in C or Fortran. The third +section is on mpi and parallel programming and only requires knowledge +of Python, though familiarity with mpi would be helpful. In the current version of this document the reader is assumed to be familiar with the techniques of numerical analysis. The goal of this @@ -33,4 +38,3 @@ where they can find more information. numerical_tools using_compiled_code_iteractively parallel_computation - visualization diff --git a/src/doc/en/thematic_tutorials/numerical_sage/installation.rst b/src/doc/en/thematic_tutorials/numerical_sage/installation.rst deleted file mode 100644 index 99507b9820e..00000000000 --- a/src/doc/en/thematic_tutorials/numerical_sage/installation.rst +++ /dev/null @@ -1,8 +0,0 @@ -Installation of Visualization Tools -=================================== - -.. toctree:: - :maxdepth: 2 - - installation_linux - installation_osx diff --git a/src/doc/en/thematic_tutorials/numerical_sage/installation_linux.rst b/src/doc/en/thematic_tutorials/numerical_sage/installation_linux.rst deleted file mode 100644 index 16df05f84ed..00000000000 --- a/src/doc/en/thematic_tutorials/numerical_sage/installation_linux.rst +++ /dev/null @@ -1,80 +0,0 @@ -Installing Visualization Tools on Linux -======================================= - -This section assumes you are running linux. You may need -administrator rights to complete this section. First try - -.. skip - -:: - - sage: import Tkinter - -If this works great if not it means your sage was not compiled with -tcl/tk bindings. There are two possible reasons. If you used a -binary then this will be the case. If you built from source but -don't have the tcl/tk libraries on your system you will have the -same problem. To fix this install the tcl and tk libraries and -development (source and headers) packages for your linux -distribution. Now you need to rebuild Sage's python - -.. skip - -:: - - sage: install_package('python-2.5.spkg') - -where you should replace :math:`<\text{version}>` by the version -of python. Type - -.. skip - -:: - - sage: !ls spkg/standard | grep python-2.5 - -This will give you the name of the python package to use above. In -the case that it gives multiple names, choose the one with the -highest version number. Now again try - -.. skip - -:: - - sage: import Tkinter - -If this works we can install vtk, but first you need cmake. Test if -your system has it by typing cmake at the shell, (or !cmake in -sage). If cmake is on your system then you are ready. If not either -install cmake on your system using your distributions tools or do - -.. skip - -:: - - sage: install_package('cmake-2.4.7') - -Now we want to compile VTK which does all the hard work. To do this -make sure you have the opengl libraries for you system installed. -This will be something like libgl1-mesa-glx, libgl1-mesa-dev. - -.. skip - -:: - - sage: install_package('vtk-5.0.3.p1') - -This will take quite a while to compile, probably 20 min to an hour -or so. Once this is done we install the python wrappers, the next -part takes about 10 seconds, - -.. skip - -:: - - sage: install_package('MayaVi-1.5') - sage: install_package('scitools++') - sage: install_package('PyVTK-0.4.74') - -Now you're done. - diff --git a/src/doc/en/thematic_tutorials/numerical_sage/installation_osx.rst b/src/doc/en/thematic_tutorials/numerical_sage/installation_osx.rst deleted file mode 100644 index 05c27e86ee6..00000000000 --- a/src/doc/en/thematic_tutorials/numerical_sage/installation_osx.rst +++ /dev/null @@ -1,38 +0,0 @@ -Installing Visualization Software on OS X -========================================= - -The first thing we need to do is rebuild Python to use OSX's -frameworks, so that it can create graphical windows. To do this -first from the terminal do - -:: - - cd $SAGE_ROOT/local/lib - rm libpng*.dylib - -where ``$SAGE_ROOT`` is the directory of your -Sage install. Next from within Sage, - -.. skip - -:: - - sage: install_package('python-2.5.1-framework') - -Next we will build vtk, this will take a while - -.. skip - -:: - - sage: install_package('vtk-5.0.3.p1') - -Finally - -.. skip - -:: - - sage: install_package('MayaVi-1.5') - sage: install_package('scitools++') - sage: install_package('PyVTK-0.4.74') diff --git a/src/doc/en/thematic_tutorials/numerical_sage/plotting.rst b/src/doc/en/thematic_tutorials/numerical_sage/plotting.rst deleted file mode 100644 index 6e52bb17175..00000000000 --- a/src/doc/en/thematic_tutorials/numerical_sage/plotting.rst +++ /dev/null @@ -1,97 +0,0 @@ -Plotting -======== - -We will plot a surface two ways. First we will use easyviz. -Consider the following code:: - - import numpy - from scitools import easyviz - x = numpy.arange(-8,8,.2) - xx,yy = numpy.meshgrid(x,x) - r = numpy.sqrt(xx**2+yy**2) + 0.01 - zz = numpy.sin(r)/r - easyviz.surfc(x,x,zz) - -The function surfc takes a list of x coordinates, and y coordinates -and a numpy array z. Its plots a surface that has height z[i,j] at -the point (x[i],y[i]). Note the use of meshgrid, and vectorized -numpy functions that let us evaluate -:math:`\frac{\sin(\sqrt{x^2+y^2})+1}{\sqrt{x^2+y^2}+1}` over the -grid very easily. We discussed meshgrid at the beginning when we -were talking about numpy. Note that you can drag the plot around -with your mouse and look at it from different angles. - -We can make this plot look a bit nicer by adding some shading and -nicer coloring and some labels as follows. - -:: - - import numpy - RealNumber=float - Integer =int - from scitools import easyviz - x = numpy.arange(-8,8,.2) - xx,yy = numpy.meshgrid(x,x) - r = numpy.sqrt(xx**2+yy**2) + 0.01 - zz = numpy.sin(r)/r - l = easyviz.Light(lightpos=(-10,-10,5), lightcolor=(1,1,1)) - easyviz.surfc(x,x,zz,shading='interp',colormap=easyviz.jet(), - zmin=-0.5,zmax=1,clevels=10, - title='r=sqrt(x**2+y**2)+eps\nsin(r)/r', - light=l, - legend='sin', - ) - -Let us now try to plot some vector fields. Consider the following -code - -:: - - import numpy - from scitools import easyviz - RealNumber=float - Integer=int - j=numpy.complex(0,1) - w=numpy.zeros((5,5,5)) - u=w+1.0 - xx,yy,zz=numpy.mgrid[-1.0:1.0:5*j,-1:1:5*j,-1:1:5*j] - easyviz.quiver3(xx,yy,zz,w,w,u) - -This should plot a vector field that points up everywhere. The -arguments to quiver3 are 6, :math:`n\times n\times n` arrays. The -first three arrays are the location of the vectors, that is there -will be a vector at :math:`(xx[i,j,k],yy[i,j,k],zz[i,j,k])` for -:math:`0\le i,j,k < n`. The second three arrays are the -directions, i.e., the vector at -:math:`(xx[i,j,k],yy[i,j,k],zz[i,j,k])` points in the direction -:math:`(w[i,j,k],w[i,j,k],u[i,j,k])`. - -Now let us give some examples with MayaVi. First lets see how to -plot a function like we did with easyviz. - -:: - - import numpy - from mayavi.tools import imv - x=numpy.arange(-8,8,.2) - def f(x,y): - r=numpy.sqrt(x**2+y**2)+.01 - return numpy.sin(r)/r - imv.surf(x,x,f) - -This will open mayavi, and display the plot of the function. The -first two arguments to surf are arrays :math:`x` and :math:`y`, -s.t. the function will be evaluated at :math:`(x[i],y[j])`. The -last argument is the function to graph. It probably looks a bit -different than the easyviz example. Lets try to make it look -similar to the easyviz example. First note that on the left there -is a list of filters and modules. Double-click the warpscalars -button in the filters menu, and change the scale factor from -:math:`1` to say :math:`5`. This should redraw the graph -similar to how easyviz drew it. There are quite a few other options -you can play around with. For example, next click on the module -surfacemap, and you will see you can make the graph transparent by -changing the opacity. You can also change it to a wireframe or make -it plot contours. - -TODO: More examples diff --git a/src/doc/en/thematic_tutorials/numerical_sage/visualization.rst b/src/doc/en/thematic_tutorials/numerical_sage/visualization.rst deleted file mode 100644 index 0913f08e7fc..00000000000 --- a/src/doc/en/thematic_tutorials/numerical_sage/visualization.rst +++ /dev/null @@ -1,22 +0,0 @@ -Visualization -============= - -One of the most common uses of computer algebra systems is of course -plotting. At the moment Sage does not have much in the way of -intrinsic support for visualization. However, there are some very -powerful open source programs for visualization that you can use from -within Sage. The goal of this chapter is to explain how to set them -up. The main tool we will be using is VTK, http://www.vtk.org. VTK is -an amazing visualization tool, and the results that can be achieved -are incredible. It is probably one of the best visualization tools in -existence, and can probably do anything you might want a visualization -tool to do. However, because it can do so much, it is a bit tricky to -use potentially. Luckily there are a few tools for using VTK from -within python that make it easier to get started. The ones we will -focus on are MavaVi, http://mayavi.sourceforge.net/, and easyviz. - -.. toctree:: - :maxdepth: 2 - - installation - plotting From a7d40cc4d4e59c6c51befbf6285aeea504c4d141 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Sat, 27 May 2017 23:59:29 +0200 Subject: [PATCH 052/126] Incorporate fast logarithm in ZpCA and ZpFM --- .../padics/padic_capped_absolute_element.pyx | 167 ++++++++++++++++++ .../padics/padic_capped_relative_element.pyx | 50 +++--- .../rings/padics/padic_fixed_mod_element.pyx | 120 +++++++++++++ .../rings/padics/padic_generic_element.pyx | 21 +-- 4 files changed, 320 insertions(+), 38 deletions(-) diff --git a/src/sage/rings/padics/padic_capped_absolute_element.pyx b/src/sage/rings/padics/padic_capped_absolute_element.pyx index a3b68f8126e..1cdb57ae1f1 100644 --- a/src/sage/rings/padics/padic_capped_absolute_element.pyx +++ b/src/sage/rings/padics/padic_capped_absolute_element.pyx @@ -27,6 +27,9 @@ include "CA_template.pxi" from sage.libs.pari.convert_gmp cimport new_gen_from_padic from sage.rings.finite_rings.integer_mod import Mod +cdef extern from "sage/rings/padics/transcendantal.c": + cdef void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, const mpz_t modulo) + cdef class PowComputer_(PowComputer_base): """ A PowComputer for a capped-absolute padic ring. @@ -281,6 +284,170 @@ cdef class pAdicCappedAbsoluteElement(CAElement): mpz_clear(ppow_minus_one) return infinity + def log(self, p_branch=None, aprec=None, change_frac=False): + r""" + Compute the `p`-adic logarithm of this element. + + The usual power series for the logarithm with values in the additive + group of a `p`-adic ring only converges for 1-units (units congruent to + 1 modulo `p`). However, there is a unique extension of the logarithm + to a homomorphism defined on all the units: If `u = a \cdot v` is a + unit with `v \equiv 1 \pmod{p}` and `a` a Teichmuller representative, + then we define `log(u) = log(v)`. This is the correct extension + because the units `U` split as a product `U = V \times \langle w + \rangle`, where `V` is the subgroup of 1-units and `w` is a fundamental + root of unity. The `\langle w \rangle` factor is torsion, so must go + to 0 under any homomorphism to the fraction field, which is a torsion + free group. + + INPUT: + + - ``p_branch`` -- an element in the base ring or its fraction + field; the implementation will choose the branch of the + logarithm which sends `p` to ``branch``. + + - ``aprec`` -- an integer or ``None`` (default: ``None``) if not + ``None``, then the result will only be correct to precision + ``aprec``. + + - ``change_frac`` -- In general the codomain of the logarithm should be + in the `p`-adic field, however, for most neighborhoods of 1, it lies + in the ring of integers. This flag decides if the codomain should be + the same as the input (default) or if it should change to the + fraction field of the input. + + NOTES: + + What some other systems do: + - PARI: Seems to define the logarithm for units not congruent + to 1 as we do. + + - MAGMA: Only implements logarithm for 1-units (as of version 2.19-2) + + ALGORITHM: + + 1. Take the unit part `u` of the input. + + 2. Raise `u` to `p-1` to obtain a 1-unit. + + 3. Write + + .. MATH:: + + u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{2^i}) + + with `0 \leq a_i < p^{2^i}` and compute `\log(1 - a_i p^{2^i})` + using the standard Taylor expansion + + .. MATH:: + + \log(1 - x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots + + together with a binary spliting method. + + 4. Divide the result by ``q-1`` and multiply by ``self.valuation()*log(p)`` + + The complexity of this algorithm is quasi-linear. + + EXAMPLES:: + + sage: Z13 = ZpCA(13, 10) + sage: a = Z13(14); a + 1 + 13 + O(13^10) + sage: a.log() + 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) + + Note that the relative precision decreases when we take log. + Precisely the absolute precision on ``\log(a)`` agrees with the relative + precision on ``a`` thanks to the relation ``d\log(a) = da/a``. + + The logarithm is not only defined for 1-units:: + + sage: R = ZpCA(5,10) + sage: a = R(2) + sage: a.log() + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + + If you want to take the logarithm of a non-unit you must specify either + ``p_branch`` or ``pi_branch`` (observe the precision as well):: + + sage: b = R(5) + sage: b.log() + Traceback (most recent call last): + ... + ValueError: You must specify a branch of the logarithm for non-units + sage: b.log(p_branch=4) + 4 + O(5^9) + sage: c = R(10) + sage: c.log(p_branch=4) + 4 + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + O(5^9) + + The branch parameters are only relevant for elements of non-zero + valuation:: + + sage: a.log(p_branch=0) + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + sage: a.log(p_branch=1) + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + + We illustrate the effect of the precision argument:: + + sage: R = ZpCA(7,10) + sage: x = R(41152263); x + 5 + 3*7^2 + 4*7^3 + 3*7^4 + 5*7^5 + 6*7^6 + 7^9 + O(7^10) + sage: x.log(aprec = 5) + 7 + 3*7^2 + 4*7^3 + 3*7^4 + O(7^5) + sage: x.log(aprec = 7) + 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + O(7^7) + sage: x.log() + 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + 7^7 + 3*7^8 + 4*7^9 + O(7^10) + + The logarithm is not defined for zero:: + + sage: R.zero().log() + Traceback (most recent call last): + ... + ValueError: logarithm is not defined at zero + + TESTS:: + + sage: Z17 = ZpCA(17, 2^20) + sage: a = Z17(18) + sage: b = a.log() # should be rather fast + """ + cdef unsigned long p = self.prime_pow.prime + cdef unsigned long val, prec + cdef pAdicCappedAbsoluteElement ans, unit + + if self.is_zero(): + raise ValueError('logarithm is not defined at zero') + + val = self.valuation_c() + if aprec is None: + prec = self.absprec - val + else: + prec = min(aprec, self.absprec - val) + + ans = self._new_c() + ans.absprec = prec + unit = self.unit_part() + sig_on() + padiclog(ans.value, unit.value, p, prec, self.prime_pow.pow_mpz_t_tmp(prec)) + sig_off() + + if val != 0: + if p_branch is None: + raise ValueError("You must specify a branch of the logarithm for non-units") + ans += val * p_branch + + if not change_frac: + R = self.parent() + if ans.valuation() < 0 and not R.is_field(): + raise ValueError("logarithm is not integral, use change_frac=True to obtain a result in the fraction field") + ans = R(ans) + return ans + + def make_pAdicCappedAbsoluteElement(parent, x, absprec): """ Unpickles a capped absolute element. diff --git a/src/sage/rings/padics/padic_capped_relative_element.pyx b/src/sage/rings/padics/padic_capped_relative_element.pyx index c8bd3159d63..3d2aee8bb72 100644 --- a/src/sage/rings/padics/padic_capped_relative_element.pyx +++ b/src/sage/rings/padics/padic_capped_relative_element.pyx @@ -403,34 +403,21 @@ cdef class pAdicCappedRelativeElement(CRElement): EXAMPLES:: - sage: Z13 = Zp(13, 10) + sage: Z13 = ZpCA(13, 10) sage: a = Z13(14); a 1 + 13 + O(13^10) - - Note that the relative precision decreases when we take log -- it is - the absolute precision that is preserved:: - sage: a.log() 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) + sage: Q13 = Qp(13, 10) sage: a = Q13(14); a 1 + 13 + O(13^10) sage: a.log() 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) - The next few examples illustrate precision when computing `p`-adic - logarithms:: - - sage: R = Zp(5,10) - sage: e = R(389); e - 4 + 2*5 + 3*5^3 + O(5^10) - sage: e.log() - 2*5 + 2*5^2 + 4*5^3 + 3*5^4 + 5^5 + 3*5^7 + 2*5^8 + 4*5^9 + O(5^10) - sage: K = Qp(5,10) - sage: e = K(389); e - 4 + 2*5 + 3*5^3 + O(5^10) - sage: e.log() - 2*5 + 2*5^2 + 4*5^3 + 3*5^4 + 5^5 + 3*5^7 + 2*5^8 + 4*5^9 + O(5^10) + Note that the relative precision decreases when we take log. + Precisely the absolute precision on ``\log(a)`` agrees with the relative + precision on ``a`` thanks to the relation ``d\log(a) = da/a``. The logarithm is not only defined for 1-units:: @@ -461,6 +448,25 @@ cdef class pAdicCappedRelativeElement(CRElement): sage: a.log(p_branch=1) 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + We illustrate the effect of the precision argument:: + + sage: R = Zp(7,10) + sage: x = R(41152263); x + 5 + 3*7^2 + 4*7^3 + 3*7^4 + 5*7^5 + 6*7^6 + 7^9 + O(7^10) + sage: x.log(aprec = 5) + 7 + 3*7^2 + 4*7^3 + 3*7^4 + O(7^5) + sage: x.log(aprec = 7) + 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + O(7^7) + sage: x.log() + 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + 7^7 + 3*7^8 + 4*7^9 + O(7^10) + + The logarithm is not defined for zero:: + + sage: R.zero().log() + Traceback (most recent call last): + ... + ValueError: logarithm is not defined at zero + TESTS:: sage: Z17 = Zp(17, 2^20) @@ -491,9 +497,11 @@ cdef class pAdicCappedRelativeElement(CRElement): raise ValueError("You must specify a branch of the logarithm for non-units") ans += self.valuation() * p_branch - if change_frac: - ans = self.parent().fraction_field()(ans) - + if not change_frac: + R = self.parent() + if ans.valuation() < 0 and not R.is_field(): + raise ValueError("logarithm is not integral, use change_frac=True to obtain a result in the fraction field") + ans = R(ans) return ans def unpickle_pcre_v1(R, unit, ordp, relprec): diff --git a/src/sage/rings/padics/padic_fixed_mod_element.pyx b/src/sage/rings/padics/padic_fixed_mod_element.pyx index f0df5623903..dab98a3dbd4 100644 --- a/src/sage/rings/padics/padic_fixed_mod_element.pyx +++ b/src/sage/rings/padics/padic_fixed_mod_element.pyx @@ -27,6 +27,9 @@ include "FM_template.pxi" from sage.libs.pari.convert_gmp cimport new_gen_from_padic from sage.rings.finite_rings.integer_mod import Mod +cdef extern from "sage/rings/padics/transcendantal.c": + cdef void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, const mpz_t modulo) + cdef class PowComputer_(PowComputer_base): """ A PowComputer for a fixed-modulus padic ring. @@ -354,6 +357,123 @@ cdef class pAdicFixedModElement(FMElement): mpz_clear(tmp) return infinity + def log(self, aprec=None): + r""" + Compute the `p`-adic logarithm of this element. + + The usual power series for the logarithm with values in the additive + group of a `p`-adic ring only converges for 1-units (units congruent to + 1 modulo `p`). However, there is a unique extension of the logarithm + to a homomorphism defined on all the units: If `u = a \cdot v` is a + unit with `v \equiv 1 \pmod{p}` and `a` a Teichmuller representative, + then we define `log(u) = log(v)`. This is the correct extension + because the units `U` split as a product `U = V \times \langle w + \rangle`, where `V` is the subgroup of 1-units and `w` is a fundamental + root of unity. The `\langle w \rangle` factor is torsion, so must go + to 0 under any homomorphism to the fraction field, which is a torsion + free group. + + INPUT: + + - ``aprec`` -- an integer or ``None`` (default: ``None``) if not + ``None``, then the result will only be correct to precision + ``aprec``. + + NOTES: + + What some other systems do: + + - PARI: Seems to define the logarithm for units not congruent + to 1 as we do. + + - MAGMA: Only implements logarithm for 1-units (as of version 2.19-2) + + ALGORITHM: + + 1. Take the unit part `u` of the input. + + 2. Raise `u` to `p-1` to obtain a 1-unit. + + 3. Write + + .. MATH:: + + u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{2^i}) + + with `0 \leq a_i < p^{2^i}` and compute `\log(1 - a_i p^{2^i})` + using the standard Taylor expansion + + .. MATH:: + + \log(1 - x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots + + together with a binary spliting method. + + 4. Divide the result by ``q-1`` and multiply by ``self.valuation()*log(p)`` + + The complexity of this algorithm is quasi-linear. + + EXAMPLES:: + + sage: Z13 = ZpFM(13, 10) + sage: a = Z13(14); a + 1 + 13 + O(13^10) + sage: a.log() + 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) + + The logarithm is not only defined for 1-units:: + + sage: R = ZpFM(5,10) + sage: a = R(2) + sage: a.log() + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + + However, note that the logarithm is not defined for non-units in the fixed + modulus framework. The reason is that the absolute precision decreases when + taking a logarithm of a non-unit:: + + sage: R = ZpFM(5,10) + sage: a = 5 * R.random_element() + sage: a.log() + Traceback (most recent call last): + ... + ValueError: Logarithm of non-units are not defined in the fixed modulus framework + + We illustrate the behaviour of ``aprec``:: + + sage: R = ZpFM(7,10) + sage: x = R(41152263); x + 5 + 3*7^2 + 4*7^3 + 3*7^4 + 5*7^5 + 6*7^6 + 7^9 + O(7^10) + sage: x.log(aprec = 5) + 7 + 3*7^2 + 4*7^3 + 3*7^4 + O(7^10) + sage: x.log(aprec = 7) + 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + O(7^10) + sage: x.log() + 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + 7^7 + 3*7^8 + 4*7^9 + O(7^10) + + TESTS:: + + sage: Z17 = ZpFM(17, 2^20) + sage: a = Z17(18) + sage: b = a.log() # should be rather fast + """ + cdef unsigned long p = self.prime_pow.prime + cdef unsigned long prec + cdef pAdicFixedModElement ans + val = self.valuation_c() + if val > 0: + raise ValueError('Logarithm of non-units are not defined in the fixed modulus framework') + ans = self._new_c() + if aprec is None: + prec = self.prime_pow.prec_cap + else: + prec = min(aprec, self.prime_pow.prec_cap) + sig_on() + padiclog(ans.value, self.value, p, prec, self.prime_pow.pow_mpz_t_tmp(prec)) + sig_off() + return ans + + def make_pAdicFixedModElement(parent, value): """ Unpickles a fixed modulus element. diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 8fa3c441f79..1be79e5d07a 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -1722,31 +1722,18 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: Z13 = Zp(13, 10) sage: a = Z13(14); a 1 + 13 + O(13^10) - - Note that the relative precision decreases when we take log -- it is - the absolute precision that is preserved:: - sage: a.log() 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) + sage: Q13 = Qp(13, 10) sage: a = Q13(14); a 1 + 13 + O(13^10) sage: a.log() 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) - The next few examples illustrate precision when computing `p`-adic - logarithms:: - - sage: R = Zp(5,10) - sage: e = R(389); e - 4 + 2*5 + 3*5^3 + O(5^10) - sage: e.log() - 2*5 + 2*5^2 + 4*5^3 + 3*5^4 + 5^5 + 3*5^7 + 2*5^8 + 4*5^9 + O(5^10) - sage: K = Qp(5,10) - sage: e = K(389); e - 4 + 2*5 + 3*5^3 + O(5^10) - sage: e.log() - 2*5 + 2*5^2 + 4*5^3 + 3*5^4 + 5^5 + 3*5^7 + 2*5^8 + 4*5^9 + O(5^10) + Note that the relative precision decreases when we take log. + Precisely the absolute precision on ``\log(a)`` agrees with the relative + precision on ``a`` thanks to the relation ``d\log(a) = da/a``. The logarithm is not only defined for 1-units:: From 33817875c41e8e182da9a7e911d7fad8562cd2ae Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Sun, 28 May 2017 00:08:57 +0200 Subject: [PATCH 053/126] Small optimization --- src/sage/rings/padics/transcendantal.c | 74 ++++++++++++++------------ 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/src/sage/rings/padics/transcendantal.c b/src/sage/rings/padics/transcendantal.c index 97b40b40e2f..e72fd992b66 100644 --- a/src/sage/rings/padics/transcendantal.c +++ b/src/sage/rings/padics/transcendantal.c @@ -65,44 +65,50 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con /* We compute f = 1 - a_i*p^(2^i) trunc_mod is p^(2^(i+1)) */ mpz_fdiv_r(f, arg, trunc_mod); - mpz_ui_sub(f, 2, f); - mpz_mul(arg, arg, f); - - /* We compute the Taylor expansion of log(f) - For now, computations are carried out over the rationals */ - for (i = 0; i < N; i++) { - mpz_set_ui(num[i], 1); - mpz_set_ui(denom[i], i+1); - } - step = 1; - mpz_ui_sub(h, 1, f); // we write f = 1 - h, i.e. h = a_i*p^(2^i) - mpz_set(hpow, h); - while(step < N) { - for (i = 0; i < N - step; i += step << 1) { - mpz_mul(mpz_tmp, hpow, num[i+step]); - mpz_mul(mpz_tmp, mpz_tmp, denom[i]); - mpz_mul(num[i], num[i], denom[i+step]); - mpz_add(num[i], num[i], mpz_tmp); - mpz_mul(denom[i], denom[i], denom[i+step]); + + if (mpz_cmp_ui(f, 1) != 0) { + + mpz_ui_sub(f, 2, f); + mpz_mul(arg, arg, f); + + /* We compute the Taylor expansion of log(f) + For now, computations are carried out over the rationals */ + for (i = 0; i < N; i++) { + mpz_set_ui(num[i], 1); + mpz_set_ui(denom[i], i+1); } - step <<= 1; - mpz_mul(hpow, hpow, hpow); - } + step = 1; + mpz_ui_sub(h, 1, f); // we write f = 1 - h, i.e. h = a_i*p^(2^i) + mpz_set(hpow, h); + while(step < N) { + for (i = 0; i < N - step; i += step << 1) { + mpz_mul(mpz_tmp, hpow, num[i+step]); + mpz_mul(mpz_tmp, mpz_tmp, denom[i]); + mpz_mul(num[i], num[i], denom[i+step]); + mpz_add(num[i], num[i], mpz_tmp); + mpz_mul(denom[i], denom[i], denom[i+step]); + } + step <<= 1; + mpz_mul(hpow, hpow, hpow); + } + + /* We simplify the fraction */ + Np = N; tmp = 0; + while(Np > 0) { Np /= p; tmp += Np; } + mpz_ui_pow_ui(d, p, tmp); + mpz_divexact(mpz_tmp, num[0], d); + mpz_divexact(denom[0], denom[0], d); - /* We compute the p-adic valuation of the denominateur (which is N!) */ - Np = N; tmp = 0; - while(Np > 0) { Np /= p; tmp += Np; } - mpz_ui_pow_ui(d, p, tmp); - mpz_divexact(mpz_tmp, num[0], d); - mpz_mul(mpz_tmp, h, mpz_tmp); + mpz_mul(mpz_tmp, h, mpz_tmp); - /* We coerce the result from Q to Zp */ - mpz_divexact(denom[0], denom[0], d); - mpz_gcdext(d, inv, NULL, denom[0], modulo); - mpz_mul(mpz_tmp, mpz_tmp, inv); + /* We coerce the result from Q to Zp */ + mpz_gcdext(d, inv, NULL, denom[0], modulo); + mpz_mul(mpz_tmp, mpz_tmp, inv); - /* We add this contribution to log(f) */ - mpz_add(ans, ans, mpz_tmp); + /* We add this contribution to log(f) */ + mpz_add(ans, ans, mpz_tmp); + + } if (trunc > prec) break; From a53027ed368efbce43b8956e5d60782dc797895c Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Mon, 29 May 2017 14:13:47 +0000 Subject: [PATCH 054/126] New JSON format for the package installed stamp files --- build/bin/sage-spkg | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/build/bin/sage-spkg b/build/bin/sage-spkg index c7e29d04fd5..f8d1a646dac 100755 --- a/build/bin/sage-spkg +++ b/build/bin/sage-spkg @@ -786,13 +786,16 @@ fi # Mark that the new package has been installed (and tested, if # applicable). PKG_NAME_INSTALLED="$SAGE_SPKG_INST/$PKG_NAME" -echo "PACKAGE NAME: $PKG_NAME" > "$PKG_NAME_INSTALLED" -echo "INSTALL DATE: `date`" >> "$PKG_NAME_INSTALLED" -echo "UNAME: `uname -a`" >> "$PKG_NAME_INSTALLED" -if [ -n "$TEST_SUITE_RESULT" ]; then - echo "TEST SUITE: $TEST_SUITE_RESULT" >> "$PKG_NAME_INSTALLED" -fi -cat "$SAGE_ROOT/VERSION.txt" >> "$PKG_NAME_INSTALLED" +cat > "$PKG_NAME_INSTALLED" << __EOF__ +{ + "package_name": "$PKG_BASE", + "package_version": "$PKG_VER", + "install_date": "$(date)", + "system_uname": "$(uname -a)", + "sage_version": "$(cat "${SAGE_ROOT}/VERSION.txt")", + "test_result": "$TEST_SUITE_RESULT" +} +__EOF__ ################################################################## From e27bc950f22b2cd160de14fa57b1da23de7e6944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 29 May 2017 22:27:19 +0200 Subject: [PATCH 055/126] setting the genus for elliptic curves over fields --- src/sage/schemes/elliptic_curves/ell_field.py | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 47958639a00..c30994653b8 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -3,10 +3,7 @@ This module defines the class ``EllipticCurve_field``, based on ``EllipticCurve_generic``, for elliptic curves over general fields. - """ -from __future__ import absolute_import - #***************************************************************************** # Copyright (C) 2006 William Stein # @@ -14,6 +11,7 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** +from __future__ import absolute_import from . import ell_generic import sage.rings.all as rings @@ -40,6 +38,23 @@ class EllipticCurve_field(ell_generic.EllipticCurve_generic): # j=0=1728, but I have never worked them out or seen them used! # + def genus(self): + """ + Return 1 for elliptic curves. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(3), [0, -1, 0, -346, 2652]) + sage: E.genus() + 1 + + sage: R = FractionField(QQ['z']) + sage: E = EllipticCurve(R, [0, -1, 0, -346, 2652]) + sage: E.genus() + 1 + """ + return rings.ZZ.one() + r""" Twists: rewritten by John Cremona as follows: @@ -755,7 +770,7 @@ def descend_to(self, K, f=None): def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True): r""" - Returns an elliptic curve isogeny from self. + Return an elliptic curve isogeny from self. The isogeny can be determined in two ways, either by a polynomial or a set of torsion points. The methods used are: @@ -868,7 +883,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True): def isogeny_codomain(self, kernel, degree=None): r""" - Returns the codomain of the isogeny from self with given + Return the codomain of the isogeny from self with given kernel. INPUT: @@ -1031,7 +1046,7 @@ def isogenies_prime_degree(self, l=None, max_l=31): def is_isogenous(self, other, field=None): """ - Returns whether or not self is isogenous to other. + Return whether or not self is isogenous to other. INPUT: @@ -1122,7 +1137,7 @@ def weierstrass_p(self, prec=20, algorithm=None): def hasse_invariant(self): r""" - Returns the Hasse invariant of this elliptic curve. + Return the Hasse invariant of this elliptic curve. OUTPUT: From 256bf191ab0472303bb11e105a246106e894c4ec Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Tue, 30 May 2017 10:53:27 +0200 Subject: [PATCH 056/126] Move richcmp stuff to new file richcmp.pyx --- src/doc/en/reference/structure/index.rst | 1 + .../coercion_and_categories.rst | 4 +- .../finite_dimensional_algebra_ideal.py | 4 +- src/sage/algebras/free_algebra_element.py | 2 +- .../algebras/free_algebra_quotient_element.py | 2 +- .../lie_algebras/lie_algebra_element.pyx | 2 +- src/sage/algebras/weyl_algebra.py | 2 +- src/sage/categories/morphism.pyx | 2 +- src/sage/combinat/alternating_sign_matrix.py | 2 +- src/sage/combinat/constellation.py | 22 ++- src/sage/combinat/crystals/affine.py | 2 +- src/sage/combinat/crystals/affinization.py | 2 +- src/sage/combinat/crystals/alcove_path.py | 2 +- src/sage/combinat/crystals/fast_crystals.py | 2 +- src/sage/combinat/crystals/pbw_crystal.py | 2 +- src/sage/combinat/crystals/subcrystal.py | 2 +- src/sage/combinat/fully_packed_loop.py | 2 +- src/sage/combinat/interval_posets.py | 2 +- .../rigged_configurations/kleber_tree.py | 2 +- src/sage/combinat/root_system/weyl_group.py | 2 +- src/sage/combinat/words/word_char.pyx | 2 +- src/sage/crypto/mq/sr.py | 2 +- .../bounded_integer_sequences.pyx | 2 +- src/sage/ext/fast_eval.pyx | 2 +- .../hyperbolic_space/hyperbolic_point.py | 2 +- src/sage/geometry/linear_expression.py | 2 +- src/sage/geometry/newton_polygon.py | 2 +- src/sage/geometry/point_collection.pyx | 2 +- src/sage/geometry/toric_lattice_element.pyx | 2 +- src/sage/groups/braid.py | 2 +- src/sage/groups/libgap_wrapper.pyx | 2 +- src/sage/groups/matrix_gps/group_element.pyx | 2 +- .../groups/perm_gps/permgroup_element.pyx | 2 +- src/sage/homology/hochschild_complex.py | 2 +- src/sage/libs/singular/function.pyx | 3 +- src/sage/libs/singular/groebner_strategy.pyx | 2 +- src/sage/matrix/matrix_dense.pyx | 2 +- src/sage/matrix/matrix_sparse.pyx | 2 +- src/sage/misc/constant_function.pyx | 14 +- .../modular/arithgroup/arithgroup_element.pyx | 2 +- src/sage/modular/arithgroup/farey_symbol.pyx | 2 +- .../modular/btquotients/pautomorphicform.py | 2 +- src/sage/modular/cusps.py | 2 +- src/sage/modular/cusps_nf.py | 2 +- src/sage/modular/dirichlet.py | 2 +- src/sage/modular/hecke/element.py | 2 +- .../graded_ring_element.py | 2 +- src/sage/modular/modsym/manin_symbol.pyx | 2 +- src/sage/modular/pollack_stevens/dist.pyx | 4 +- src/sage/modular/pollack_stevens/modsym.py | 2 +- src/sage/modular/pollack_stevens/sigma0.py | 2 +- src/sage/modules/fg_pid/fgp_element.py | 2 +- src/sage/modules/free_module_element.pyx | 2 +- .../modules/with_basis/indexed_element.pyx | 2 +- src/sage/modules/with_basis/morphism.py | 2 +- .../monoids/free_abelian_monoid_element.py | 2 +- src/sage/monoids/indexed_free_monoid.py | 2 +- src/sage/monoids/string_monoid_element.py | 2 +- src/sage/quivers/algebra_elements.pxi | 2 +- src/sage/quivers/algebra_elements.pyx | 2 +- src/sage/quivers/paths.pyx | 2 +- src/sage/rings/asymptotic/misc.py | 2 +- src/sage/rings/complex_double.pyx | 2 +- src/sage/rings/complex_mpc.pyx | 2 +- .../rings/finite_rings/element_givaro.pyx | 3 +- .../rings/finite_rings/element_ntl_gf2e.pyx | 5 +- src/sage/rings/finite_rings/residue_field.pyx | 2 +- src/sage/rings/fraction_field_element.pyx | 2 +- .../function_field/function_field_element.pyx | 2 +- src/sage/rings/integer.pyx | 3 +- src/sage/rings/integer_ring.pyx | 2 +- .../rings/laurent_series_ring_element.pyx | 2 +- src/sage/rings/morphism.pyx | 4 +- .../rings/multi_power_series_ring_element.py | 2 +- .../number_field/number_field_element.pyx | 2 +- .../number_field_element_quadratic.pyx | 2 +- src/sage/rings/padics/morphism.pyx | 4 +- src/sage/rings/padics/padic_base_leaves.py | 2 +- .../rings/padics/padic_extension_generic.py | 2 +- src/sage/rings/padics/padic_printing.pyx | 2 +- src/sage/rings/padics/pow_computer.pyx | 2 +- src/sage/rings/padics/pow_computer_flint.pyx | 2 +- .../rings/polynomial/laurent_polynomial.pyx | 2 +- .../multi_polynomial_libsingular.pyx | 2 +- .../multi_polynomial_ring_generic.pyx | 2 +- src/sage/rings/polynomial/pbori.pyx | 2 +- .../rings/polynomial/polynomial_element.pyx | 2 +- .../polynomial/polynomial_element_generic.py | 4 +- .../rings/polynomial/polynomial_template.pxi | 2 +- .../rings/polynomial/symmetric_reduction.pyx | 2 +- src/sage/rings/power_series_ring_element.pyx | 2 +- src/sage/rings/qqbar.py | 9 +- src/sage/rings/real_double.pyx | 2 +- src/sage/rings/real_lazy.pyx | 2 +- src/sage/rings/real_mpfi.pyx | 2 +- src/sage/rings/real_mpfr.pyx | 2 +- src/sage/rings/universal_cyclotomic_field.py | 2 +- .../elliptic_curves/ell_curve_isogeny.py | 2 +- src/sage/schemes/elliptic_curves/ell_point.py | 2 +- src/sage/schemes/generic/morphism.py | 2 +- src/sage/schemes/generic/point.py | 2 +- src/sage/schemes/product_projective/point.py | 2 +- .../schemes/projective/projective_point.py | 2 +- src/sage/schemes/toric/morphism.py | 2 +- src/sage/structure/coerce.pyx | 5 +- src/sage/structure/element.pyx | 4 +- src/sage/structure/list_clone.pyx | 2 +- src/sage/structure/parent.pyx | 3 +- src/sage/structure/richcmp.pxd | 146 ++++++++++++++++ src/sage/structure/richcmp.pyx | 89 ++++++++++ src/sage/structure/sage_object.pxd | 159 ------------------ src/sage/structure/sage_object.pyx | 65 +++++-- src/sage/symbolic/function.pyx | 2 +- src/sage/tests/stl_vector.pyx | 2 +- 114 files changed, 440 insertions(+), 301 deletions(-) create mode 100644 src/sage/structure/richcmp.pxd create mode 100644 src/sage/structure/richcmp.pyx diff --git a/src/doc/en/reference/structure/index.rst b/src/doc/en/reference/structure/index.rst index 8bbbdf03f71..a24b48183a6 100644 --- a/src/doc/en/reference/structure/index.rst +++ b/src/doc/en/reference/structure/index.rst @@ -74,6 +74,7 @@ Utilities .. toctree:: :maxdepth: 1 + sage/structure/richcmp sage/structure/unique_representation sage/structure/factory sage/structure/dynamic_class diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 8cbbe2ea643..6b4c5468816 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -367,7 +367,7 @@ This gives rise to the following code:: ....: def _repr_(self): ....: return "(%s):(%s)"%(self.n,self.d) ....: def _richcmp_(self, other, op): - ....: from sage.structure.sage_object import richcmp + ....: from sage.structure.richcmp import richcmp ....: return richcmp(self.n*other.denominator(), other.numerator()*self.d, op) ....: def _add_(self, other): ....: C = self.__class__ @@ -1858,7 +1858,7 @@ Appendix: The complete code # are allowed to use the denominator() and numerator() methods # on the second argument. def _richcmp_(self, other, op): - from sage.structure.sage_object import richcmp + from sage.structure.richcmp import richcmp return richcmp(self.n*other.denominator(), other.numerator()*self.d, op) # Arithmetic methods, single underscore. We can assume that both diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py index 52969d597ff..f2541a0538d 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_ideal.py @@ -24,8 +24,8 @@ from sage.misc.cachefunc import cached_method from functools import reduce -from sage.structure.sage_object import (op_LT, op_LE, op_EQ, op_NE, - op_GT, op_GE) +from sage.structure.richcmp import (op_LT, op_LE, op_EQ, op_NE, + op_GT, op_GE) class FiniteDimensionalAlgebraIdeal(Ideal_generic): diff --git a/src/sage/algebras/free_algebra_element.py b/src/sage/algebras/free_algebra_element.py index b719b53b733..9aaa39fa91a 100644 --- a/src/sage/algebras/free_algebra_element.py +++ b/src/sage/algebras/free_algebra_element.py @@ -40,7 +40,7 @@ from sage.modules.with_basis.indexed_element import IndexedFreeModuleElement from sage.combinat.free_module import CombinatorialFreeModule from sage.structure.element import AlgebraElement -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp import six diff --git a/src/sage/algebras/free_algebra_quotient_element.py b/src/sage/algebras/free_algebra_quotient_element.py index 441670da879..a44d42e8f85 100644 --- a/src/sage/algebras/free_algebra_quotient_element.py +++ b/src/sage/algebras/free_algebra_quotient_element.py @@ -26,7 +26,7 @@ from sage.misc.misc import repr_lincomb from sage.structure.element import RingElement, AlgebraElement from sage.structure.parent_gens import localvars -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.rings.integer import Integer from sage.modules.free_module_element import FreeModuleElement from sage.monoids.free_monoid_element import FreeMonoidElement diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx index 1162172fd3b..7f7a0ecc102 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -24,7 +24,7 @@ from sage.misc.misc import repr_lincomb from sage.combinat.free_module import CombinatorialFreeModule from sage.structure.element cimport have_same_parent, coercion_model, parent from sage.structure.element_wrapper cimport ElementWrapper -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp from sage.data_structures.blas_dict cimport axpy, negate, scal # TODO: Inherit from IndexedFreeModuleElement and make cdef once #22632 is merged diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index daafa6d8eff..da118c0e357 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -18,7 +18,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.latex import latex -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.structure.element import AlgebraElement from sage.structure.unique_representation import UniqueRepresentation from copy import copy diff --git a/src/sage/categories/morphism.pyx b/src/sage/categories/morphism.pyx index eae6483ce5f..c449ba44051 100644 --- a/src/sage/categories/morphism.pyx +++ b/src/sage/categories/morphism.pyx @@ -29,7 +29,7 @@ import operator import homset from sage.structure.element cimport Element -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool def is_Morphism(x): return isinstance(x, Morphism) diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 3cafa2ddf44..7261164c60b 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -40,7 +40,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import Element -from sage.structure.sage_object import op_NE, richcmp +from sage.structure.richcmp import op_NE, richcmp from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix diff --git a/src/sage/combinat/constellation.py b/src/sage/combinat/constellation.py index fc45e5e5f87..b7e5c79e6f1 100644 --- a/src/sage/combinat/constellation.py +++ b/src/sage/combinat/constellation.py @@ -41,14 +41,18 @@ .. [LaZv04] S. Lando and A. Zvonkine, "Graphs on surfaces and their applications", Springer-Verlag, 2004. """ -# ************************************************************************* -# Copyright (C) 2015-2016 Vincent Delecroix <20100.delecroix@gmail.com> -# Frederic Chapoton -# -# Distributed under the terms of the GNU General Public License (GPL) + +#***************************************************************************** +# Copyright (C) 2015-2016 Vincent Delecroix <20100.delecroix@gmail.com> +# Frederic Chapoton # -# The full text of the GPL is available at http://www.gnu.org/licenses/ -# ************************************************************************* +# 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 six.moves import range from six import integer_types @@ -56,8 +60,8 @@ from sage.structure.parent import Parent from sage.structure.element import Element from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.sage_object import (op_NE, op_EQ, richcmp_not_equal, - rich_to_bool) +from sage.structure.richcmp import (op_NE, op_EQ, richcmp_not_equal, + rich_to_bool) from sage.groups.perm_gps.permgroup_named import SymmetricGroup from sage.rings.integer import Integer diff --git a/src/sage/combinat/crystals/affine.py b/src/sage/combinat/crystals/affine.py index 286784f5174..ff18f2801d5 100644 --- a/src/sage/combinat/crystals/affine.py +++ b/src/sage/combinat/crystals/affine.py @@ -19,7 +19,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper from sage.combinat.root_system.cartan_type import CartanType -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp class AffineCrystalFromClassical(UniqueRepresentation, Parent): diff --git a/src/sage/combinat/crystals/affinization.py b/src/sage/combinat/crystals/affinization.py index e1dbce27e3b..e89f37ff8c1 100644 --- a/src/sage/combinat/crystals/affinization.py +++ b/src/sage/combinat/crystals/affinization.py @@ -21,7 +21,7 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element import Element -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.categories.regular_crystals import RegularCrystals from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.rings.infinity import Infinity diff --git a/src/sage/combinat/crystals/alcove_path.py b/src/sage/combinat/crystals/alcove_path.py index 3a766a82c72..6baeae9166d 100644 --- a/src/sage/combinat/crystals/alcove_path.py +++ b/src/sage/combinat/crystals/alcove_path.py @@ -27,7 +27,7 @@ from sage.structure.element import Element from sage.structure.element_wrapper import ElementWrapper from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.categories.finite_crystals import FiniteCrystals from sage.categories.classical_crystals import ClassicalCrystals from sage.categories.loop_crystals import LoopCrystals diff --git a/src/sage/combinat/crystals/fast_crystals.py b/src/sage/combinat/crystals/fast_crystals.py index 6e1976cb8ff..c007c4dbd39 100644 --- a/src/sage/combinat/crystals/fast_crystals.py +++ b/src/sage/combinat/crystals/fast_crystals.py @@ -25,7 +25,7 @@ from sage.categories.classical_crystals import ClassicalCrystals from sage.structure.element import Element, parent from sage.combinat.root_system.cartan_type import CartanType -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp class FastCrystal(UniqueRepresentation, Parent): diff --git a/src/sage/combinat/crystals/pbw_crystal.py b/src/sage/combinat/crystals/pbw_crystal.py index 4edb3576587..42467d2e85c 100644 --- a/src/sage/combinat/crystals/pbw_crystal.py +++ b/src/sage/combinat/crystals/pbw_crystal.py @@ -26,7 +26,7 @@ from sage.structure.element import Element from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.categories.highest_weight_crystals import HighestWeightCrystals from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.combinat.root_system.cartan_type import CartanType diff --git a/src/sage/combinat/crystals/subcrystal.py b/src/sage/combinat/crystals/subcrystal.py index 476fa40907c..c1bfd52854f 100644 --- a/src/sage/combinat/crystals/subcrystal.py +++ b/src/sage/combinat/crystals/subcrystal.py @@ -33,7 +33,7 @@ from sage.combinat.root_system.cartan_type import CartanType from sage.rings.integer import Integer from sage.rings.infinity import infinity -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp class Subcrystal(UniqueRepresentation, Parent): diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index 956059f72fb..b39ab4fde01 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -9,7 +9,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import Element -from sage.structure.sage_object import op_EQ, op_NE +from sage.structure.richcmp import op_EQ, op_NE from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.six_vertex_model import (SquareIceModel, diff --git a/src/sage/combinat/interval_posets.py b/src/sage/combinat/interval_posets.py index 20dc94d26fa..fcd2d254fb9 100644 --- a/src/sage/combinat/interval_posets.py +++ b/src/sage/combinat/interval_posets.py @@ -84,7 +84,7 @@ from sage.structure.element import Element from sage.structure.global_options import GlobalOptions from sage.structure.parent import Parent -from sage.structure.sage_object import op_NE, op_EQ, op_LT, op_LE, op_GT, op_GE +from sage.structure.richcmp import op_NE, op_EQ, op_LT, op_LE, op_GT, op_GE from sage.structure.unique_representation import UniqueRepresentation from sage.graphs.digraph import DiGraph diff --git a/src/sage/combinat/rigged_configurations/kleber_tree.py b/src/sage/combinat/rigged_configurations/kleber_tree.py index eedd0ad9d54..abb7dfe554e 100644 --- a/src/sage/combinat/rigged_configurations/kleber_tree.py +++ b/src/sage/combinat/rigged_configurations/kleber_tree.py @@ -78,7 +78,7 @@ from sage.structure.parent import Parent from sage.structure.element import Element from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.sage_object import richcmp_not_equal, richcmp +from sage.structure.richcmp import richcmp_not_equal, richcmp from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.modules.free_module import FreeModule diff --git a/src/sage/combinat/root_system/weyl_group.py b/src/sage/combinat/root_system/weyl_group.py index d00fb12dc27..4ae3ca7baf0 100644 --- a/src/sage/combinat/root_system/weyl_group.py +++ b/src/sage/combinat/root_system/weyl_group.py @@ -49,7 +49,7 @@ from sage.matrix.constructor import matrix, diagonal_matrix from sage.combinat.root_system.root_lattice_realizations import RootLatticeRealizations from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.sage_object import richcmp, richcmp_not_equal +from sage.structure.richcmp import richcmp, richcmp_not_equal from sage.categories.all import WeylGroups, FiniteWeylGroups, AffineWeylGroups from sage.categories.permutation_groups import PermutationGroups from sage.sets.family import Family diff --git a/src/sage/combinat/words/word_char.pyx b/src/sage/combinat/words/word_char.pyx index 9506db034b1..5b5b98adf81 100644 --- a/src/sage/combinat/words/word_char.pyx +++ b/src/sage/combinat/words/word_char.pyx @@ -22,7 +22,7 @@ from sage.rings.integer cimport Integer, smallInteger from sage.rings.rational cimport Rational from libc.string cimport memcpy, memcmp from sage.combinat.words.word_datatypes cimport WordDatatype -from sage.structure.sage_object cimport rich_to_bool +from sage.structure.richcmp cimport rich_to_bool from cpython.number cimport PyIndex_Check, PyNumber_Check from cpython.sequence cimport PySequence_Check diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index d9df6818912..c9f8ac41410 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -326,7 +326,7 @@ from .mpolynomialsystemgenerator import MPolynomialSystemGenerator from sage.rings.polynomial.term_order import TermOrder -from sage.structure.sage_object import richcmp_not_equal, rich_to_bool, op_LT +from sage.structure.richcmp import richcmp_not_equal, rich_to_bool, op_LT def SR(n=1, r=1, c=1, e=4, star=False, **kwargs): diff --git a/src/sage/data_structures/bounded_integer_sequences.pyx b/src/sage/data_structures/bounded_integer_sequences.pyx index a03836f2787..0f7b3873cec 100644 --- a/src/sage/data_structures/bounded_integer_sequences.pyx +++ b/src/sage/data_structures/bounded_integer_sequences.pyx @@ -115,7 +115,7 @@ from cpython.int cimport PyInt_FromSize_t from cpython.slice cimport PySlice_GetIndicesEx from sage.libs.gmp.mpn cimport mpn_rshift, mpn_lshift, mpn_copyi, mpn_ior_n, mpn_zero, mpn_copyd, mpn_cmp from sage.libs.flint.flint cimport FLINT_BIT_COUNT as BIT_COUNT -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool cimport cython diff --git a/src/sage/ext/fast_eval.pyx b/src/sage/ext/fast_eval.pyx index 6513ac991bb..b10d130134b 100644 --- a/src/sage/ext/fast_eval.pyx +++ b/src/sage/ext/fast_eval.pyx @@ -89,7 +89,7 @@ AUTHORS: from sage.ext.fast_callable import fast_callable, Wrapper -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool include "cysignals/memory.pxi" diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py index c18ecc4a327..f2b862fa448 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_point.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_point.py @@ -61,7 +61,7 @@ #*********************************************************************** from sage.structure.element import Element -from sage.structure.sage_object import richcmp, op_NE +from sage.structure.richcmp import richcmp, op_NE from sage.symbolic.all import I from sage.misc.latex import latex from sage.matrix.matrix import is_Matrix diff --git a/src/sage/geometry/linear_expression.py b/src/sage/geometry/linear_expression.py index 50b2c74e270..5a93e06f6eb 100644 --- a/src/sage/geometry/linear_expression.py +++ b/src/sage/geometry/linear_expression.py @@ -39,7 +39,7 @@ from six.moves import zip from sage.structure.parent import Parent -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.structure.element import ModuleElement from sage.structure.unique_representation import UniqueRepresentation from sage.misc.cachefunc import cached_method diff --git a/src/sage/geometry/newton_polygon.py b/src/sage/geometry/newton_polygon.py index d8755fadca5..795692b10bf 100644 --- a/src/sage/geometry/newton_polygon.py +++ b/src/sage/geometry/newton_polygon.py @@ -17,7 +17,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import Element -from sage.structure.sage_object import op_EQ, op_NE, op_LE, op_GE, op_LT +from sage.structure.richcmp import op_EQ, op_NE, op_LE, op_GE, op_LT from sage.misc.cachefunc import cached_method from sage.rings.infinity import Infinity diff --git a/src/sage/geometry/point_collection.pyx b/src/sage/geometry/point_collection.pyx index c901159e462..b0df2f0a541 100644 --- a/src/sage/geometry/point_collection.pyx +++ b/src/sage/geometry/point_collection.pyx @@ -78,7 +78,7 @@ need to spend time and memory four times. from __future__ import print_function from sage.structure.sage_object cimport SageObject -from sage.structure.sage_object cimport richcmp_not_equal, richcmp +from sage.structure.richcmp cimport richcmp_not_equal, richcmp from sage.matrix.all import matrix from sage.misc.all import latex diff --git a/src/sage/geometry/toric_lattice_element.pyx b/src/sage/geometry/toric_lattice_element.pyx index 910edcb8f17..1ca5187e4e3 100644 --- a/src/sage/geometry/toric_lattice_element.pyx +++ b/src/sage/geometry/toric_lattice_element.pyx @@ -101,7 +101,7 @@ from sage.modules.vector_integer_dense cimport Vector_integer_dense from sage.structure.coerce_exceptions import CoercionException from sage.structure.element cimport Element, Vector from sage.rings.integer cimport Integer -from sage.structure.sage_object cimport richcmp_not_equal, richcmp +from sage.structure.richcmp cimport richcmp_not_equal, richcmp def is_ToricLatticeElement(x): diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 4416858946c..fa2639ba424 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -76,7 +76,7 @@ from sage.sets.set import Set from sage.groups.finitely_presented import FinitelyPresentedGroup, FinitelyPresentedGroupElement from sage.misc.package import PackageNotFoundError -from sage.structure.sage_object import richcmp, rich_to_bool +from sage.structure.richcmp import richcmp, rich_to_bool class Braid(FinitelyPresentedGroupElement): diff --git a/src/sage/groups/libgap_wrapper.pyx b/src/sage/groups/libgap_wrapper.pyx index f31236bf74d..8f76df86089 100644 --- a/src/sage/groups/libgap_wrapper.pyx +++ b/src/sage/groups/libgap_wrapper.pyx @@ -65,7 +65,7 @@ from sage.rings.integer_ring import IntegerRing from sage.misc.cachefunc import cached_method from sage.structure.sage_object import SageObject from sage.structure.element cimport Element -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp class ParentLibGAP(SageObject): diff --git a/src/sage/groups/matrix_gps/group_element.pyx b/src/sage/groups/matrix_gps/group_element.pyx index 6dec90b407a..dca3f3ff963 100644 --- a/src/sage/groups/matrix_gps/group_element.pyx +++ b/src/sage/groups/matrix_gps/group_element.pyx @@ -78,7 +78,7 @@ from __future__ import print_function from sage.structure.element cimport MultiplicativeGroupElement, Element, MonoidElement, Matrix from sage.structure.parent cimport Parent -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp from sage.libs.gap.element cimport GapElement, GapElement_List from sage.groups.libgap_wrapper cimport ElementLibGAP diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 4e91c4b23bf..9337c45f7ec 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -75,7 +75,7 @@ from sage.interfaces.all import gap from sage.interfaces.gap import is_GapElement from sage.sets.finite_enumerated_set import FiniteEnumeratedSet import sage.structure.coerce as coerce -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool import operator diff --git a/src/sage/homology/hochschild_complex.py b/src/sage/homology/hochschild_complex.py index bd5f04b703a..e463db7179b 100644 --- a/src/sage/homology/hochschild_complex.py +++ b/src/sage/homology/hochschild_complex.py @@ -16,7 +16,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent from sage.structure.element import ModuleElement, parent -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.categories.category_types import ChainComplexes from sage.categories.tensor import tensor from sage.combinat.free_module import CombinatorialFreeModule diff --git a/src/sage/libs/singular/function.pyx b/src/sage/libs/singular/function.pyx index d0c13b8d4cf..79c9aa77bf1 100644 --- a/src/sage/libs/singular/function.pyx +++ b/src/sage/libs/singular/function.pyx @@ -80,7 +80,8 @@ from libc.string cimport memcpy include "cysignals/signals.pxi" -from sage.structure.sage_object cimport SageObject, richcmp +from sage.structure.sage_object cimport SageObject +from sage.structure.richcmp cimport richcmp from sage.rings.integer cimport Integer diff --git a/src/sage/libs/singular/groebner_strategy.pyx b/src/sage/libs/singular/groebner_strategy.pyx index 62e002d6302..4810d3f6565 100644 --- a/src/sage/libs/singular/groebner_strategy.pyx +++ b/src/sage/libs/singular/groebner_strategy.pyx @@ -21,7 +21,7 @@ cdef extern from *: # hack to get at cython macro int unlikely(int) int likely(int) -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp from sage.libs.singular.decl cimport ideal, ring, poly, currRing from sage.libs.singular.decl cimport rChangeCurrRing from sage.libs.singular.decl cimport new_skStrategy, delete_skStrategy, id_RankFreeModule diff --git a/src/sage/matrix/matrix_dense.pyx b/src/sage/matrix/matrix_dense.pyx index 7f71a383565..0a6b864c665 100644 --- a/src/sage/matrix/matrix_dense.pyx +++ b/src/sage/matrix/matrix_dense.pyx @@ -13,7 +13,7 @@ from __future__ import print_function cimport sage.matrix.matrix as matrix from sage.structure.element cimport Element, RingElement -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool import sage.matrix.matrix_space import sage.structure.sequence diff --git a/src/sage/matrix/matrix_sparse.pyx b/src/sage/matrix/matrix_sparse.pyx index 4cd99ca1788..27c27c29f06 100644 --- a/src/sage/matrix/matrix_sparse.pyx +++ b/src/sage/matrix/matrix_sparse.pyx @@ -16,7 +16,7 @@ cimport cython cimport sage.matrix.matrix as matrix cimport sage.matrix.matrix0 as matrix0 from sage.structure.element cimport Element, RingElement, ModuleElement, Vector -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp from sage.rings.ring import is_Ring from sage.misc.misc import verbose diff --git a/src/sage/misc/constant_function.pyx b/src/sage/misc/constant_function.pyx index d4129f2a9aa..09a1f4ce888 100644 --- a/src/sage/misc/constant_function.pyx +++ b/src/sage/misc/constant_function.pyx @@ -1,13 +1,19 @@ r""" Constant functions """ + #***************************************************************************** -# Copyright (C) 2009 Nicolas M. Thiery +# Copyright (C) 2009 Nicolas M. Thiery # -# Distributed under the terms of the GNU General Public License (GPL) +# 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 sage.structure.sage_object cimport SageObject, richcmp +#***************************************************************************** + +from sage.structure.richcmp cimport richcmp +from sage.structure.sage_object cimport SageObject cdef class ConstantFunction(SageObject): diff --git a/src/sage/modular/arithgroup/arithgroup_element.pyx b/src/sage/modular/arithgroup/arithgroup_element.pyx index 7cae7d26067..dd80644c965 100644 --- a/src/sage/modular/arithgroup/arithgroup_element.pyx +++ b/src/sage/modular/arithgroup/arithgroup_element.pyx @@ -16,7 +16,7 @@ Elements of Arithmetic Subgroups from __future__ import absolute_import from sage.structure.element cimport MultiplicativeGroupElement, MonoidElement, Element -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp from sage.rings.all import ZZ from sage.modular.cusps import Cusp diff --git a/src/sage/modular/arithgroup/farey_symbol.pyx b/src/sage/modular/arithgroup/farey_symbol.pyx index 7df08d4017a..cf946ecee82 100644 --- a/src/sage/modular/arithgroup/farey_symbol.pyx +++ b/src/sage/modular/arithgroup/farey_symbol.pyx @@ -47,7 +47,7 @@ from sage.plot.all import hyperbolic_arc, hyperbolic_triangle, text from sage.misc.latex import latex from sage.misc.lazy_attribute import lazy_attribute from sage.misc.cachefunc import cached_method -from sage.structure.sage_object cimport richcmp_not_equal +from sage.structure.richcmp cimport richcmp_not_equal cdef extern from "sage/modular/arithgroup/sl2z.hpp": diff --git a/src/sage/modular/btquotients/pautomorphicform.py b/src/sage/modular/btquotients/pautomorphicform.py index a30256add0e..d5ceabdf36c 100644 --- a/src/sage/modular/btquotients/pautomorphicform.py +++ b/src/sage/modular/btquotients/pautomorphicform.py @@ -51,7 +51,7 @@ from sage.modular.btquotients.btquotient import DoubleCosetReduction from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.sage_object import op_EQ, op_NE +from sage.structure.richcmp import op_EQ, op_NE from sage.matrix.matrix_space import MatrixSpace from sage.structure.element import ModuleElement diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index c724394f053..405608a3d6d 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -35,7 +35,7 @@ from sage.structure.parent_base import ParentWithBase from sage.structure.element import Element, is_InfinityElement -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.modular.modsym.p1list import lift_to_sl2z_llong from sage.matrix.matrix import is_Matrix diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index 31d68826b12..e9440aaff49 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -86,7 +86,7 @@ from sage.structure.parent_base import ParentWithBase from sage.structure.element import Element, is_InfinityElement -from sage.structure.sage_object import richcmp, rich_to_bool +from sage.structure.richcmp import richcmp, rich_to_bool from sage.misc.cachefunc import cached_method from sage.misc.superseded import deprecated_function_alias diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index f8669f478a0..682a303bae6 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -80,7 +80,7 @@ from sage.structure.parent import Parent from sage.structure.sequence import Sequence from sage.structure.factory import UniqueFactory -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.arith.all import (binomial, bernoulli, kronecker, factor, gcd, lcm, fundamental_discriminant, euler_phi, factorial, valuation) diff --git a/src/sage/modular/hecke/element.py b/src/sage/modular/hecke/element.py index 4d7aa4317aa..f8af57a63d4 100644 --- a/src/sage/modular/hecke/element.py +++ b/src/sage/modular/hecke/element.py @@ -23,7 +23,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.sage_object import richcmp, op_NE +from sage.structure.richcmp import richcmp, op_NE from sage.structure.element import ModuleElement def is_HeckeModuleElement(x): diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index b90249e604f..fbf1d7abaca 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -24,7 +24,7 @@ from sage.symbolic.all import pi from sage.structure.parent_gens import localvars -from sage.structure.sage_object import op_NE, op_EQ +from sage.structure.richcmp import op_NE, op_EQ from sage.structure.element import CommutativeAlgebraElement from sage.structure.unique_representation import UniqueRepresentation diff --git a/src/sage/modular/modsym/manin_symbol.pyx b/src/sage/modular/modsym/manin_symbol.pyx index be67254638d..d9a7c8b1f1a 100644 --- a/src/sage/modular/modsym/manin_symbol.pyx +++ b/src/sage/modular/modsym/manin_symbol.pyx @@ -27,7 +27,7 @@ from sage.rings.all import Infinity, ZZ from sage.rings.integer cimport Integer from sage.structure.element cimport Element from sage.structure.sage_object import register_unpickle_override -from sage.structure.sage_object cimport richcmp_not_equal, richcmp +from sage.structure.richcmp cimport richcmp_not_equal, richcmp def is_ManinSymbol(x): diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index 65c58d1bf12..c8f72a6497b 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -28,8 +28,8 @@ REFERENCES: # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import print_function -from sage.structure.sage_object import SageObject -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.sage_object cimport SageObject +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.power_series_ring import PowerSeriesRing diff --git a/src/sage/modular/pollack_stevens/modsym.py b/src/sage/modular/pollack_stevens/modsym.py index 7c0ea81dc6a..259af464b2d 100644 --- a/src/sage/modular/pollack_stevens/modsym.py +++ b/src/sage/modular/pollack_stevens/modsym.py @@ -40,7 +40,7 @@ from __future__ import absolute_import import operator from sage.structure.element import ModuleElement -from sage.structure.sage_object import op_EQ, op_NE +from sage.structure.richcmp import op_EQ, op_NE from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.misc.cachefunc import cached_method diff --git a/src/sage/modular/pollack_stevens/sigma0.py b/src/sage/modular/pollack_stevens/sigma0.py index ea74d2ba1cf..e2a4f65074d 100644 --- a/src/sage/modular/pollack_stevens/sigma0.py +++ b/src/sage/modular/pollack_stevens/sigma0.py @@ -51,7 +51,7 @@ from sage.misc.abstract_method import abstract_method from sage.structure.factory import UniqueFactory from sage.structure.element import MonoidElement -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.categories.monoids import Monoids from sage.categories.morphism import Morphism from sage.structure.parent import Parent diff --git a/src/sage/modules/fg_pid/fgp_element.py b/src/sage/modules/fg_pid/fgp_element.py index 1fd2a399652..4dd63a9ed2b 100644 --- a/src/sage/modules/fg_pid/fgp_element.py +++ b/src/sage/modules/fg_pid/fgp_element.py @@ -16,7 +16,7 @@ #***************************************************************************** from sage.structure.element import ModuleElement -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp # This adds extra maybe-not-necessary checks in the code, but could # slow things down. It can impact what happens in more than just this diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index 91873f2a4ae..a244724e491 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -112,7 +112,7 @@ from cpython.slice cimport PySlice_GetIndicesEx from sage.structure.sequence import Sequence from sage.structure.element cimport Element, ModuleElement, RingElement, Vector from sage.structure.element import canonical_coercion -from sage.structure.sage_object cimport richcmp_not_equal, richcmp, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, richcmp, rich_to_bool from sage.rings.ring import is_Ring from sage.rings.infinity import Infinity, AnInfinity diff --git a/src/sage/modules/with_basis/indexed_element.pyx b/src/sage/modules/with_basis/indexed_element.pyx index 7e93a8bc522..aa272b92a65 100644 --- a/src/sage/modules/with_basis/indexed_element.pyx +++ b/src/sage/modules/with_basis/indexed_element.pyx @@ -22,7 +22,7 @@ from __future__ import print_function from six import iteritems from sage.structure.element cimport parent -from sage.structure.sage_object cimport richcmp, richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp, richcmp_not_equal, rich_to_bool from cpython.object cimport Py_NE, Py_EQ from sage.misc.misc import repr_lincomb diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index a4558d90161..4590627ac0a 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -119,7 +119,7 @@ from sage.categories.sets_cat import Sets from sage.categories.sets_with_partial_maps import SetsWithPartialMaps from sage.structure.element import parent -from sage.structure.sage_object import op_EQ, op_NE +from sage.structure.richcmp import op_EQ, op_NE from sage.matrix.matrix import is_Matrix class ModuleMorphism(Morphism): diff --git a/src/sage/monoids/free_abelian_monoid_element.py b/src/sage/monoids/free_abelian_monoid_element.py index 0c7d859068d..64168e86254 100644 --- a/src/sage/monoids/free_abelian_monoid_element.py +++ b/src/sage/monoids/free_abelian_monoid_element.py @@ -35,7 +35,7 @@ #***************************************************************************** from six import integer_types -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.rings.integer import Integer from sage.structure.element import MonoidElement diff --git a/src/sage/monoids/indexed_free_monoid.py b/src/sage/monoids/indexed_free_monoid.py index a8df61db4a2..06c8b6a678a 100644 --- a/src/sage/monoids/indexed_free_monoid.py +++ b/src/sage/monoids/indexed_free_monoid.py @@ -21,7 +21,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element import MonoidElement from sage.structure.indexed_generators import IndexedGenerators -from sage.structure.sage_object import op_EQ, op_NE, richcmp, rich_to_bool +from sage.structure.richcmp import op_EQ, op_NE, richcmp, rich_to_bool import sage.data_structures.blas_dict as blas from sage.categories.monoids import Monoids diff --git a/src/sage/monoids/string_monoid_element.py b/src/sage/monoids/string_monoid_element.py index a4d46bb38e9..e4bf95f1314 100644 --- a/src/sage/monoids/string_monoid_element.py +++ b/src/sage/monoids/string_monoid_element.py @@ -26,7 +26,7 @@ from sage.rings.integer import Integer from sage.rings.all import RealField from .free_monoid_element import FreeMonoidElement -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp def is_StringMonoidElement(x): diff --git a/src/sage/quivers/algebra_elements.pxi b/src/sage/quivers/algebra_elements.pxi index 177833fc117..db845f26141 100644 --- a/src/sage/quivers/algebra_elements.pxi +++ b/src/sage/quivers/algebra_elements.pxi @@ -22,7 +22,7 @@ include "sage/data_structures/bitset.pxi" from cpython.ref cimport * from cython.operator cimport predecrement as predec, postincrement as postinc -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool from sage.libs.gmp.mpn cimport mpn_cmp from libc.stdlib cimport free diff --git a/src/sage/quivers/algebra_elements.pyx b/src/sage/quivers/algebra_elements.pyx index 289044eaa22..65c51ce19f2 100644 --- a/src/sage/quivers/algebra_elements.pyx +++ b/src/sage/quivers/algebra_elements.pyx @@ -20,7 +20,7 @@ from __future__ import division, print_function include "algebra_elements.pxi" from sage.misc.cachefunc import cached_method from sage.misc.misc import repr_lincomb -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool cdef class PathAlgebraElement(RingElement): diff --git a/src/sage/quivers/paths.pyx b/src/sage/quivers/paths.pyx index 88c5a1c952c..6a9fbce2251 100644 --- a/src/sage/quivers/paths.pyx +++ b/src/sage/quivers/paths.pyx @@ -21,7 +21,7 @@ from __future__ import print_function from sage.data_structures.bounded_integer_sequences cimport * from cpython.slice cimport PySlice_GetIndicesEx -from sage.structure.sage_object cimport rich_to_bool +from sage.structure.richcmp cimport rich_to_bool include "cysignals/signals.pxi" include "sage/data_structures/bitset.pxi" diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index 6c0eba0b9cb..2782fd92f50 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -820,7 +820,7 @@ def richcmp_by_eq_and_lt(left, right, op): sage: z < x, x < z, z > x, x > z, z <= x, x <= z, z >= x, x >= z (False, True, True, False, False, True, True, False) """ - from sage.structure.sage_object import (rich_to_bool, + from sage.structure.richcmp import (rich_to_bool, op_NE, op_EQ, op_LT, op_LE, op_GT, op_GE) diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 2595e1515bb..05f8ebabd13 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -84,7 +84,7 @@ cimport sage.rings.integer from sage.structure.element cimport RingElement, Element, ModuleElement, FieldElement from sage.structure.parent cimport Parent from sage.structure.parent_gens import ParentWithGens -from sage.structure.sage_object cimport rich_to_bool +from sage.structure.richcmp cimport rich_to_bool from sage.categories.morphism cimport Morphism from sage.structure.coerce cimport is_numpy_type diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 2c1b137d57e..abd46a33100 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -77,7 +77,7 @@ from sage.misc.randstate cimport randstate, current_randstate from sage.misc.superseded import deprecated_function_alias from .real_mpfr cimport RealField_class, RealNumber from .real_mpfr import mpfr_prec_min, mpfr_prec_max -from sage.structure.sage_object cimport rich_to_bool, richcmp +from sage.structure.richcmp cimport rich_to_bool, richcmp NumberFieldElement_quadratic = None AlgebraicNumber_base = None diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index 743ac9fd5a3..cb0ed430164 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -61,7 +61,8 @@ from sage.rings.finite_rings.finite_field_base cimport FiniteField from sage.rings.ring cimport Ring from .element_ext_pari import FiniteField_ext_pariElement from .element_pari_ffelt cimport FiniteFieldElement_pari_ffelt -from sage.structure.sage_object cimport SageObject, richcmp +from sage.structure.richcmp cimport richcmp +from sage.structure.sage_object cimport SageObject from sage.structure.element cimport Element, ModuleElement, RingElement import operator import sage.arith.all diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index c46207d8021..3c974ed390c 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -25,8 +25,9 @@ include "cysignals/signals.pxi" include "sage/libs/ntl/decl.pxi" from cypari2.paridecl cimport * -from sage.structure.sage_object cimport (SageObject, richcmp, - richcmp_not_equal, rich_to_bool) +from sage.structure.richcmp cimport (richcmp, + richcmp_not_equal, rich_to_bool) +from sage.structure.sage_object cimport SageObject from sage.structure.element cimport Element, ModuleElement, RingElement from sage.structure.parent cimport Parent diff --git a/src/sage/rings/finite_rings/residue_field.pyx b/src/sage/rings/finite_rings/residue_field.pyx index 7a585027c57..ca389e173ae 100644 --- a/src/sage/rings/finite_rings/residue_field.pyx +++ b/src/sage/rings/finite_rings/residue_field.pyx @@ -172,7 +172,7 @@ from sage.rings.polynomial.polynomial_element import is_Polynomial from sage.structure.factory import UniqueFactory from sage.structure.element cimport parent -from sage.structure.sage_object cimport richcmp, richcmp_not_equal +from sage.structure.richcmp cimport richcmp, richcmp_not_equal class ResidueFieldFactory(UniqueFactory): diff --git a/src/sage/rings/fraction_field_element.pyx b/src/sage/rings/fraction_field_element.pyx index afefa4358cd..80b3b003637 100644 --- a/src/sage/rings/fraction_field_element.pyx +++ b/src/sage/rings/fraction_field_element.pyx @@ -39,7 +39,7 @@ import operator from sage.structure.element cimport (FieldElement, ModuleElement, RingElement, Element) from sage.structure.element import parent -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp import integer_ring from integer_ring import ZZ diff --git a/src/sage/rings/function_field/function_field_element.pyx b/src/sage/rings/function_field/function_field_element.pyx index 802390328a1..7b5fb6f4afc 100644 --- a/src/sage/rings/function_field/function_field_element.pyx +++ b/src/sage/rings/function_field/function_field_element.pyx @@ -25,7 +25,7 @@ AUTHORS: from sage.structure.element cimport FieldElement, RingElement, ModuleElement, Element -from sage.structure.sage_object cimport richcmp, richcmp_not_equal +from sage.structure.richcmp cimport richcmp, richcmp_not_equal def is_FunctionFieldElement(x): diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index 3f01782c078..8f4a94d2608 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -339,7 +339,8 @@ cdef _digits_internal(mpz_t v,l,int offset,int power_index,power_list,digits): mpz_clear(mpz_quot) mpz_clear(mpz_res) -from sage.structure.sage_object cimport SageObject, rich_to_bool_sgn +from sage.structure.sage_object cimport SageObject +from sage.structure.richcmp cimport rich_to_bool_sgn from sage.structure.element cimport EuclideanDomainElement, ModuleElement, Element from sage.structure.element import bin_op from sage.structure.coerce_exceptions import CoercionException diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index 14639f74a08..1e4d05ed360 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -64,7 +64,7 @@ from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets from sage.structure.coerce cimport is_numpy_type from sage.structure.parent_gens import ParentWithGens from sage.structure.parent cimport Parent -from sage.structure.sage_object cimport rich_to_bool +from sage.structure.richcmp cimport rich_to_bool from sage.structure.sequence import Sequence from sage.misc.misc_c import prod diff --git a/src/sage/rings/laurent_series_ring_element.pyx b/src/sage/rings/laurent_series_ring_element.pyx index 35442e87a2b..53518ac656a 100644 --- a/src/sage/rings/laurent_series_ring_element.pyx +++ b/src/sage/rings/laurent_series_ring_element.pyx @@ -63,7 +63,7 @@ from sage.rings.integer import Integer from sage.rings.polynomial.laurent_polynomial import LaurentPolynomial_univariate from .power_series_ring_element cimport PowerSeries from sage.structure.element cimport Element, ModuleElement, RingElement, AlgebraElement -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool from sage.misc.derivative import multi_derivative diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index 9e2a88d0a02..47e429fa540 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -357,8 +357,8 @@ from __future__ import print_function import ideal import homset from cpython.object cimport Py_EQ, Py_NE -from sage.structure.sage_object cimport (richcmp, rich_to_bool, - richcmp_not_equal) +from sage.structure.richcmp cimport (richcmp, rich_to_bool, + richcmp_not_equal) def is_RingHomomorphism(phi): diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index be398ae74e9..45d67d50e75 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -157,7 +157,7 @@ #***************************************************************************** from six import iteritems, integer_types -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.rings.infinity import infinity, is_Infinite diff --git a/src/sage/rings/number_field/number_field_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 772ceba3f95..4aaeb6b60f2 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -44,7 +44,7 @@ from sage.libs.mpfi cimport mpfi_t, mpfi_init, mpfi_set, mpfi_clear, mpfi_div_z, from sage.libs.mpfr cimport mpfr_less_p, mpfr_greater_p, mpfr_greaterequal_p from sage.libs.ntl.error import NTLError from cpython.object cimport Py_EQ, Py_NE, Py_LT, Py_GT, Py_LE, Py_GE -from sage.structure.sage_object cimport rich_to_bool +from sage.structure.richcmp cimport rich_to_bool import sage.rings.infinity import sage.rings.polynomial.polynomial_element diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 7ac8c88236d..4762ad2448a 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -42,7 +42,7 @@ from sage.libs.mpfi cimport mpfi_set_z, mpfi_set_q, mpfi_sqrt, mpfi_add_z, mpfi_ from sage.structure.parent_base cimport ParentWithBase from sage.structure.element cimport Element, ModuleElement, RingElement -from sage.structure.sage_object cimport rich_to_bool_sgn +from sage.structure.richcmp cimport rich_to_bool_sgn from sage.rings.rational cimport Rational from sage.rings.integer_ring import ZZ diff --git a/src/sage/rings/padics/morphism.pyx b/src/sage/rings/padics/morphism.pyx index 3e33397c04d..7accf763fd8 100644 --- a/src/sage/rings/padics/morphism.pyx +++ b/src/sage/rings/padics/morphism.pyx @@ -18,8 +18,8 @@ from sage.rings.infinity import Infinity from sage.rings.ring import CommutativeRing from sage.categories.homset import Hom from sage.structure.element cimport Element -from sage.structure.sage_object cimport (richcmp, rich_to_bool, - richcmp_not_equal) +from sage.structure.richcmp cimport (richcmp, rich_to_bool, + richcmp_not_equal) from sage.rings.morphism cimport RingHomomorphism from padic_generic import pAdicGeneric diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 376c85919a7..5cb70123585 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -188,7 +188,7 @@ class names.:: # # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.sage_object import op_LE +from sage.structure.richcmp import op_LE from .generic_nodes import pAdicFieldBaseGeneric, \ pAdicCappedRelativeFieldGeneric, \ diff --git a/src/sage/rings/padics/padic_extension_generic.py b/src/sage/rings/padics/padic_extension_generic.py index d1c36d69e6e..cd904fd0010 100644 --- a/src/sage/rings/padics/padic_extension_generic.py +++ b/src/sage/rings/padics/padic_extension_generic.py @@ -22,7 +22,7 @@ from .padic_generic import pAdicGeneric from .padic_base_generic import pAdicBaseGeneric -from sage.structure.sage_object import op_EQ +from sage.structure.richcmp import op_EQ from functools import reduce diff --git a/src/sage/rings/padics/padic_printing.pyx b/src/sage/rings/padics/padic_printing.pyx index bd19a160f09..4c53cd957eb 100644 --- a/src/sage/rings/padics/padic_printing.pyx +++ b/src/sage/rings/padics/padic_printing.pyx @@ -25,7 +25,7 @@ from __future__ import print_function from cpython.list cimport * from sage.libs.gmp.mpz cimport * -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool import sys diff --git a/src/sage/rings/padics/pow_computer.pyx b/src/sage/rings/padics/pow_computer.pyx index e182ea381ce..4c041c79453 100644 --- a/src/sage/rings/padics/pow_computer.pyx +++ b/src/sage/rings/padics/pow_computer.pyx @@ -35,7 +35,7 @@ AUTHORS: import weakref from sage.rings.infinity import infinity from sage.libs.gmp.mpz cimport * -from sage.structure.sage_object cimport richcmp_not_equal, richcmp +from sage.structure.richcmp cimport richcmp_not_equal, richcmp from cpython.object cimport Py_EQ, Py_NE from sage.ext.stdsage cimport PY_NEW diff --git a/src/sage/rings/padics/pow_computer_flint.pyx b/src/sage/rings/padics/pow_computer_flint.pyx index c8ddd3f2826..b9cc0ce39e7 100644 --- a/src/sage/rings/padics/pow_computer_flint.pyx +++ b/src/sage/rings/padics/pow_computer_flint.pyx @@ -11,7 +11,7 @@ from sage.libs.flint.fmpz_vec cimport * from sage.libs.flint.fmpz cimport fmpz_init, fmpz_one, fmpz_mul, fmpz_set, fmpz_get_mpz, fmpz_clear, fmpz_pow_ui, fmpz_set_mpz, fmpz_fdiv_q_2exp from cpython.object cimport Py_EQ, Py_NE -from sage.structure.sage_object cimport richcmp_not_equal +from sage.structure.richcmp cimport richcmp_not_equal from sage.rings.integer cimport Integer from sage.rings.all import ZZ from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 1204e629147..0607c876c90 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -17,7 +17,7 @@ from sage.misc.misc import union from sage.structure.factorization import Factorization from sage.misc.derivative import multi_derivative from sage.rings.polynomial.polynomial_element import Polynomial -from sage.structure.sage_object cimport richcmp, rich_to_bool +from sage.structure.richcmp cimport richcmp, rich_to_bool cdef class LaurentPolynomial_generic(CommutativeAlgebraElement): diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index cf5596875aa..d4a77ce005b 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -247,7 +247,7 @@ from sage.structure.element cimport Element from sage.structure.element cimport CommutativeRingElement from sage.structure.element cimport coercion_model -from sage.structure.sage_object cimport rich_to_bool, richcmp +from sage.structure.richcmp cimport rich_to_bool, richcmp from sage.structure.factorization import Factorization from sage.structure.sequence import Sequence diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx index 2c38245b0fa..55d6ae35020 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_generic.pyx @@ -9,7 +9,7 @@ from sage.misc.latex import latex_variable_name from sage.misc.misc_c import prod from sage.structure.parent cimport Parent -from sage.structure.sage_object cimport rich_to_bool, richcmp +from sage.structure.richcmp cimport rich_to_bool, richcmp from cpython.object cimport Py_NE from sage.categories.commutative_rings import CommutativeRings diff --git a/src/sage/rings/polynomial/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index 812f3b9ebca..cd930aed9cf 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -211,7 +211,7 @@ from sage.structure.parent cimport Parent from sage.structure.sequence import Sequence from sage.structure.element import coerce_binop from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.sage_object cimport richcmp, richcmp_not_equal +from sage.structure.richcmp cimport richcmp, richcmp_not_equal from sage.categories.action cimport Action diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index f263e37c2d4..7cf75b49fd5 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -67,7 +67,7 @@ from sage.misc.latex import latex from sage.misc.long cimport pyobject_to_long from sage.structure.factorization import Factorization from sage.structure.element import coerce_binop -from sage.structure.sage_object cimport (richcmp, richcmp_not_equal, +from sage.structure.richcmp cimport (richcmp, richcmp_not_equal, rich_to_bool, rich_to_bool_sgn) from sage.interfaces.singular import singular as singular_default, is_SingularElement diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index b99a3fb5726..8bf32464545 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -39,6 +39,7 @@ from sage.rings.polynomial.polynomial_singular_interface import Polynomial_singular_repr from sage.libs.pari.all import pari_gen +from sage.structure.richcmp import richcmp, richcmp_not_equal, rich_to_bool, rich_to_bool_sgn from sage.structure.element import coerce_binop from sage.rings.infinity import infinity, Infinity @@ -1415,8 +1416,7 @@ class Polynomial_generic_sparse_cdvf(Polynomial_generic_sparse_cdv, Polynomial_g # XXX: Ensures that the generic polynomials implemented in SAGE via PARI # # until at least until 4.5.0 unpickle correctly as polynomials implemented # # via FLINT. # -from sage.structure.sage_object import (register_unpickle_override, - richcmp, richcmp_not_equal, rich_to_bool, rich_to_bool_sgn) +from sage.structure.sage_object import register_unpickle_override from sage.rings.polynomial.polynomial_rational_flint import Polynomial_rational_flint register_unpickle_override( \ diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index 000050098f2..bfd49a279a0 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -17,7 +17,7 @@ Polynomial Template for C/C++ Library Interfaces from sage.rings.polynomial.polynomial_element cimport Polynomial from sage.structure.element cimport ModuleElement, Element, RingElement from sage.structure.element import coerce_binop, bin_op -from sage.structure.sage_object cimport rich_to_bool +from sage.structure.richcmp cimport rich_to_bool from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.integer cimport Integer from sage.libs.all import pari_gen diff --git a/src/sage/rings/polynomial/symmetric_reduction.pyx b/src/sage/rings/polynomial/symmetric_reduction.pyx index fa02df012b4..f3e1db1c6cf 100644 --- a/src/sage/rings/polynomial/symmetric_reduction.pyx +++ b/src/sage/rings/polynomial/symmetric_reduction.pyx @@ -121,7 +121,7 @@ from __future__ import print_function import copy import operator import sys -from sage.structure.sage_object cimport richcmp, Py_NE, Py_EQ +from sage.structure.richcmp cimport richcmp, Py_NE, Py_EQ cdef class SymmetricReductionStrategy: diff --git a/src/sage/rings/power_series_ring_element.pyx b/src/sage/rings/power_series_ring_element.pyx index 212acb30fe5..6b670db7b1d 100644 --- a/src/sage/rings/power_series_ring_element.pyx +++ b/src/sage/rings/power_series_ring_element.pyx @@ -118,7 +118,7 @@ from sage.misc.derivative import multi_derivative Polynomial = sage.rings.polynomial.polynomial_element.Polynomial_generic_dense from sage.structure.element cimport AlgebraElement, RingElement, ModuleElement, Element -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp def is_PowerSeries(x): diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 2621249f1b5..9dfcdf75d01 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -510,10 +510,11 @@ import sage.rings.ring from sage.misc.fast_methods import Singleton from sage.misc.cachefunc import cached_method -from sage.structure.sage_object import (SageObject, richcmp, - rich_to_bool, richcmp_not_equal, - op_EQ, op_NE, op_LE, op_LT, - op_GE, op_GT) +from sage.structure.sage_object import SageObject +from sage.structure.richcmp import (richcmp, + rich_to_bool, richcmp_not_equal, + op_EQ, op_NE, op_LE, op_LT, + op_GE, op_GT) from sage.rings.real_mpfr import RR from sage.rings.real_mpfi import RealIntervalField, RIF, is_RealIntervalFieldElement, RealIntervalField_class from sage.rings.complex_field import ComplexField diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index a0a7d902a9e..3a6459d8123 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -68,7 +68,7 @@ from sage.rings.integer_ring import ZZ from sage.categories.morphism cimport Morphism from sage.structure.coerce cimport is_numpy_type from sage.misc.randstate cimport randstate, current_randstate -from sage.structure.sage_object cimport rich_to_bool +from sage.structure.richcmp cimport rich_to_bool def is_RealDoubleField(x): diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index 2eeff8ee879..c16a97f9623 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -29,7 +29,7 @@ from operator import add, sub, mul, div, pow, neg, inv cdef canonical_coercion from sage.structure.element import canonical_coercion from sage.structure.all import parent -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp import sage.categories.map from sage.categories.morphism cimport Morphism diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 3bad4a6f4ea..bd9cbb63663 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -256,7 +256,7 @@ from sage.libs.gmp.mpz cimport * cimport sage.rings.ring cimport sage.structure.element from sage.structure.element cimport RingElement, Element, ModuleElement -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp cimport sage.rings.real_mpfr as real_mpfr from .real_mpfr cimport RealField_class, RealNumber, RealField diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index e7fc8a28eeb..dc1d0bcab62 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -128,7 +128,7 @@ from sage.libs.gmp.mpz cimport * from sage.misc.randstate cimport randstate, current_randstate from sage.structure.element cimport RingElement, Element, ModuleElement -from sage.structure.sage_object cimport rich_to_bool_sgn +from sage.structure.richcmp cimport rich_to_bool_sgn cdef bin_op from sage.structure.element import bin_op diff --git a/src/sage/rings/universal_cyclotomic_field.py b/src/sage/rings/universal_cyclotomic_field.py index a94f2c00603..aa8461bfa60 100644 --- a/src/sage/rings/universal_cyclotomic_field.py +++ b/src/sage/rings/universal_cyclotomic_field.py @@ -156,7 +156,7 @@ from sage.misc.cachefunc import cached_method from sage.misc.superseded import deprecated_function_alias -from sage.structure.sage_object import rich_to_bool +from sage.structure.richcmp import rich_to_bool from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element import FieldElement, parent from sage.structure.coerce import py_scalar_to_element diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 47c9a0477af..f15ef68c216 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -84,7 +84,7 @@ from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism, isomorphisms from sage.sets.set import Set -from sage.structure.sage_object import richcmp_not_equal, richcmp +from sage.structure.richcmp import richcmp_not_equal, richcmp from sage.misc.cachefunc import cached_function # diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index cecd357b727..763c5f8ff06 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -134,7 +134,7 @@ from sage.libs.pari import pari from cypari2.pari_instance import prec_words_to_bits from sage.structure.sequence import Sequence -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.schemes.curves.projective_curve import Hasse_bounds from sage.schemes.projective.projective_point import (SchemeMorphism_point_projective_ring, diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index f0ac03a2c48..a07fb13f148 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -83,7 +83,7 @@ import operator from sage.structure.element import (AdditiveGroupElement, RingElement, Element, generic_power, parent, coercion_model) -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.structure.sequence import Sequence from sage.categories.homset import Homset, Hom, End from sage.categories.number_fields import NumberFields diff --git a/src/sage/schemes/generic/point.py b/src/sage/schemes/generic/point.py index 29bcb769056..0cadc10957e 100644 --- a/src/sage/schemes/generic/point.py +++ b/src/sage/schemes/generic/point.py @@ -9,7 +9,7 @@ #******************************************************************************* from sage.structure.element import Element -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp ######################################################## # Base class for points on a scheme, either topological diff --git a/src/sage/schemes/product_projective/point.py b/src/sage/schemes/product_projective/point.py index 8921e7a638e..f4eebd64385 100644 --- a/src/sage/schemes/product_projective/point.py +++ b/src/sage/schemes/product_projective/point.py @@ -27,7 +27,7 @@ from sage.schemes.generic.morphism import SchemeMorphism from sage.schemes.generic.morphism import SchemeMorphism_point from sage.structure.sequence import Sequence -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp class ProductProjectiveSpaces_point_ring(SchemeMorphism_point): diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py index da9a63ebe0d..575d616f3cd 100644 --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -56,7 +56,7 @@ SchemeMorphism_point) from sage.structure.element import AdditiveGroupElement from sage.structure.sequence import Sequence -from sage.structure.sage_object import rich_to_bool, richcmp, op_EQ, op_NE +from sage.structure.richcmp import rich_to_bool, richcmp, op_EQ, op_NE #******************************************************************* # Projective varieties diff --git a/src/sage/schemes/toric/morphism.py b/src/sage/schemes/toric/morphism.py index 268aecde9f1..04d47bc7b44 100644 --- a/src/sage/schemes/toric/morphism.py +++ b/src/sage/schemes/toric/morphism.py @@ -375,7 +375,7 @@ # https://groups.google.com/d/msg/sage-devel/qF4yU6Vdmao/wQlNrneSmWAJ from sage.categories.morphism import Morphism -from sage.structure.sage_object import richcmp_not_equal, richcmp +from sage.structure.richcmp import richcmp_not_equal, richcmp from sage.structure.sequence import Sequence from sage.rings.all import ZZ diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 3cf0012efb8..ebf8016b4ae 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -85,7 +85,8 @@ import operator cdef dict operator_dict = operator.__dict__ from operator import add, sub, mul, div, truediv, iadd, isub, imul, idiv -from .sage_object cimport SageObject, rich_to_bool +from .richcmp cimport rich_to_bool +from .sage_object cimport SageObject from .parent cimport Set_PythonType, Parent_richcmp_element_without_coercion from .element cimport bin_op_exception, parent, Element from .coerce_actions import LeftModuleAction, RightModuleAction, IntegerMulAction @@ -1807,7 +1808,7 @@ cdef class CoercionModel_cache_maps(CoercionModel): EXAMPLES:: sage: from sage.structure.element import get_coercion_model - sage: from sage.structure.sage_object import op_LT, op_LE, op_EQ, op_NE, op_GT, op_GE + sage: from sage.structure.richcmp import op_LT, op_LE, op_EQ, op_NE, op_GT, op_GE sage: richcmp = get_coercion_model().richcmp sage: richcmp(None, None, op_EQ) True diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 81d06d2428c..cfb9fdd8b78 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -293,7 +293,7 @@ cdef dict _coerce_op_symbols = dict( cdef MethodType from types import MethodType -from sage.structure.sage_object cimport rich_to_bool +from sage.structure.richcmp cimport rich_to_bool from sage.structure.coerce cimport py_scalar_to_element from sage.structure.parent cimport Parent from sage.structure.misc import is_extension_type @@ -1010,7 +1010,7 @@ cdef class Element(SageObject): and check that comparison works:: sage: cython(''' - ....: from sage.structure.sage_object cimport rich_to_bool + ....: from sage.structure.richcmp cimport rich_to_bool ....: from sage.structure.element cimport Element ....: cdef class FloatCmp(Element): ....: cdef float x diff --git a/src/sage/structure/list_clone.pyx b/src/sage/structure/list_clone.pyx index 4f7de4deb79..cff6398da22 100644 --- a/src/sage/structure/list_clone.pyx +++ b/src/sage/structure/list_clone.pyx @@ -153,7 +153,7 @@ import sage from sage.ext.stdsage cimport HAS_DICTIONARY from sage.structure.element cimport Element from sage.structure.parent cimport Parent -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp ############################################################################ ### Basic clone elements ### diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index a7ec72d0642..932aad89368 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -99,7 +99,8 @@ from sage.structure.element cimport parent, coercion_model cimport sage.categories.morphism as morphism cimport sage.categories.map as map from sage.structure.debug_options cimport debug -from sage.structure.sage_object cimport SageObject, rich_to_bool +from sage.structure.richcmp cimport rich_to_bool +from sage.structure.sage_object cimport SageObject from sage.structure.misc import is_extension_type from sage.misc.lazy_attribute import lazy_attribute from sage.categories.sets_cat import Sets, EmptySetError diff --git a/src/sage/structure/richcmp.pxd b/src/sage/structure/richcmp.pxd new file mode 100644 index 00000000000..ac7a6d4042e --- /dev/null +++ b/src/sage/structure/richcmp.pxd @@ -0,0 +1,146 @@ +from libc.stdint cimport uint32_t +from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE +from cpython.object cimport PyObject_RichCompare as richcmp + + +cpdef inline richcmp_not_equal(x, y, int op): + """ + Like ``richcmp(x, y, op)`` but assuming that `x` is not equal to `y`. + + INPUT: + + - ``op`` -- a rich comparison operation (e.g. ``Py_EQ``) + + OUTPUT: + + If ``op`` is not ``op_EQ`` or ``op_NE``, the result of + ``richcmp(x, y, op)``. If ``op`` is ``op_EQ``, return + ``False``. If ``op`` is ``op_NE``, return ``True``. + + This is useful to compare lazily two objects A and B according to 2 + (or more) different parameters, say width and height for example. + One could use:: + + return richcmp((A.width(), A.height()), (B.width(), B.height()), op) + + but this will compute both width and height in all cases, even if + A.width() and B.width() are enough to decide the comparison. + + Instead one can do:: + + wA = A.width() + wB = B.width() + if wA != wB: + return richcmp_not_equal(wA, wB, op) + return richcmp(A.height(), B.height(), op) + + The difference with ``richcmp`` is that ``richcmp_not_equal`` + assumes that its arguments are not equal, which is excluding the case + where the comparison cannot be decided so far, without + knowing the rest of the parameters. + + EXAMPLES:: + + sage: from sage.structure.richcmp import (richcmp_not_equal, + ....: op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE) + sage: for op in (op_LT, op_LE, op_EQ, op_NE, op_GT, op_GE): + ....: print(richcmp_not_equal(3, 4, op)) + True + True + False + True + False + False + sage: for op in (op_LT, op_LE, op_EQ, op_NE, op_GT, op_GE): + ....: print(richcmp_not_equal(5, 4, op)) + False + False + False + True + True + True + """ + if op == Py_EQ: + return False + elif op == Py_NE: + return True + return richcmp(x, y, op) + + +cpdef inline bint rich_to_bool(int op, int c): + """ + Return the corresponding ``True`` or ``False`` value for a rich + comparison, given the result of an old-style comparison. + + INPUT: + + - ``op`` -- a rich comparison operation (e.g. ``Py_EQ``) + + - ``c`` -- the result of an old-style comparison: -1, 0 or 1. + + OUTPUT: 1 or 0 (corresponding to ``True`` and ``False``) + + .. SEEALSO:: + + :func:`rich_to_bool_sgn` if ``c`` could be outside the + [-1, 0, 1] range. + + EXAMPLES:: + + sage: from sage.structure.richcmp import (rich_to_bool, + ....: op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE) + sage: for op in (op_LT, op_LE, op_EQ, op_NE, op_GT, op_GE): + ....: for c in (-1,0,1): + ....: print(rich_to_bool(op, c)) + True False False + True True False + False True False + True False True + False False True + False True True + + Indirect tests using integers:: + + sage: 0 < 5, 5 < 5, 5 < -8 + (True, False, False) + sage: 0 <= 5, 5 <= 5, 5 <= -8 + (True, True, False) + sage: 0 >= 5, 5 >= 5, 5 >= -8 + (False, True, True) + sage: 0 > 5, 5 > 5, 5 > -8 + (False, False, True) + sage: 0 == 5, 5 == 5, 5 == -8 + (False, True, False) + sage: 0 != 5, 5 != 5, 5 != -8 + (True, False, True) + """ + # op is a value in [0,5], c a value in [-1,1]. We implement this + # function very efficienly using a bitfield. Note that the masking + # below implies we consider c mod 4, so c = -1 implicitly becomes + # c = 3. + + # The 4 lines below involve just constants, so the compiler should + # optimize them to just one constant value for "bits". + cdef uint32_t less_bits = (1 << Py_LT) + (1 << Py_LE) + (1 << Py_NE) + cdef uint32_t equal_bits = (1 << Py_LE) + (1 << Py_GE) + (1 << Py_EQ) + cdef uint32_t greater_bits = (1 << Py_GT) + (1 << Py_GE) + (1 << Py_NE) + cdef uint32_t bits = (less_bits << 24) + (equal_bits) + (greater_bits << 8) + + cdef int shift = 8*c + op + + # The shift masking (shift & 31) will likely be optimized away by + # the compiler since shift and bit test instructions implicitly + # mask their offset. + return (bits >> (shift & 31)) & 1 + + +cpdef inline bint rich_to_bool_sgn(int op, Py_ssize_t c): + """ + Same as ``rich_to_bool``, but allow any `c < 0` and `c > 0` + instead of only `-1` and `1`. + + .. NOTE:: + + This is in particular needed for ``mpz_cmp()``. + """ + return rich_to_bool(op, (c > 0) - (c < 0)) diff --git a/src/sage/structure/richcmp.pyx b/src/sage/structure/richcmp.pyx new file mode 100644 index 00000000000..7800ab30fe3 --- /dev/null +++ b/src/sage/structure/richcmp.pyx @@ -0,0 +1,89 @@ +r""" +Cython-like rich comparisons in Python + +With "rich comparisons", we mean the Python 3 comparisons which are +usually implemented in Python using methods like ``__eq__`` and +``__lt__``. Internally in Python, there is only one rich comparison +slot ``tp_richcompare``. The actual operator is passed as an integer +constant (defined in this module as +``op_LT``, ``op_LE``, ``op_EQ``, ``op_NE``, ``op_GT``, ``op_GE``). + +Cython exposes rich comparisons in ``cdef`` classes as the +``__richcmp__`` special method. The Sage coercion model also supports +rich comparisons this way: for two instances ``x`` and ``y`` +of :class:`~sage.structure.element.Element`, ``x._richcmp_(y, op)`` +is called when the user does something like ``x <= y`` +(possibly after coercion if ``x`` and ``y`` have different parents). + +Various helper functions exist to make it easier to implement rich +comparison: the most important one is the :func:`richcmp` function. +This is analogous to the Python 2 function ``cmp()`` but implements +rich comparison, with the comparison operator (e.g. ``op_GE``) as +third argument. There is also :func:`richcmp_not_equal` which is like +:func:`richcmp` but it is optimized assuming that the compared objects +are not equal. + +The functions :func:`rich_to_bool` and :func:`rich_to_bool_sgn` can be +used to convert results of ``cmp()`` (i.e. -1, 0 or 1) to a boolean +``True``/``False`` for rich comparisons. + +AUTHORS: + +- Jeroen Demeyer +""" + +from cpython.object cimport PyObject_RichCompare + +op_LT = Py_LT # operator < +op_LE = Py_LE # operator <= +op_EQ = Py_EQ # operator == +op_NE = Py_NE # operator != +op_GT = Py_GT # operator > +op_GE = Py_GE # operator >= + + +def richcmp(x, y, int op): + """ + Return the result of the rich comparison of ``x`` and ``y`` with + operator ``op``. + + INPUT: + + - ``x``, ``y`` -- arbitrary Python objects + + - ``op`` -- comparison operator (one of ``op_LT`, ``op_LE``, + ``op_EQ``, ``op_NE``, ``op_GT``, ``op_GE``). + + EXAMPLES:: + + sage: from sage.structure.richcmp import * + sage: richcmp(3, 4, op_LT) + True + sage: richcmp(x, x^2, op_EQ) + x == x^2 + + The two examples above are completely equivalent to ``3 < 4`` + and ``x == x^2``. For this reason, it only makes sense in practice + to call ``richcmp`` with a non-constant value for ``op``. + + We can write a custom ``Element`` class which shows a more + realistic example of how to use this:: + + sage: from sage.structure.element import Element + sage: class MyElement(Element): + ....: def __init__(self, parent, value): + ....: Element.__init__(self, parent) + ....: self.v = value + ....: def _richcmp_(self, other, op): + ....: return richcmp(self.v, other.v, op) + sage: P = Parent() + sage: x = MyElement(P, 3) + sage: y = MyElement(P, 3) + sage: x < y + False + sage: x == y + True + sage: x > y + False + """ + return PyObject_RichCompare(x, y, op) diff --git a/src/sage/structure/sage_object.pxd b/src/sage/structure/sage_object.pxd index 2461dce633c..5e3e442c896 100644 --- a/src/sage/structure/sage_object.pxd +++ b/src/sage/structure/sage_object.pxd @@ -1,161 +1,2 @@ -from libc.stdint cimport uint32_t -from cpython.object cimport Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE - -# Export this for use by Python modules -cdef extern from "Python.h": - cpdef richcmp "PyObject_RichCompare"(object, object, int) - - cdef class SageObject: pass - - -cpdef inline richcmp_not_equal(x, y, int op): - """ - Like ``richcmp(x, y, op)`` but assuming that `x` is not equal to `y`. - - INPUT: - - - ``op`` -- a rich comparison operation (e.g. ``Py_EQ``) - - OUTPUT: - - If ``op`` is not ``op_EQ`` or ``op_NE``, the result of - ``richcmp(x, y, op)``. If ``op`` is ``op_EQ``, return - ``False``. If ``op`` is ``op_NE``, return ``True``. - - This is useful to compare lazily two objects A and B according to 2 - (or more) different parameters, say width and height for example. - One could use:: - - return richcmp((A.width(), A.height()), (B.width(), B.height()), op) - - but this will compute both width and height in all cases, even if - A.width() and B.width() are enough to decide the comparison. - - Instead one can do:: - - wA = A.width() - wB = B.width() - if wA != wB: - return richcmp_not_equal(wA, wB, op) - return richcmp(A.height(), B.height(), op) - - The difference with ``richcmp`` is that ``richcmp_not_equal`` - assumes that its arguments are not equal, which is excluding the case - where the comparison cannot be decided so far, without - knowing the rest of the parameters. - - EXAMPLES:: - - sage: from sage.structure.sage_object import (richcmp_not_equal, - ....: op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE) - sage: for op in (op_LT, op_LE, op_EQ, op_NE, op_GT, op_GE): - ....: print(richcmp_not_equal(3, 4, op)) - True - True - False - True - False - False - sage: for op in (op_LT, op_LE, op_EQ, op_NE, op_GT, op_GE): - ....: print(richcmp_not_equal(5, 4, op)) - False - False - False - True - True - True - """ - if op == Py_EQ: - return False - elif op == Py_NE: - return True - return richcmp(x, y, op) - - -cpdef inline bint rich_to_bool(int op, int c): - """ - Return the corresponding ``True`` or ``False`` value for a rich - comparison, given the result of an ordinary comparison. - - INPUT: - - - ``op`` -- a rich comparison operation (e.g. ``Py_EQ``) - - - ``c`` -- the result of an ordinary comparison: -1, 0 or 1. - - OUTPUT: 1 or 0 (corresponding to ``True`` and ``False``) - - .. SEEALSO:: - - ``rich_to_bool_sgn`` if ``c`` could be outside the [-1, 1] - range. - - EXAMPLES:: - - sage: from sage.structure.sage_object import (rich_to_bool, - ....: op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE) - sage: for op in (op_LT, op_LE, op_EQ, op_NE, op_GT, op_GE): - ....: for c in (-1,0,1): - ....: print(rich_to_bool(op, c)) - True False False - True True False - False True False - True False True - False False True - False True True - - Indirect tests using integers:: - - sage: 0 < 5, 5 < 5, 5 < -8 - (True, False, False) - sage: 0 <= 5, 5 <= 5, 5 <= -8 - (True, True, False) - sage: 0 >= 5, 5 >= 5, 5 >= -8 - (False, True, True) - sage: 0 > 5, 5 > 5, 5 > -8 - (False, False, True) - sage: 0 == 5, 5 == 5, 5 == -8 - (False, True, False) - sage: 0 != 5, 5 != 5, 5 != -8 - (True, False, True) - - TESTS:: - - sage: from sage.structure.sage_object import py_rich_to_bool - sage: py_rich_to_bool(op_EQ, 0) - doctest:...: DeprecationWarning: py_rich_to_bool is deprecated. Please use sage.structure.sage_object.rich_to_bool instead. - See http://trac.sagemath.org/21128 for details. - True - """ - # op is a value in [0,5], c a value in [-1,1]. We implement this - # function very efficienly using a bitfield. Note that the masking - # below implies we consider c mod 4, so c = -1 implicitly becomes - # c = 3. - - # The 4 lines below involve just constants, so the compiler should - # optimize them to just one constant value for "bits". - cdef uint32_t less_bits = (1 << Py_LT) + (1 << Py_LE) + (1 << Py_NE) - cdef uint32_t equal_bits = (1 << Py_LE) + (1 << Py_GE) + (1 << Py_EQ) - cdef uint32_t greater_bits = (1 << Py_GT) + (1 << Py_GE) + (1 << Py_NE) - cdef uint32_t bits = (less_bits << 24) + (equal_bits) + (greater_bits << 8) - - cdef int shift = 8*c + op - - # The shift masking (shift & 31) will likely be optimized away by - # the compiler since shift and bit test instructions implicitly - # mask their offset. - return (bits >> (shift & 31)) & 1 - - -cpdef inline bint rich_to_bool_sgn(int op, Py_ssize_t c): - """ - Same as ``rich_to_bool``, but allow any `c < 0` and `c > 0` - instead of only `-1` and `1`. - - .. NOTE:: - - This is in particular needed for ``mpz_cmp()``. - """ - return rich_to_bool(op, (c > 0) - (c < 0)) diff --git a/src/sage/structure/sage_object.pyx b/src/sage/structure/sage_object.pyx index bb62a4a3410..b98e3a6383f 100644 --- a/src/sage/structure/sage_object.pyx +++ b/src/sage/structure/sage_object.pyx @@ -2,6 +2,49 @@ # cython: old_style_globals=True r""" Abstract base class for Sage objects + +TESTS: + +Test deprecations:: + + sage: from sage.structure.sage_object import ( + ....: richcmp, richcmp_not_equal, + ....: rich_to_bool, py_rich_to_bool, rich_to_bool_sgn, + ....: op_EQ, op_NE, op_LT, op_LE, op_GT, op_GE) + sage: richcmp(2, 3, op_EQ) + doctest:...: DeprecationWarning: Importing richcmp from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/23103 for details. + doctest:...: DeprecationWarning: Importing op_EQ from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/23103 for details. + False + sage: richcmp_not_equal(2, 3, op_LT) + doctest:...: DeprecationWarning: Importing richcmp_not_equal from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/23103 for details. + doctest:...: DeprecationWarning: Importing op_LT from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/23103 for details. + True + sage: rich_to_bool(op_NE, 0) + doctest:...: DeprecationWarning: Importing rich_to_bool from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/23103 for details. + doctest:...: DeprecationWarning: Importing op_NE from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/23103 for details. + False + sage: py_rich_to_bool(op_GT, 1) + doctest:...: DeprecationWarning: Importing rich_to_bool from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/21128 for details. + doctest:...: DeprecationWarning: Importing op_GT from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/23103 for details. + True + sage: rich_to_bool_sgn(op_LE, -123) + doctest:...: DeprecationWarning: Importing rich_to_bool_sgn from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/23103 for details. + doctest:...: DeprecationWarning: Importing op_LE from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/23103 for details. + True + sage: op_GE + doctest:...: DeprecationWarning: Importing op_GE from here is deprecated. If you need to use it, please import it directly from sage.structure.richcmp + See http://trac.sagemath.org/23103 for details. + 5 """ from __future__ import absolute_import, print_function @@ -19,16 +62,18 @@ sys_modules = sys.modules import zlib; comp = zlib import bz2; comp_other = bz2 -op_LT = Py_LT # operator < -op_LE = Py_LE # operator <= -op_EQ = Py_EQ # operator == -op_NE = Py_NE # operator != -op_GT = Py_GT # operator > -op_GE = Py_GE # operator >= - - -from sage.misc.superseded import deprecated_function_alias -py_rich_to_bool = deprecated_function_alias(21128, rich_to_bool) +from sage.misc.lazy_import import LazyImport +richcmp = LazyImport('sage.structure.richcmp', 'richcmp', deprecation=23103) +richcmp_not_equal = LazyImport('sage.structure.richcmp', 'richcmp_not_equal', deprecation=23103) +rich_to_bool = LazyImport('sage.structure.richcmp', 'rich_to_bool', deprecation=23103) +py_rich_to_bool = LazyImport('sage.structure.richcmp', 'rich_to_bool', deprecation=21128) +rich_to_bool_sgn = LazyImport('sage.structure.richcmp', 'rich_to_bool_sgn', deprecation=23103) +op_LT = LazyImport('sage.structure.richcmp', 'op_LT', deprecation=23103) +op_LE = LazyImport('sage.structure.richcmp', 'op_LE', deprecation=23103) +op_EQ = LazyImport('sage.structure.richcmp', 'op_EQ', deprecation=23103) +op_NE = LazyImport('sage.structure.richcmp', 'op_NE', deprecation=23103) +op_GT = LazyImport('sage.structure.richcmp', 'op_GT', deprecation=23103) +op_GE = LazyImport('sage.structure.richcmp', 'op_GE', deprecation=23103) cdef process(s): diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 976960b7b02..4f863f67f1f 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -24,7 +24,7 @@ from ring import SR from sage.structure.coerce cimport py_scalar_to_element, is_numpy_type, is_mpmath_type from sage.structure.element cimport coercion_model -from sage.structure.sage_object cimport richcmp +from sage.structure.richcmp cimport richcmp # we keep a database of symbolic functions initialized in a session # this also makes the .operator() method of symbolic expressions work diff --git a/src/sage/tests/stl_vector.pyx b/src/sage/tests/stl_vector.pyx index 05c0adfe327..6caf880136a 100644 --- a/src/sage/tests/stl_vector.pyx +++ b/src/sage/tests/stl_vector.pyx @@ -32,7 +32,7 @@ from sage.rings.integer cimport Integer from sage.libs.gmp.mpz cimport mpz_add_ui from libcpp.vector cimport vector from libcpp.string cimport string -from sage.structure.sage_object cimport richcmp_not_equal, rich_to_bool +from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool cdef class stl_int_vector(SageObject): From aaedeff71f36c5d55545d8594dbfee76b9ad1939 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Mon, 29 May 2017 15:03:29 +0200 Subject: [PATCH 057/126] Rebuild interpreters if any source file changed --- .../autogen/interpreters/__init__.py | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/sage_setup/autogen/interpreters/__init__.py b/src/sage_setup/autogen/interpreters/__init__.py index bcb742da057..37d0108802d 100644 --- a/src/sage_setup/autogen/interpreters/__init__.py +++ b/src/sage_setup/autogen/interpreters/__init__.py @@ -183,6 +183,7 @@ def rebuild(dirname, force=False): sage: testdir = tmp_dir() sage: rebuild(testdir) Building interpreters for fast_callable + -> First build of interpreters sage: open(testdir + '/wrapper_el.pyx').readline() '# Automatically generated by ...\n' """ @@ -198,12 +199,28 @@ def rebuild(dirname, force=False): # Although multiple files are generated by this function, since # they are all generated at once it suffices to make sure if just # one of the generated files is older than the generator sources - src_file = __file__ - gen_file = os.path.join(dirname, '__init__.py') - - if os.path.exists(gen_file): - if getmtime(gen_file) > getmtime(src_file) and not force: - return + class NeedToRebuild(Exception): pass + try: + if force: + raise NeedToRebuild("-> Force rebuilding interpreters") + gen_file = os.path.join(dirname, '__init__.py') + if not os.path.isfile(gen_file): + raise NeedToRebuild("-> First build of interpreters") + + gen_timestamp = getmtime(gen_file) + src_dir = os.path.dirname(__file__) + for root, dirs, files in os.walk(src_dir): + for basename in files: + if basename.endswith(".py"): + src_file = os.path.join(root, basename) + src_timestamp = getmtime(src_file) + if src_timestamp > gen_timestamp: + raise NeedToRebuild("-> Rebuilding interpreters because {} changed".format(src_file)) + except NeedToRebuild as E: + # Rebuild + print(E) + else: + return # Up-to-date for interp in _INTERPRETERS: build_interp(interp(), dirname) From 4d28734ff8660e5892d0ac7d22d6df3dd80644d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 30 May 2017 22:19:00 +0200 Subject: [PATCH 058/126] py3: changing to <... 'object'> in doctests --- src/sage/categories/category.py | 14 +++++++------- src/sage/categories/category_singleton.pyx | 2 +- src/sage/categories/polyhedra.py | 2 +- src/sage/categories/sets_cat.py | 4 ++-- src/sage/combinat/root_system/type_reducible.py | 2 +- src/sage/misc/bindable_class.py | 2 +- src/sage/misc/c3_controlled.pyx | 6 +++--- src/sage/misc/test_class_pickling.py | 6 +++--- src/sage/structure/coerce.pyx | 2 +- src/sage/structure/dynamic_class.py | 10 +++++----- 10 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index b231350c8da..08849b7d824 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -275,9 +275,9 @@ class inheritance from ``C.parent_class``. sage: As().parent_class sage: As().parent_class.__bases__ - (,) + (<... 'object'>,) sage: As().parent_class.mro() - [, ] + [, <... 'object'>] :: @@ -286,7 +286,7 @@ class inheritance from ``C.parent_class``. sage: Bs().parent_class.__bases__ (,) sage: Bs().parent_class.mro() - [, , ] + [, , <... 'object'>] :: @@ -295,7 +295,7 @@ class inheritance from ``C.parent_class``. sage: Cs().parent_class.__bases__ (,) sage: Cs().parent_class.__mro__ - (, , ) + (, , <... 'object'>) :: @@ -304,7 +304,7 @@ class inheritance from ``C.parent_class``. sage: Ds().parent_class.__bases__ (, ) sage: Ds().parent_class.mro() - [, , , , ] + [, , , , <... 'object'>] Note that that two categories in the same class need not have the same ``super_categories``. For example, ``Algebras(QQ)`` has @@ -351,7 +351,7 @@ class inheritance from ``C.parent_class``. , , , - ] + <... 'object'>] sage: D.fA() 'A' sage: D.fB() @@ -376,7 +376,7 @@ class inheritance from ``C.parent_class``. , , , - ] + <... 'object'>] TESTS:: diff --git a/src/sage/categories/category_singleton.pyx b/src/sage/categories/category_singleton.pyx index 5da62ca3b07..51b0e197147 100644 --- a/src/sage/categories/category_singleton.pyx +++ b/src/sage/categories/category_singleton.pyx @@ -224,7 +224,7 @@ class Category_singleton(Category): , , , - ] + <... 'object'>] sage: R() is R() True sage: R() is R().__class__() diff --git a/src/sage/categories/polyhedra.py b/src/sage/categories/polyhedra.py index 7fae8ec433d..a20538948f2 100644 --- a/src/sage/categories/polyhedra.py +++ b/src/sage/categories/polyhedra.py @@ -40,7 +40,7 @@ class PolyhedralSets(Category_over_base_ring): , , , - ] + <... 'object'>] sage: isinstance(P, P.parent().category().element_class) True """ diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index c498cc55447..11246a597c5 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -125,7 +125,7 @@ class Sets(Category_singleton): - + <... 'object'> We run some generic checks on P:: @@ -183,7 +183,7 @@ class Sets(Category_singleton): - + <... 'object'> FIXME: Objects.element_class is not very meaningful ... diff --git a/src/sage/combinat/root_system/type_reducible.py b/src/sage/combinat/root_system/type_reducible.py index 2c336c9fadf..3a25075deda 100644 --- a/src/sage/combinat/root_system/type_reducible.py +++ b/src/sage/combinat/root_system/type_reducible.py @@ -56,7 +56,7 @@ class CartanType(SageObject, CartanType_abstract): super classes (see :meth:`~sage.combinat.root_system.cartan_type.CartanType_abstract._add_abstract_superclass`):: sage: t.__class__.mro() - [, , , , , , ] + [, , , , , , <... 'object'>] The index set of the reducible Cartan type is obtained by relabelling successively the nodes of the Dynkin diagrams of diff --git a/src/sage/misc/bindable_class.py b/src/sage/misc/bindable_class.py index 84d4d2cd6cc..065893f43d4 100644 --- a/src/sage/misc/bindable_class.py +++ b/src/sage/misc/bindable_class.py @@ -117,7 +117,7 @@ class BindableClass(six.with_metaclass(ClasscallMetaclass)): sage: type(outer.Inner).mro() [, , - ] + <... 'object'>] Still, documentation works as usual:: diff --git a/src/sage/misc/c3_controlled.pyx b/src/sage/misc/c3_controlled.pyx index 19c9ac3792d..e9fabf1754d 100644 --- a/src/sage/misc/c3_controlled.pyx +++ b/src/sage/misc/c3_controlled.pyx @@ -1041,7 +1041,7 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): sage: x.cls sage: x.cls.mro() - [, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ] + [, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , <... 'object'>] """ @staticmethod def __classcall__(cls, value, succ, key = None): @@ -1307,12 +1307,12 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): sage: x.cls sage: x.cls.mro() - [, ] + [, <... 'object'>] sage: x = HierarchyElement(30, P) sage: x.cls sage: x.cls.mro() - [, , , , , , , , ] + [, , , , , , , , <... 'object'>] """ super_classes = tuple(self._from_value(base).cls for base in self._bases_controlled) if not super_classes: diff --git a/src/sage/misc/test_class_pickling.py b/src/sage/misc/test_class_pickling.py index f43c09cb3c1..3ff5b9cff50 100644 --- a/src/sage/misc/test_class_pickling.py +++ b/src/sage/misc/test_class_pickling.py @@ -24,7 +24,7 @@ def metaclass(name, bases): sage: type(c) sage: c.__bases__ - (, ) + (<... 'object'>, ) """ print("constructing class") @@ -63,7 +63,7 @@ def __eq__(self, other): def __reduce__(self): """ - Implements the pickle protocol for classes in this metaclass + Implement the pickle protocol for classes in this metaclass (not for the instances of this class!!!) EXAMPLES:: @@ -73,7 +73,7 @@ def __reduce__(self): constructing class sage: c.__class__.__reduce__(c) reducing a class - (, ('foo3', (, ))) + (, ('foo3', (<... 'object'>, ))) """ print("reducing a class") return (metaclass, self.reduce_args) diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index 3cf0012efb8..d7f7b249056 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -278,7 +278,7 @@ cpdef bint is_numpy_type(t): sage: 1 + object() Traceback (most recent call last): ... - TypeError: unsupported operand parent(s) for +: 'Integer Ring' and '' + TypeError: unsupported operand parent(s) for +: 'Integer Ring' and '<... 'object'>' """ if not isinstance(t, type): return False diff --git a/src/sage/structure/dynamic_class.py b/src/sage/structure/dynamic_class.py index a2f5ea0f574..2269bd78e39 100644 --- a/src/sage/structure/dynamic_class.py +++ b/src/sage/structure/dynamic_class.py @@ -198,13 +198,13 @@ def dynamic_class(name, bases, cls=None, reduction=None, doccls=None, '__main__' sage: Foo.__bases__ - (,) + (<... 'object'>,) sage: FooBar.__bases__ - (, ) + (<... 'object'>, ) sage: Foo.mro() - [, ] + [, <... 'object'>] sage: FooBar.mro() - [, , ] + [, <... 'object'>, ] .. RUBRIC:: Pickling @@ -466,7 +466,7 @@ def __reduce__(self): sage: C = sage.structure.dynamic_class.dynamic_class_internal("bla", (object,), Foo, doccls = DocClass) sage: type(C).__reduce__(C) (, - ('bla', (,), , None, )) + ('bla', (<... 'object'>,), , None, )) sage: C = sage.structure.dynamic_class.dynamic_class_internal("bla", (object,), Foo, doccls = DocClass, reduction = "blah") sage: type(C).__reduce__(C) 'blah' From f1c7c2e0cba402c402f81001a357c0c986a975d1 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Tue, 30 May 2017 23:54:42 +0200 Subject: [PATCH 059/126] Memory leak problems fixed --- src/sage/rings/padics/transcendantal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/padics/transcendantal.c b/src/sage/rings/padics/transcendantal.c index e72fd992b66..1630f8c18b8 100644 --- a/src/sage/rings/padics/transcendantal.c +++ b/src/sage/rings/padics/transcendantal.c @@ -127,6 +127,7 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con mpz_fdiv_r(ans, ans, modulo); /* We clear memory */ + mpz_clear(arg); mpz_clear(f); mpz_clear(trunc_mod); mpz_clear(h); @@ -138,5 +139,6 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con mpz_clear(num[i]); mpz_clear(denom[i]); } - + free(num); + free(denom); } From af9c989bdc87c833ca2963745092e3600264699a Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Wed, 31 May 2017 08:41:25 +0200 Subject: [PATCH 060/126] Doctest issue fixed --- src/sage/rings/padics/padic_capped_absolute_element.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sage/rings/padics/padic_capped_absolute_element.pyx b/src/sage/rings/padics/padic_capped_absolute_element.pyx index 1cdb57ae1f1..d22952355bd 100644 --- a/src/sage/rings/padics/padic_capped_absolute_element.pyx +++ b/src/sage/rings/padics/padic_capped_absolute_element.pyx @@ -319,6 +319,7 @@ cdef class pAdicCappedAbsoluteElement(CAElement): NOTES: What some other systems do: + - PARI: Seems to define the logarithm for units not congruent to 1 as we do. From 6be6fe73c08e38154a8c1ad00f3c959924a96efb Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Wed, 31 May 2017 08:52:34 +0200 Subject: [PATCH 061/126] add cos example to expand_trig --- src/sage/symbolic/expression.pyx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 8517128d815..b6fa140ee30 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -4509,6 +4509,12 @@ cdef class Expression(CommutativeRingElement): sage: sin(x/2).expand_trig(half_angles=True) (-1)^floor(1/2*x/pi)*sqrt(-1/2*cos(x) + 1/2) + If the expression contains terms which are factored, we expand first:: + + sage: (x, k1, k2) = var('x, k1, k2') + sage: cos((k1-k2)*x).expand().expand_trig() + cos(k1*x)*cos(k2*x) + sin(k1*x)*sin(k2*x) + ALIASES: :meth:`trig_expand` and :meth:`expand_trig` are the same From acba60a87a465139a2f9cab59a9976b9366a01ac Mon Sep 17 00:00:00 2001 From: David Coudert Date: Wed, 31 May 2017 11:58:14 +0200 Subject: [PATCH 062/126] trac #22908: corrections --- src/sage/graphs/generators/random.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 942825a96df..182ee00e688 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -282,7 +282,7 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): EXAMPLES: - A block graph with only 1 block is a clique:: + A block graph with a single block is a clique:: sage: B = graphs.RandomBlockGraph(1, 4) sage: B.is_clique() @@ -294,7 +294,7 @@ def RandomBlockGraph(m, k, kmax=None, incidence_structure=False): sage: B.is_tree() True - Every biconnected components of a block graph are cliques:: + Every biconnected component of a block graph is a clique:: sage: B = graphs.RandomBlockGraph(5, 3, kmax=6) sage: blocks,cuts = B.blocks_and_cut_vertices() From 8f2bb4e8fc976c937e63222e4c52f7ea135b31fb Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Wed, 31 May 2017 12:31:20 +0200 Subject: [PATCH 063/126] 3 doc fixes in base.py --- src/sage/geometry/polyhedron/base.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index 13877571a54..8ed573ade30 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -574,7 +574,7 @@ def plot(self, - ``projection_direction`` -- coordinate list/tuple/iterable or ``None`` (default). The direction to use for the - :meth:`schlegel_projection`` of the polytope. If not + :meth:`schlegel_projection` of the polytope. If not specified, no projection is used in dimensions `< 4` and parallel projection is used in dimension `4`. @@ -1333,7 +1333,7 @@ def Vrepresentation(self, index=None): OUTPUT: The optional argument is an index running from ``0`` to - `self.n_Vrepresentation()-1``. If present, the + ``self.n_Vrepresentation()-1``. If present, the V-representation object at the given index will be returned. Without an argument, returns the list of all V-representation objects. @@ -2225,7 +2225,7 @@ def is_inscribed(self, certificate=False): ALGORITHM: The function first computes the circumsphere of a full-dimensional - simplex with vertices of `self`. It is found by lifting the points on a + simplex with vertices of ``self``. It is found by lifting the points on a paraboloid to find the hyperplane on which the circumsphere is lifted. Then, it checks if all other vertices are equidistant to the circumcenter of that simplex. @@ -3216,8 +3216,8 @@ def truncation(self, cut_frac=None): INPUT: - - ``cut_frac`` -- integer. how deeply to cut into the edge. - Default is `\frac{1}{3}`. + - ``cut_frac`` -- integer, how deeply to cut into the edge. + Default is `\frac{1}{3}`. OUTPUT: From 9caf02f07d17c193b5e79b636e29712ed1d46699 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 1 Jun 2017 13:55:22 +0200 Subject: [PATCH 064/126] Stop using cysignals .pxi files (part 4) --- src/sage/rings/bernmm.pyx | 3 ++- src/sage/rings/complex_arb.pyx | 2 +- src/sage/rings/complex_double.pyx | 6 +++--- src/sage/rings/complex_interval.pyx | 3 ++- src/sage/rings/finite_rings/element_givaro.pyx | 7 ++++--- src/sage/rings/finite_rings/element_ntl_gf2e.pyx | 13 ++++++------- src/sage/rings/finite_rings/element_pari_ffelt.pyx | 4 ++-- src/sage/rings/fraction_field_FpT.pyx | 2 +- src/sage/rings/number_field/totallyreal_data.pyx | 2 +- src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx | 2 +- src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx | 2 +- src/sage/rings/padics/pow_computer.pyx | 5 +++-- src/sage/rings/padics/pow_computer_flint.pyx | 4 ++-- src/sage/rings/polynomial/cyclotomic.pyx | 12 +++--------- .../multi_polynomial_ideal_libsingular.pyx | 5 ++--- .../polynomial/multi_polynomial_libsingular.pyx | 5 ++--- src/sage/rings/polynomial/pbori.pyx | 4 ++-- src/sage/rings/polynomial/plural.pyx | 2 +- src/sage/rings/polynomial/polydict.pyx | 2 +- .../rings/polynomial/polynomial_complex_arb.pyx | 2 +- .../rings/polynomial/polynomial_modn_dense_ntl.pyx | 5 +++-- .../polynomial/polynomial_real_mpfr_dense.pyx | 4 ++-- src/sage/rings/real_arb.pyx | 14 ++++++++------ src/sage/rings/real_mpfi.pyx | 2 +- src/sage/rings/real_mpfr.pyx | 7 +++---- src/sage/rings/sum_of_squares.pyx | 8 +++----- 26 files changed, 61 insertions(+), 66 deletions(-) diff --git a/src/sage/rings/bernmm.pyx b/src/sage/rings/bernmm.pyx index 9538e3d16c3..03246461e87 100644 --- a/src/sage/rings/bernmm.pyx +++ b/src/sage/rings/bernmm.pyx @@ -14,7 +14,8 @@ AUTHOR: # http://www.gnu.org/licenses/ #***************************************************************************** -include "cysignals/signals.pxi" +from cysignals.signals cimport sig_on, sig_off + from sage.libs.gmp.types cimport mpq_t diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index b949b249621..6cb9a338f74 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -128,9 +128,9 @@ Classes and Methods # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -include "cysignals/signals.pxi" import operator +from cysignals.signals cimport sig_on, sig_str, sig_off, sig_error import sage.categories.fields diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 4133bc1ab23..c34646b3d77 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -61,16 +61,16 @@ AUTHORS: # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import absolute_import -from __future__ import print_function + +from __future__ import absolute_import, print_function import operator from cpython.object cimport Py_NE +from cysignals.signals cimport sig_on, sig_off from sage.misc.randstate cimport randstate, current_randstate from cypari2.paridecl cimport * -include "cysignals/signals.pxi" from sage.libs.gsl.complex cimport * diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index c0b40e11ff7..1b876d59959 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -41,7 +41,8 @@ heavily modified: from __future__ import absolute_import, print_function -include "cysignals/signals.pxi" +from cysignals.signals cimport sig_on, sig_off + from sage.libs.gmp.mpz cimport mpz_sgn, mpz_cmpabs_ui from sage.libs.flint.fmpz cimport * from cypari2.gen cimport Gen as pari_gen diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index 743ac9fd5a3..7dc5e23ac4f 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -49,10 +49,11 @@ AUTHORS: # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import absolute_import -from __future__ import print_function -include "cysignals/signals.pxi" +from __future__ import absolute_import, print_function + +from cysignals.signals cimport sig_on, sig_off + include "sage/libs/ntl/decl.pxi" from cypari2.paridecl cimport * diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index c46207d8021..0a05ea6b106 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -20,8 +20,9 @@ AUTHORS: #***************************************************************************** from __future__ import absolute_import -include "cysignals/memory.pxi" -include "cysignals/signals.pxi" +from cysignals.memory cimport check_malloc, sig_free +from cysignals.signals cimport sig_on, sig_off + include "sage/libs/ntl/decl.pxi" from cypari2.paridecl cimport * @@ -426,9 +427,6 @@ cdef class Cache_ntl_gf2e(SageObject): self.F.restore() - cdef unsigned char *p - cdef int i - if number < 0 or number >= self.order(): raise TypeError("n must be between 0 and self.order()") @@ -443,8 +441,9 @@ cdef class Cache_ntl_gf2e(SageObject): else: raise TypeError("number %s is not an integer" % number) - p = sig_malloc(n) - for i from 0 <= i < n: + cdef unsigned char* p = check_malloc(n) + cdef long i + for i in range(n): p[i] = (number%256) number = number >> 8 GF2XFromBytes(_a, p, n) diff --git a/src/sage/rings/finite_rings/element_pari_ffelt.pyx b/src/sage/rings/finite_rings/element_pari_ffelt.pyx index 2d633b81117..a6ef1adaa8f 100644 --- a/src/sage/rings/finite_rings/element_pari_ffelt.pyx +++ b/src/sage/rings/finite_rings/element_pari_ffelt.pyx @@ -17,9 +17,9 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** +from cysignals.memory cimport sig_free +from cysignals.signals cimport sig_on, sig_off -include "cysignals/memory.pxi" -include "cysignals/signals.pxi" from cypari2.paridecl cimport * from cypari2.paripriv cimport * from sage.libs.pari.convert_gmp cimport _new_GEN_from_mpz_t diff --git a/src/sage/rings/fraction_field_FpT.pyx b/src/sage/rings/fraction_field_FpT.pyx index fdb885b48c1..685d97b1650 100644 --- a/src/sage/rings/fraction_field_FpT.pyx +++ b/src/sage/rings/fraction_field_FpT.pyx @@ -3,7 +3,7 @@ from __future__ import print_function import sys -include "cysignals/signals.pxi" +from cysignals.signals cimport sig_on, sig_off from sage.libs.gmp.mpz cimport * from sage.rings.all import GF diff --git a/src/sage/rings/number_field/totallyreal_data.pyx b/src/sage/rings/number_field/totallyreal_data.pyx index 81023469a66..10f73166a47 100644 --- a/src/sage/rings/number_field/totallyreal_data.pyx +++ b/src/sage/rings/number_field/totallyreal_data.pyx @@ -25,8 +25,8 @@ AUTHORS: from __future__ import absolute_import, print_function -include "cysignals/memory.pxi" from libc.math cimport sqrt +from cysignals.memory cimport sig_malloc, sig_free from sage.arith.all import binomial, gcd from sage.libs.gmp.mpz cimport * diff --git a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx index ffce738e1c2..1c13338a9f0 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CA_element.pyx @@ -159,8 +159,8 @@ AUTHORS: # http://www.gnu.org/licenses/ #***************************************************************************** +from cysignals.signals cimport sig_on, sig_off from sage.ext.stdsage cimport PY_NEW -include "cysignals/signals.pxi" include "sage/libs/ntl/decl.pxi" from sage.rings.integer cimport Integer diff --git a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx index bc4c5e68068..a9250cc8661 100644 --- a/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx +++ b/src/sage/rings/padics/padic_ZZ_pX_CR_element.pyx @@ -183,8 +183,8 @@ AUTHORS: #***************************************************************************** from __future__ import print_function +from cysignals.signals cimport sig_on, sig_off from sage.ext.stdsage cimport PY_NEW -include "cysignals/signals.pxi" include "sage/libs/ntl/decl.pxi" from sage.rings.integer cimport Integer diff --git a/src/sage/rings/padics/pow_computer.pyx b/src/sage/rings/padics/pow_computer.pyx index e182ea381ce..7e64802939e 100644 --- a/src/sage/rings/padics/pow_computer.pyx +++ b/src/sage/rings/padics/pow_computer.pyx @@ -33,14 +33,15 @@ AUTHORS: #***************************************************************************** import weakref +from cysignals.memory cimport sig_malloc, sig_free +from cysignals.signals cimport sig_on, sig_off + from sage.rings.infinity import infinity from sage.libs.gmp.mpz cimport * from sage.structure.sage_object cimport richcmp_not_equal, richcmp from cpython.object cimport Py_EQ, Py_NE from sage.ext.stdsage cimport PY_NEW -include "cysignals/signals.pxi" -include "cysignals/memory.pxi" cdef long maxpreccap = (1L << (sizeof(long) * 8 - 2)) - 1 diff --git a/src/sage/rings/padics/pow_computer_flint.pyx b/src/sage/rings/padics/pow_computer_flint.pyx index c8ddd3f2826..57e02e4f2b8 100644 --- a/src/sage/rings/padics/pow_computer_flint.pyx +++ b/src/sage/rings/padics/pow_computer_flint.pyx @@ -1,7 +1,7 @@ from __future__ import absolute_import -include "cysignals/signals.pxi" -include "cysignals/memory.pxi" +from cysignals.memory cimport sig_malloc, sig_free +from cysignals.signals cimport sig_on, sig_off from sage.libs.gmp.mpz cimport mpz_init, mpz_clear, mpz_pow_ui from sage.libs.flint.padic cimport * diff --git a/src/sage/rings/polynomial/cyclotomic.pyx b/src/sage/rings/polynomial/cyclotomic.pyx index e1ca22dcbe1..02083ce0b65 100644 --- a/src/sage/rings/polynomial/cyclotomic.pyx +++ b/src/sage/rings/polynomial/cyclotomic.pyx @@ -28,9 +28,8 @@ from __future__ import print_function import sys -include "cysignals/memory.pxi" -include "cysignals/signals.pxi" -from libc.string cimport memset +from cysignals.memory cimport sig_malloc, check_calloc, sig_free +from cysignals.signals cimport sig_on, sig_off from sage.structure.element cimport parent @@ -148,12 +147,7 @@ def cyclotomic_coeffs(nn, sparse=None): d = prod(s) max_deg += n / d - if (max_deg)*sizeof(long) > sys.maxsize: - raise MemoryError("Not enough memory to calculate cyclotomic polynomial of %s" % n) - cdef long* coeffs = sig_malloc(sizeof(long) * (max_deg+1)) - if coeffs == NULL: - raise MemoryError("Not enough memory to calculate cyclotomic polynomial of %s" % n) - memset(coeffs, 0, sizeof(long) * (max_deg+1)) + cdef long* coeffs = check_calloc(max_deg+1, sizeof(long)) coeffs[0] = 1 cdef long k, dd, offset = 0, deg = 0 diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx index 8c3754db3ad..14a33278563 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ideal_libsingular.pyx @@ -48,8 +48,7 @@ Two examples from the Mathematica documentation (done in Sage): # http://www.gnu.org/licenses/ #***************************************************************************** - -include "cysignals/signals.pxi" +from cysignals.signals cimport sig_on, sig_off from sage.libs.singular.decl cimport tHomog, number, IDELEMS, p_Copy, rChangeCurrRing from sage.libs.singular.decl cimport idInit, id_Delete, currRing, Sy_bit, OPT_REDSB @@ -57,7 +56,7 @@ from sage.libs.singular.decl cimport scKBase, poly, testHomog, idSkipZeroes, id_ from sage.libs.singular.decl cimport OPT_REDTAIL, singular_options, kInterRed, t_rep_gb, p_GetCoeff from sage.libs.singular.decl cimport pp_Mult_nn, p_Delete, n_Delete from sage.libs.singular.decl cimport rIsPluralRing -from sage.libs.singular.decl cimport n_unknown, n_Zp, n_Q, n_R, n_GF, n_long_R, n_algExt,n_transExt,n_long_C, n_Z, n_Zn, n_Znm, n_Z2m, n_CF +from sage.libs.singular.decl cimport n_unknown, n_Zp, n_Q, n_R, n_GF, n_long_R, n_algExt,n_transExt,n_long_C, n_Z, n_Zn, n_Znm, n_Z2m, n_CF from sage.rings.polynomial.multi_polynomial_libsingular cimport new_MP from sage.rings.polynomial.plural cimport new_NCP diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index ea51f00518e..c47a689b616 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -174,10 +174,9 @@ from __future__ import absolute_import, print_function # * pNext and pIter don't need currRing # * p_Normalize apparently needs currRing -include "cysignals/memory.pxi" -include "cysignals/signals.pxi" - from cpython.object cimport Py_NE +from cysignals.memory cimport sig_malloc, sig_free +from cysignals.signals cimport sig_on, sig_off # singular types from sage.libs.singular.decl cimport ring, poly, ideal, intvec, number, currRing diff --git a/src/sage/rings/polynomial/pbori.pyx b/src/sage/rings/polynomial/pbori.pyx index 1d3fc804c40..c89c9a8e273 100644 --- a/src/sage/rings/polynomial/pbori.pyx +++ b/src/sage/rings/polynomial/pbori.pyx @@ -183,9 +183,9 @@ REFERENCES: """ from __future__ import print_function -include "cysignals/signals.pxi" -include "cysignals/memory.pxi" from cpython.object cimport Py_EQ, Py_NE +from cysignals.memory cimport sig_malloc, sig_free +from cysignals.signals cimport sig_on, sig_off import operator diff --git a/src/sage/rings/polynomial/plural.pyx b/src/sage/rings/polynomial/plural.pyx index d92f1172fbd..d66048ae902 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -104,7 +104,7 @@ TESTS:: """ from __future__ import print_function -include "cysignals/memory.pxi" +from cysignals.memory cimport sig_malloc, sig_free from sage.categories.algebras import Algebras diff --git a/src/sage/rings/polynomial/polydict.pyx b/src/sage/rings/polynomial/polydict.pyx index e91022c6ae5..0ffb14b6097 100644 --- a/src/sage/rings/polynomial/polydict.pyx +++ b/src/sage/rings/polynomial/polydict.pyx @@ -38,11 +38,11 @@ AUTHORS: #***************************************************************************** from __future__ import print_function -include "cysignals/memory.pxi" from libc.string cimport memcpy from cpython.dict cimport * from cpython.object cimport (PyObject_RichCompare, Py_EQ, Py_NE, Py_LT, Py_LE, Py_GT, Py_GE) +from cysignals.memory cimport sig_malloc, sig_free import copy from functools import reduce diff --git a/src/sage/rings/polynomial/polynomial_complex_arb.pyx b/src/sage/rings/polynomial/polynomial_complex_arb.pyx index 2e6539da4cd..7332dc213ea 100644 --- a/src/sage/rings/polynomial/polynomial_complex_arb.pyx +++ b/src/sage/rings/polynomial/polynomial_complex_arb.pyx @@ -23,7 +23,7 @@ TESTS: """ -include "cysignals/signals.pxi" +from cysignals.signals cimport sig_on, sig_off from sage.libs.arb.acb cimport * from sage.rings.integer cimport Integer, smallInteger diff --git a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx index 457327c1666..3de0b0cb93b 100644 --- a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx @@ -28,6 +28,9 @@ AUTHORS: #***************************************************************************** from __future__ import absolute_import +from cysignals.memory cimport sig_malloc, sig_free +from cysignals.signals cimport sig_on, sig_off + from sage.rings.polynomial.polynomial_element cimport Polynomial, _dict_to_list from sage.libs.all import pari, pari_gen @@ -56,8 +59,6 @@ from sage.libs.ntl.ZZ_pX cimport * def make_element(parent, args): return parent(*args) -include "cysignals/signals.pxi" - zz_p_max = NTL_SP_BOUND cdef class Polynomial_dense_mod_n(Polynomial): diff --git a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx index f5858775d5c..5a9267732e5 100644 --- a/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx +++ b/src/sage/rings/polynomial/polynomial_real_mpfr_dense.pyx @@ -23,8 +23,8 @@ Check that operations with numpy elements work well (see :trac:`18076` and """ from __future__ import absolute_import -include "cysignals/signals.pxi" -include "cysignals/memory.pxi" +from cysignals.memory cimport check_allocarray, check_reallocarray, sig_free +from cysignals.signals cimport sig_on, sig_off from cpython cimport PyInt_AS_LONG, PyFloat_AS_DOUBLE diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 1ea5d3841d0..0dfc4f46d60 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -178,16 +178,18 @@ TESTS:: Classes and Methods =================== """ + #***************************************************************************** -# Copyright (C) 2014 Clemens Heuberger +# Copyright (C) 2014 Clemens Heuberger # -# Distributed under the terms of the GNU General Public License (GPL) -# 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/ +# 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/ #***************************************************************************** -include "cysignals/signals.pxi" +from cysignals.signals cimport sig_on, sig_str, sig_off from cpython.float cimport PyFloat_AS_DOUBLE from cpython.int cimport PyInt_AS_LONG diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 3bad4a6f4ea..9f2897ead28 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -247,10 +247,10 @@ import math # for log import sys import operator -include "cysignals/signals.pxi" from cpython.mem cimport * from cpython.object cimport Py_EQ, Py_NE, Py_LT, Py_LE, Py_GT, Py_GE from libc.string cimport strlen +from cysignals.signals cimport sig_on, sig_off from sage.libs.gmp.mpz cimport * cimport sage.rings.ring diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index e7fc8a28eeb..55adf5e21c4 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -112,16 +112,15 @@ Make sure we don't have a new field for every new literal:: # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import absolute_import -from __future__ import print_function + +from __future__ import absolute_import, print_function import math # for log import sys import re -include "cysignals/signals.pxi" - from cpython.object cimport Py_NE +from cysignals.signals cimport sig_on, sig_off from sage.ext.stdsage cimport PY_NEW from sage.libs.gmp.mpz cimport * diff --git a/src/sage/rings/sum_of_squares.pyx b/src/sage/rings/sum_of_squares.pyx index 2a8bdb0036e..63d253eea73 100644 --- a/src/sage/rings/sum_of_squares.pyx +++ b/src/sage/rings/sum_of_squares.pyx @@ -16,13 +16,11 @@ AUTHORS: # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import absolute_import -from __future__ import print_function - -from libc.math cimport sqrt +from __future__ import absolute_import, print_function -include "cysignals/signals.pxi" +from libc.math cimport sqrt +from cysignals.signals cimport sig_on, sig_off cimport sage.rings.integer as integer from . import integer From d59afe3bf4ee03da91184ae6183a6dd6a9d3656f Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 1 Jun 2017 15:26:50 +0200 Subject: [PATCH 065/126] Load the correct zlib library --- src/sage/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sage/__init__.py b/src/sage/__init__.py index 7127bcda4cc..8cd4918ff97 100644 --- a/src/sage/__init__.py +++ b/src/sage/__init__.py @@ -1,5 +1,10 @@ __all__ = ['all'] +# Make sure that the correct zlib library is loaded. This is needed +# to prevent the system zlib to be loaded instead of the Sage one. +# See https://trac.sagemath.org/ticket/23122 +import zlib + # IPython calls this when starting up def load_ipython_extension(*args): import sage.repl.ipython_extension From 711d819151f9e536f0f7b0246513544ac2e17def Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Thu, 1 Jun 2017 16:02:25 +0200 Subject: [PATCH 066/126] Clean up boost_graph.pyx --- src/sage/graphs/base/boost_graph.pyx | 310 ++++++++++++----------- src/sage/graphs/base/boost_interface.cpp | 4 +- src/sage/graphs/generic_graph.py | 17 +- 3 files changed, 166 insertions(+), 165 deletions(-) diff --git a/src/sage/graphs/base/boost_graph.pyx b/src/sage/graphs/base/boost_graph.pyx index 832c29ba4ec..796c966b10b 100644 --- a/src/sage/graphs/base/boost_graph.pyx +++ b/src/sage/graphs/base/boost_graph.pyx @@ -1,11 +1,3 @@ -#***************************************************************************** -# Copyright (C) 2015 Michele Borassi michele.borassi@imtlucca.it -# -# Distributed under the terms of the GNU General Public License (GPL) -# 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/ -#***************************************************************************** r""" Interface to run Boost algorithms @@ -44,7 +36,18 @@ Functions --------- """ -include "cysignals/signals.pxi" +#***************************************************************************** +# Copyright (C) 2015 Michele Borassi michele.borassi@imtlucca.it +# +# 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 cysignals.signals cimport sig_check, sig_on, sig_off + cdef boost_graph_from_sage_graph(BoostGenGraph *g, g_sage): r""" @@ -57,10 +60,10 @@ cdef boost_graph_from_sage_graph(BoostGenGraph *g, g_sage): from sage.graphs.generic_graph import GenericGraph if not isinstance(g_sage, GenericGraph): - raise ValueError("The input parameter must be a Sage graph.") + raise TypeError("the input must be a Sage graph") if g.num_verts() > 0: - raise ValueError("The Boost graph in input must be empty") + raise AssertionError("the given Boost graph must be empty") N = g_sage.num_verts() cdef dict vertex_to_int = {v:i for i,v in enumerate(g_sage.vertices())} @@ -71,9 +74,10 @@ cdef boost_graph_from_sage_graph(BoostGenGraph *g, g_sage): for u,v in g_sage.edge_iterator(labels=None): g.add_edge(vertex_to_int[u], vertex_to_int[v]) + cdef boost_weighted_graph_from_sage_graph(BoostWeightedGraph *g, g_sage, - weight_function = None): + weight_function=None): r""" Initializes the Boost weighted graph ``g`` to be equal to ``g_sage``. @@ -96,10 +100,10 @@ cdef boost_weighted_graph_from_sage_graph(BoostWeightedGraph *g, from sage.graphs.generic_graph import GenericGraph if not isinstance(g_sage, GenericGraph): - raise ValueError("The input parameter must be a Sage graph.") + raise TypeError("the input must be a Sage graph") if g.num_verts() > 0: - raise ValueError("The Boost graph in input must be empty") + raise AssertionError("the given Boost graph must be empty") N = g_sage.num_verts() cdef dict vertex_to_int = {v:i for i,v in enumerate(g_sage.vertices())} @@ -109,28 +113,17 @@ cdef boost_weighted_graph_from_sage_graph(BoostWeightedGraph *g, if weight_function is not None: for e in g_sage.edge_iterator(): - try: - g.add_edge(vertex_to_int[e[0]], - vertex_to_int[e[1]], - float(weight_function(e))) - - except (ValueError, TypeError): - raise ValueError("The weight function cannot find the" + - " weight of " + str(e) + ".") - + g.add_edge(vertex_to_int[e[0]], + vertex_to_int[e[1]], + float(weight_function(e))) elif g_sage.weighted(): for u,v,w in g_sage.edge_iterator(): - try: - g.add_edge(vertex_to_int[u], vertex_to_int[v], float(w)) - except (ValueError, TypeError): - raise ValueError("The weight function cannot find the" + - " weight of " + str((u,v,w)) + ".") + g.add_edge(vertex_to_int[u], vertex_to_int[v], float(w)) else: for u,v in g_sage.edge_iterator(labels=False): g.add_edge(vertex_to_int[u], vertex_to_int[v], 1) - cdef boost_edge_connectivity(BoostVecGenGraph *g): r""" Computes the edge connectivity of the input Boost graph. @@ -138,20 +131,25 @@ cdef boost_edge_connectivity(BoostVecGenGraph *g): The output is a pair ``[ec,edges]``, where ``ec`` is the edge connectivity, ``edges`` is the list of edges in a minimum cut. """ + cdef result_ec result + + sig_on() result = g[0].edge_connectivity() + sig_off() - cdef int i + cdef size_t i edges = [(result.edges[i], result.edges[i+1]) for i in range(0, result.edges.size(), 2)] - return [result.ec, edges] + return (result.ec, edges) + cpdef edge_connectivity(g): r""" Computes the edge connectivity of the input graph, using Boost. - The output is a pair ``[ec,edges]``, where ``ec`` is the edge connectivity, - ``edges`` is the list of edges in a minimum cut. + OUTPUT: a pair ``(ec, edges)``, where ``ec`` is the edge + connectivity, ``edges`` is the list of edges in a minimum cut. .. SEEALSO:: @@ -164,15 +162,14 @@ cpdef edge_connectivity(g): sage: from sage.graphs.base.boost_graph import edge_connectivity sage: g = graphs.CompleteGraph(5) sage: edge_connectivity(g) - [4, [(0, 1), (0, 2), (0, 3), (0, 4)]] + (4, [(0, 1), (0, 2), (0, 3), (0, 4)]) Vertex-labeled graphs:: sage: from sage.graphs.base.boost_graph import edge_connectivity sage: g = graphs.GridGraph([2,2]) sage: edge_connectivity(g) - [2, [((0, 0), (0, 1)), ((0, 0), (1, 0))]] - + (2, [((0, 0), (0, 1)), ((0, 0), (1, 0))]) """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph @@ -184,7 +181,6 @@ cpdef edge_connectivity(g): if isinstance(g, Graph): boost_graph_from_sage_graph(&g_boost_und, g) - sig_check() ec, edges = boost_edge_connectivity(&g_boost_und) elif isinstance(g, DiGraph): @@ -193,13 +189,13 @@ cpdef edge_connectivity(g): "in Boost. The result may be mathematically unreliable.",18753) boost_graph_from_sage_graph(&g_boost_dir, g) - sig_check() ec, edges = boost_edge_connectivity(&g_boost_dir) else: - raise ValueError("The input must be a Sage graph.") + raise TypeError("the input must be a Sage graph") + + return (ec, [(int_to_vertex[u], int_to_vertex[v]) for (u,v) in edges]) - return [ec, [(int_to_vertex[u], int_to_vertex[v]) for (u,v) in edges]] cdef boost_clustering_coeff(BoostGenGraph *g, vertices): r""" @@ -211,28 +207,32 @@ cdef boost_clustering_coeff(BoostGenGraph *g, vertices): each vertex (stored as an integer) its clustering coefficient. """ cdef result_cc result + cdef double result_d + cdef v_index vi cdef dict clust_of_v if len(vertices) == g.num_verts(): + sig_on() result = g[0].clustering_coeff_all() + sig_off() clust_of_v = {v:result.clust_of_v[v] for v in range(g.num_verts())} - return [result.average_clustering_coefficient, clust_of_v] + return (result.average_clustering_coefficient, clust_of_v) else: - clust_of_v = {v:g[0].clustering_coeff(v) for v in vertices} - return [(sum(clust_of_v.itervalues()) / len(clust_of_v)), clust_of_v] + clust_of_v = {} + for v in vertices: + vi = v + sig_on() + result_d = g[0].clustering_coeff(vi) + sig_off() + clust_of_v[v] = result_d + return ((sum(clust_of_v.itervalues()) / len(clust_of_v)), clust_of_v) -cpdef clustering_coeff(g, vertices = None): +cpdef clustering_coeff(g, vertices=None): r""" Computes the clustering coefficient of the input graph, using Boost. - The output is a pair ``[average_clustering_coefficient, clust_of_v]``, where - ``average_clustering_coefficient`` is the average clustering of the vertices - in variable ``vertices``, ``clust_of_v`` is a dictionary that associates to - each vertex its clustering coefficient. If ``vertices`` is ``None``, all - vertices are considered. - .. SEEALSO:: :meth:`sage.graphs.generic_graph.GenericGraph.clustering_coeff` @@ -244,6 +244,12 @@ cpdef clustering_coeff(g, vertices = None): - ``vertices`` (list) - the list of vertices we need to analyze (if ``None``, we will compute the clustering coefficient of all vertices). + OUTPUT: a pair ``(average_clustering_coefficient, clust_of_v)``, where + ``average_clustering_coefficient`` is the average clustering of the vertices + in variable ``vertices``, ``clust_of_v`` is a dictionary that associates to + each vertex its clustering coefficient. If ``vertices`` is ``None``, all + vertices are considered. + EXAMPLES: Computing the clustering coefficient of a clique:: @@ -251,33 +257,31 @@ cpdef clustering_coeff(g, vertices = None): sage: from sage.graphs.base.boost_graph import clustering_coeff sage: g = graphs.CompleteGraph(5) sage: clustering_coeff(g) - [1.0, {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0}] + (1.0, {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0}) sage: clustering_coeff(g, vertices = [0,1,2]) - [1.0, {0: 1.0, 1: 1.0, 2: 1.0}] + (1.0, {0: 1.0, 1: 1.0, 2: 1.0}) Of a non-clique graph with triangles:: sage: g = graphs.IcosahedralGraph() sage: clustering_coeff(g, vertices=[1,2,3]) - [0.5, {1: 0.5, 2: 0.5, 3: 0.5}] + (0.5, {1: 0.5, 2: 0.5, 3: 0.5}) With labels:: sage: g.relabel(list("abcdefghiklm")) sage: clustering_coeff(g, vertices="abde") - [0.5, {'a': 0.5, 'b': 0.5, 'd': 0.5, 'e': 0.5}] + (0.5, {'a': 0.5, 'b': 0.5, 'd': 0.5, 'e': 0.5}) """ from sage.graphs.graph import Graph - sig_on() # These variables are automatically deleted when the function terminates. cdef BoostVecGraph g_boost cdef list g_vertices = g.vertices() cdef dict vertex_to_int = {v:i for i,v in enumerate(g_vertices)} if not isinstance(g, Graph): - sig_off() - raise ValueError("The input must be a Sage graph.") + raise TypeError("the input must be a Sage Graph") boost_graph_from_sage_graph(&g_boost, g) @@ -285,13 +289,12 @@ cpdef clustering_coeff(g, vertices = None): vertices = g_vertices vertices_boost = [vertex_to_int[v] for v in vertices] - [average_clustering, clust_v_int] = boost_clustering_coeff(&g_boost, vertices_boost) + average_clustering, clust_v_int = boost_clustering_coeff(&g_boost, vertices_boost) clust_v_sage = {g_vertices[v]: clust_v_int[v] for v in vertices_boost} - sig_off() - return [average_clustering, clust_v_sage] + return (average_clustering, clust_v_sage) -cpdef dominator_tree(g, root, return_dict = False): +cpdef dominator_tree(g, root, return_dict=False): r""" Uses Boost to compute the dominator tree of ``g``, rooted at ``root``. @@ -376,50 +379,53 @@ cpdef dominator_tree(g, root, return_dict = False): sage: dominator_tree('I am not a graph', 0) Traceback (most recent call last): ... - ValueError: The input g must be a Sage graph. + TypeError: the input must be a Sage Graph or DiGraph If ``root`` is not a vertex, an error is raised:: sage: digraphs.TransitiveTournament(10).dominator_tree('Not a vertex!') Traceback (most recent call last): ... - ValueError: The input root must be a vertex of g. + ValueError: the input root must be a vertex of the given graph sage: graphs.GridGraph([2,2]).dominator_tree(0) Traceback (most recent call last): ... - ValueError: The input root must be a vertex of g. - + ValueError: the input root must be a vertex of the given graph """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph - if not isinstance(g, Graph) and not isinstance(g, DiGraph): - raise ValueError("The input g must be a Sage graph.") + if not isinstance(g, (Graph, DiGraph)): + raise TypeError("the input must be a Sage Graph or DiGraph") if not root in g.vertices(): - raise ValueError("The input root must be a vertex of g.") + raise ValueError("the input root must be a vertex of the given graph") - sig_on() # These variables are automatically deleted when the function terminates. cdef BoostVecGraph g_boost_und cdef BoostVecDiGraph g_boost_dir cdef vector[v_index] result + cdef v_index vi cdef dict vertex_to_int = {v:i for i,v in enumerate(g.vertices())} cdef list int_to_vertex = g.vertices() if isinstance(g, Graph): boost_graph_from_sage_graph(&g_boost_und, g) - result = g_boost_und.dominator_tree(vertex_to_int[root]) + vi = vertex_to_int[root] + sig_on() + result = g_boost_und.dominator_tree(vi) + sig_off() elif isinstance(g, DiGraph): boost_graph_from_sage_graph(&g_boost_dir, g) - result = g_boost_dir.dominator_tree(vertex_to_int[root]) - - sig_off() + vi = vertex_to_int[root] + sig_on() + result = g_boost_dir.dominator_tree(vi) + sig_off() cdef v_index no_parent = -1 if return_dict: - return {v:(None if result[vertex_to_int[v]] == no_parent else int_to_vertex[ result[vertex_to_int[v]]]) for v in g.vertices()}; + return {v:(None if result[vertex_to_int[v]] == no_parent else int_to_vertex[ result[vertex_to_int[v]]]) for v in g.vertices()} edges = [[int_to_vertex[ result[vertex_to_int[v]]], v] for v in g.vertices() if result[vertex_to_int[v]] != no_parent] @@ -439,7 +445,7 @@ cpdef dominator_tree(g, root, return_dict = False): return Graph(edges) -cpdef bandwidth_heuristics(g, algorithm = 'cuthill_mckee'): +cpdef bandwidth_heuristics(g, algorithm='cuthill_mckee'): r""" Uses Boost heuristics to approximate the bandwidth of the input graph. @@ -492,11 +498,11 @@ cpdef bandwidth_heuristics(g, algorithm = 'cuthill_mckee'): sage: bandwidth_heuristics(digraphs.Path(10)) Traceback (most recent call last): ... - ValueError: The input g must be a Graph. + TypeError: the input must be a Sage Graph sage: bandwidth_heuristics("I am not a graph!") Traceback (most recent call last): ... - ValueError: The input g must be a Graph. + TypeError: the input must be a Sage Graph Given a wrong algorithm:: @@ -504,7 +510,7 @@ cpdef bandwidth_heuristics(g, algorithm = 'cuthill_mckee'): sage: bandwidth_heuristics(graphs.PathGraph(3), algorithm='tip top') Traceback (most recent call last): ... - ValueError: Algorithm 'tip top' not yet implemented. Please contribute. + ValueError: unknown algorithm 'tip top' Given a graph with no edges:: @@ -519,13 +525,12 @@ cpdef bandwidth_heuristics(g, algorithm = 'cuthill_mckee'): # Tests for errors and trivial cases if not isinstance(g, Graph): - raise ValueError("The input g must be a Graph.") + raise TypeError("the input must be a Sage Graph") if not algorithm in ['cuthill_mckee', 'king']: - raise ValueError("Algorithm '%s' not yet implemented. Please contribute." %(algorithm)) + raise ValueError(f"unknown algorithm {algorithm!r}") if g.num_edges()==0: - return (0, g.vertices()); + return (0, g.vertices()) - sig_on() # These variables are automatically deleted when the function terminates. cdef BoostVecGraph g_boost cdef vector[v_index] result @@ -533,15 +538,18 @@ cpdef bandwidth_heuristics(g, algorithm = 'cuthill_mckee'): cdef list int_to_vertex = g.vertices() boost_graph_from_sage_graph(&g_boost, g) - result = g_boost.bandwidth_ordering(algorithm=='cuthill_mckee') + cdef bint use_cuthill_mckee = (algorithm == 'cuthill_mckee') + sig_on() + result = g_boost.bandwidth_ordering(use_cuthill_mckee) + sig_off() cdef int n = g.num_verts() cdef dict pos = {int_to_vertex[ result[i]]:i for i in range(n)} cdef int bandwidth = max([abs(pos[u]-pos[v]) for u,v in g.edges(labels=False)]) - sig_off() return (bandwidth, [int_to_vertex[ result[i]] for i in range(n)]) + cpdef min_spanning_tree(g, weight_function=None, algorithm='Kruskal'): @@ -599,7 +607,7 @@ cpdef min_spanning_tree(g, sage: min_spanning_tree("I am not a graph!") Traceback (most recent call last): ... - ValueError: The input g must be a Sage Graph. + TypeError: the input must be a Sage Graph Given a wrong algorithm:: @@ -614,45 +622,45 @@ cpdef min_spanning_tree(g, sage: min_spanning_tree(g) Traceback (most recent call last): ... - ValueError: The weight function cannot find the weight of (1, 2, 'a'). + ValueError: could not convert string to float: a sage: g = Graph([(0,1,1), (1,2,[1,2,3])], weighted=True) sage: min_spanning_tree(g) Traceback (most recent call last): ... - ValueError: The weight function cannot find the weight of (1, 2, [1, 2, 3]). - + TypeError: float() argument must be a string or a number """ from sage.graphs.graph import Graph if not isinstance(g, Graph): - raise ValueError("The input g must be a Sage Graph.") + raise TypeError("the input must be a Sage Graph") if not algorithm in ['Kruskal', 'Prim']: raise ValueError("Algorithm '%s' not yet implemented. Please contribute." %(algorithm)) if g.allows_loops() or g.allows_multiple_edges(): g = g.to_simple() # Now g has no self loops and no multiple edges. - sig_on() # These variables are automatically deleted when the function terminates. cdef BoostVecWeightedGraph g_boost cdef vector[v_index] result cdef dict vertex_to_int = {v:i for i,v in enumerate(g.vertices())} cdef list int_to_vertex = g.vertices() - try: - boost_weighted_graph_from_sage_graph(&g_boost, g, weight_function) - except Exception as e: - sig_off() - raise e + boost_weighted_graph_from_sage_graph(&g_boost, g, weight_function) - if algorithm=='Kruskal': - result = g_boost.kruskal_min_spanning_tree() - elif algorithm=='Prim': - result = g_boost.prim_min_spanning_tree() + if algorithm == 'Kruskal': + sig_on() + result = g_boost.kruskal_min_spanning_tree() + sig_off() + elif algorithm == 'Prim': + sig_on() + result = g_boost.prim_min_spanning_tree() + sig_off() + else: + raise ValueError(f"unknown algorithm {algorithm!r}") - cdef int n = g.num_verts() - sig_off() + cdef size_t i + cdef size_t n = g.num_verts() if result.size() != 2 * (n - 1): return [] @@ -702,7 +710,7 @@ cpdef shortest_paths(g, start, weight_function=None, algorithm=None): OUTPUT: - A pair of dictionaries ``[distances, predecessors]`` such that, for each + A pair of dictionaries ``(distances, predecessors)`` such that, for each vertex ``v``, ``distances[v]`` is the distance from ``start`` to ``v``, ``predecessors[v]`` is the last vertex in a shortest path from ``start`` to ``v``. @@ -714,17 +722,17 @@ cpdef shortest_paths(g, start, weight_function=None, algorithm=None): sage: from sage.graphs.base.boost_graph import shortest_paths sage: g = Graph([(0,1,1),(1,2,2),(1,3,4),(2,3,1)], weighted=True) sage: shortest_paths(g, 1) - [{0: 1, 1: 0, 2: 2, 3: 3}, {0: 1, 1: None, 2: 1, 3: 2}] + ({0: 1, 1: 0, 2: 2, 3: 3}, {0: 1, 1: None, 2: 1, 3: 2}) sage: g = graphs.GridGraph([2,2]) sage: shortest_paths(g,(0,0),weight_function=lambda e:2) - [{(0, 0): 0, (0, 1): 2, (1, 0): 2, (1, 1): 4}, - {(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 1)}] + ({(0, 0): 0, (0, 1): 2, (1, 0): 2, (1, 1): 4}, + {(0, 0): None, (0, 1): (0, 0), (1, 0): (0, 0), (1, 1): (0, 1)}) Directed graphs:: sage: g = DiGraph([(0,1,1),(1,2,2),(1,3,4),(2,3,1)], weighted=True) sage: shortest_paths(g, 1) - [{1: 0, 2: 2, 3: 3}, {1: None, 2: 1, 3: 2}] + ({1: 0, 2: 2, 3: 3}, {1: None, 2: 1, 3: 2}) TESTS: @@ -733,7 +741,7 @@ cpdef shortest_paths(g, start, weight_function=None, algorithm=None): sage: shortest_paths("I am not a graph!", 1) Traceback (most recent call last): ... - ValueError: The input g must be a Sage Graph or DiGraph. + TypeError: the input must be a Sage graph If there is a negative cycle:: @@ -742,7 +750,7 @@ cpdef shortest_paths(g, start, weight_function=None, algorithm=None): sage: shortest_paths(g, 1) Traceback (most recent call last): ... - ValueError: The graph contains a negative cycle. + ValueError: the graph contains a negative cycle If Dijkstra is used with negative weights:: @@ -751,7 +759,7 @@ cpdef shortest_paths(g, start, weight_function=None, algorithm=None): sage: shortest_paths(g, 1, algorithm='Dijkstra') Traceback (most recent call last): ... - ValueError: Dijkstra algorithm does not work with negative weights. Please, use Bellman-Ford. + RuntimeError: Dijkstra algorithm does not work with negative weights. Use Bellman-Ford instead Wrong starting vartex:: @@ -763,11 +771,10 @@ cpdef shortest_paths(g, start, weight_function=None, algorithm=None): from sage.graphs.generic_graph import GenericGraph if not isinstance(g, GenericGraph): - raise ValueError("The input g must be a Sage Graph or DiGraph.") - elif g.num_edges() == 0: - from sage.rings.infinity import Infinity - return [{start:0}, {start:None}] + raise TypeError("the input must be a Sage graph") + if g.num_edges() == 0: + return ({start:0}, {start:None}) # These variables are automatically deleted when the function terminates. cdef dict v_to_int = {v:i for i,v in enumerate(g.vertices())} @@ -784,58 +791,53 @@ cpdef shortest_paths(g, start, weight_function=None, algorithm=None): # Check if there are edges with negative weights if weight_function is not None: for e in g.edge_iterator(): - try: - if float(weight_function(e)) < 0: - algorithm = 'Bellman-Ford' - break - except (ValueError, TypeError): - raise ValueError("I cannot find the weight of edge " + - str(e) + ".") - + if float(weight_function(e)) < 0: + algorithm = 'Bellman-Ford' + break else: for _,_,w in g.edge_iterator(): - try: - if float(w) < 0: - algorithm = 'Bellman-Ford' - break - except (ValueError, TypeError): - raise ValueError("The label '", str(w), "' is not convertible " + - "to a float.") + if float(w) < 0: + algorithm = 'Bellman-Ford' + break if algorithm is None: algorithm = 'Dijkstra' + cdef v_index vi if algorithm in ['Bellman-Ford', 'Bellman-Ford_Boost']: if g.is_directed(): boost_weighted_graph_from_sage_graph(&g_boost_dir, g, weight_function) + vi = v_to_int[start] sig_on() - result = g_boost_dir.bellman_ford_shortest_paths(v_to_int[start]) + result = g_boost_dir.bellman_ford_shortest_paths(vi) sig_off() else: boost_weighted_graph_from_sage_graph(&g_boost_und, g, weight_function) + vi = v_to_int[start] sig_on() - result = g_boost_und.bellman_ford_shortest_paths(v_to_int[start]) + result = g_boost_und.bellman_ford_shortest_paths(vi) sig_off() if result.distances.size() == 0: - raise ValueError("The graph contains a negative cycle."); + raise ValueError("the graph contains a negative cycle") elif algorithm in ['Dijkstra', 'Dijkstra_Boost']: if g.is_directed(): boost_weighted_graph_from_sage_graph(&g_boost_dir, g, weight_function) + vi = v_to_int[start] sig_on() - result = g_boost_dir.dijkstra_shortest_paths(v_to_int[start]) + result = g_boost_dir.dijkstra_shortest_paths(vi) sig_off() else: boost_weighted_graph_from_sage_graph(&g_boost_und, g, weight_function) + vi = v_to_int[start] sig_on() - result = g_boost_und.dijkstra_shortest_paths(v_to_int[start]) + result = g_boost_und.dijkstra_shortest_paths(vi) sig_off() if result.distances.size() == 0: - raise ValueError("Dijkstra algorithm does not work with negative weights. Please, use Bellman-Ford."); + raise RuntimeError("Dijkstra algorithm does not work with negative weights. Use Bellman-Ford instead") else: - raise ValueError("Algorithm '%s' not yet implemented. Please contribute." %(algorithm)) - + raise ValueError(f"unknown algorithm {algorithm!r}") dist = {} pred = {} @@ -857,9 +859,10 @@ cpdef shortest_paths(g, start, weight_function=None, algorithm=None): w = int_to_v[v] dist[w] = correct_type(result.distances[v]) pred[w] = int_to_v[result.predecessors[v]] if result.predecessors[v] != v else None - return [dist, pred] + return (dist, pred) -cpdef johnson_shortest_paths(g, weight_function = None): + +cpdef johnson_shortest_paths(g, weight_function=None): r""" Uses Johnson algorithm to solve the all-pairs-shortest-paths. @@ -913,7 +916,7 @@ cpdef johnson_shortest_paths(g, weight_function = None): sage: johnson_shortest_paths("I am not a graph!") Traceback (most recent call last): ... - ValueError: The input g must be a Sage Graph or DiGraph. + TypeError: the input must be a Sage graph If there is a negative cycle:: @@ -921,15 +924,13 @@ cpdef johnson_shortest_paths(g, weight_function = None): sage: johnson_shortest_paths(g) Traceback (most recent call last): ... - ValueError: The graph contains a negative cycle. - + ValueError: the graph contains a negative cycle """ from sage.graphs.generic_graph import GenericGraph if not isinstance(g, GenericGraph): - raise ValueError("The input g must be a Sage Graph or DiGraph.") + raise TypeError("the input must be a Sage graph") elif g.num_edges() == 0: - from sage.rings.infinity import Infinity return {v:{v:0} for v in g.vertices()} # These variables are automatically deleted when the function terminates. cdef dict v_to_int = {v:i for i,v in enumerate(g.vertices())} @@ -951,7 +952,7 @@ cpdef johnson_shortest_paths(g, weight_function = None): sig_off() if result.size() == 0: - raise ValueError("The graph contains a negative cycle.") + raise ValueError("the graph contains a negative cycle") if weight_function is not None: correct_type = type(weight_function(next(g.edge_iterator()))) @@ -969,7 +970,8 @@ cpdef johnson_shortest_paths(g, weight_function = None): for w in range(N) if result[v][w] != sys.float_info.max} for v in range(N)} -cpdef johnson_closeness_centrality(g, weight_function = None): + +cpdef johnson_closeness_centrality(g, weight_function=None): r""" Uses Johnson algorithm to compute the closeness centrality of all vertices. @@ -1016,7 +1018,7 @@ cpdef johnson_closeness_centrality(g, weight_function = None): sage: johnson_closeness_centrality("I am not a graph!") Traceback (most recent call last): ... - ValueError: The input g must be a Sage Graph or DiGraph. + TypeError: the input must be a Sage graph If there is a negative cycle:: @@ -1025,17 +1027,14 @@ cpdef johnson_closeness_centrality(g, weight_function = None): sage: johnson_closeness_centrality(g) Traceback (most recent call last): ... - ValueError: The graph contains a negative cycle. - + ValueError: the graph contains a negative cycle """ from sage.graphs.generic_graph import GenericGraph if not isinstance(g, GenericGraph): - raise ValueError("The input g must be a Sage Graph or DiGraph.") + raise TypeError("the input must be a Sage graph") elif g.num_edges() == 0: - from sage.rings.infinity import Infinity return {} - sig_on() # These variables are automatically deleted when the function terminates. cdef BoostVecWeightedDiGraphU g_boost_dir cdef BoostVecWeightedGraph g_boost_und @@ -1047,14 +1046,17 @@ cpdef johnson_closeness_centrality(g, weight_function = None): if g.is_directed(): boost_weighted_graph_from_sage_graph(&g_boost_dir, g, weight_function) + sig_on() result = g_boost_dir.johnson_shortest_paths() + sig_off() else: boost_weighted_graph_from_sage_graph(&g_boost_und, g, weight_function) + sig_on() result = g_boost_und.johnson_shortest_paths() + sig_off() if result.size() == 0: - sig_off() - raise ValueError("The graph contains a negative cycle.") + raise ValueError("the graph contains a negative cycle") import sys for i in range(N): @@ -1068,5 +1070,5 @@ cpdef johnson_closeness_centrality(g, weight_function = None): closeness.push_back((reach-1) * (reach-1) / ((N-1) * farness)) else: closeness.push_back(sys.float_info.max) - sig_off() + sig_check() return {v: closeness[i] for i,v in enumerate(g.vertices()) if closeness[i] != sys.float_info.max} diff --git a/src/sage/graphs/base/boost_interface.cpp b/src/sage/graphs/base/boost_interface.cpp index 65f4d2e9d84..81cf793960d 100644 --- a/src/sage/graphs/base/boost_interface.cpp +++ b/src/sage/graphs/base/boost_interface.cpp @@ -105,7 +105,7 @@ class BoostGraph std::back_insert_iterator inserter(disconnecting_set); to_return.ec = boost::edge_connectivity(graph, inserter); - for (v_index i = 0; i < disconnecting_set.size(); i++) { + for (size_t i = 0; i < disconnecting_set.size(); i++) { edge_descriptor edge = disconnecting_set[i]; to_return.edges.push_back(index[boost::source(edge, graph)]); to_return.edges.push_back(index[boost::target(edge, graph)]); @@ -156,7 +156,7 @@ class BoostGraph boost::king_ordering(graph, inv_perm.rbegin()); } - for (int i = 0; i < inv_perm.size(); i++) { + for (size_t i = 0; i < inv_perm.size(); i++) { to_return.push_back(index[inv_perm[i]]); } return to_return; diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index a3fec74f674..7dcb7bf5d8a 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -3716,7 +3716,7 @@ def min_spanning_tree(self, sage: g.min_spanning_tree(algorithm="Prim_Boost") Traceback (most recent call last): ... - ValueError: The weight function cannot find the weight of (1, 2, 'a'). + ValueError: could not convert string to float: a sage: g.min_spanning_tree(algorithm="Prim_fringe") Traceback (most recent call last): ... @@ -3732,7 +3732,7 @@ def min_spanning_tree(self, sage: g.min_spanning_tree(algorithm="Kruskal_Boost") Traceback (most recent call last): ... - ValueError: The weight function cannot find the weight of (1, 2, 'a'). + ValueError: could not convert string to float: a sage: g.min_spanning_tree(algorithm="NetworkX") Traceback (most recent call last): ... @@ -3743,7 +3743,7 @@ def min_spanning_tree(self, sage: g.min_spanning_tree(algorithm="Prim_Boost") Traceback (most recent call last): ... - ValueError: The weight function cannot find the weight of (1, 2, [1, 2, 3]). + TypeError: float() argument must be a string or a number sage: g.min_spanning_tree(algorithm="Prim_fringe") Traceback (most recent call last): ... @@ -3759,7 +3759,7 @@ def min_spanning_tree(self, sage: g.min_spanning_tree(algorithm="Kruskal_Boost") Traceback (most recent call last): ... - ValueError: The weight function cannot find the weight of (1, 2, [1, 2, 3]). + TypeError: float() argument must be a string or a number sage: g.min_spanning_tree(algorithm="NetworkX") Traceback (most recent call last): ... @@ -15454,7 +15454,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, sage: D.shortest_paths(0, by_weight=True) Traceback (most recent call last): ... - ValueError: The graph contains a negative cycle. + ValueError: the graph contains a negative cycle TESTS: @@ -15479,7 +15479,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, sage: D.shortest_paths(0, algorithm='Dijkstra_Boost', by_weight=True) Traceback (most recent call last): ... - ValueError: Dijkstra algorithm does not work with negative weights. Please, use Bellman-Ford. + RuntimeError: Dijkstra algorithm does not work with negative weights. Use Bellman-Ford instead sage: D.shortest_paths(0, algorithm='Dijkstra_NetworkX', by_weight=True) Traceback (most recent call last): ... @@ -15697,7 +15697,7 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, sage: D.shortest_path_lengths(0, weight_function=weight_function) Traceback (most recent call last): ... - ValueError: The graph contains a negative cycle. + ValueError: the graph contains a negative cycle Checking that distances are equal regardless of the algorithm used:: @@ -15988,8 +15988,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: g.shortest_path_all_pairs(algorithm="Dijkstra_Boost", by_weight=True) Traceback (most recent call last): ... - ValueError: Dijkstra algorithm does not work with negative weights. Please, use Bellman-Ford. - + RuntimeError: Dijkstra algorithm does not work with negative weights. Use Bellman-Ford instead """ if default_weight is not None: deprecation(18938, "Variable default_weight is deprecated: hence," + From d454946185c59930f794a32f0c7accfdbfa81b99 Mon Sep 17 00:00:00 2001 From: Lokesh Jain Date: Thu, 1 Jun 2017 23:08:36 +0530 Subject: [PATCH 067/126] trac #7675: fixed float type dependency of weights in bidirectional dijkstra --- src/sage/graphs/base/c_graph.pyx | 36 +++++++++++++++++--------------- src/sage/graphs/generic_graph.py | 8 +++---- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index c78e5f525ae..18736aeeab2 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -2086,13 +2086,15 @@ cdef class CGraphBackend(GenericGraphBackend): - ``y`` -- the end vertex in the shortest path from ``x`` to ``y``. - - ``distance_flag`` -- flag to indicate whether shortest path or distance - from ``x`` to ``y`` is returned. If true, distance is returned. + - ``distance_flag`` -- boolean (default: ``False``). When set to + ``True``, the shortest path distance from ``x`` to ``y`` is + returned instead of the path. OUTPUT: - A list of vertices in the shortest path from ``x`` to ``y`` or - integer specifying the distance from ``x`` to ``y``. + distance from ``x`` to ``y`` is returned depending upon the value + of parameter ``distance_flag`` EXAMPLES:: @@ -2230,13 +2232,14 @@ cdef class CGraphBackend(GenericGraphBackend): ``(u, v, l)`` and outputs its weight. If ``None``, we use the edge label ``l`` as a weight. - - ``distance_flag`` -- flag to indicate whether shortest path or distance - from ``x`` to ``y`` is returned. If true, distance is returned. + - ``distance_flag`` -- boolean (default: ``False``). When set to ``True``, + the shortest path distance from ``x`` to ``y`` is returned instead of the path. OUTPUT: - A list of vertices in the shortest path from ``x`` to ``y`` or - integer specifying the distance from ``x`` to ``y``. + distance from ``x`` to ``y`` is returned depending upon the value + of parameter ``distance_flag`` EXAMPLES:: @@ -2246,12 +2249,12 @@ cdef class CGraphBackend(GenericGraphBackend): sage: G.shortest_path(0, 1, by_weight=True) [0, 1] sage: G.shortest_path_length(0, 1, by_weight=True) - 1.0 + 1 sage: G = DiGraph([(1,2,{'weight':1}), (1,3,{'weight':5}), (2,3,{'weight':1})]) sage: G.shortest_path(1, 3, weight_function=lambda e:e[2]['weight']) [1, 2, 3] sage: G.shortest_path_length(1, 3, weight_function=lambda e:e[2]['weight']) - 2.0 + 2 TEST: @@ -2259,7 +2262,7 @@ cdef class CGraphBackend(GenericGraphBackend): sage: G = Graph([(0,1,9),(0,2,8),(1,2,7)]) sage: G.shortest_path_length(0,1,by_weight=True) - 9.0 + 9 """ if x == y: return 0 @@ -2280,10 +2283,7 @@ cdef class CGraphBackend(GenericGraphBackend): cdef int v = 0 cdef int w = 0 cdef int pred - cdef float distance - cdef float edge_label cdef int side - cdef float f_tmp # Each vertex knows its predecessors in the search, for each side cdef dict pred_x = {} @@ -2310,7 +2310,6 @@ cdef class CGraphBackend(GenericGraphBackend): # which defines the shortest path found # (of length shortest_path_length). cdef int meeting_vertex = -1 - cdef float shortest_path_length if weight_function is None: weight_function = lambda e:e[2] @@ -2397,13 +2396,16 @@ cdef class CGraphBackend(GenericGraphBackend): - ``cutoff`` -- maximal distance. Longer paths will not be returned. - - ``distance_flag`` -- flag to indicate whether shortest path or distance - is returned for each vertex u. If true, distance is returned. + - ``distance_flag`` -- boolean (default: ``False``). When set to + ``True``, each vertex ``u`` connected to ``v`` is mapped to shortest path + distance from ``v`` to ``u`` instead of the shortest path in the output + dictionary. OUTPUT: - - A dictionary which associates to each vertex ``u`` the shortest path list - or distance from ``v`` to ``u`` if they are connected to each other. + - A dictionary which maps each vertex ``u`` connected to ``v`` to the + shortest path list or distance from ``v`` to ``u`` depending upon the value + of parameter ``distance_flag`` .. NOTE:: diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 99b77246a3a..5ed7076a0ac 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -13410,7 +13410,7 @@ def distance(self, u, v, by_weight=False): sage: G.distance(0, 3) 2 sage: G.distance(0, 3, by_weight=True) - 3.0 + 3 """ return self.shortest_path_length(u, v, by_weight = by_weight) @@ -15202,7 +15202,7 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_Bid_NetworkX') 5 sage: D.shortest_path_length(4, 9, algorithm='Dijkstra_Bid') - 5.0 + 5 sage: D.shortest_path_length(4, 9, algorithm='Bellman-Ford_Boost') 5 sage: D.shortest_path_length(5, 5) @@ -15215,7 +15215,7 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, sage: G.shortest_path_length(0, 3) 2 sage: G.shortest_path_length(0, 3, by_weight=True) - 3.0 + 3 sage: G.shortest_path_length(0, 3, by_weight=True, algorithm='Dijkstra_NetworkX') 3 sage: G.shortest_path_length(0, 3, by_weight=True, algorithm='Dijkstra_Bid_NetworkX') @@ -15237,7 +15237,7 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, sage: G.shortest_path_length(0, 2, by_weight=True, algorithm='Bellman-Ford_Boost') -1000 sage: G.shortest_path_length(0, 2, by_weight=True) - 2.0 + 2 """ if weight_sum is not None: deprecation(18938, "Now weight_sum is replaced by by_weight.") From 764d0587f3b1231890d6af43a6c622f21be7d251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 2 Jun 2017 09:07:41 +0200 Subject: [PATCH 068/126] py3: some care for map --- src/sage/algebras/cluster_algebra.py | 8 +++-- src/sage/arith/numerical_approx.pyx | 13 ++++---- src/sage/combinat/binary_tree.py | 2 +- src/sage/combinat/constellation.py | 2 +- src/sage/combinat/designs/database.py | 12 ++++--- src/sage/combinat/lyndon_word.py | 15 +++++---- src/sage/combinat/matrices/hadamard_matrix.py | 31 ++++++++++--------- src/sage/databases/db_modular_polynomials.py | 9 ++++-- .../dynamics/interval_exchanges/reduced.py | 11 ++++--- .../dynamics/interval_exchanges/template.py | 15 ++++----- src/sage/graphs/generators/smallgraphs.py | 16 +++++----- 11 files changed, 75 insertions(+), 59 deletions(-) diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index 02f61a8554b..bcb43f2e388 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -344,11 +344,13 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** - from __future__ import absolute_import +from six.moves import range as range +from future_builtins import map + from copy import copy from functools import wraps -from future_builtins import map + from sage.categories.homset import Hom from sage.categories.morphism import SetMorphism from sage.categories.rings import Rings @@ -374,7 +376,7 @@ from sage.structure.parent import Parent from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation -from six.moves import range as range + ############################################################################## # Elements of a cluster algebra diff --git a/src/sage/arith/numerical_approx.pyx b/src/sage/arith/numerical_approx.pyx index d445abf71f7..b53d7679099 100644 --- a/src/sage/arith/numerical_approx.pyx +++ b/src/sage/arith/numerical_approx.pyx @@ -36,13 +36,14 @@ def numerical_approx_generic(x, prec): P = parent(x) cdef Parent RR = RealField(prec) - map = RR.coerce_map_from(P) - if map is not None: - return map(x) + cmap = RR.coerce_map_from(P) + if cmap is not None: + return cmap(x) + cdef Parent CC = ComplexField(prec) - map = CC.coerce_map_from(P) - if map is not None: - return map(x) + cmap = CC.coerce_map_from(P) + if cmap is not None: + return cmap(x) # Coercion didn't work: there are 3 possibilities: # (1) There is a coercion possible to a lower precision diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 21864b8b462..9157e6bc4e9 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -4520,7 +4520,7 @@ def labelled_trees(self): # sage: BTsp_to_bintrees(BT.isotypes(range(5))[0]) # [., [., [., [., [., .]]]]] # sage: def spls(size): -# ....: return map(BTsp_to_bintrees, BT.isotypes(range(size)).list()) +# ....: return [BTsp_to_bintrees(u) for u in BT.isotypes(range(size)).list()] # sage: spls(3) # [[., [., [., .]]], [., [[., .], .]], [[., .], [., .]], [[., [., .]], .], [[[., .], .], .]] # sage: all(spls(i) == BinaryTrees(i).list() for i in range(5)) diff --git a/src/sage/combinat/constellation.py b/src/sage/combinat/constellation.py index 3edee8ee181..d3030af2ed2 100644 --- a/src/sage/combinat/constellation.py +++ b/src/sage/combinat/constellation.py @@ -1464,7 +1464,7 @@ def perm_sym_domain(g): domain = set().union(*[a for cyc in g[1:-1].split(')(') for a in cyc.split(',')]) if all(s.isdigit() for s in domain): - return map(int, domain) + return [int(x) for x in domain] else: return domain elif parent(g) in Groups: diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index ed1d9d9586f..38556471f11 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -4202,10 +4202,11 @@ def BIBD_45_9_8(from_code=False): '6q533lm6w', '6rsie7cbk', '6tjgpxic0', '70k7ao9m0', '7103zqlvk', '71i1x52bm', '7447g0dfw', '7sogja9z4', '7up5z9m9u', '7w7esu6fm', '7zmqtlrpd', '81tsbnzsw', '8kofgi1he', '8mhi35nc1', '9cv1pjiaw', '9d6ef1dah', '9dftsor9c', '9du8c1vcw', '9jr5vsnj4', 'a8b405mps', 'ajqhmxkj4', 'ax2xsvfic'] - B = [Integer(x,base=36) for x in B] + B = [Integer(x, base=36) for x in B] return [[i for i in range(45) if x&(1< 0): + if nintervals <= 0: raise ValueError('number of intervals must be positive') - a0 = range(1,nintervals+1) - f = lambda x: ReducedPermutationIET([a0,list(x)], - alphabet=alphabet) + a0 = range(1, nintervals + 1) + f = lambda x: ReducedPermutationIET([a0, list(x)], + alphabet=alphabet) return map(f, Permutations(nintervals)) else: return filter(lambda x: x.is_irreducible(), - ReducedPermutationsIET_iterator(nintervals,False,alphabet)) + ReducedPermutationsIET_iterator(nintervals, False, alphabet)) + class ReducedPermutationIET(ReducedPermutation, PermutationIET): """ diff --git a/src/sage/dynamics/interval_exchanges/template.py b/src/sage/dynamics/interval_exchanges/template.py index 852d0b993aa..857ceff7fc9 100644 --- a/src/sage/dynamics/interval_exchanges/template.py +++ b/src/sage/dynamics/interval_exchanges/template.py @@ -29,10 +29,9 @@ from six.moves import range from six import iteritems, add_metaclass -from sage.structure.sage_object import SageObject - from copy import copy +from sage.structure.sage_object import SageObject from sage.rings.integer import Integer from sage.combinat.words.alphabet import Alphabet from sage.graphs.graph import DiGraph @@ -302,7 +301,7 @@ def _repr_(self): return '' elif self._repr_type == 'reduced': - return ''.join(map(str,self[1])) + return ''.join(map(str, self[1])) else: f = getattr(self, self._repr_type) @@ -354,8 +353,8 @@ def str(self, sep= "\n"): """ l = self.list() - s0 = ' '.join(map(str,l[0])) - s1 = ' '.join(map(str,l[1])) + s0 = ' '.join(map(str, l[0])) + s1 = ' '.join(map(str, l[1])) return s0 + sep + s1 _repr_type = 'str' @@ -2797,10 +2796,8 @@ def vertex_iterator(self): a b c d d c b a """ - from builtins import map - return map( - lambda x: self._vertex_to_permutation(x), - self._succ.keys()) + for x in self._succ.keys(): + yield self._vertex_to_permutation(x) def edges(self,labels=True): r""" diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index 9f810cf4c1b..0428f69ee5b 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -4793,14 +4793,16 @@ def _EllipticLinesProjectivePlaneScheme(k): from sage.matrix.constructor import matrix from itertools import product q = 2**k - g0 = libgap.GeneralOrthogonalGroup(3,q) # invariant form x0^2+x1*x2 - g = libgap.Group(libgap.List(g0.GeneratorsOfGroup(),libgap.TransposedMat)) + g0 = libgap.GeneralOrthogonalGroup(3,q) # invariant form x0^2+x1*x2 + g = libgap.Group(libgap.List(g0.GeneratorsOfGroup(), libgap.TransposedMat)) W = libgap.FullRowSpace(libgap.GF(q), 3) - l=sum(libgap.Elements(libgap.Basis(W))) - gp = libgap.Action(g,libgap.Orbit(g,l,libgap.OnLines),libgap.OnLines) - orbitals = gp.Orbits(list(product(gp.Orbit(1),gp.Orbit(1))),libgap.OnTuples) - mats = map(lambda o: map(lambda x: (int(x[0])-1,int(x[1])-1), o), orbitals) - return map(lambda x: matrix(q*(q-1)/2, lambda i,j: 1 if (i,j) in x else 0), mats) + l = sum(libgap.Elements(libgap.Basis(W))) + gp = libgap.Action(g, libgap.Orbit(g, l, libgap.OnLines), libgap.OnLines) + orbitals = gp.Orbits(list(product(gp.Orbit(1), gp.Orbit(1))), + libgap.OnTuples) + mats = map(lambda o: [(int(x[0]) - 1, int(x[1]) - 1) for x in o], orbitals) + return [matrix(q * (q - 1) / 2, lambda i, j: 1 if (i, j) in x else 0) + for x in mats] def MathonStronglyRegularGraph(t): From d391c877165a61f305324c7296691df4ec4e4981 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 2 Jun 2017 10:59:55 +0200 Subject: [PATCH 069/126] Stop using cysignals .pxi files (part 5) --- src/sage/graphs/asteroidal_triples.pyx | 15 +++-- .../graphs/base/static_sparse_backend.pyx | 3 +- src/sage/graphs/base/static_sparse_graph.pyx | 66 +++++++------------ src/sage/graphs/centrality.pyx | 31 +++++---- src/sage/graphs/chrompoly.pyx | 18 ++--- src/sage/graphs/cliquer.pyx | 5 +- src/sage/graphs/comparability.pyx | 2 +- src/sage/graphs/generic_graph_pyx.pyx | 5 +- src/sage/graphs/genus.pyx | 6 +- .../graphs/graph_decompositions/bandwidth.pyx | 19 ++++-- .../graphs/graph_decompositions/cutwidth.pyx | 8 +-- .../graph_decompositions/fast_digraph.pyx | 6 +- .../graphs/graph_decompositions/rankwidth.pyx | 16 +++-- .../graphs/graph_decompositions/tdlib.pyx | 3 +- .../vertex_separation.pyx | 17 ++--- src/sage/graphs/hyperbolicity.pyx | 27 ++------ src/sage/graphs/modular_decomposition.pyx | 11 ++-- src/sage/graphs/trees.pyx | 21 ++---- 18 files changed, 118 insertions(+), 161 deletions(-) diff --git a/src/sage/graphs/asteroidal_triples.pyx b/src/sage/graphs/asteroidal_triples.pyx index c15986baf80..73d2f9899eb 100644 --- a/src/sage/graphs/asteroidal_triples.pyx +++ b/src/sage/graphs/asteroidal_triples.pyx @@ -60,17 +60,22 @@ References Functions --------- """ + #***************************************************************************** -# Copyright (C) 2015 David Coudert +# Copyright (C) 2015 David Coudert # -# Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# 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/ #***************************************************************************** -include "cysignals/signals.pxi" +from libc.stdint cimport uint32_t +from cysignals.signals cimport sig_on, sig_off + include "sage/data_structures/bitset.pxi" -from libc.stdint cimport uint32_t from sage.graphs.base.static_sparse_graph cimport short_digraph, init_short_digraph, free_short_digraph from sage.ext.memory_allocator cimport MemoryAllocator diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index 71d5a6b8906..a5f62c73cb4 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -36,6 +36,8 @@ Classes and methods """ from __future__ import print_function +from cysignals.memory cimport check_calloc, sig_free + from sage.graphs.base.static_sparse_graph cimport (init_short_digraph, init_reverse, out_degree, @@ -46,7 +48,6 @@ from .c_graph cimport CGraphBackend from sage.data_structures.bitset cimport FrozenBitset from libc.stdint cimport uint32_t include 'sage/data_structures/bitset.pxi' -include "cysignals/memory.pxi" cdef class StaticSparseCGraph(CGraph): """ diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 33fdded6c31..b3aa2f73dff 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -185,12 +185,14 @@ include "sage/data_structures/bitset.pxi" cimport cpython from libc.string cimport memset from libc.limits cimport INT_MAX +from libcpp.vector cimport vector +from cysignals.memory cimport check_allocarray, check_calloc, sig_free +from cysignals.signals cimport sig_on, sig_off + from sage.graphs.base.c_graph cimport CGraph from .static_sparse_backend cimport StaticSparseCGraph from .static_sparse_backend cimport StaticSparseBackend from sage.ext.memory_allocator cimport MemoryAllocator -include "cysignals/memory.pxi" -from libcpp.vector cimport vector cdef extern from "fenv.h": int FE_TONEAREST @@ -237,13 +239,8 @@ cdef int init_short_digraph(short_digraph g, G, edge_labelled = False) except -1 for i, v in enumerate(vertices): v_to_id[v] = i - g.edges = sig_malloc(n_edges*sizeof(uint32_t)) - if g.edges == NULL: - raise ValueError("Problem while allocating memory (edges)") - - g.neighbors = sig_malloc((1+g.n)*sizeof(uint32_t *)) - if g.neighbors == NULL: - raise ValueError("Problem while allocating memory (neighbors)") + g.edges = check_allocarray(n_edges, sizeof(uint32_t)) + g.neighbors = check_allocarray(1 + g.n, sizeof(uint32_t *)) # Initializing the value of neighbors g.neighbors[0] = g.edges @@ -314,13 +311,8 @@ cdef int init_empty_copy(short_digraph dst, short_digraph src) except -1: dst.edge_labels = NULL cdef list edge_labels - dst.edges = sig_malloc(n_edges(src)*sizeof(uint32_t)) - if dst.edges == NULL: - raise ValueError("Problem while allocating memory (edges)") - - dst.neighbors = sig_malloc((src.n+1)*sizeof(uint32_t *)) - if dst.neighbors == NULL: - raise ValueError("Problem while allocating memory (neighbors)") + dst.edges = check_allocarray(n_edges(src), sizeof(uint32_t)) + dst.neighbors = check_allocarray(src.n + 1, sizeof(uint32_t *)) if src.edge_labels != NULL: edge_labels = [None]*n_edges(src) @@ -342,12 +334,7 @@ cdef int init_reverse(short_digraph dst, short_digraph src) except -1: # vector. With this information, we can initialize dst.neighbors to its # correct value. The content of dst.edges is not touched at this level. - cdef int * in_degree = sig_malloc(src.n*sizeof(int)) - if in_degree == NULL: - raise ValueError("Problem while allocating memory (in_degree)") - - # Counting the degrees - memset(in_degree, 0, src.n*sizeof(int)) + cdef int * in_degree = check_calloc(src.n, sizeof(int)) for i in range(n_edges(src)): in_degree[src.edges[i]] += 1 @@ -413,9 +400,7 @@ cdef int can_be_reached_from(short_digraph g, int src, bitset_t reached) except # We will be doing a Depth-First Search. We allocate the stack we need for # that, and put "src" on top of it. - cdef int * stack = sig_malloc(g.n*sizeof(int)) - if stack == NULL: - raise ValueError("Problem while allocating memory (stack)") + cdef int * stack = check_allocarray(g.n, sizeof(int)) stack[0] = src cdef int stack_size = 1 @@ -630,18 +615,18 @@ def tarjan_strongly_connected_components(G): if not isinstance(G, DiGraph): raise ValueError("G must be a DiGraph.") - sig_on() cdef MemoryAllocator mem = MemoryAllocator() cdef short_digraph g init_short_digraph(g, G) cdef int * scc = mem.malloc(g.n * sizeof(int)) + sig_on() cdef int nscc = tarjan_strongly_connected_components_C(g, scc) + sig_off() cdef int i - cdef list output = list(list() for i in range(nscc)) # We cannot use [] here + cdef list output = [[] for i in range(nscc)] for i,v in enumerate(G.vertices()): output[scc[i]].append(v) - sig_off() return output cdef void strongly_connected_components_digraph_C(short_digraph g, int nscc, int *scc, short_digraph output): @@ -778,14 +763,9 @@ cdef strongly_connected_component_containing_vertex(short_digraph g, short_digra bitset_intersection(scc, scc, scc_reversed) cdef void free_short_digraph(short_digraph g): - if g.edges != NULL: - sig_free(g.edges) - - if g.neighbors != NULL: - sig_free(g.neighbors) - - if g.edge_labels != NULL: - cpython.Py_XDECREF(g.edge_labels) + sig_free(g.edges) + sig_free(g.neighbors) + cpython.Py_XDECREF(g.edge_labels) def triangles_count(G): r""" @@ -973,13 +953,12 @@ def spectral_radius(G, prec=1e-10): cdef long m = g.m cdef uint32_t ** neighbors = g.neighbors - cdef double * v1 = sig_malloc(n * sizeof(double)) - cdef double * v2 = sig_malloc(n * sizeof(double)) + # v1 and v2 are two arrays of length n, allocated as one array + # of length 2n for efficiency. + cdef double * vmem = check_allocarray(2*n, sizeof(double)) + cdef double * v1 = vmem + cdef double * v2 = vmem + n cdef double * v3 - if v1 == NULL or v2 == NULL: - sig_free(v1) - sig_free(v2) - raise MemoryError cdef size_t i cdef uint32_t *p @@ -1046,7 +1025,6 @@ def spectral_radius(G, prec=1e-10): fesetround(old_rounding) # and that the memory is freed - sig_free(v1) - sig_free(v2) + sig_free(vmem) return (e_min, e_max) diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx index a3c61a5f3c0..ec42d610c4a 100644 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -16,22 +16,22 @@ Functions """ from __future__ import print_function -include "sage/data_structures/bitset.pxi" -include "cysignals/signals.pxi" - -from sage.graphs.base.static_sparse_graph cimport * from libc.string cimport memset from libc.stdint cimport uint32_t +from cysignals.memory cimport check_allocarray, sig_free +from cysignals.signals cimport sig_check + +include "sage/data_structures/bitset.pxi" +from sage.graphs.base.static_sparse_graph cimport * from sage.libs.gmp.mpq cimport * from sage.rings.rational cimport Rational -include "cysignals/memory.pxi" from sage.ext.memory_allocator cimport MemoryAllocator ctypedef fused numerical_type: mpq_t double -import cython +cimport cython def centrality_betweenness(G, exact=False, normalize=True): r""" @@ -181,11 +181,11 @@ cdef dict centrality_betweenness_C(G, numerical_type _, normalize=True): init_short_digraph(g, G, edge_labelled = False) init_reverse(bfs_dag, g) - queue = check_malloc(n*sizeof(uint32_t)) - degrees = check_malloc(n*sizeof(uint32_t)) - n_paths_from_source = check_malloc(n*sizeof(numerical_type)) - betweenness_source = check_malloc(n*sizeof(numerical_type)) - betweenness = check_malloc(n*sizeof(numerical_type)) + queue = check_allocarray(n, sizeof(uint32_t)) + degrees = check_allocarray(n, sizeof(uint32_t)) + n_paths_from_source = check_allocarray(n, sizeof(numerical_type)) + betweenness_source = check_allocarray(n, sizeof(numerical_type)) + betweenness = check_allocarray(n, sizeof(numerical_type)) bitset_init(seen,n) bitset_init(next_layer,n) @@ -675,7 +675,6 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): if G.num_verts()==0 or G.num_verts()==1: return [] - sig_on() cdef MemoryAllocator mem = MemoryAllocator() cdef short_digraph sd # Copying the whole graph to obtain the list of neighbors quicker than by @@ -716,6 +715,8 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): _sort_vertices_degree(sd, sorted_vert) for x in sorted_vert[:n]: + sig_check() + if out_degree(sd, x) == 0: break # We start a BFSCut from x: @@ -741,6 +742,7 @@ def centrality_closeness_top_k(G, int k=1, int verbose=0): # The graph is explored layer by layer. while layer_current_beginning (sd.neighbors[sd.n]-sd.edges)))) - sig_off() if verbose > 0: print("Final performance ratio: {}".format(visited / (n * (sd.neighbors[sd.n]-sd.edges)))) diff --git a/src/sage/graphs/chrompoly.pyx b/src/sage/graphs/chrompoly.pyx index e05dc858ff7..c5027ae830b 100644 --- a/src/sage/graphs/chrompoly.pyx +++ b/src/sage/graphs/chrompoly.pyx @@ -23,12 +23,13 @@ REFERENCE: # http://www.gnu.org/licenses/ #***************************************************************************** +from cysignals.signals cimport sig_check + from sage.libs.gmp.mpz cimport * from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer from sage.ext.memory_allocator cimport MemoryAllocator from sage.misc.all import prod -include "cysignals/signals.pxi" def chromatic_polynomial(G, return_tree_basis=False): @@ -173,11 +174,7 @@ def chromatic_polynomial(G, return_tree_basis=False): chords2[i] = j i -= 1 try: - sig_on() - try: - contract_and_count(chords1, chords2, num_chords, nverts, tot, parent) - finally: - sig_off() + contract_and_count(chords1, chords2, num_chords, nverts, tot, parent) except BaseException: for i in range(nverts): mpz_clear(tot[i]) @@ -221,8 +218,9 @@ def chromatic_polynomial(G, return_tree_basis=False): return f -cdef int contract_and_count(int *chords1, int *chords2, int num_chords, int nverts, \ - mpz_t *tot, int *parent): + +cdef int contract_and_count(int *chords1, int *chords2, int num_chords, int nverts, + mpz_t *tot, int *parent) except -1: if num_chords == 0: mpz_add_ui(tot[nverts], tot[nverts], 1) return 0 @@ -232,7 +230,9 @@ cdef int contract_and_count(int *chords1, int *chords2, int num_chords, int nver cdef int *ins_list1 = mem.allocarray(num_chords, sizeof(int)) cdef int *ins_list2 = mem.allocarray(num_chords, sizeof(int)) cdef int i, j, k, x1, xj, z, num, insnum, parent_checked - for i from 0 <= i < num_chords: + for i in range(num_chords): + sig_check() + # contract chord i, and recurse z = chords1[i] x1 = chords2[i] diff --git a/src/sage/graphs/cliquer.pyx b/src/sage/graphs/cliquer.pyx index f2d6c2b1a44..1e78c3837d9 100644 --- a/src/sage/graphs/cliquer.pyx +++ b/src/sage/graphs/cliquer.pyx @@ -34,9 +34,8 @@ Methods # http://www.gnu.org/licenses/ #***************************************************************************** - -include "cysignals/signals.pxi" -include "cysignals/memory.pxi" +from cysignals.memory cimport sig_free +from cysignals.signals cimport sig_on, sig_off cdef extern from "sage/graphs/cliquer/cl.c": diff --git a/src/sage/graphs/comparability.pyx b/src/sage/graphs/comparability.pyx index 99e41afcfaa..5d7ec382f85 100644 --- a/src/sage/graphs/comparability.pyx +++ b/src/sage/graphs/comparability.pyx @@ -211,7 +211,7 @@ Methods #***************************************************************************** from __future__ import print_function -include "cysignals/memory.pxi" +from cysignals.memory cimport sig_free from copy import copy diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index 6847af92c46..0605ee7203c 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -22,8 +22,9 @@ AUTHORS: from __future__ import absolute_import, print_function -include "cysignals/signals.pxi" -include "cysignals/memory.pxi" +from cysignals.memory cimport check_allocarray, sig_free +from cysignals.signals cimport sig_on, sig_off + include "sage/data_structures/binary_matrix.pxi" from libc.math cimport sqrt from libc.string cimport memset diff --git a/src/sage/graphs/genus.pyx b/src/sage/graphs/genus.pyx index 8408c2a06ab..2d86e0b0fdd 100644 --- a/src/sage/graphs/genus.pyx +++ b/src/sage/graphs/genus.pyx @@ -39,6 +39,8 @@ described throughout the file. from __future__ import print_function from libc.string cimport memcpy +from cysignals.memory cimport sig_malloc, sig_free +from cysignals.signals cimport sig_on, sig_off cimport sage.combinat.permutation_cython @@ -48,10 +50,6 @@ from sage.graphs.base.dense_graph cimport DenseGraph from sage.graphs.graph import Graph -include "cysignals/memory.pxi" -include "cysignals/signals.pxi" - - cdef inline int edge_map(int i): """ We might as well make the edge map nice, since the vertex map diff --git a/src/sage/graphs/graph_decompositions/bandwidth.pyx b/src/sage/graphs/graph_decompositions/bandwidth.pyx index 00f1f506021..f1ee2198e23 100644 --- a/src/sage/graphs/graph_decompositions/bandwidth.pyx +++ b/src/sage/graphs/graph_decompositions/bandwidth.pyx @@ -100,15 +100,20 @@ This module contains the following methods Functions --------- """ + #***************************************************************************** -# Copyright (C) 2015 Nathann Cohen +# Copyright (C) 2015 Nathann Cohen # -# Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# 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/ #***************************************************************************** -include "cysignals/signals.pxi" from libc.stdint cimport uint16_t +from cysignals.signals cimport sig_check + from sage.graphs.distances_all_pairs cimport all_pairs_shortest_path_BFS from sage.graphs.base.boost_graph import bandwidth_heuristics from sage.ext.memory_allocator cimport MemoryAllocator @@ -263,7 +268,6 @@ def bandwidth(G, k=None): for i in range(n): left_to_order[i] = i - sig_on() if k is None: for kk in range((n-1)//G.diameter(),n): if bandwidth_C(n,kk,d,current,ordering,left_to_order,index_array_tmp,ith_range_array,range_array_tmp): @@ -275,13 +279,12 @@ def bandwidth(G, k=None): if ans: order = [int_to_vertex[ordering[i]] for i in range(n)] - sig_off() - if ans: ans = (kk, order) if k is None else order return ans + cdef bint bandwidth_C(int n, int k, unsigned short ** d, index_t * current, # choice of vertex for the current position @@ -304,6 +307,7 @@ cdef bint bandwidth_C(int n, int k, i = 0 while True: + sig_check() # There are (n-i) choices for vertex i, as i-1 have already been # determined. Thus, i<=current[i] +# Copyright (C) 2011 Nathann Cohen # -# Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# 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 -include "cysignals/memory.pxi" -include "cysignals/signals.pxi" +from cysignals.memory cimport check_allocarray, sig_free +from cysignals.signals cimport * from libc.string cimport memset @@ -313,7 +317,7 @@ def mkgraph(int num_vertices): from sage.graphs.graph import Graph g = Graph() - cdef subset_t * tab = sig_malloc(sizeof(subset_t) * (2*num_vertices -1)) + cdef subset_t * tab = check_allocarray(2*num_vertices - 1, sizeof(subset_t)) tab[0] = 0x7ffffffful >> (31 - num_vertices) cdef int beg = 0 diff --git a/src/sage/graphs/graph_decompositions/tdlib.pyx b/src/sage/graphs/graph_decompositions/tdlib.pyx index 968f3c3149e..252b35fa585 100644 --- a/src/sage/graphs/graph_decompositions/tdlib.pyx +++ b/src/sage/graphs/graph_decompositions/tdlib.pyx @@ -65,12 +65,11 @@ Methods """ from libcpp.vector cimport vector +from cysignals.signals cimport sig_on, sig_off from sage.sets.set import Set from sage.graphs.graph import Graph -include "cysignals/signals.pxi" - cdef extern from "tdlib/sage_tdlib.cpp": int sage_exact_decomposition(vector[unsigned int] &V_G, vector[unsigned int] &E_G, vector[vector[int]] &V_T, vector[unsigned int] &E_T, int lb) diff --git a/src/sage/graphs/graph_decompositions/vertex_separation.pyx b/src/sage/graphs/graph_decompositions/vertex_separation.pyx index de8bd6cdfa3..4683b242a17 100644 --- a/src/sage/graphs/graph_decompositions/vertex_separation.pyx +++ b/src/sage/graphs/graph_decompositions/vertex_separation.pyx @@ -283,9 +283,10 @@ Methods from __future__ import absolute_import, print_function -include "cysignals/memory.pxi" -include "cysignals/signals.pxi" from libc.string cimport memset +from cysignals.memory cimport check_malloc, sig_malloc, sig_free +from cysignals.signals cimport sig_check, sig_on, sig_off + from sage.graphs.graph_decompositions.fast_digraph cimport FastDigraph, compute_out_neighborhood_cardinality, popcount32 from libc.stdint cimport uint8_t, int8_t include "sage/data_structures/binary_matrix.pxi" @@ -355,7 +356,7 @@ def lower_bound(G): cdef int n = FD.n # minimums[i] is means to store the value of c'_{i+1} - minimums = sig_malloc(sizeof(uint8_t)* n) + minimums = check_malloc(n) cdef unsigned int i # They are initialized to n @@ -956,14 +957,8 @@ def vertex_separation_exp(G, verbose = False): print("Memory allocation") g.print_adjacency_matrix() - sig_on() - cdef unsigned int mem = 1 << g.n - cdef uint8_t * neighborhoods = sig_malloc(mem) - - if neighborhoods == NULL: - sig_off() - raise MemoryError("Error allocating memory. I just tried to allocate "+str(mem>>10)+"MB, could that be too much ?") + cdef uint8_t * neighborhoods = check_malloc(mem) memset(neighborhoods, -1, mem) @@ -972,6 +967,7 @@ def vertex_separation_exp(G, verbose = False): if verbose: print("Looking for a strategy of cost", str(k)) + sig_check() if exists(g, neighborhoods, 0, k) <= k: break @@ -982,7 +978,6 @@ def vertex_separation_exp(G, verbose = False): cdef list order = find_order(g, neighborhoods, k) sig_free(neighborhoods) - sig_off() return k, list( g.int_to_vertices[i] for i in order ) diff --git a/src/sage/graphs/hyperbolicity.pyx b/src/sage/graphs/hyperbolicity.pyx index 9569be77aa5..4ef8b6b3892 100644 --- a/src/sage/graphs/hyperbolicity.pyx +++ b/src/sage/graphs/hyperbolicity.pyx @@ -171,8 +171,10 @@ Methods #***************************************************************************** from __future__ import print_function -# imports from libc.string cimport memset +from cysignals.memory cimport check_allocarray, sig_free +from cysignals.signals cimport sig_on, sig_off + from sage.graphs.graph import Graph from sage.graphs.distances_all_pairs cimport c_distances_all_pairs from sage.arith.all import binomial @@ -180,13 +182,11 @@ from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR from sage.functions.other import floor from sage.data_structures.bitset import Bitset -include "cysignals/memory.pxi" from sage.ext.memory_allocator cimport MemoryAllocator from sage.graphs.base.static_sparse_graph cimport short_digraph from sage.graphs.base.static_sparse_graph cimport init_short_digraph from sage.graphs.base.static_sparse_graph cimport free_short_digraph from libc.stdint cimport uint16_t, uint32_t, uint64_t -include "cysignals/signals.pxi" include "sage/data_structures/bitset.pxi" @@ -535,7 +535,7 @@ cdef inline pair** sort_pairs(uint32_t N, position k a pointer to the first included pair (i,j) such that values[i][j] = k. """ - # pairs_of_length[d] is the list of pairs of vertices at distance d + # pairs_of_length[d] is the list of pairs of vertices at distance d cdef pair ** pairs_of_length = check_allocarray(D+1, sizeof(pair *)) cdef unsigned short *p_to_include cdef uint32_t i,j,k @@ -557,22 +557,11 @@ cdef inline pair** sort_pairs(uint32_t N, nb_p[0] += 1 nb_pairs_of_length[ values[i][j] ] += 1 - if pairs_of_length != NULL: - pairs_of_length[0] = check_allocarray(nb_p[0], sizeof(pair)) + pairs_of_length[0] = check_allocarray(nb_p[0], sizeof(pair)) # temporary variable used to fill pairs_of_length cdef uint32_t * cpt_pairs = check_calloc(D+1, sizeof(uint32_t)) - if (pairs_of_length == NULL or - pairs_of_length[0] == NULL or - cpt_pairs == NULL): - if pairs_of_length != NULL: - sig_free(pairs_of_length[0]) - sig_free(nb_pairs_of_length) - sig_free(pairs_of_length) - sig_free(cpt_pairs) - raise MemoryError - # ==> Defines pairs_of_length[d] for all d for i from 1 <= i <= D: pairs_of_length[i] = pairs_of_length[i-1] + nb_pairs_of_length[i-1] @@ -1406,12 +1395,6 @@ def hyperbolicity(G, _distances_ = check_allocarray(N * N, sizeof(unsigned short)) _far_apart_pairs_ = check_allocarray(N * N, sizeof(unsigned short)) far_apart_pairs = check_allocarray(N, sizeof(unsigned short *)) - if _distances_ == NULL or _far_apart_pairs_ == NULL or far_apart_pairs == NULL: - sig_free(_distances_) - sig_free(distances) - sig_free(_far_apart_pairs_) - sig_free(far_apart_pairs) - raise MemoryError("Unable to allocate array '_distances_' or '_far_apart_pairs_'.") distances_and_far_apart_pairs(G, _distances_, _far_apart_pairs_) diff --git a/src/sage/graphs/modular_decomposition.pyx b/src/sage/graphs/modular_decomposition.pyx index c822b5685e4..03150f1491a 100644 --- a/src/sage/graphs/modular_decomposition.pyx +++ b/src/sage/graphs/modular_decomposition.pyx @@ -2,9 +2,8 @@ r""" Modular decomposition """ -include "cysignals/memory.pxi" +from cysignals.memory cimport check_calloc, check_malloc -from libc.string cimport memset ##################################################### # The following code is mainly a Cythonized @@ -120,9 +119,7 @@ cpdef modular_decomposition(g): label_id[label] = id G.n = g.order() - G.G = sig_malloc(G.n*sizeof(c_adj *)) - - memset( G.G, 0, G.n*sizeof(c_adj *)) + G.G = check_calloc(G.n, sizeof(c_adj *)) # Creating the graph structure for u,v in g.edges(labels = False): @@ -130,12 +127,12 @@ cpdef modular_decomposition(g): i = label_id[u] j = label_id[v] - a= sig_malloc(sizeof(c_adj)) + a = check_malloc(sizeof(c_adj)) a.s = j a.suiv = G.G[i] G.G[i] = a - a= sig_malloc(sizeof(c_adj)) + a = check_malloc(sizeof(c_adj)) a.s = i a.suiv = G.G[j] G.G[j] = a diff --git a/src/sage/graphs/trees.pyx b/src/sage/graphs/trees.pyx index dcc21f1b1c3..3ad0de3fb42 100644 --- a/src/sage/graphs/trees.pyx +++ b/src/sage/graphs/trees.pyx @@ -16,10 +16,8 @@ REFERENCES: """ from __future__ import print_function -cdef extern from "limits.h": - cdef int INT_MAX - -include "cysignals/memory.pxi" +from libc.limits cimport INT_MAX +from cysignals.memory cimport check_allocarray, sig_free # from networkx import MultiGraph @@ -85,12 +83,8 @@ cdef class TreeIterator: sage: t = TreeIterator(100) sage: t = None # indirect doctest """ - if self.l != NULL: - sig_free(self.l) - self.l = NULL - if self.current_level_sequence != NULL: - sig_free(self.current_level_sequence) - self.current_level_sequence = NULL + sig_free(self.l) + sig_free(self.current_level_sequence) def __str__(self): r""" @@ -147,11 +141,8 @@ cdef class TreeIterator: self.first_time = 0 self.q = 0 else: - self.l = sig_malloc(self.vertices * sizeof(int)) - self.current_level_sequence = sig_malloc(self.vertices * sizeof(int)) - - if self.l == NULL or self.current_level_sequence == NULL: - raise MemoryError + self.l = check_allocarray(self.vertices, sizeof(int)) + self.current_level_sequence = check_allocarray(self.vertices, sizeof(int)) self.generate_first_level_sequence() self.first_time = 0 From 8c8d474e2225952ae918418233a5767ca97f2f0d Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Wed, 31 May 2017 17:17:43 +0200 Subject: [PATCH 070/126] =?UTF-8?q?Honor=20complex=20embeddings=20in=20con?= =?UTF-8?q?version=20=E2=84=9A[i]=20=E2=86=92=20CIF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is important because the actual complex value of number field elements (= the semantics of the embedding) often is ultimately determined by what conversions to interval fields return. --- src/sage/rings/complex_interval_field.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/complex_interval_field.py b/src/sage/rings/complex_interval_field.py index f5ea8a909bb..d9e5af767d3 100644 --- a/src/sage/rings/complex_interval_field.py +++ b/src/sage/rings/complex_interval_field.py @@ -430,6 +430,18 @@ def __call__(self, x, im=None): 3.141592653589794? + 2.718281828459046?*I sage: ComplexIntervalField(100)(CIF(RIF(2,3))) 3.? + + sage: QQi. = QuadraticField(-1) + sage: CIF(i) + 1*I + sage: QQi. = QuadraticField(-1, embedding=CC(0,-1)) + sage: CIF(i) + -1*I + sage: QQi. = QuadraticField(-1, embedding=None) + sage: CIF(i) + Traceback (most recent call last): + ... + ValueError: can not convert complex algebraic number to real interval """ if im is None: if isinstance(x, complex_interval.ComplexIntervalFieldElement): @@ -446,9 +458,14 @@ def __call__(self, x, im=None): sage_eval(x.replace(' ',''), locals={"I":self.gen(),"i":self.gen()})) late_import() - if isinstance(x, NumberFieldElement_quadratic) and list(x.parent().polynomial()) == [1, 0, 1]: - (re, im) = list(x) - return complex_interval.ComplexIntervalFieldElement(self, re, im) + if isinstance(x, NumberFieldElement_quadratic): + parent = x.parent() + if (list(parent.polynomial()) == [1, 0, 1] and + parent.coerce_embedding() is not None): + (re, im) = list(x) + if not parent._standard_embedding: + im = -im + return complex_interval.ComplexIntervalFieldElement(self, re, im) try: return x._complex_mpfi_( self ) From bd36878014430b91b557ed962c40c65eba100224 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 2 Jun 2017 12:14:37 +0200 Subject: [PATCH 071/126] Fix matchpoly() for graphs without edges --- src/sage/graphs/matchpoly.pyx | 44 +++++++++++++++++------------------ 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/sage/graphs/matchpoly.pyx b/src/sage/graphs/matchpoly.pyx index dc3f0b7b9b8..8c6b87fca3c 100644 --- a/src/sage/graphs/matchpoly.pyx +++ b/src/sage/graphs/matchpoly.pyx @@ -25,18 +25,22 @@ Methods """ #***************************************************************************** -# Copyright (C) 2010 Robert Miller +# Copyright (C) 2010 Robert Miller # -# Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# 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 cysignals.memory cimport check_allocarray, sig_free +from cysignals.signals cimport sig_on, sig_off + from sage.rings.polynomial.polynomial_ring import polygen from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer from sage.misc.all import prod -include "cysignals/signals.pxi" -include "cysignals/memory.pxi" from sage.libs.flint.fmpz cimport * from sage.libs.flint.fmpz_poly cimport * @@ -250,26 +254,20 @@ def matching_polynomial(G, complement=True, name=None): # The edges_mem table is of size (2 * nedges * nedges), and is to be read as # nedges blocks of size (2 * nedges). These blocks of size (2 * nedges) are # themselves to be read as two blocks of length nedges, addressed as edges1 - # and edges2 - - # Only the first block of size (2*nedges) is here filled. The function + # and edges2. + # + # Only the first block of size (2 * nedges) is here filled. The function # delete_and_add will need the rest of the memory. fmpz_poly_init(pol) # sets to zero - edges_mem = sig_malloc(2 * nedges * nedges * sizeof(int)) - edges = sig_malloc(2 * nedges * sizeof(int *)) - if edges_mem is NULL or edges is NULL: - if edges_mem is not NULL: - sig_free(edges_mem) - if edges is not NULL: - sig_free(edges) - raise MemoryError("Error allocating memory for matchpoly.") - - for i from 0 <= i < 2 * nedges: + edges = check_allocarray(2 * nedges, sizeof(int *)) + edges_mem = check_allocarray(2 * nedges * nedges, sizeof(int)) + + for i in range(2 * nedges): edges[i] = edges_mem + i * nedges - edges1 = edges[0] - edges2 = edges[1] + edges1 = edges_mem # edges[0] + edges2 = edges_mem + nedges # edges[1] cur = 0 for i, j in sorted(map(sorted, G.edges(labels=False))): @@ -285,12 +283,12 @@ def matching_polynomial(G, complement=True, name=None): # Building the actual matching polynomial - coeffs_ZZ = [] + cdef list coeffs_ZZ = [] cdef Integer c_ZZ - for i from 0 <= i <= nverts: + for i in range(nverts + 1): c_ZZ = Integer(0) fmpz_poly_get_coeff_mpz(c_ZZ.value, pol, i) - coeffs_ZZ.append(c_ZZ * (-1)**((nverts - i) / 2)) + coeffs_ZZ.append(c_ZZ * (-1)**((nverts - i) // 2)) f = x.parent()(coeffs_ZZ) sig_free(edges_mem) From 6e22ec42f4d22c14231399a4447d711c277487bb Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Tue, 30 May 2017 16:32:47 +0200 Subject: [PATCH 072/126] Remove this unnecessary hack for Cygwin; we don't need to use gslcblas for Cygwin --- src/sage/misc/cython.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 7731e153e5c..3cdfcfcfe4d 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -35,12 +35,8 @@ cblas_library_dirs = list(cblas_pc['library_dirs']) cblas_include_dirs = list(cblas_pc['include_dirs']) -# TODO: Remove Cygwin hack by installing a suitable cblas.pc -if os.path.exists('/usr/lib/libblas.dll.a'): - cblas_libs = 'gslcblas' - standard_libs = [ - 'mpfr', 'gmp', 'gmpxx', 'stdc++', 'pari', 'm', + 'mpfr', 'gmp', 'gmpxx', 'stdc++', 'pari', 'm', 'ec', 'gsl', ] + cblas_libs + [ 'ntl'] From 031761f6ead116e4fa0a0fd3bf21fca5546df6d7 Mon Sep 17 00:00:00 2001 From: Jeroen Demeyer Date: Fri, 2 Jun 2017 21:16:33 +0200 Subject: [PATCH 073/126] Fix two more imports --- src/sage/rings/padics/padic_generic.py | 2 +- src/sage/schemes/elliptic_curves/weierstrass_morphism.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 079d2cd6cba..67ca6678c92 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -38,7 +38,7 @@ from sage.rings.padics.padic_printing import pAdicPrinter from sage.rings.padics.precision_error import PrecisionError from sage.misc.cachefunc import cached_method -from sage.structure.sage_object import richcmp_not_equal +from sage.structure.richcmp import richcmp_not_equal class pAdicGeneric(PrincipalIdealDomain, LocalGeneric): diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index 86648d76b5e..8e39abaf108 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -26,8 +26,8 @@ from sage.categories.morphism import Morphism from .constructor import EllipticCurve from sage.categories.homset import Hom -from sage.structure.sage_object import (richcmp, richcmp_not_equal, - op_NE, op_EQ, op_LT) +from sage.structure.richcmp import (richcmp, richcmp_not_equal, + op_NE, op_EQ, op_LT) class baseWI: From 77233e1481e8a22699889e863f0e0bb68e47ce83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Fri, 2 Jun 2017 23:11:47 +0200 Subject: [PATCH 074/126] trac 23130 fixing strange range import --- src/sage/algebras/cluster_algebra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index bcb43f2e388..6e39df3e880 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -345,7 +345,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import absolute_import -from six.moves import range as range +from six.moves import range from future_builtins import map from copy import copy From d3ae56f3d4e8de46121b2e2e64e2996885357447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sat, 3 Jun 2017 10:00:20 +0200 Subject: [PATCH 075/126] py3: deprecate lexico comparison for complex intervals --- src/sage/rings/complex_interval.pyx | 35 +++++++++++++++++++++++------ src/sage/rings/real_mpfi.pyx | 2 +- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index c0b40e11ff7..1bccb5ca15c 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -1478,7 +1478,7 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): elif op == Py_GE: return real_diff > 0 or (real_diff == 0 and imag_diff >= 0) - cpdef int _cmp_(left, right) except -2: + def lexico_cmp(left, right): """ Intervals are compared lexicographically on the 4-tuple: ``(x.real().lower(), x.real().upper(), @@ -1489,15 +1489,15 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): sage: a = CIF(RIF(0,1), RIF(0,1)) sage: b = CIF(RIF(0,1), RIF(0,2)) sage: c = CIF(RIF(0,2), RIF(0,2)) - sage: cmp(a, b) + sage: a.lexico_cmp(b) -1 - sage: cmp(b, c) + sage: b.lexico_cmp(c) -1 - sage: cmp(a, c) + sage: a.lexico_cmp(c) -1 - sage: cmp(a, a) + sage: a.lexico_cmp(a) 0 - sage: cmp(b, a) + sage: b.lexico_cmp(a) 1 TESTS:: @@ -1510,7 +1510,12 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): ....: tests.append((CIF(RIF(rl, ru), RIF(il, iu)), (rl, ru, il, iu))) sage: for (i1, t1) in tests: ....: for (i2, t2) in tests: - ....: assert(cmp(i1, i2) == cmp(t1, t2)) + ....: if t1 == t2: + ....: assert(i1.lexico_cmp(i2) == 0) + ....: elif t1 < t2: + ....: assert(i1.lexico_cmp(i2) == -1) + ....: elif t1 > t2: + ....: assert(i1.lexico_cmp(i2) == 1) """ cdef int a, b a = mpfi_nan_p(left.__re) @@ -1541,6 +1546,22 @@ cdef class ComplexIntervalFieldElement(sage.structure.element.FieldElement): return 1 return 0 + cpdef int _cmp_(self, other) except -2: + """ + Deprecated method (:trac:`23133`) + + EXAMPLES:: + + sage: a = CIF(RIF(0,1), RIF(0,1)) + sage: a._cmp_(a) + doctest:...: DeprecationWarning: for CIF elements, do not use cmp + See http://trac.sagemath.org/23133 for details. + 0 + """ + from sage.misc.superseded import deprecation + deprecation(23133, 'for CIF elements, do not use cmp') + return self.lexico_cmp(other) + ######################################################################## # Transcendental (and other) functions ######################################################################## diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 3bad4a6f4ea..45a79f605fd 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -3824,7 +3824,7 @@ cdef class RealIntervalFieldElement(RingElement): EXAMPLES:: sage: a = RIF(1) - sage: a.__cmp__(a) + sage: a._cmp_(a) doctest:...: DeprecationWarning: for RIF elements, do not use cmp See http://trac.sagemath.org/22907 for details. 0 From db5e54baa7eb69afd4dace8c4aeaf10e780c2a1f Mon Sep 17 00:00:00 2001 From: Lokesh Jain Date: Sat, 3 Jun 2017 20:38:05 +0530 Subject: [PATCH 076/126] trac #7675: distances_int removed from shortest_path_all_vertices + improved error message --- src/sage/graphs/base/c_graph.pyx | 15 ++++++++------- src/sage/graphs/generic_graph.py | 25 ++++++++++++------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index 18736aeeab2..b5a206371a9 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -2216,7 +2216,8 @@ cdef class CGraphBackend(GenericGraphBackend): return Infinity return [] - def bidirectional_dijkstra(self, x, y, weight_function=None, distance_flag = False): + def bidirectional_dijkstra(self, x, y, weight_function=None, + distance_flag = False): r""" Returns the shortest path or distance from ``x`` to ``y`` using a bidirectional version of Dijkstra's algorithm. @@ -2385,7 +2386,8 @@ cdef class CGraphBackend(GenericGraphBackend): return shortest_path - def shortest_path_all_vertices(self, v, cutoff=None, distance_flag = False): + def shortest_path_all_vertices(self, v, cutoff=None, + distance_flag = False): r""" Returns for each vertex ``u`` a shortest ``v-u`` path or distance from ``v`` to ``u``. @@ -2445,7 +2447,6 @@ cdef class CGraphBackend(GenericGraphBackend): cdef bitset_t seen cdef int v_int cdef int u_int - cdef dict distances_int = {} cdef dict distances cdef int d @@ -2463,8 +2464,8 @@ cdef class CGraphBackend(GenericGraphBackend): current_layer = [(u_int, v_int) for u_int in self._cg.out_neighbors(v_int)] next_layer = [] - distances[v] = [v] - distances_int[v] = 0 + + distances[v] = 0 if distance_flag else [v] while current_layer: if cutoff is not None and d >= cutoff: @@ -2477,7 +2478,7 @@ cdef class CGraphBackend(GenericGraphBackend): if bitset_not_in(seen, v_int): bitset_add(seen, v_int) if distance_flag: - distances_int[self.vertex_label(v_int)] = d + distances[self.vertex_label(v_int)] = d else: distances[self.vertex_label(v_int)] = distances[self.vertex_label(u_int)] + [self.vertex_label(v_int)] next_layer.extend([(u_int, v_int) for u_int in self._cg.out_neighbors(v_int)]) @@ -2493,7 +2494,7 @@ cdef class CGraphBackend(GenericGraphBackend): # distances[vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)] = [] bitset_free(seen) - return distances_int if distance_flag else distances + return distances def depth_first_search(self, v, reverse=False, ignore_direction=False): r""" diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 5ed7076a0ac..24d4932794f 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -13613,7 +13613,7 @@ def eccentricity(self, v=None, by_weight=False, algorithm=None, sage: G.eccentricity(algorithm = 'boh') Traceback (most recent call last): ... - ValueError: Algorithm boh not yet implemented. Please, contribute! + ValueError: unknown algorithm "boh" An algorithm that does not work with edge weights:: @@ -15263,16 +15263,16 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, if by_weight: if algorithm == 'BFS_Bid': - raise ValueError("The 'BFS_Bid' algorithm does not " + - "work on weighted graphs.") + raise ValueError("the 'BFS_Bid' algorithm does not " + + "work on weighted graphs") if check_weight: self._check_weight_function(weight_function) else: weight_function = lambda e:1 - if algorithm=="Dijkstra_Bid": + if algorithm == "Dijkstra_Bid": return self._backend.bidirectional_dijkstra(u, v, weight_function, distance_flag=True) - elif algorithm=="Dijkstra_Bid_NetworkX": + elif algorithm == "Dijkstra_Bid_NetworkX": import networkx if self.is_directed(): G = networkx.DiGraph([(e[0], e[1], dict(weight=weight_function(e))) for e in self.edge_iterator()]) @@ -15280,10 +15280,10 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, G = networkx.Graph([(e[0], e[1], dict(weight=weight_function(e))) for e in self.edge_iterator()]) G.add_nodes_from(self.vertices()) return networkx.bidirectional_dijkstra(G, u, v)[0] - elif algorithm=="BFS_Bid": + elif algorithm == "BFS_Bid": return self._backend.shortest_path(u, v, distance_flag=True) else: - raise ValueError("Algorithm '" + algorithm + "' not yet implemented.") + raise ValueError('unknown algorithm "{}"'.format(algorithm)) def _check_weight_function(self, weight_function=None): r""" @@ -15712,13 +15712,13 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, if by_weight and check_weight: self._check_weight_function(weight_function) - if algorithm=='BFS': + if algorithm == 'BFS': if by_weight: - raise ValueError("The 'BFS' algorithm does not work on " + - "weighted graphs.") + raise ValueError("the 'BFS' algorithm does not work on " + + "weighted graphs") return self._backend.shortest_path_all_vertices(u, cutoff=None, distance_flag=True) - elif algorithm=='Dijkstra_NetworkX': + elif algorithm == 'Dijkstra_NetworkX': import networkx # If this is not present, an error might be raised by NetworkX if self.num_verts()==1 and self.vertices()[0]==u: @@ -15743,8 +15743,7 @@ def shortest_path_lengths(self, u, by_weight=False, algorithm=None, return shortest_paths(self, u, weight_function, algorithm)[0] else: - raise ValueError("Algorithm " + algorithm + " not yet " + - "implemented. Please, contribute!") + raise ValueError('unknown algorithm "{}"'.format(algorithm)) def shortest_path_all_pairs(self, by_weight=False, algorithm=None, weight_function=None, check_weight=True, From 7b85dc25f339d0988761c22da2f3dd4a2edc94c4 Mon Sep 17 00:00:00 2001 From: Dima Pasechnik Date: Sat, 3 Jun 2017 08:53:33 +0100 Subject: [PATCH 077/126] bumping up the version --- build/pkgs/sagenb/checksums.ini | 6 +++--- build/pkgs/sagenb/package-version.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/pkgs/sagenb/checksums.ini b/build/pkgs/sagenb/checksums.ini index 2ed6a82d220..234b621d739 100644 --- a/build/pkgs/sagenb/checksums.ini +++ b/build/pkgs/sagenb/checksums.ini @@ -1,4 +1,4 @@ tarball=sagenb-VERSION.tar.bz2 -sha1=96ad0750cf953ac5d5f5d987f15bfad75f1dcb24 -md5=005a97641e8c5bc74f10d438d0056903 -cksum=1197603683 +sha1=cd46f50bf3f71a452735e7ad5573928ebc190f23 +md5=fea1225a9d630ac4a4f35fc6d936de0a +cksum=1620865525 diff --git a/build/pkgs/sagenb/package-version.txt b/build/pkgs/sagenb/package-version.txt index d3827e75a5c..7dea76edb3d 100644 --- a/build/pkgs/sagenb/package-version.txt +++ b/build/pkgs/sagenb/package-version.txt @@ -1 +1 @@ -1.0 +1.0.1 From 63c8f65e52c1684d7599ed86e947edb3b2b10f0d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Sun, 4 Jun 2017 03:13:17 -0500 Subject: [PATCH 078/126] Use matrix_space. --- src/sage/matrix/matrix2.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index ea11131ca90..f016de3e60e 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -8089,13 +8089,13 @@ cdef class Matrix(matrix1.Matrix): sage: m2.tensor_product(m3).dimensions() (0, 6) """ - from sage.matrix.constructor import block_matrix if not isinstance(A, Matrix): raise TypeError('tensor product requires a second matrix, not {0}'.format(A)) + from sage.matrix.constructor import matrix, block_matrix # Special case when one of the matrices is 0 \times m or m \times 0 if self.nrows() == 0 or self.ncols() == 0 or A.nrows() == 0 or A.ncols() == 0: - return sage.matrix.constructor.matrix(QQ, self.nrows()*A.nrows(), - self.ncols()*A.ncols(), []) + return self.matrix_space(self.nrows()*A.nrows(), + self.ncols()*A.ncols())([]) return block_matrix(self.nrows(), self.ncols(), [x * A for x in self.list()], subdivide=subdivide) From 622ab02a8e5d81b1609f93974f438fe69c902a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 4 Jun 2017 15:52:14 +0200 Subject: [PATCH 079/126] free dendriform algebras also adding the required sorting keys and some methods for binary trees --- src/doc/en/reference/algebras/index.rst | 1 + src/doc/en/reference/combinat/module_list.rst | 1 + src/sage/algebras/catalog.py | 5 +- src/sage/combinat/algebraic_combinatorics.py | 2 + src/sage/combinat/binary_tree.py | 229 ++++++- src/sage/combinat/free_dendriform_algebra.py | 595 ++++++++++++++++++ 6 files changed, 829 insertions(+), 4 deletions(-) create mode 100644 src/sage/combinat/free_dendriform_algebra.py diff --git a/src/doc/en/reference/algebras/index.rst b/src/doc/en/reference/algebras/index.rst index 71ebb39b6f3..a6cf3cab270 100644 --- a/src/doc/en/reference/algebras/index.rst +++ b/src/doc/en/reference/algebras/index.rst @@ -80,6 +80,7 @@ Non-associative algebras lie_algebras sage/algebras/jordan_algebra + sage/combinat/free_dendriform_algebra sage/combinat/free_prelie_algebra sage/algebras/shuffle_algebra sage/algebras/free_zinbiel_algebra diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 06a3214d6ef..2d8863be5ca 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -118,6 +118,7 @@ Comprehensive Module list sage/combinat/finite_state_machine sage/combinat/finite_state_machine_generators sage/combinat/free_module + sage/combinat/free_dendriform_algebra sage/combinat/free_prelie_algebra sage/combinat/fully_packed_loop sage/combinat/gelfand_tsetlin_patterns diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index 449268d5c54..b1795f21afa 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -20,7 +20,8 @@ ` - :class:`algebras.Free ` - :class:`algebras.FreeZinbiel ` -- :class:`algebras.PreLieAlgebra ` +- :class:`algebras.FreePreLie ` +- :class:`algebras.FreeDendriform ` - :func:`algebras.GradedCommutative ` - :class:`algebras.Group ` @@ -82,6 +83,6 @@ lazy_import('sage.combinat.diagram_algebras', 'TemperleyLiebAlgebra', 'TemperleyLieb') lazy_import('sage.combinat.posets.moebius_algebra', 'MoebiusAlgebra', 'Moebius') lazy_import('sage.combinat.free_prelie_algebra', 'FreePreLieAlgebra', 'FreePreLie') +lazy_import('sage.combinat.free_dendriform_algebra', 'FreeDendriformAlgebra', 'FreeDendriform') lazy_import('sage.algebras.tensor_algebra', 'TensorAlgebra', 'Tensor') del lazy_import # We remove the object from here so it doesn't appear under tab completion - diff --git a/src/sage/combinat/algebraic_combinatorics.py b/src/sage/combinat/algebraic_combinatorics.py index d241a8b7bd5..5883e42f82e 100644 --- a/src/sage/combinat/algebraic_combinatorics.py +++ b/src/sage/combinat/algebraic_combinatorics.py @@ -60,5 +60,7 @@ Operads and their algebras -------------------------- +- :ref:`sage.combinat.free_dendriform_algebra` - :ref:`sage.combinat.free_prelie_algebra` +- :ref:`sage.algebras.free_zinbiel_algebra` """ diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 21864b8b462..df2cf946666 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -643,6 +643,35 @@ def node_to_str(bt): t_repr._baseline = t_repr._h - 1 return t_repr + def sort_key(self): + """ + Return a tuple of nonnegative integers encoding the binary + tree ``self``. + + The first entry of the tuple is the number of children of the + root. Then the rest of the tuple is the concatenation of the + tuples associated to these children (we view the children of + a tree as trees themselves) from left to right. + + This tuple characterizes the tree uniquely, and can be used to + sort the binary trees. + + EXAMPLES:: + + sage: x = BinaryTree([]) + sage: y = (x.under(x)).over(x) + sage: y.sort_key() + (2, 2, 0, 0, 2, 0, 0) + sage: z = (x.over(x)).under(x) + sage: z.sort_key() + (2, 2, 0, 2, 0, 0, 0) + """ + l = len(self) + if l == 0: + return (0,) + resu = [l] + [u for t in self for u in t.sort_key()] + return tuple(resu) + def is_empty(self): """ Return whether ``self`` is empty. @@ -2453,6 +2482,10 @@ def comb(self, side='left'): A list of binary trees. + .. SEEALSO:: + + :meth:`left_decomposition`, :meth:`right_decomposition` + EXAMPLES:: sage: BT = BinaryTree( '.' ) @@ -3193,10 +3226,9 @@ def under(self, bt): [ \ ] [ 4 ] """ - B = self.parent()._element_constructor_ if bt.is_empty(): return self - lab = None + B = self.parent()._element_constructor_ if hasattr(bt, "label"): lab = bt.label() return B([self.under(bt[0]), bt[1]], lab) @@ -3205,6 +3237,170 @@ def under(self, bt): _backslash_ = under + def left_decomposition(self): + """ + Return the unique maximal decomposition as an under product. + + This means that the tree is cut along all edges of its leftmost path. + + .. SEEALSO:: + + :meth:`comb` + + EXAMPLES:: + + sage: g = BinaryTree([]) + sage: r = g.over(g); r + [., [., .]] + sage: l = g.under(g); l + [[., .], .] + sage: l.left_decomposition() + [[., .], [., .]] + sage: r.left_decomposition() == [r] + True + + sage: x = r\g\r\g + sage: ascii_art(x) + o + / + o + / \ + o o + / + o + \ + o + sage: x.left_decomposition() == [g,r,g,r] + True + """ + if self.is_empty(): + return [] + B = self.parent()._element_constructor_ + resu = [] + bt = self + while not bt.is_empty(): + if hasattr(bt, "label"): + lab = bt.label() + resu.append(B([None, bt[1]], lab)) + else: + resu.append(B([None, bt[1]])) + bt = bt[0] + return resu + + def right_decomposition(self): + """ + Return the unique maximal decomposition as an over product. + + This means that the tree is cut along all edges of its rightmost path. + + .. SEEALSO:: + + :meth:`comb` + + EXAMPLES:: + + sage: g = BinaryTree([]) + sage: r = g.over(g); r + [., [., .]] + sage: l = g.under(g); l + [[., .], .] + sage: r.right_decomposition() + [[., .], [., .]] + sage: l.right_decomposition() == [l] + True + + sage: x = g/l/l/g/g + sage: ascii_art(x) + o + \ + _o_ + / \ + o o + / \ + o o + \ + o + sage: x.right_decomposition() == [g,l,l,g,g] + True + """ + if self.is_empty(): + return [] + B = self.parent()._element_constructor_ + resu = [] + bt = self + while not bt.is_empty(): + if hasattr(bt, "label"): + lab = bt.label() + resu.append(B([bt[0], None], lab)) + else: + resu.append(B([bt[0], None])) + bt = bt[1] + return resu + + def dendriform_shuffle(self, other): + """ + Return the list of terms in the dendriform product. + + This is the list of all binary trees that can be obtained by + ... + + EXAMPLES:: + + sage: u = BinaryTree() + sage: g = BinaryTree([]) + sage: l = BinaryTree([g, u]) + sage: r = BinaryTree([u, g]) + + sage: list(g.dendriform_shuffle(g)) + [[[., .], .], [., [., .]]] + + sage: list(l.dendriform_shuffle(l)) + [[[[[., .], .], .], .], [[[., .], [., .]], .], + [[., .], [[., .], .]]] + + sage: list(l.dendriform_shuffle(r)) + [[[[., .], .], [., .]], [[., .], [., [., .]]]] + + TESTS:: + + sage: list(u.dendriform_shuffle(u)) + [.] + sage: list(u.dendriform_shuffle(g)) + [[., .]] + sage: list(u.dendriform_shuffle(l)) + [[[., .], .]] + sage: list(u.dendriform_shuffle(r)) + [[., [., .]]] + sage: list(r.dendriform_shuffle(u)) + [[., [., .]]] + sage: list(l.dendriform_shuffle(u)) + [[[., .], .]] + """ + from sage.combinat.words.shuffle_product import ShuffleProduct_w1w2 + from sage.combinat.words.word import Word + if self.is_empty(): + yield other + elif other.is_empty(): + yield self + else: + B = self.parent()._element_constructor_ + left_list = self.right_decomposition() + right_list = other.left_decomposition() + w_left = Word('L' * len(left_list)) + w_right = Word('R' * len(right_list)) + for w in ShuffleProduct_w1w2(w_left, w_right): + t = B(None) + c_left_list = list(left_list) + c_right_list = list(right_list) + for letter in w: + if letter == 'L': + lt = c_left_list.pop() + t = lt.over(t) + else: + rt = c_right_list.pop() + t = t.under(rt) + yield t + def sylvester_class(self, left_to_right=False): r""" Iterate over the sylvester class corresponding to the binary tree @@ -4062,6 +4258,35 @@ def _repr_(self): else: return "%s%s" % (self._label, self[:]) + def sort_key(self): + """ + Return a tuple of nonnegative integers encoding the labelled + tree ``self``. + + The first entry of the tuple is a pair consisting of the + number of children of the root and the label of the root. Then + the rest of the tuple is the concatenation of the tuples + associated to these children (we view the children of + a tree as trees themselves) from left to right. + + This tuple characterizes the labelled tree uniquely, and can + be used to sort the labelled ordered trees provided that the + labels belong to a type which is totally ordered. + + EXAMPLES:: + + sage: L2 = LabelledBinaryTree([], label='a') + sage: L3 = LabelledBinaryTree([], label='b') + sage: T23 = LabelledBinaryTree([L2, L3], label='c') + sage: T23.sort_key() + ((2, 'c'), (2, 'a'), (0,), (0,), (2, 'b'), (0,), (0,)) + """ + l = len(self) + if l == 0: + return ((0,),) + resu = [(l, self.label())] + [u for t in self for u in t.sort_key()] + return tuple(resu) + def binary_search_insert(self, letter): """ Return the result of inserting a letter ``letter`` into the diff --git a/src/sage/combinat/free_dendriform_algebra.py b/src/sage/combinat/free_dendriform_algebra.py new file mode 100644 index 00000000000..73018637bc3 --- /dev/null +++ b/src/sage/combinat/free_dendriform_algebra.py @@ -0,0 +1,595 @@ +# -*- coding: utf-8 -*- +r""" +Free Dendriform Algebras + +AUTHORS: + +Frédéric Chapoton (2017) +""" +# **************************************************************************** +# Copyright (C) 2010-2015 Frédéric Chapoton , +# +# Distributed under the terms of the GNU General Public License (GPL) +# 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 sage.categories.algebras import Algebras +from sage.categories.magmatic_algebras import MagmaticAlgebras +from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.words.alphabet import Alphabet +from sage.combinat.binary_tree import (BinaryTrees, BinaryTree, + LabelledBinaryTrees, + LabelledBinaryTree) +from sage.combinat.ordered_tree import OrderedTree, LabelledOrderedTree +from sage.misc.lazy_attribute import lazy_attribute +from sage.misc.cachefunc import cached_method +from sage.categories.rings import Rings +from sage.sets.family import Family + + +class FreeDendriformAlgebra(CombinatorialFreeModule): + r""" + The free dendriform algebra. + + Dendriform algebras are associative algebras, where the associative + product `*` is decomposed as a sum of two binary operations + + .. MATH:: + + x * y = x \succ y + x \prec y + + that satisfy the axioms: + + .. MATH:: + + (x \succ y) \prec z = x \succ (y \prec z), + + .. MATH:: + + (x \prec y) \prec z = x \prec (y * z). + + .. MATH:: + + (x * y) \succ z = (x \succ y) \succ z. + + The free Dendriform algebra on a given set `E` has an explicit + description using (planar) binary trees, just as the free + associative algebra can be described using words. The underlying + vector space has a basis indexed by finite binary trees endowed + with a map from their vertices to `E`. In this basis, the + associative product of two (decorated) binary trees `S * T` is the + sum over all possible ways of identifying the rightmost path in + `S` and the leftmost path in `T`. + + The decomposition of the associative product as the sum of two + binary operations `\succ` and + `\prec` is made by separating the terms according to the origin of + the root vertex. For `x \succ y`, one keeps the terms where the root + vertex comes from `y`, whereas for `x \prec y` one keeps the terms + where the root vertex comes from `x`. + + The free dendriform algebra can also be considered as the free + algebra over the Dendriform operad. + + .. NOTE:: + + The usual binary operator ``*`` is used for the + associative product. + + EXAMPLES:: + + sage: F = algebras.FreeDendriform(ZZ, 'xyz') + sage: x,y,z = F.gens() + sage: (x * y) * z + B[x[., y[., z[., .]]]] + B[x[., z[y[., .], .]]] + B[y[x[., .], z[., .]]] + B[z[x[., y[., .]], .]] + B[z[y[x[., .], .], .]] + sage: (x * y) * z - x * (y * z) == (x * z) * y - x * (z * y) + True + + The free dendriform algebra is associative:: + + sage: x * (y * z) == (x * y) * z + True + + When there is only one generator, unlabelled trees are used instead:: + + sage: F1 = algebras.FreeDendriform(QQ, 'w') + sage: w = F1.gen(0); w + B[[., .]] + sage: w * w * w + B[[., [., [., .]]]] + B[[., [[., .], .]]] + B[[[., .], [., .]]] + B[[[., [., .]], .]] + B[[[[., .], .], .]] + + REFERENCES: + + - [LodayRonco]_ + """ + @staticmethod + def __classcall_private__(cls, R, names): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: F1 = algebras.FreeDendriform(QQ, 'xyz') + sage: F2 = algebras.FreeDendriform(QQ, ['x','y','z']) + sage: F3 = algebras.FreeDendriform(QQ, Alphabet('xyz')) + sage: F1 is F2 and F1 is F3 + True + """ + if R not in Rings(): + raise TypeError("argument R must be a ring") + return super(FreeDendriformAlgebra, cls).__classcall__(cls, R, + Alphabet(names)) + + def __init__(self, R, names=None): + """ + Initialize ``self``. + + TESTS:: + + sage: A = algebras.FreeDendriform(QQ, '@'); A + Free Dendriform algebra on one generator ['@'] over Rational Field + sage: TestSuite(A).run() + + sage: F = algebras.FreeDendriform(QQ, 'xy') + sage: TestSuite(F).run() # long time + + sage: F = algebras.FreeDendriform(QQ, ZZ) + sage: elts = F.some_elements()[:-1] # Skip the last element + sage: TestSuite(F).run(some_elements=elts) # long time + """ + if names.cardinality() == 1: + Trees = BinaryTrees() + else: + Trees = LabelledBinaryTrees() + # Here one would need LabelledBinaryTrees(names) + # so that one can restrict the labels to some fixed set + key = lambda x: x.sort_key() + self._alphabet = names + cat = Algebras(R).WithBasis().Graded() + CombinatorialFreeModule.__init__(self, R, Trees, + latex_prefix="", + sorting_key=key, + category=cat) + + def variable_names(self): + r""" + Return the names of the variables. + + EXAMPLES:: + + sage: R = algebras.FreeDendriform(QQ, 'xy') + sage: R.variable_names() + {'x', 'y'} + """ + return self._alphabet + + def _repr_(self): + """ + Return the string representation of ``self``. + + EXAMPLES:: + + sage: algebras.FreeDendriform(QQ, '@') # indirect doctest + Free Dendriform algebra on one generator ['@'] over Rational Field + """ + n = self.algebra_generators().cardinality() + if n == 1: + gen = "one generator" + else: + gen = "{} generators".format(n) + s = "Free Dendriform algebra on {} {} over {}" + try: + return s.format(gen, self._alphabet.list(), self.base_ring()) + except NotImplementedError: + return s.format(gen, self._alphabet, self.base_ring()) + + def gen(self, i): + r""" + Return the `i`-th generator of the algebra. + + INPUT: + + - `i` -- an integer + + EXAMPLES:: + + sage: F = algebras.FreeDendriform(ZZ, 'xyz') + sage: F.gen(0) + B[x[., .]] + + sage: F.gen(4) + Traceback (most recent call last): + ... + IndexError: argument i (= 4) must be between 0 and 2 + """ + G = self.algebra_generators() + n = G.cardinality() + if i < 0 or not i < n: + m = "argument i (= {}) must be between 0 and {}".format(i, n - 1) + raise IndexError(m) + return G[G.keys().unrank(i)] + + @cached_method + def algebra_generators(self): + r""" + Return the generators of this algebra. + + These are the binary trees with just one vertex. + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(ZZ, 'fgh'); A + Free Dendriform algebra on 3 generators ['f', 'g', 'h'] + over Integer Ring + sage: list(A.algebra_generators()) + [B[f[., .]], B[g[., .]], B[h[., .]]] + + sage: A = algebras.FreeDendriform(QQ, ['x1','x2']) + sage: list(A.algebra_generators()) + [B[x1[., .]], B[x2[., .]]] + """ + Trees = self.basis().keys() + return Family(self._alphabet, lambda a: self.monomial(Trees([], a))) + + def gens(self): + """ + Return the generators of ``self`` (as an algebra). + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(ZZ, 'fgh') + sage: A.gens() + (B[f[., .]], B[g[., .]], B[h[., .]]) + """ + return tuple(self.algebra_generators()) + + def degree_on_basis(self, t): + """ + Return the degree of a rooted tree in the free Dendriform algebra. + + This is the number of vertices. + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ,'@') + sage: RT = A.basis().keys() + sage: u = RT([], '@') + sage: A.degree_on_basis(u.over(u)) + 2 + """ + return t.node_number() + + @cached_method + def an_element(self): + """ + Return an element of ``self``. + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ, 'xy') + sage: A.an_element() + B[x[., .]] + 2*B[x[., x[., .]]] + 2*B[x[x[., .], .]] + """ + o = self.gen(0) + return o + 2 * o * o + + def some_elements(self): + """ + Return some elements of the free dendriform algebra. + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ,'@') + sage: A.some_elements() + [B[.], + B[[., .]], + B[[., [., .]]] + B[[[., .], .]], + B[.] + B[[., [., .]]] + B[[[., .], .]]] + + With several generators:: + + sage: A = algebras.FreeDendriform(QQ, 'xy') + sage: A.some_elements() + [B[.], + B[x[., .]], + B[x[., x[., .]]] + B[x[x[., .], .]], + B[.] + B[x[., x[., .]]] + B[x[x[., .], .]]] + """ + u = self.one() + o = self.gen(0) + x = o * o + y = u + x + return [u, o, x, y] + + @cached_method + def one(self): + """ + Return the element `1` of ``self``. + + This is the unit for the associative dendriform product. + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ, '@') + sage: A.one() + B[.] + sage: A = algebras.FreeDendriform(QQ, 'xy') + sage: A.one() + B[.] + """ + Trees = self.basis().keys() + return self._monomial(Trees(None)) + + def product_on_basis(self, x, y): + """ + Return the * associative dendriform product of two trees. + + This is the sum over all possible ways to identify the rightmost path + in `x` and the leftmost path in `y`. Every term corresponds to + a shuffle of the vertices on the rightmost path + in `x` and the vertices on the leftmost path in `y`. + + .. SEEALSO:: + + - :meth:`succ_product_on_basis`, :meth:`prec_product_on_basis` + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ, '@') + sage: RT = A.basis().keys() + sage: x = RT([], '@') + sage: A.product_on_basis(x, x) + B[[., [., .]]] + B[[[., .], .]] + """ + return self.sum(self.basis()[u] for u in x.dendriform_shuffle(y)) + + def succ_product_on_basis(self, x, y): + r""" + Return the > dendriform product of two trees. + + This is the sum over all possible ways to identify the rightmost path + in `x` and the leftmost path in `y`, with the additional condition + that the root vertex of the result comes from `y`. + + The usual symbol for this operation is `\succ`. + + .. SEEALSO:: + + - :meth:`product_on_basis`, :meth:`prec_product_on_basis` + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ, '@') + sage: RT = A.basis().keys() + sage: x = RT([], '@') + sage: A.succ_product_on_basis(x, x) + B[[[., .], .]] + + TESTS:: + + sage: u = A.one().support()[0] + sage: A.succ_product_on_basis(u, u) + Traceback (most recent call last): + ... + ValueError: dendriform products are not defined on (|,|) + """ + if y.is_empty(): + if x.is_empty(): + raise ValueError("dendriform products are not defined on (|,|)") + else: + return [] + if x.is_empty(): + return [y] + K = self.basis().keys() + if hasattr(y, 'label'): + return self.sum(self.basis()[K([u, y[1]], y.label())] + for u in x.dendriform_shuffle(y[0])) + + return self.sum(self.basis()[K([u, y[1]])] + for u in x.dendriform_shuffle(y[0])) + + @lazy_attribute + def succ_product(self): + """ + Return the > dendriform product. + + This is the sum over all possible ways to identify the rightmost path + in `x` and the leftmost path in `y`, with the additional condition + that the root vertex of the result comes from `y`. + + The usual symbol for this operation is `\succ`. + + .. SEEALSO:: + + - :meth:`product`, :meth:`prec_product` + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ, '@') + sage: RT = A.basis().keys() + sage: x = A.gen(0) + sage: A.succ_product(x, x) + B[[[., .], .]] + """ + succ = self.succ_product_on_basis + return self._module_morphism(self._module_morphism(succ, position=0, + codomain=self), + position=1) + + def prec_product_on_basis(self, x, y): + r""" + Return the < dendriform product of two trees. + + This is the sum over all possible ways to identify the rightmost path + in `x` and the leftmost path in `y`, with the additional condition + that the root vertex of the result comes from `x`. + + The usual symbol for this operation is `\prec`. + + .. SEEALSO:: + + - :meth:`product_on_basis`, :meth:`succ_product_on_basis` + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ, '@') + sage: RT = A.basis().keys() + sage: x = RT([], '@') + sage: A.prec_product_on_basis(x, x) + B[[., [., .]]] + + TESTS:: + + sage: u = A.one().support()[0] + sage: A.prec_product_on_basis(u, u) + Traceback (most recent call last): + ... + ValueError: dendriform products are not defined on (|,|) + """ + if x.is_empty() and y.is_empty(): + raise ValueError("dendriform products are not defined on (|,|)") + if x.is_empty(): + return [] + if y.is_empty(): + return [x] + K = self.basis().keys() + if hasattr(y, 'label'): + return self.sum(self.basis()[K([x[0], u], x.label())] + for u in x[1].dendriform_shuffle(y)) + + return self.sum(self.basis()[K([x[0], u])] + for u in x[1].dendriform_shuffle(y)) + + @lazy_attribute + def prec_product(self): + """ + Return the < dendriform product. + + This is the sum over all possible ways to identify the rightmost path + in `x` and the leftmost path in `y`, with the additional condition + that the root vertex of the result comes from `x`. + + The usual symbol for this operation is `\prec`. + + .. SEEALSO:: + + - :meth:`prec_product_on_basis` + - :meth:`succ_product`, :meth:`product` + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ, '@') + sage: RT = A.basis().keys() + sage: x = A.gen(0) + sage: A.prec_product(x, x) + B[[., [., .]]] + """ + prec = self.prec_product_on_basis + return self._module_morphism(self._module_morphism(prec, position=0, + codomain=self), + position=1) + + # after this line : coercion + def _element_constructor_(self, x): + r""" + Convert ``x`` into ``self``. + + EXAMPLES:: + + sage: R = algebras.FreeDendriform(QQ, 'xy') + sage: x, y = R.gens() + sage: R(x) + B[x[., .]] + sage: R(x+4*y) + B[x[., .]] + 4*B[y[., .]] + + sage: Trees = R.basis().keys() + sage: R(Trees([],'x')) + B[x[., .]] + sage: D = algebras.FreeDendriform(ZZ, 'xy') + sage: X, Y = D.gens() + sage: R(X-Y).parent() + Free Dendriform algebra on 2 generators ['x', 'y'] over Rational Field + """ + if x in self.basis().keys(): + return self.monomial(x) + try: + P = x.parent() + if isinstance(P, FreeDendriformAlgebra): + if P is self: + return x + return self.element_class(self, x.monomial_coefficients()) + except AttributeError: + raise TypeError('not able to coerce this in this algebra') + # Ok, not a dendriform algebra element (or should not be viewed as one). + + def _coerce_map_from_(self, R): + r""" + Return ``True`` if there is a coercion from ``R`` into ``self`` + and ``False`` otherwise. + + The things that coerce into ``self`` are + + - free dendriform algebras in the same variables over a base with + a coercion map into ``self.base_ring()`` + + EXAMPLES:: + + sage: F = algebras.FreeDendriform(GF(7), 'xyz'); F + Free Dendriform algebra on 3 generators ['x', 'y', 'z'] + over Finite Field of size 7 + + Elements of the free dendriform algebra canonically coerce in:: + + sage: x, y, z = F.gens() + sage: F.coerce(x+y) == x+y + True + + The free dendriform algebra over `\ZZ` on `x, y, z` coerces in, since + `\ZZ` coerces to `\GF{7}`:: + + sage: G = algebras.FreeDendriform(ZZ, 'xyz') + sage: Gx,Gy,Gz = G.gens() + sage: z = F.coerce(Gx+Gy); z + B[x[., .]] + B[y[., .]] + sage: z.parent() is F + True + + However, `\GF{7}` does not coerce to `\ZZ`, so the free dendriform + algebra over `\GF{7}` does not coerce to the one over `\ZZ`:: + + sage: G.coerce(y) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Free Dendriform algebra + on 3 generators ['x', 'y', 'z'] over Finite Field of size + 7 to Free Dendriform algebra on 3 generators ['x', 'y', 'z'] + over Integer Ring + + TESTS:: + + sage: F = algebras.FreeDendriform(ZZ, 'xyz') + sage: G = algebras.FreeDendriform(QQ, 'xyz') + sage: H = algebras.FreeDendriform(ZZ, 'y') + sage: F._coerce_map_from_(G) + False + sage: G._coerce_map_from_(F) + True + sage: F._coerce_map_from_(H) + False + sage: F._coerce_map_from_(QQ) + False + sage: G._coerce_map_from_(QQ) + False + sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z')) + False + """ + # free prelie algebras in the same variables + # over any base that coerces in: + if isinstance(R, FreeDendriformAlgebra): + if R.variable_names() == self.variable_names(): + if self.base_ring().has_coerce_map_from(R.base_ring()): + return True + return False From e094db43490b0739ba079ec620f13ac0e92dc771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 4 Jun 2017 19:21:41 +0200 Subject: [PATCH 080/126] trac 23137 some details --- src/sage/combinat/binary_tree.py | 10 ++++++---- src/sage/combinat/free_dendriform_algebra.py | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index df2cf946666..8150c712f6c 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -3342,7 +3342,10 @@ def dendriform_shuffle(self, other): Return the list of terms in the dendriform product. This is the list of all binary trees that can be obtained by - ... + identifying the rightmost path in ``self`` and the leftmost + path in ``other``. Every term corresponds to a shuffle of the + vertices on the rightmost path in ``self`` and the vertices on + the leftmost path in ``other``. EXAMPLES:: @@ -4260,8 +4263,7 @@ def _repr_(self): def sort_key(self): """ - Return a tuple of nonnegative integers encoding the labelled - tree ``self``. + Return a tuple encoding the labelled binary tree ``self``. The first entry of the tuple is a pair consisting of the number of children of the root and the label of the root. Then @@ -4270,7 +4272,7 @@ def sort_key(self): a tree as trees themselves) from left to right. This tuple characterizes the labelled tree uniquely, and can - be used to sort the labelled ordered trees provided that the + be used to sort the labelled binary trees provided that the labels belong to a type which is totally ordered. EXAMPLES:: diff --git a/src/sage/combinat/free_dendriform_algebra.py b/src/sage/combinat/free_dendriform_algebra.py index 73018637bc3..5d56510f90d 100644 --- a/src/sage/combinat/free_dendriform_algebra.py +++ b/src/sage/combinat/free_dendriform_algebra.py @@ -141,11 +141,12 @@ def __init__(self, R, names=None): """ if names.cardinality() == 1: Trees = BinaryTrees() + key = BinaryTree.sort_key else: Trees = LabelledBinaryTrees() + key = LabelledBinaryTree.sort_key # Here one would need LabelledBinaryTrees(names) # so that one can restrict the labels to some fixed set - key = lambda x: x.sort_key() self._alphabet = names cat = Algebras(R).WithBasis().Graded() CombinatorialFreeModule.__init__(self, R, Trees, From 47ce6c0dd0cad23ad777fa855e37abb6a0d8de74 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Sun, 4 Jun 2017 19:27:50 +0200 Subject: [PATCH 081/126] Faster algorithm (hopefully) --- .../padics/padic_capped_absolute_element.pyx | 17 ++++--- .../padics/padic_capped_relative_element.pyx | 17 ++++--- .../rings/padics/padic_fixed_mod_element.pyx | 17 ++++--- src/sage/rings/padics/transcendantal.c | 46 +++++++++++++------ 4 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/sage/rings/padics/padic_capped_absolute_element.pyx b/src/sage/rings/padics/padic_capped_absolute_element.pyx index d22952355bd..63af00cbcea 100644 --- a/src/sage/rings/padics/padic_capped_absolute_element.pyx +++ b/src/sage/rings/padics/padic_capped_absolute_element.pyx @@ -329,16 +329,20 @@ cdef class pAdicCappedAbsoluteElement(CAElement): 1. Take the unit part `u` of the input. - 2. Raise `u` to `p-1` to obtain a 1-unit. + 2. Raise `u` to the power `p-1` to obtain a 1-unit. - 3. Write + 3. Raise `u` to the power `p^v` for a suitable `v` in order + to make it closer to 1. (`v` is chosen such that `p^v` is + close to the precision.) + + 4. Write .. MATH:: - u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{2^i}) + u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{(v+1)*2^i}) - with `0 \leq a_i < p^{2^i}` and compute `\log(1 - a_i p^{2^i})` - using the standard Taylor expansion + with `0 \leq a_i < p^{(v+1)*2^i}` and compute + `\log(1 - a_i p^{(v+1)*2^i})` using the standard Taylor expansion .. MATH:: @@ -346,7 +350,8 @@ cdef class pAdicCappedAbsoluteElement(CAElement): together with a binary spliting method. - 4. Divide the result by ``q-1`` and multiply by ``self.valuation()*log(p)`` + 5. Divide the result by `p^v*(p-1)` + and multiply by ``self.valuation()*log(p)`` The complexity of this algorithm is quasi-linear. diff --git a/src/sage/rings/padics/padic_capped_relative_element.pyx b/src/sage/rings/padics/padic_capped_relative_element.pyx index 3d2aee8bb72..de6cace44d9 100644 --- a/src/sage/rings/padics/padic_capped_relative_element.pyx +++ b/src/sage/rings/padics/padic_capped_relative_element.pyx @@ -380,16 +380,20 @@ cdef class pAdicCappedRelativeElement(CRElement): 1. Take the unit part `u` of the input. - 2. Raise `u` to `p-1` to obtain a 1-unit. + 2. Raise `u` to the power `p-1` to obtain a 1-unit. - 3. Write + 3. Raise `u` to the power `p^v` for a suitable `v` in order + to make it closer to 1. (`v` is chosen such that `p^v` is + close to the precision.) + + 4. Write .. MATH:: - u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{2^i}) + u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{(v+1)*2^i}) - with `0 \leq a_i < p^{2^i}` and compute `\log(1 - a_i p^{2^i})` - using the standard Taylor expansion + with `0 \leq a_i < p^{(v+1)*2^i}` and compute + `\log(1 - a_i p^{(v+1)*2^i})` using the standard Taylor expansion .. MATH:: @@ -397,7 +401,8 @@ cdef class pAdicCappedRelativeElement(CRElement): together with a binary spliting method. - 4. Divide the result by ``q-1`` and multiply by ``self.valuation()*log(p)`` + 5. Divide the result by `p^v*(p-1)` + and multiply by ``self.valuation()*log(p)`` The complexity of this algorithm is quasi-linear. diff --git a/src/sage/rings/padics/padic_fixed_mod_element.pyx b/src/sage/rings/padics/padic_fixed_mod_element.pyx index dab98a3dbd4..add97be0c6d 100644 --- a/src/sage/rings/padics/padic_fixed_mod_element.pyx +++ b/src/sage/rings/padics/padic_fixed_mod_element.pyx @@ -392,16 +392,20 @@ cdef class pAdicFixedModElement(FMElement): 1. Take the unit part `u` of the input. - 2. Raise `u` to `p-1` to obtain a 1-unit. + 2. Raise `u` to the power `p-1` to obtain a 1-unit. - 3. Write + 3. Raise `u` to the power `p^v` for a suitable `v` in order + to make it closer to 1. (`v` is chosen such that `p^v` is + close to the precision.) + + 4. Write .. MATH:: - u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{2^i}) + u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{(v+1)*2^i}) - with `0 \leq a_i < p^{2^i}` and compute `\log(1 - a_i p^{2^i})` - using the standard Taylor expansion + with `0 \leq a_i < p^{(v+1)*2^i}` and compute + `\log(1 - a_i p^{(v+1)*2^i})` using the standard Taylor expansion .. MATH:: @@ -409,7 +413,8 @@ cdef class pAdicFixedModElement(FMElement): together with a binary spliting method. - 4. Divide the result by ``q-1`` and multiply by ``self.valuation()*log(p)`` + 5. Divide the result by `p^v*(p-1)` + and multiply by ``self.valuation()*log(p)`` The complexity of this algorithm is quasi-linear. diff --git a/src/sage/rings/padics/transcendantal.c b/src/sage/rings/padics/transcendantal.c index 1630f8c18b8..b645dafb3da 100644 --- a/src/sage/rings/padics/transcendantal.c +++ b/src/sage/rings/padics/transcendantal.c @@ -14,15 +14,20 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con /* Compute the p-adic logarithm of a, which is supposed to be a unit - Algorithm: If a = 1 (mod p), write a as a product - 1/a = (1 - a_0*p) (1 - a_1*p^2) (1 - a_2*p^4) (1 - a_3*p^8) ... - with 0 <= a_i < p^(2^i). - Then compute each log(1 - a_i*p^(2^i)) using Taylor expansion - and a binary spliting strategy. - For general a, compute log(a^(p-1)) and then divide by p-1 */ + Algorithm: If a = 1 (mod p): + 1. we raise a at the power p^(v-1) (for a suitable v) in order + to make it closer to 1 + 2. we write the new a as a product + 1/a = (1 - a_0*p^v) (1 - a_1*p^(2*v) (1 - a_2*p^(4*v) ... + with 0 <= a_i < p^(v*2^i). + 3. we compute each log(1 - a_i*p^(v*2^i)) using Taylor expansion + and a binary spliting strategy. + + For general a, compute log(a^(p-1)) and then divide by p-1 */ char congruent_to_one; - unsigned long i, N, saveN, Np, tmp, trunc, step; + unsigned long i, v, e, N, saveN, Np, tmp, trunc, step; + double den = log(p); mpz_t f, arg, trunc_mod, h, hpow, mpz_tmp, d, inv; mpz_t *num, *denom; @@ -38,10 +43,22 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con mpz_powm_ui(arg, a, p-1, modulo); } + /* First we make the argument closer to 1 by raising it to the p^(v-1) */ + if (prec < p) { + v = 0; e = 1; + } else { + v = (unsigned long)(log(prec)/den); // v here is v-1 + e = pow(p,v); + mpz_mul_ui(mpz_tmp, modulo, e); + mpz_powm_ui(arg, arg, e, mpz_tmp); + prec += v; + } + /* Where do we need to truncate the Taylor expansion */ - N = prec; + N = saveN = (prec+v)/++v; // note the ++v + den *= v; while(1) { - tmp = prec + (unsigned long)(log(N)/log(p)); + tmp = saveN + (unsigned long)(log(N)/den); if (tmp == N) break; N = tmp; } @@ -58,12 +75,12 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con mpz_init(denom[i]); } - trunc = 2; - mpz_init_set_ui(trunc_mod, p); - mpz_mul_ui(trunc_mod, trunc_mod, p); + trunc = v << 1; + mpz_init(trunc_mod); + mpz_ui_pow_ui(trunc_mod, p, trunc); while(1) { - /* We compute f = 1 - a_i*p^(2^i) - trunc_mod is p^(2^(i+1)) */ + /* We compute f = 1 - a_i*p^((v+1)*2^i) + trunc_mod is p^((v+1)*2^(i+1)) */ mpz_fdiv_r(f, arg, trunc_mod); if (mpz_cmp_ui(f, 1) != 0) { @@ -99,6 +116,7 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con mpz_divexact(mpz_tmp, num[0], d); mpz_divexact(denom[0], denom[0], d); + mpz_divexact_ui(h, h, e); mpz_mul(mpz_tmp, h, mpz_tmp); /* We coerce the result from Q to Zp */ From 3d704c9f6c7325ab691a281888cd6a5ee8a8fc6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 4 Jun 2017 21:40:37 +0200 Subject: [PATCH 082/126] =?UTF-8?q?trac=202313=C2=B57=20caring=20for=20the?= =?UTF-8?q?=20doc=20of=20free=20dendriform=20algebras?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sage/combinat/binary_tree.py | 36 ++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index 8150c712f6c..d371fca8ce5 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -2484,7 +2484,7 @@ def comb(self, side='left'): .. SEEALSO:: - :meth:`left_decomposition`, :meth:`right_decomposition` + :meth:`over_decomposition`, :meth:`under_decomposition` EXAMPLES:: @@ -3237,15 +3237,17 @@ def under(self, bt): _backslash_ = under - def left_decomposition(self): - """ + def under_decomposition(self): + r""" Return the unique maximal decomposition as an under product. This means that the tree is cut along all edges of its leftmost path. + Beware that the factors are ordered starting from the root. + .. SEEALSO:: - :meth:`comb` + :meth:`comb`, :meth:`over_decomposition` EXAMPLES:: @@ -3254,12 +3256,12 @@ def left_decomposition(self): [., [., .]] sage: l = g.under(g); l [[., .], .] - sage: l.left_decomposition() + sage: l.under_decomposition() [[., .], [., .]] - sage: r.left_decomposition() == [r] + sage: r.under_decomposition() == [r] True - sage: x = r\g\r\g + sage: x = r.under(g).under(r).under(g) sage: ascii_art(x) o / @@ -3270,7 +3272,7 @@ def left_decomposition(self): o \ o - sage: x.left_decomposition() == [g,r,g,r] + sage: x.under_decomposition() == [g,r,g,r] True """ if self.is_empty(): @@ -3287,15 +3289,17 @@ def left_decomposition(self): bt = bt[0] return resu - def right_decomposition(self): + def over_decomposition(self): """ Return the unique maximal decomposition as an over product. This means that the tree is cut along all edges of its rightmost path. + Beware that the factors are ordered starting from the root. + .. SEEALSO:: - :meth:`comb` + :meth:`comb`, :meth:`under_decomposition` EXAMPLES:: @@ -3304,12 +3308,12 @@ def right_decomposition(self): [., [., .]] sage: l = g.under(g); l [[., .], .] - sage: r.right_decomposition() + sage: r.over_decomposition() [[., .], [., .]] - sage: l.right_decomposition() == [l] + sage: l.over_decomposition() == [l] True - sage: x = g/l/l/g/g + sage: x = g.over(l).over(l).over(g).over(g) sage: ascii_art(x) o \ @@ -3320,7 +3324,7 @@ def right_decomposition(self): o o \ o - sage: x.right_decomposition() == [g,l,l,g,g] + sage: x.over_decomposition() == [g,l,l,g,g] True """ if self.is_empty(): @@ -3387,8 +3391,8 @@ def dendriform_shuffle(self, other): yield self else: B = self.parent()._element_constructor_ - left_list = self.right_decomposition() - right_list = other.left_decomposition() + left_list = self.over_decomposition() + right_list = other.under_decomposition() w_left = Word('L' * len(left_list)) w_right = Word('R' * len(right_list)) for w in ShuffleProduct_w1w2(w_left, w_right): From 756b862f13610ac957403dc7daa9bc6cab557d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Sun, 4 Jun 2017 22:37:12 +0200 Subject: [PATCH 083/126] trac 23137, some details, and adding over and under products --- src/sage/combinat/free_dendriform_algebra.py | 129 +++++++++++++------ 1 file changed, 90 insertions(+), 39 deletions(-) diff --git a/src/sage/combinat/free_dendriform_algebra.py b/src/sage/combinat/free_dendriform_algebra.py index 5d56510f90d..2e4521f414e 100644 --- a/src/sage/combinat/free_dendriform_algebra.py +++ b/src/sage/combinat/free_dendriform_algebra.py @@ -60,7 +60,7 @@ class FreeDendriformAlgebra(CombinatorialFreeModule): vector space has a basis indexed by finite binary trees endowed with a map from their vertices to `E`. In this basis, the associative product of two (decorated) binary trees `S * T` is the - sum over all possible ways of identifying the rightmost path in + sum over all possible ways of identifying (glueing) the rightmost path in `S` and the leftmost path in `T`. The decomposition of the associative product as the sum of two @@ -75,7 +75,7 @@ class FreeDendriformAlgebra(CombinatorialFreeModule): .. NOTE:: - The usual binary operator ``*`` is used for the + The usual binary operator `*` is used for the associative product. EXAMPLES:: @@ -84,8 +84,6 @@ class FreeDendriformAlgebra(CombinatorialFreeModule): sage: x,y,z = F.gens() sage: (x * y) * z B[x[., y[., z[., .]]]] + B[x[., z[y[., .], .]]] + B[y[x[., .], z[., .]]] + B[z[x[., y[., .]], .]] + B[z[y[x[., .], .], .]] - sage: (x * y) * z - x * (y * z) == (x * z) * y - x * (z * y) - True The free dendriform algebra is associative:: @@ -134,10 +132,6 @@ def __init__(self, R, names=None): sage: F = algebras.FreeDendriform(QQ, 'xy') sage: TestSuite(F).run() # long time - - sage: F = algebras.FreeDendriform(QQ, ZZ) - sage: elts = F.some_elements()[:-1] # Skip the last element - sage: TestSuite(F).run(some_elements=elts) # long time """ if names.cardinality() == 1: Trees = BinaryTrees() @@ -248,7 +242,7 @@ def gens(self): def degree_on_basis(self, t): """ - Return the degree of a rooted tree in the free Dendriform algebra. + Return the degree of a binary tree in the free Dendriform algebra. This is the number of vertices. @@ -309,7 +303,7 @@ def one(self): """ Return the element `1` of ``self``. - This is the unit for the associative dendriform product. + This is the unit for the associative dendriform product `*`. EXAMPLES:: @@ -325,11 +319,11 @@ def one(self): def product_on_basis(self, x, y): """ - Return the * associative dendriform product of two trees. + Return the `*` associative dendriform product of two trees. - This is the sum over all possible ways to identify the rightmost path - in `x` and the leftmost path in `y`. Every term corresponds to - a shuffle of the vertices on the rightmost path + This is the sum over all possible ways of identifying the + rightmost path in `x` and the leftmost path in `y`. Every term + corresponds to a shuffle of the vertices on the rightmost path in `x` and the vertices on the leftmost path in `y`. .. SEEALSO:: @@ -348,7 +342,7 @@ def product_on_basis(self, x, y): def succ_product_on_basis(self, x, y): r""" - Return the > dendriform product of two trees. + Return the `>` dendriform product of two trees. This is the sum over all possible ways to identify the rightmost path in `x` and the leftmost path in `y`, with the additional condition @@ -374,11 +368,12 @@ def succ_product_on_basis(self, x, y): sage: A.succ_product_on_basis(u, u) Traceback (most recent call last): ... - ValueError: dendriform products are not defined on (|,|) + ValueError: dendriform products | < | and | > | are not defined """ if y.is_empty(): if x.is_empty(): - raise ValueError("dendriform products are not defined on (|,|)") + raise ValueError("dendriform products | < | and | > | are " + "not defined") else: return [] if x.is_empty(): @@ -392,40 +387,42 @@ def succ_product_on_basis(self, x, y): for u in x.dendriform_shuffle(y[0])) @lazy_attribute - def succ_product(self): + def succ(self): """ - Return the > dendriform product. + Return the `>` dendriform product. - This is the sum over all possible ways to identify the rightmost path - in `x` and the leftmost path in `y`, with the additional condition - that the root vertex of the result comes from `y`. + This is the sum over all possible ways of identifying the + rightmost path in `x` and the leftmost path in `y`, with the + additional condition that the root vertex of the result comes + from `y`. The usual symbol for this operation is `\succ`. .. SEEALSO:: - - :meth:`product`, :meth:`prec_product` + :meth:`product`, :meth:`prec`, :meth:`over`, :meth:`under` EXAMPLES:: sage: A = algebras.FreeDendriform(QQ, '@') sage: RT = A.basis().keys() sage: x = A.gen(0) - sage: A.succ_product(x, x) + sage: A.succ(x, x) B[[[., .], .]] """ - succ = self.succ_product_on_basis - return self._module_morphism(self._module_morphism(succ, position=0, + suc = self.succ_product_on_basis + return self._module_morphism(self._module_morphism(suc, position=0, codomain=self), position=1) def prec_product_on_basis(self, x, y): r""" - Return the < dendriform product of two trees. + Return the `<` dendriform product of two trees. - This is the sum over all possible ways to identify the rightmost path - in `x` and the leftmost path in `y`, with the additional condition - that the root vertex of the result comes from `x`. + This is the sum over all possible ways of identifying the + rightmost path in `x` and the leftmost path in `y`, with the + additional condition that the root vertex of the result comes + from `x`. The usual symbol for this operation is `\prec`. @@ -447,10 +444,11 @@ def prec_product_on_basis(self, x, y): sage: A.prec_product_on_basis(u, u) Traceback (most recent call last): ... - ValueError: dendriform products are not defined on (|,|) + ValueError: dendriform products | < | and | > | are not defined """ if x.is_empty() and y.is_empty(): - raise ValueError("dendriform products are not defined on (|,|)") + raise ValueError("dendriform products | < | and | > | are " + "not defined") if x.is_empty(): return [] if y.is_empty(): @@ -464,9 +462,9 @@ def prec_product_on_basis(self, x, y): for u in x[1].dendriform_shuffle(y)) @lazy_attribute - def prec_product(self): + def prec(self): """ - Return the < dendriform product. + Return the `<` dendriform product. This is the sum over all possible ways to identify the rightmost path in `x` and the leftmost path in `y`, with the additional condition @@ -476,19 +474,72 @@ def prec_product(self): .. SEEALSO:: - - :meth:`prec_product_on_basis` - - :meth:`succ_product`, :meth:`product` + :meth:`product`, :meth:`succ`, :meth:`over`, :meth:`under` EXAMPLES:: sage: A = algebras.FreeDendriform(QQ, '@') sage: RT = A.basis().keys() sage: x = A.gen(0) - sage: A.prec_product(x, x) + sage: A.prec(x, x) B[[., [., .]]] """ - prec = self.prec_product_on_basis - return self._module_morphism(self._module_morphism(prec, position=0, + pre = self.prec_product_on_basis + return self._module_morphism(self._module_morphism(pre, position=0, + codomain=self), + position=1) + + @lazy_attribute + def over(self): + """ + Return the over product. + + The over product `x/y` is the binary tree obtained by + grafting the root of `y` at the rightmost leaf of `x`. + + The usual symbol for this operation is `/`. + + .. SEEALSO:: + + :meth:`product`, :meth:`succ`, :meth:`prec`, :meth:`under` + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ, '@') + sage: RT = A.basis().keys() + sage: x = A.gen(0) + sage: A.over(x, x) + B[[., [., .]]] + """ + ov = lambda x, y: self._monomial(x.over(y)) + return self._module_morphism(self._module_morphism(ov, position=0, + codomain=self), + position=1) + + @lazy_attribute + def under(self): + r""" + Return the under product. + + The over product `x \backslash y` is the binary tree obtained by + grafting the root of `x` at the leftmost leaf of `y`. + + The usual symbol for this operation is `\backslash`. + + .. SEEALSO:: + + :meth:`product`, :meth:`succ`, :meth:`prec`, :meth:`over` + + EXAMPLES:: + + sage: A = algebras.FreeDendriform(QQ, '@') + sage: RT = A.basis().keys() + sage: x = A.gen(0) + sage: A.under(x, x) + B[[[., .], .]] + """ + und = lambda x, y: self._monomial(x.under(y)) + return self._module_morphism(self._module_morphism(und, position=0, codomain=self), position=1) From 81e3fbabc4d05832f20d04ff216e112e607aa1d1 Mon Sep 17 00:00:00 2001 From: Ralf Stephan Date: Mon, 5 Jun 2017 09:48:53 +0200 Subject: [PATCH 084/126] 22026: Doctest: Even reals are integer --- src/sage/symbolic/assumptions.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sage/symbolic/assumptions.py b/src/sage/symbolic/assumptions.py index d55bb20e73c..fddc82251e8 100644 --- a/src/sage/symbolic/assumptions.py +++ b/src/sage/symbolic/assumptions.py @@ -43,6 +43,18 @@ sage: assumptions() [x > 0] +Assumptions also affect operations that do not use Maxima:: + + sage: forget() + sage: assume(x, 'even') + sage: assume(x, 'real') + sage: (-1)^x + 1 + sage: (-gamma(pi))^x + gamma(pi)^x + sage: binomial(2*x, x).is_integer() + True + Assumptions are added and in some cases checked for consistency:: sage: assume(x>0) From 86b52c157bd8145634107cf555b6dfd18736c874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 5 Jun 2017 10:04:46 +0200 Subject: [PATCH 085/126] trac 23137 more doc --- src/sage/combinat/free_dendriform_algebra.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/sage/combinat/free_dendriform_algebra.py b/src/sage/combinat/free_dendriform_algebra.py index 2e4521f414e..633bd4c79b8 100644 --- a/src/sage/combinat/free_dendriform_algebra.py +++ b/src/sage/combinat/free_dendriform_algebra.py @@ -52,7 +52,7 @@ class FreeDendriformAlgebra(CombinatorialFreeModule): .. MATH:: - (x * y) \succ z = (x \succ y) \succ z. + (x * y) \succ z = x \succ (y \succ z). The free Dendriform algebra on a given set `E` has an explicit description using (planar) binary trees, just as the free @@ -90,6 +90,20 @@ class FreeDendriformAlgebra(CombinatorialFreeModule): sage: x * (y * z) == (x * y) * z True + The associative product decomposes in two parts:: + + sage: x * y == F.prec(x, y) + F.succ(x, y) + True + + The axioms hold:: + + sage: F.prec(F.succ(x, y), z) == F.succ(x, F.prec(y, z)) + True + sage: F.prec(F.prec(x, y), z) == F.prec(x, y * z) + True + sage: F.succ(x * y, z) == F.succ(x, F.succ(y, z)) + True + When there is only one generator, unlabelled trees are used instead:: sage: F1 = algebras.FreeDendriform(QQ, 'w') From f768d7ca21e04025ff1ccf2de3c802d8a30bb3e1 Mon Sep 17 00:00:00 2001 From: Lokesh Jain Date: Mon, 5 Jun 2017 22:48:43 +0530 Subject: [PATCH 086/126] trac #7675: error message improved to 'unknown algorithm' --- src/sage/graphs/base/c_graph.pyx | 4 ++-- src/sage/graphs/generic_graph.py | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index b5a206371a9..d0fd6192dc6 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -2217,7 +2217,7 @@ cdef class CGraphBackend(GenericGraphBackend): return [] def bidirectional_dijkstra(self, x, y, weight_function=None, - distance_flag = False): + distance_flag=False): r""" Returns the shortest path or distance from ``x`` to ``y`` using a bidirectional version of Dijkstra's algorithm. @@ -2387,7 +2387,7 @@ cdef class CGraphBackend(GenericGraphBackend): return shortest_path def shortest_path_all_vertices(self, v, cutoff=None, - distance_flag = False): + distance_flag=False): r""" Returns for each vertex ``u`` a shortest ``v-u`` path or distance from ``v`` to ``u``. diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 24d4932794f..32684d782f3 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -14960,7 +14960,7 @@ def triangles_count(self, algorithm=None): elif algorithm=='matrix': return (self.adjacency_matrix()**3).trace() // 6 else: - raise ValueError("Algorithm '%s' not yet implemented. Please contribute." %(algorithm)) + raise ValueError('unknown algorithm "{}"'.format(algorithm)) def shortest_path(self, u, v, by_weight=False, algorithm=None, weight_function=None, check_weight=True, @@ -15117,7 +15117,7 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, elif algorithm=="BFS_Bid": return self._backend.shortest_path(u,v) else: - raise ValueError("Algorithm '" + algorithm + "' not yet implemented.") + raise ValueError('unknown algorithm "{}"'.format(algorithm)) def shortest_path_length(self, u, v, by_weight=False, algorithm=None, weight_function=None, check_weight=True, @@ -15494,7 +15494,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, elif algorithm=='Dijkstra_NetworkX': import networkx # If this is not present, an error might be raised by NetworkX - if self.num_verts()==1 and self.vertices()[0]==u: + if self.order() == 1 and self.has_vertex(u): return {u:[u]} if by_weight: if self.is_directed(): @@ -15525,8 +15525,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, return paths else: - raise ValueError("Algorithm " + algorithm + " not yet " + - "implemented. Please, contribute!") + raise ValueError('unknown algorithm "{}"'.format(algorithm)) def _path_length(self, path, by_weight=False, weight_function=None): r""" @@ -16077,7 +16076,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, return dist, pred elif algorithm != "Floyd-Warshall-Python": - raise ValueError("Algorithm " + algorithm + " is not implemented.") + raise ValueError('unknown algorithm "{}"'.format(algorithm)) from sage.rings.infinity import Infinity From 3294d1f1e579d43bba953361ead511650434e9a8 Mon Sep 17 00:00:00 2001 From: Lokesh Jain Date: Tue, 6 Jun 2017 00:24:32 +0530 Subject: [PATCH 087/126] trac #7675: updated tests for error message in previous commit --- src/sage/graphs/generic_graph.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 32684d782f3..3f71ce24565 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -14923,7 +14923,7 @@ def triangles_count(self, algorithm=None): sage: G.triangles_count(algorithm='tip top') Traceback (most recent call last): ... - ValueError: Algorithm 'tip top' not yet implemented. Please contribute. + ValueError: unknown algorithm "tip top" sage: digraphs.Path(5).triangles_count(algorithm="sparse_copy") Traceback (most recent call last): ... @@ -15062,7 +15062,7 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, sage: G.shortest_path(0, 3, by_weight=True, algorithm='tip top') Traceback (most recent call last): ... - ValueError: Algorithm 'tip top' not yet implemented. + ValueError: unknown algorithm "tip top" BFS on weighted graphs:: @@ -15451,7 +15451,7 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, sage: D.shortest_paths(0, algorithm='tip top') Traceback (most recent call last): ... - ValueError: Algorithm tip top not yet implemented. Please, contribute! + ValueError: unknown algorithm "tip top" If we ask for BFS in a weighted graph:: @@ -15986,7 +15986,7 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: g.shortest_path_all_pairs(algorithm="Bob") Traceback (most recent call last): ... - ValueError: Algorithm Bob is not implemented. + ValueError: unknown algorithm "Bob" Algorithms that do not work with weights:: From d573cc2b4c91c65f8ececbea78a256a8d355d478 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Mon, 5 Jun 2017 18:49:22 -0500 Subject: [PATCH 088/126] Taking care of reviewer suggestions. --- src/sage/matrix/matrix2.pyx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index f016de3e60e..5274c12a699 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -8088,14 +8088,19 @@ cdef class Matrix(matrix1.Matrix): (0, 6) sage: m2.tensor_product(m3).dimensions() (0, 6) + + sage: m1 = MatrixSpace(GF(5), 3, 2).an_element() + sage: m2 = MatrixSpace(GF(5), 0, 4).an_element() + sage: m1.tensor_product(m2).parent() + Full MatrixSpace of 0 by 8 dense matrices over Finite Field of size 5 """ if not isinstance(A, Matrix): raise TypeError('tensor product requires a second matrix, not {0}'.format(A)) - from sage.matrix.constructor import matrix, block_matrix + from sage.matrix.constructor import block_matrix # Special case when one of the matrices is 0 \times m or m \times 0 if self.nrows() == 0 or self.ncols() == 0 or A.nrows() == 0 or A.ncols() == 0: return self.matrix_space(self.nrows()*A.nrows(), - self.ncols()*A.ncols())([]) + self.ncols()*A.ncols())() return block_matrix(self.nrows(), self.ncols(), [x * A for x in self.list()], subdivide=subdivide) From fda6e26cb2965c8d863062eaacaf6ac288106b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Mon, 5 Jun 2017 22:06:36 -0400 Subject: [PATCH 089/126] 23132: Fix missing synchronisation upon starting gap3 + doc + skip gap3 banner --- src/sage/interfaces/gap3.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/interfaces/gap3.py b/src/sage/interfaces/gap3.py index af057778810..ca73b91614c 100644 --- a/src/sage/interfaces/gap3.py +++ b/src/sage/interfaces/gap3.py @@ -311,7 +311,7 @@ def __init__(self, command=gap3_cmd): Expect.__init__(self, name='gap3', prompt='gap> ', - command=self.__gap3_command_string + " -p -y 500", + command=self.__gap3_command_string + " -p -b -y 500", server=None, ulimit=None, script_subdirectory=None, @@ -327,6 +327,8 @@ def __init__(self, command=gap3_cmd): def _start(self): r""" + Initialize the interface and start gap3. + EXAMPLES:: sage: gap3 = Gap3() #optional - gap3 @@ -335,6 +337,11 @@ def _start(self): sage: gap3._start() #optional - gap3 sage: gap3.is_running() #optional - gap3 True + + Check that :trac:`23142` is fixed:: + + sage: gap3.eval("1+1") #optional - gap3 + 2 sage: gap3.quit() #optional - gap3 """ Expect._start(self) @@ -345,6 +352,7 @@ def _start(self): '@p\d+\.','@@','@[A-Z]','@[123456!"#$%&][^+]*\+', '@e','@c', '@f','@h','@i','@m','@n','@r','@s\d','@w.*\+','@x','@z']) self._compiled_small_pattern = self._expect.compile_pattern_list('@J') + self._expect.expect("@i") def _object_class(self): r""" From db64578235be03558fe04ac0d10ccd2849abbf29 Mon Sep 17 00:00:00 2001 From: Marc Mezzarobba Date: Wed, 31 May 2017 17:28:56 +0200 Subject: [PATCH 090/126] Set up embeddings for extensions created with R[alg] This fixes in particular the following issue, found thanks to a question of Paul Zimmermann: sage: QQ[I](I.pyobject()) ... TypeError: No compatible natural embeddings found for Number Field in I with defining polynomial x^2 + 1 and Complex Lazy Field --- src/sage/categories/rings.py | 73 ++++++++++++++++++- src/sage/rings/complex_field.py | 2 + src/sage/rings/polynomial/complex_roots.py | 2 +- .../rings/polynomial/polynomial_element.pyx | 2 +- src/sage/symbolic/expression_conversions.py | 6 ++ 5 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index 8e1ff35786b..eb1c74577ae 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -870,8 +870,24 @@ def __getitem__(self, arg): sage: QQ[I] Number Field in I with defining polynomial x^2 + 1 + sage: QQ[I].coerce_embedding() + Generic morphism: + From: Number Field in I with defining polynomial x^2 + 1 + To: Complex Lazy Field + Defn: I -> 1*I + + :: + sage: QQ[sqrt(2)] Number Field in sqrt2 with defining polynomial x^2 - 2 + sage: QQ[sqrt(2)].coerce_embedding() + Generic morphism: + From: Number Field in sqrt2 with defining polynomial x^2 - 2 + To: Real Lazy Field + Defn: sqrt2 -> 1.414213562373095? + + :: + sage: QQ[sqrt(2),sqrt(3)] Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field @@ -884,6 +900,18 @@ def __getitem__(self, arg): sage: ZZ[sqrt(2)+sqrt(3)] Order in Number Field in a with defining polynomial x^4 - 10*x^2 + 1 + Embeddings are found for simple extensions (when that makes sense):: + + sage: QQi. = QuadraticField(-1, 'i') + sage: QQ[i].coerce_embedding() + Generic morphism: + From: Number Field in i with defining polynomial x^2 + 1 + To: Complex Lazy Field + Defn: i -> 1*I + sage: QQi. = QuadraticField(-1, embedding=None) + sage: QQ[i].coerce_embedding() is None + True + TESTS: A few corner cases:: @@ -929,6 +957,21 @@ def __getitem__(self, arg): sage: K.base_field().base_field() Number Field in b with defining polynomial x^3 - 3 + Embeddings:: + + sage: QQ[I](I.pyobject()) + I + sage: a = 10^100; expr = (2*a + sqrt(2))/(2*a^2-1) + sage: QQ[expr].coerce_embedding() is None + False + sage: QQ[sqrt(5)].gen() > 0 + True + sage: expr = sqrt(2) + I*(cos(pi/4, hold=True) - sqrt(2)/2) + sage: QQ[expr].coerce_embedding() + Generic morphism: + From: Number Field in a with defining polynomial x^2 - 2 + To: Real Lazy Field + Defn: a -> 1.414213562373095? """ def normalize_arg(arg): if isinstance(arg, (tuple, list)): @@ -973,8 +1016,36 @@ def normalize_arg(arg): if minpolys: # how to pass in names? - # TODO: set up embeddings names = tuple(_gen_names(elts)) + if len(elts) == 1: + from sage.rings.all import CIF, CLF, RIF, RLF + elt = elts[0] + try: + iv = CIF(elt) + except (TypeError, ValueError): + emb = None + else: + # First try creating an ANRoot manually, because + # extension(..., embedding=CLF(expr)) (or + # ...QQbar(expr)) would normalize the expression in + # QQbar, which currently is VERY slow in many cases. + # This may fail when minpoly has close roots or elt is + # a complicated symbolic expression. + # TODO: Rewrite using #19362 and/or #17886 and/or + # #15600 once those issues are solved. + from sage.rings.qqbar import AlgebraicNumber, ANRoot + try: + elt = AlgebraicNumber(ANRoot(minpolys[0], iv)) + except ValueError: + pass + # Force a real embedding when possible, to get the + # right ordered ring structure. + if (iv.imag().is_zero() or iv.imag().contains_zero() + and elt.imag().is_zero()): + emb = RLF(elt) + else: + emb = CLF(elt) + return self.extension(minpolys[0], names[0], embedding=emb) try: # Doing the extension all at once is best, if possible... return self.extension(minpolys, names) diff --git a/src/sage/rings/complex_field.py b/src/sage/rings/complex_field.py index 1796fcccbcb..57a80cb0c84 100644 --- a/src/sage/rings/complex_field.py +++ b/src/sage/rings/complex_field.py @@ -333,6 +333,8 @@ def __call__(self, x=None, im=None): sage: CC(QQ[I].gen()) 1.00000000000000*I sage: CC.gen() + QQ[I].gen() + 2.00000000000000*I + sage: CC.gen() + QQ.extension(x^2 + 1, 'I', embedding=None).gen() Traceback (most recent call last): ... TypeError: unsupported operand parent(s) for +: 'Complex Field with 53 bits of precision' and 'Number Field in I with defining polynomial x^2 + 1' diff --git a/src/sage/rings/polynomial/complex_roots.py b/src/sage/rings/polynomial/complex_roots.py index 7ffab6741ae..529ff9277bb 100644 --- a/src/sage/rings/polynomial/complex_roots.py +++ b/src/sage/rings/polynomial/complex_roots.py @@ -186,7 +186,7 @@ def complex_roots(p, skip_squarefree=False, retval='interval', min_prec=0): sage: v[1][0].imag() < 1e25 True - sage: K. = NumberField(x^2 + 1) + sage: K. = QuadraticField(-1) sage: eps = 1/2^100 sage: x = polygen(K) sage: p = (x-1)*(x-1-eps)*(x-1+eps)*(x-1-eps*im)*(x-1+eps*im) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 00e4f94176d..9b575fb2863 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -7030,7 +7030,7 @@ cdef class Polynomial(CommutativeAlgebraElement): :: - sage: K. = NumberField(x^2 + 1) + sage: K. = QuadraticField(-1) sage: y = polygen(K) sage: p = y^4 - 2 - im sage: p.roots(ring=CC) diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index 1774b053587..66db6e940b4 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -1008,6 +1008,12 @@ def __init__(self, ex, base_ring=None, ring=None): Traceback (most recent call last): ... TypeError: y is not a variable of Univariate Polynomial Ring in x over Rational Field + + TESTS:: + + sage: t, x, z = SR.var('t,x,z') + sage: QQ[i]['x,y,z,t'](4*I*t + 2*x -12*z + 2) + 2*x - 12*z + (4*I)*t + 2 """ if not (ring is None or base_ring is None): raise TypeError("either base_ring or ring must be specified, but not both") From 5873c8ddcd3465ebdd0c8e1604b5ec36f5ab8589 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Tue, 6 Jun 2017 09:32:24 +0000 Subject: [PATCH 091/126] Fix GNU as version detection. Disable --enable-fat when as is too old, and add additional warning message --- build/pkgs/mpir/spkg-install | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/build/pkgs/mpir/spkg-install b/build/pkgs/mpir/spkg-install index 09fb7e68c72..36d896f67af 100755 --- a/build/pkgs/mpir/spkg-install +++ b/build/pkgs/mpir/spkg-install @@ -166,12 +166,16 @@ fi # Workaround old GNU as version by disabling assembly use. if [ "$UNAME" = Linux ]; then as_version=`$AS --version | head -1 | awk 'NF>1{print $NF}'` - case "$as_version" in - 1.*|2.1*|2.[0-2]*) + as_version_major=${as_version%%.*} + as_version_rest=${as_version#*.} + as_version_minor=${as_version_rest%%.*} + if [ $as_version_major -lt 2 ] || \ + [ $as_version_major -eq 2 -a $as_version_minor -lt 24 ]; then echo "Disable use of assembly because of GNU as < 2.23." + echo "This also disables SAGE_FAT_BINARY=yes." export MPN_PATH=generic - ;; - esac + SAGE_FAT_BINARY=no + fi fi # Work around a bug in GCC 4.7.0 which breaks the build on Itanium CPUs. From 691a2dea644bed1749e224f53b9f9822aac39a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 6 Jun 2017 11:45:49 +0200 Subject: [PATCH 092/126] py3: tolerance for u prefix in doctests --- src/sage/doctest/parsing.py | 79 ++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 5 deletions(-) diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 48f6a7d19e9..77a1c8f8488 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -1,4 +1,4 @@ -## -*- encoding: utf-8 -*- +# -*- encoding: utf-8 -*- """ Parsing docstrings @@ -22,15 +22,18 @@ # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import print_function -from __future__ import absolute_import +from __future__ import print_function, absolute_import +from sage.misc.six import u -import re, sys +import re +import sys import doctest import collections from sage.repl.preparse import preparse, strip_string_literals +from Cython.Build.Dependencies import strip_string_literals as cython_strip_string_literals from functools import reduce + from .external import available_software float_regex = re.compile('\s*([+-]?\s*((\d*\.?\d+)|(\d+\.?))([eE][+-]?\d+)?)') @@ -64,6 +67,56 @@ ansi_escape_sequence = re.compile(r'(\x1b[@-Z\\-~]|\x1b\[.*?[@-~])') +def remove_unicode_u(string): + """ + Given a string, try to remove all unicode u prefixes inside. + + This will help to keep the same doctest results in Python2 and Python3. + The input string is typically the documentation of a method or function. + This string may contain some letters u that are unicode python2 prefixes. + The aim is to remove all of these u and only them. + + INPUT: + + - ``string`` -- either ``unicode`` or ``bytes`` (if ``bytes``, it + will be converted to ``unicode`` assuming UTF-8) + + OUTPUT: ``unicode`` string + + EXAMPLES:: + + sage: from sage.doctest.parsing import remove_unicode_u as remu + sage: remu("u'you'") + "'you'" + sage: remu('u') + 'u' + sage: remu("[u'am', 'stram', u'gram']") + "['am', 'stram', 'gram']" + sage: remu('[u"am", "stram", u"gram"]') + '["am", "stram", "gram"]' + + This deals correctly with nested quotes:: + + sage: str = '''[u"Singular's stuff", u'good']''' + sage: print(remu(str)) + ["Singular's stuff", 'good'] + + TESTS: + + This supports python2 str type as input:: + + sage: euro = "'€'" + sage: print(remu(euro)) + '€' + """ + stripped, replacements = cython_strip_string_literals(u(string), + "__remove_unicode_u") + string = stripped.replace('u"', '"').replace("u'", "'") + for magic, literal in replacements.items(): + string = string.replace(magic, literal) + return string + + def parse_optional_tags(string): """ Returns a set consisting of the optional tags from the following @@ -811,6 +864,15 @@ def check_output(self, want, got, optionflags): sage: print("[ - 1, 2]") # abs tol 1e-10 [-1,2] + + Tolerance for string results with unicode prefix:: + + sage: a = u'Cyrano'; a + 'Cyrano' + sage: b = [u'Fermat', u'Euler']; b + ['Fermat', 'Euler'] + sage: c = u'you'; c + 'you' """ got = self.human_readable_escape_sequences(got) if isinstance(want, MarkedOutput): @@ -834,8 +896,15 @@ def check_output(self, want, got, optionflags): # The doctest is successful if the "want" and "got" # intervals have a non-empty intersection return all(a.overlaps(b) for a, b in zip(want_intervals, got_values)) + ok = doctest.OutputChecker.check_output(self, want, got, optionflags) - return ok + if ok or 'u' not in got: + return ok + + # accept the same answer where strings have unicode prefix u + # for smoother transition to python3 + got = remove_unicode_u(got) + return doctest.OutputChecker.check_output(self, want, got, optionflags) def output_difference(self, example, got, optionflags): r""" From d3f012d5001ffd879e08cfb5a382f6587d672f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 6 Jun 2017 11:52:39 +0200 Subject: [PATCH 093/126] some cleanup of unicode and six --- src/sage/algebras/clifford_algebra.py | 27 ++++++++++++++------------- src/sage/algebras/commutative_dga.py | 9 +++++---- src/sage/misc/converting_dict.py | 1 + src/sage/misc/dev_tools.py | 6 +++--- src/sage/misc/inline_fortran.py | 2 ++ src/sage/misc/mathml.py | 1 + src/sage/misc/nested_class_test.py | 2 +- src/sage/misc/sagedoc.py | 6 ++++-- src/sage/misc/sageinspect.py | 13 +++++++++---- src/sage/misc/six.py | 18 ++++++++++++++++-- src/sage/misc/superseded.py | 2 +- 11 files changed, 57 insertions(+), 30 deletions(-) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index a7983b7c5f4..eae3a35bfd5 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -15,8 +15,9 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** +from six import iteritems -from sage.misc import six +from sage.misc.six import with_metaclass from sage.misc.cachefunc import cached_method from sage.structure.unique_representation import UniqueRepresentation from copy import copy @@ -119,7 +120,7 @@ def _mul_(self, other): # the dictionary describing the element # ``e[i]`` * (the element described by the dictionary ``cur``) # (where ``e[i]`` is the ``i``-th standard basis vector). - for mr,cr in six.iteritems(cur): + for mr,cr in iteritems(cur): # Commute the factor as necessary until we are in order pos = 0 for j in mr: @@ -155,7 +156,7 @@ def _mul_(self, other): cur = next # Add the distributed terms to the total - for index,coeff in six.iteritems(cur): + for index,coeff in iteritems(cur): d[index] = d.get(index, zero) + cl * coeff if d[index] == zero: del d[index] @@ -729,8 +730,8 @@ def _element_constructor_(self, x): if x in self.free_module(): R = self.base_ring() if x.parent().base_ring() is R: - return self.element_class(self, {(i,): c for i,c in six.iteritems(x)}) - return self.element_class(self, {(i,): R(c) for i,c in six.iteritems(x) if R(c) != R.zero()}) + return self.element_class(self, {(i,): c for i,c in iteritems(x)}) + return self.element_class(self, {(i,): R(c) for i,c in iteritems(x) if R(c) != R.zero()}) if isinstance(x, CliffordAlgebraElement): if x.parent() is self: @@ -1206,7 +1207,7 @@ def center_basis(self): for m,c in (Bi*Bj - Bj*Bi): d[(a, K.index(m)+k*b)] = c m = Matrix(R, d, nrows=k, ncols=k*k, sparse=True) - from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in six.iteritems(x)), + from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in iteritems(x)), distinct=True) return tuple(map( from_vector, m.kernel().basis() )) @@ -1220,7 +1221,7 @@ def center_basis(self): # v = B[i]*B[j] - B[j]*B[i] # eqns[a].extend([v[k] for k in K]) # m = Matrix(R, eqns) - # from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in six.iteritems(x)), + # from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in iteritems(x)), # distinct=True) # return tuple(map( from_vector, m.kernel().basis() )) @@ -1303,7 +1304,7 @@ def supercenter_basis(self): for m,c in supercommutator: d[(a, K.index(m)+k*b)] = c m = Matrix(R, d, nrows=k, ncols=k*k, sparse=True) - from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in six.iteritems(x)), + from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in iteritems(x)), distinct=True) return tuple(map( from_vector, m.kernel().basis() )) @@ -1317,7 +1318,7 @@ def supercenter_basis(self): # v = B[i].supercommutator(B[j]) # or better an if-loop as above # eqns[a].extend([v[k] for k in K]) # m = Matrix(R, eqns) - # from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in six.iteritems(x)), + # from_vector = lambda x: self.sum_of_terms(((K[i], c) for i,c in iteritems(x)), # distinct=True) # return tuple(map( from_vector, m.kernel().basis() )) @@ -2160,7 +2161,7 @@ def scalar(self, other): ##################################################################### ## Differentials -class ExteriorAlgebraDifferential(six.with_metaclass( +class ExteriorAlgebraDifferential(with_metaclass( InheritComparisonClasscallMetaclass, ModuleMorphismByLinearity, UniqueRepresentation )): @@ -2202,13 +2203,13 @@ def __classcall__(cls, E, s_coeff): """ d = {} - for k,v in six.iteritems(dict(s_coeff)): + for k,v in iteritems(dict(s_coeff)): if not v: # Strip terms with 0 continue if isinstance(v, dict): R = E.base_ring() - v = E._from_dict({(i,): R(c) for i,c in six.iteritems(v)}) + v = E._from_dict({(i,): R(c) for i,c in iteritems(v)}) else: # Make sure v is in ``E`` v = E(v) @@ -2627,7 +2628,7 @@ def __init__(self, E, s_coeff): self._cos_coeff = {} zero = E.zero() B = E.basis() - for k,v in six.iteritems(dict(s_coeff)): + for k, v in iteritems(dict(s_coeff)): k = B[k] for m,c in v: self._cos_coeff[m] = self._cos_coeff.get(m, zero) + c * k diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index a44f14a0f90..e571a51c30a 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -71,9 +71,10 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** -from __future__ import print_function +from __future__ import print_function, absolute_import +from six import string_types -from sage.misc import six +from sage.misc.six import with_metaclass from sage.structure.unique_representation import UniqueRepresentation from sage.structure.sage_object import SageObject from sage.misc.cachefunc import cached_method @@ -98,7 +99,7 @@ from sage.rings.quotient_ring_element import QuotientRingElement -class Differential(six.with_metaclass( +class Differential(with_metaclass( InheritComparisonClasscallMetaclass, UniqueRepresentation, Morphism )): @@ -849,7 +850,7 @@ def __classcall__(cls, base, names=None, degrees=None, R=None, I=None): else: n = len(degrees) names = tuple('x{}'.format(i) for i in range(n)) - elif isinstance(names, six.string_types): + elif isinstance(names, string_types): names = tuple(names.split(',')) n = len(names) else: diff --git a/src/sage/misc/converting_dict.py b/src/sage/misc/converting_dict.py index 2902e2f8c6f..78338478bf3 100644 --- a/src/sage/misc/converting_dict.py +++ b/src/sage/misc/converting_dict.py @@ -46,6 +46,7 @@ # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** +from __future__ import absolute_import from six import iteritems import collections diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index 34b8500048b..9274984b707 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -14,7 +14,7 @@ # http://www.gnu.org/licenses/ #****************************************************************************** from __future__ import absolute_import -from six import iteritems +from six import iteritems, string_types def runsnake(command): @@ -519,10 +519,10 @@ def import_statements(*objects, **kwds): name = None # the name of the object # 1. if obj is a string, we look for an object that has that name - if isinstance(obj, str): + if isinstance(obj, string_types): name = obj obj = find_objects_from_name(name, 'sage') - if len(obj) == 0: + if not obj: obj = find_objects_from_name(name) # remove lazy imported objects from list obj diff --git a/src/sage/misc/inline_fortran.py b/src/sage/misc/inline_fortran.py index 2701a6f0533..faf115d0099 100644 --- a/src/sage/misc/inline_fortran.py +++ b/src/sage/misc/inline_fortran.py @@ -1,7 +1,9 @@ """ Fortran compiler """ +from __future__ import absolute_import from six import iteritems + import os import imp import shutil diff --git a/src/sage/misc/mathml.py b/src/sage/misc/mathml.py index aa987c45cbb..d584a481900 100644 --- a/src/sage/misc/mathml.py +++ b/src/sage/misc/mathml.py @@ -22,6 +22,7 @@ # # http://www.gnu.org/licenses/ #***************************************************************************** +from __future__ import absolute_import from six import iteritems, integer_types diff --git a/src/sage/misc/nested_class_test.py b/src/sage/misc/nested_class_test.py index a60bf68831c..8bba13b90ab 100644 --- a/src/sage/misc/nested_class_test.py +++ b/src/sage/misc/nested_class_test.py @@ -44,7 +44,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # http://www.gnu.org/licenses/ #****************************************************************************** -from __future__ import print_function +from __future__ import print_function, absolute_import from six import add_metaclass __all__ = [] # Don't document any parents diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index e2593b116ae..ebe1015364f 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -41,6 +41,8 @@ from __future__ import print_function from __future__ import absolute_import +from six import string_types + import os, re, sys import pydoc from sage.misc.temporary_file import tmp_dir @@ -635,7 +637,7 @@ def format(s, embedded=False): ... """ - if not isinstance(s, str): + if not isinstance(s, string_types): raise TypeError("s must be a string") # Leading empty lines must be removed, since we search for directives @@ -717,7 +719,7 @@ def format_src(s): sage: format_src('<<>>')[5:15] 'Sq(*nums):' """ - if not isinstance(s, str): + if not isinstance(s, string_types): raise TypeError("s must be a string") docs = set([]) import sage.all diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 91254e18395..18b54c91795 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -114,7 +114,8 @@ def foo(unsigned int x=1, a=')"', b={not (2+1==3):'bar'}, *args, **kwds): return """ from __future__ import print_function, absolute_import from six.moves import range -from six import iteritems, string_types, class_types +from six import iteritems, string_types, class_types, text_type +from sage.misc.six import u import ast import inspect @@ -354,9 +355,9 @@ def _extract_source(lines, lineno): raise ValueError("Line numbering starts at 1! (tried to extract line {})".format(lineno)) lineno -= 1 - if isinstance(lines, str): + if isinstance(lines, string_types): lines = lines.splitlines(True) # true keeps the '\n' - if len(lines) > 0: + if len(lines): # Fixes an issue with getblock lines[-1] += '\n' @@ -1635,7 +1636,7 @@ def _sage_getdoc_unformatted(obj): # not a 'getset_descriptor' or similar. if not isinstance(r, string_types): return '' - elif isinstance(r, unicode): + elif isinstance(r, text_type): # unicode (py2) = str (py3) return r.encode('utf-8', 'ignore') else: return r @@ -2115,7 +2116,11 @@ class Element: pos = _extract_embedded_position(d) if pos is None: try: + # BEWARE HERE + # inspect gives str (=bytes) in python2 + # and str (=unicode) in python3 return inspect.getsourcelines(obj) + except (IOError, TypeError) as err: try: objinit = obj.__init__ diff --git a/src/sage/misc/six.py b/src/sage/misc/six.py index 37295c7aeca..92ea494324d 100644 --- a/src/sage/misc/six.py +++ b/src/sage/misc/six.py @@ -108,6 +108,18 @@ def u(x): r""" Convert `x` to unicode, assuming UTF-8 encoding. + Python2 behaviour: + + If input is unicode, returns the input. + + If input is str (assumed to be utf-8 encoded), convert to unicode. + + Python3 behaviour: + + If input is str, returns the input. + + If input is bytes (assumed to be utf-8 encoded), convert to unicode. + EXAMPLES:: sage: from sage.misc.six import u @@ -116,6 +128,8 @@ def u(x): sage: u(u"500 \u20ac") u'500 \u20ac' """ - if isinstance(x, unicode): + if isinstance(x, text_type): # py2 unicode and py3 str return x - return str(x).decode("utf-8") + if isinstance(x, bytes): + return x.decode("utf-8") + raise TypeError('input has no conversion to unicode') diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index 7cb1c225d46..2628bde18be 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -22,7 +22,7 @@ # # http://www.gnu.org/licenses/ ######################################################################## -from __future__ import print_function +from __future__ import print_function, absolute_import from six import iteritems from warnings import warn From cfa028dba188c396a39b77a303a4089fa5c8a38d Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Tue, 6 Jun 2017 06:01:36 -0500 Subject: [PATCH 094/126] Use zero_matrix().__copy__(). --- src/sage/matrix/matrix2.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 5274c12a699..905b409ea09 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -8100,7 +8100,7 @@ cdef class Matrix(matrix1.Matrix): # Special case when one of the matrices is 0 \times m or m \times 0 if self.nrows() == 0 or self.ncols() == 0 or A.nrows() == 0 or A.ncols() == 0: return self.matrix_space(self.nrows()*A.nrows(), - self.ncols()*A.ncols())() + self.ncols()*A.ncols()).zero_matrix().__copy__() return block_matrix(self.nrows(), self.ncols(), [x * A for x in self.list()], subdivide=subdivide) From edfcbf421550e6045ed7c861237b3cbfc887858a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 6 Jun 2017 13:38:20 +0200 Subject: [PATCH 095/126] py3: richcmp in Pari Ring --- src/sage/rings/pari_ring.py | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/sage/rings/pari_ring.py b/src/sage/rings/pari_ring.py index 3a9697f5ddb..5cc2ae53c49 100644 --- a/src/sage/rings/pari_ring.py +++ b/src/sage/rings/pari_ring.py @@ -6,10 +6,8 @@ - William Stein (2004): Initial version. - Simon King (2011-08-24): Use UniqueRepresentation, element_class and proper initialisation of elements. - """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -17,23 +15,22 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** - -import operator - +# **************************************************************************** import sage.libs.pari.all as pari import sage.rings.ring as ring from sage.structure.element import RingElement - +from sage.structure.sage_object import richcmp from sage.misc.fast_methods import Singleton + class Pari(RingElement): """ Element of Pari pseudo-ring. """ def __init__(self, x, parent=None): """ - EXAMPLES: + EXAMPLES:: + sage: R = PariRing() sage: f = R('x^3 + 1/2') sage: f @@ -141,17 +138,21 @@ def __invert__(self): """ return self.__class__(~self.__x, parent=_inst) - def __cmp__(self, other): + def _richcmp_(self, other, op): """ EXAMPLES:: sage: R = PariRing() sage: a = R(3) sage: b = R(11) - sage: cmp(a,b) - -1 + sage: a < b + True + sage: a == b + False + sage: a > b + False """ - return cmp(self.__x, other.__x) + return richcmp(self.__x, other.__x, op) def __int__(self): return int(self.__x) @@ -159,7 +160,8 @@ def __int__(self): class PariRing(Singleton, ring.Ring): """ - EXAMPLES: + EXAMPLES:: + sage: R = PariRing(); R Pseudoring of all PARI objects. sage: loads(R.dumps()) is R @@ -169,6 +171,7 @@ class PariRing(Singleton, ring.Ring): def __init__(self): ring.Ring.__init__(self, self) + def __repr__(self): return 'Pseudoring of all PARI objects.' @@ -177,20 +180,19 @@ def _element_constructor_(self, x): return x return self.element_class(x, parent=self) - def is_field(self, proof = True): + def is_field(self, proof=True): return False def characteristic(self): raise RuntimeError("Not defined.") - #return 0 def random_element(self, x=None, y=None, distribution=None): """ Return a random integer in Pari. - NOTE: + .. NOTE:: - The given arguments are passed to ``ZZ.random_element(...)``. + The given arguments are passed to ``ZZ.random_element(...)``. INPUT: @@ -214,7 +216,7 @@ def random_element(self, x=None, y=None, distribution=None): """ from sage.all import ZZ - return self(ZZ.random_element(x,y,distribution)) + return self(ZZ.random_element(x, y, distribution)) def zeta(self): """ @@ -229,4 +231,3 @@ def zeta(self): return self(-1) _inst = PariRing() - From 2d9823c6b328e03705c3c40333d30c6dee30e44b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 6 Jun 2017 15:34:24 +0200 Subject: [PATCH 096/126] py3: no more cmp_props --- src/sage/misc/misc.py | 7 +++++- src/sage/modular/modsym/ambient.py | 39 +++++++++++++++++++++--------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index fcd31c823ab..1e85b4c6b0f 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -571,12 +571,17 @@ def generic_cmp(x,y): return 0 return 1 + def cmp_props(left, right, props): + from sage.misc.superseded import deprecation + deprecation(23149, "cmp_props is deprecated") for a in props: c = cmp(left.__getattribute__(a)(), right.__getattribute__(a)()) - if c: return c + if c: + return c return 0 + def union(x, y=None): """ Return the union of x and y, as a list. The resulting list need not diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index af89067356e..41dbd9a8e3a 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -182,27 +182,42 @@ def __init__(self, group, weight, sign, base_ring, hecke.AmbientHeckeModule.__init__(self, base_ring, rank, group.level(), weight, category=category) - def __cmp__(self, other): + def __eq__(self, other): """ - Standard comparison function. + Check that ``self`` is equal to ``other``. EXAMPLES:: - sage: ModularSymbols(11,2) == ModularSymbols(11,2) # indirect doctest + sage: ModularSymbols(11,2) == ModularSymbols(11,2) True - sage: ModularSymbols(11,2) == ModularSymbols(11,4) # indirect doctest + sage: ModularSymbols(11,2) == ModularSymbols(11,4) False - """ if not isinstance(other, ModularSymbolsSpace): - return cmp(type(self), type(other)) + return False + if isinstance(other, ModularSymbolsAmbient): - return misc.cmp_props(self, other, ['group', 'weight', 'sign', 'base_ring', 'character']) - c = cmp(self, other.ambient_hecke_module()) - if c: return c - if self.free_module() == other.free_module(): - return 0 - return -1 + return (self.group() == other.group() and + self.weight() == other.weight() and + self.sign() == other.sign() and + self.base_ring() == other.base_ring() and + self.character() == other.character()) + + return (self == other.ambient_hecke_module() and + self.free_module() == other.free_module()) + + def __ne__(self, other): + """ + Check that ``self`` is not equal to ``other``. + + EXAMPLES:: + + sage: ModularSymbols(11,2) != ModularSymbols(11,2) + False + sage: ModularSymbols(11,2) != ModularSymbols(11,4) + True + """ + return not (self == other) def new_submodule(self, p=None): r""" From 50798771d9b30d558c9446699c2374667bf256ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 6 Jun 2017 16:11:37 -0400 Subject: [PATCH 097/126] 23142: trivial doctest update --- src/sage/interfaces/gap3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/gap3.py b/src/sage/interfaces/gap3.py index ca73b91614c..c25092cd11a 100644 --- a/src/sage/interfaces/gap3.py +++ b/src/sage/interfaces/gap3.py @@ -565,7 +565,7 @@ def _install_hints(self): sage: gap3('3+2') Traceback (most recent call last): ... - TypeError: unable to start gap3 because the command '/wrongpath/gap3 -p -y 500' failed: The command was not found or was not executable: /wrongpath/gap3. + TypeError: unable to start gap3 because the command '/wrongpath/gap3 ...' failed: The command was not found or was not executable: /wrongpath/gap3. Your attempt to start GAP3 failed, either because you do not have have GAP3 installed, or because it is not configured correctly. From 529e4d3cc40f80dda2022a5ef4336d0ea8ed35fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20M=2E=20Thi=C3=A9ry?= Date: Tue, 6 Jun 2017 16:15:50 -0400 Subject: [PATCH 098/126] 23142: another trivial doctest update --- src/sage/interfaces/gap3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/interfaces/gap3.py b/src/sage/interfaces/gap3.py index c25092cd11a..f4cac6c3ee5 100644 --- a/src/sage/interfaces/gap3.py +++ b/src/sage/interfaces/gap3.py @@ -341,7 +341,7 @@ def _start(self): Check that :trac:`23142` is fixed:: sage: gap3.eval("1+1") #optional - gap3 - 2 + '2' sage: gap3.quit() #optional - gap3 """ Expect._start(self) From f1287234af088ddf7d631e75aa6a9581c09b860c Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Mon, 5 Jun 2017 23:14:07 +0000 Subject: [PATCH 099/126] Creation of a vectorized gauss_legendre integrator --- src/module_list.py | 3 + src/sage/numerical/gauss_legendre.pyx | 235 ++++++++++++++++++++++++++ 2 files changed, 238 insertions(+) create mode 100644 src/sage/numerical/gauss_legendre.pyx diff --git a/src/module_list.py b/src/module_list.py index 7b5f2fe7064..173c9ad2f26 100644 --- a/src/module_list.py +++ b/src/module_list.py @@ -1056,6 +1056,9 @@ def uname_specific(name, value, alternative): ["sage/numerical/linear_tensor_element.pyx"], libraries=["stdc++"]), + Extension("sage.numerical.gauss_legendre", + ["sage/numerical/gauss_legendre.pyx"]), + Extension("sage.numerical.sdp", ["sage/numerical/sdp.pyx"]), diff --git a/src/sage/numerical/gauss_legendre.pyx b/src/sage/numerical/gauss_legendre.pyx new file mode 100644 index 00000000000..c919de55490 --- /dev/null +++ b/src/sage/numerical/gauss_legendre.pyx @@ -0,0 +1,235 @@ +r""" +Gauss-Legendre integration for vector-valued functions + +Routine to perform Gauss-Legendre integration for vector-functions. + +AUTHORS: + + - Nils Bruin (2017-06-06): initial version + +EXAMPLES:: + +NOTE: + +The code here is directly based on mpmath (see http://mpmath.org), but has a highly +optimized routine to compute the nodes. +""" + +#***************************************************************************** +# Copyright (C) 2017 Nils Bruin +# +# 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/ +#***************************************************************************** + +#as it turns out, computing the nodes can easily turn out to be more +#expensive than computing the integrals. So it's worth optimizing this. +#making the function into a cython routine helps a little bit. If we really +#want to we can optimize this further, probably to a point where +#we don't have to bother with node computation routines that have a better order +#than this naive approach (which is quadratic) +from sage.libs.mpfr cimport * +import math +from sage.rings.real_mpfr import RealField +from sage.misc.cachefunc import cached_function +from sage.rings.real_mpfr cimport RealNumber, RealField_class + +@cached_function +def nodes(degree,prec): + r""" + Compute the integration nodes and weights for the Gauss-Legendre quadrature scheme. + + INPUT: + + - ``degree`` -- integer. A measure for how many nodes to compute. + + - ``prec`` -- integer (minimal value 53). Binary precision with which the nodes and weights are computed. + + OUTPUT: + + A list of (node,weight) pairs, of length 3*2**(degree-1). + + EXAMPLE: + + The nodes for the Gauss-Legendre scheme are roots of Legendre polynomials. + The weights can be computed by a straightforward formula (note that evaluating + a derivative of a Legendre polynomial isn't particularly numerically stable):: + + sage: from sage.numerical.gauss_legendre import nodes + sage: L1=nodes(4,53) + sage: P=RR['x'](sage.functions.orthogonal_polys.legendre_P(24,x)) + sage: Pdif=P.diff() + sage: L2=[( (r+1)/2,1/(1-r^2)/Pdif(r)^2) for r,_ in RR['x'](P).roots()] + sage: all((a[0]-b[0]).abs() < 10^-15 and (a[1]-b[1]).abs() < 10^-9 for a,b in zip(L1,L2)) + True + """ + cdef int j,j1,n + cdef RealNumber r,t1,t2,t3,t4,a,w + cdef mpfr_t u,v + cdef RealField_class R + if prec < 53: + prec = 53 + R=RealField(int(prec*3/2)) + Rout=RealField(prec) + mpfr_init2(u,R.__prec) + mpfr_init2(v,R.__prec) + ZERO=R.zero() + ONE=R.one() + HALF=ONE/2 + TWO=2*ONE + rnd=R.rnd + epsilon=R(1)>>(prec+8) + if degree == 1: + x=R(3)/5 + w=R(5)/18 + nodes = [((1-x)/2,w),(HALF,R(4)/9),((1+x)/2,w)] + else: + nodes=[] + n=3*2**(degree-1) + upto = n//2+1 + for j in xrange(1,upto): + r=R(math.cos(math.pi*(j-0.25)/(n+0.5))) + while True: + t1,t2=ONE,ZERO + for j1 in xrange(1,n+1): + mpfr_mul(u,r.value,t1.value,rnd) + mpfr_mul_si(u,u,2*j1-1,rnd) + mpfr_mul_si(v,t2.value,j1-1,rnd) + mpfr_sub(u,u,v,rnd) + mpfr_div_si(u,u,j1,rnd) + t2=t1 + t1=R._new() + mpfr_set(t1.value,u,rnd) + t4=R(n)*(r*t1-t2)/(r**2-ONE) + a=t1/t4 + r=r-a + if a.abs() 1: + err= estimate_error(results,prec,epsilon) + if err <= epsilon: + return I + degree +=1 From c4ecf47912e15f2b332b7ba52d69f8db71990dd9 Mon Sep 17 00:00:00 2001 From: Marcelo Forets Date: Wed, 7 Jun 2017 08:31:07 +0200 Subject: [PATCH 100/126] use aligned environment --- src/sage/calculus/desolvers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index d7bfb0f85c1..8aed1258316 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -937,10 +937,10 @@ def eulers_method_2x2(f,g, t0, x0, y0, h, t1,algorithm="table"): .. MATH:: - \begin{align} + \begin{aligned} x' &= f(t, x, y), x(t_0)=x_0 \\ y' &= g(t, x, y), y(t_0)=y_0. - \end{align} + \end{aligned} The ``t`` column of the table increments from `t_0` to `t_1` by `h` (so `\frac{t_1-t_0}{h}` must be an integer). In the ``x`` column, From b0f1552f8e07d80c529f349fa3ce2898636d65f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Tue, 6 Jun 2017 16:40:02 +0200 Subject: [PATCH 101/126] py3: caring for a few cmp in modular folder --- .../modular/arithgroup/arithgroup_perm.py | 39 +++++++++++++++---- .../modular/arithgroup/congroup_generic.py | 39 +++++++++++++------ src/sage/modular/cusps.py | 27 +++++++++---- src/sage/modular/cusps_nf.py | 33 +++++++++++----- src/sage/modular/etaproducts.py | 32 ++++++++++----- src/sage/modular/quatalg/brandt.py | 11 ++---- 6 files changed, 128 insertions(+), 53 deletions(-) diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index 577c23369f4..4133d24c602 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -502,7 +502,7 @@ class ArithmeticSubgroup_Permutation_class(ArithmeticSubgroup): sage: TestSuite(G).run() """ - def __cmp__(self, other): + def __eq__(self, other): r""" Equality test. @@ -525,17 +525,40 @@ def __cmp__(self, other): True """ if isinstance(other, ArithmeticSubgroup_Permutation_class): - - return (cmp(self.is_odd(), other.is_odd()) or - cmp(self.index(), other.index()) or - cmp(self.relabel(inplace=False)._S2, other.relabel(inplace=False)._S2) or - cmp(self.relabel(inplace=False)._S3, other.relabel(inplace=False)._S3)) + return (self.is_odd() == other.is_odd() and + self.index() == other.index() and + self.relabel(inplace=False)._S2 == other.relabel(inplace=False)._S2 and + self.relabel(inplace=False)._S3 == other.relabel(inplace=False)._S3) elif isinstance(other, ArithmeticSubgroup): - return cmp(self, other.as_permutation_group()) + return self == other.as_permutation_group() else: - return cmp(type(self), type(other)) + return False + + def __ne__(self, other): + """ + Check that ``self`` is not equal to ``other``. + + TESTS:: + + sage: G2 = Gamma(2) + sage: G3 = Gamma(3) + sage: H = ArithmeticSubgroup_Permutation(S2="(1,4)(2,6)(3,5)",S3="(1,2,3)(4,5,6)") + sage: (G2 != H) or (H != G2) + False + sage: (G3 != H) and (H != G3) + True + + sage: G2 = Gamma1(2) + sage: G3 = Gamma1(3) + sage: H = ArithmeticSubgroup_Permutation(S2="(1,6,4,3)(2,7,5,8)",S3="(1,2,3,4,5,6)(7,8)") + sage: (G2 != H) and (H != G2) + True + sage: (G3 != H) or (H != G3) + False + """ + return not (self == other) def __hash__(self): r""" diff --git a/src/sage/modular/arithgroup/congroup_generic.py b/src/sage/modular/arithgroup/congroup_generic.py index 5439bab7f9e..3c89d9d0cad 100644 --- a/src/sage/modular/arithgroup/congroup_generic.py +++ b/src/sage/modular/arithgroup/congroup_generic.py @@ -9,8 +9,6 @@ - William Stein - David Loeffler (2009, 10) -- modifications to work with more general arithmetic subgroups """ -from __future__ import absolute_import - ################################################################################ # # Copyright (C) 2004, 2006 William Stein @@ -22,6 +20,7 @@ # http://www.gnu.org/licenses/ # ################################################################################ +from __future__ import absolute_import from sage.rings.all import QQ, ZZ, Zmod from sage.arith.all import gcd @@ -199,8 +198,10 @@ def level(self): """ return self.__level - def __cmp__(self, other): + def __eq__(self, other): r""" + Check that ``self`` is equal to ``other``. + EXAMPLES:: sage: CongruenceSubgroup(3,[ [1,1,0,1] ]) == Gamma1(3) @@ -218,24 +219,40 @@ def __cmp__(self, other): # Note that lazy_import doesn't work here, because it doesn't play # nicely with isinstance(). if not isinstance(other, ArithmeticSubgroup): - return cmp(type(self), type(other)) + return False elif is_CongruenceSubgroup(other): - t = cmp(self.level(), other.level()) - if t: return t - if self.level() == 1: return 0 # shouldn't come up except with pickling/unpickling - t = cmp(self.index(), other.index()) - if t: return t - return cmp(self.image_mod_n(),other.image_mod_n()) + if self.level() == other.level() == 1: + return True + # shouldn't come up except with pickling/unpickling + return (self.level() == other.level() and + self.index() == other.index() and + self.image_mod_n() == other.image_mod_n()) from sage.modular.arithgroup.arithgroup_perm import ArithmeticSubgroup_Permutation_class if isinstance(other, ArithmeticSubgroup_Permutation_class): - return cmp(self.as_permutation_group(), other) + return self.as_permutation_group() == other else: # we shouldn't ever get here raise NotImplementedError + def __ne__(self, other): + """ + Check that ``self`` is not equal to ``other``. + + EXAMPLES:: + + sage: CongruenceSubgroup(3,[ [1,1,0,1] ]) != Gamma1(3) + False + sage: CongruenceSubgroup(3,[ [1,1,0,1] ]) != Gamma(3) + True + sage: CongruenceSubgroup(3,[ [1,1,0,1] ]) != QQ + True + """ + return not (self == other) + + class CongruenceSubgroupFromGroup(CongruenceSubgroupBase): r""" A congruence subgroup, defined by the data of an integer `N` and a subgroup diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index 15cd18de80f..c7ebc31c68a 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -67,9 +67,9 @@ def __init__(self): """ ParentWithBase.__init__(self, self) - def __cmp__(self, right): + def __eq__(self, right): """ - Return equality only if right is the set of cusps. + Return equality only if ``right`` is the set of cusps. EXAMPLES:: @@ -78,7 +78,20 @@ def __cmp__(self, right): sage: Cusps == QQ False """ - return cmp(type(self), type(right)) + return isinstance(right, Cusps_class) + + def __ne__(self, right): + """ + Check that ``self`` is not equal to ``right``. + + EXAMPLES:: + + sage: Cusps != Cusps + False + sage: Cusps != QQ + True + """ + return not (self == right) def _repr_(self): """ @@ -162,16 +175,15 @@ def zero(self): """ Return the zero cusp. - NOTE: + .. NOTE:: - The existence of this method is assumed by some - parts of Sage's coercion model. + The existence of this method is assumed by some + parts of Sage's coercion model. EXAMPLES:: sage: Cusps.zero() 0 - """ return Cusp(0, parent=self) @@ -373,7 +385,6 @@ def __init__(self, a, b=None, parent=None, check=True): self.__a = r.numer() self.__b = r.denom() - def __hash__(self): """ EXAMPLES: diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index 31d68826b12..bcab523d321 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -269,13 +269,10 @@ def __init__(self, number_field): self.__number_field = number_field ParentWithBase.__init__(self, self) - def __cmp__(self, right): + def __eq__(self, right): """ Return equality only if right is the set of cusps for the same field. - Comparing sets of cusps for two different fields gives the same - result as comparing the two fields. - EXAMPLES:: sage: k. = NumberField(x^2 + 5) @@ -290,13 +287,31 @@ def __cmp__(self, right): True sage: LCusps == kCusps False + """ + if not isinstance(right, NFCuspsSpace): + return False + return self.number_field() == right.number_field() + def __ne__(self, right): """ - t = cmp(type(self), type(right)) - if t: - return t - else: - return cmp(self.number_field(), right.number_field()) + Check that ``self`` is not equal to ``right``. + + EXAMPLES:: + + sage: k. = NumberField(x^2 + 5) + sage: L. = NumberField(x^2 + 23) + sage: kCusps = NFCusps(k); kCusps + Set of all cusps of Number Field in a with defining polynomial x^2 + 5 + sage: LCusps = NFCusps(L); LCusps + Set of all cusps of Number Field in a with defining polynomial x^2 + 23 + sage: kCusps != NFCusps(k) + False + sage: LCusps != NFCusps(L) + False + sage: LCusps != kCusps + True + """ + return not (self == right) def _repr_(self): """ diff --git a/src/sage/modular/etaproducts.py b/src/sage/modular/etaproducts.py index 15025a39d15..930ae4a675d 100644 --- a/src/sage/modular/etaproducts.py +++ b/src/sage/modular/etaproducts.py @@ -108,25 +108,39 @@ def __reduce__(self): """ return (EtaGroup, (self.level(),)) - def __cmp__(self, other): + def __eq__(self, other): r""" - Compare self to other. If other is not an EtaGroup, compare by - type; otherwise compare by level. EtaGroups of the same level + Check that ``self`` is equal to ``other``. + + If other is not an EtaGroup, return ``False``. + + Otherwise compare the levels. EtaGroups of the same level compare as identical. EXAMPLES:: - sage: EtaGroup(12) == 12 - False - sage: EtaGroup(12) < EtaGroup(13) - True sage: EtaGroup(12) == EtaGroup(12) True + sage: EtaGroup(12) == EtaGroup(13) + False """ if not isinstance(other, EtaGroup_class): - return cmp(type(self), type(other)) + return False else: - return cmp(self.level(), other.level()) + return self.level() == other.level() + + def __ne__(self, other): + """ + Check that ``self`` is not equal to ``other``. + + EXAMPLES:: + + sage: EtaGroup(12) != EtaGroup(12) + False + sage: EtaGroup(12) != EtaGroup(13) + True + """ + return not (self == other) def _repr_(self): r""" diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index 9ec32b92192..dda92640404 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -207,7 +207,7 @@ class if `I=aJ` for some `a \in A^*`. (Left `\mathcal{O}`-ideals are from sage.modular.dirichlet import TrivialCharacter from sage.matrix.all import MatrixSpace, matrix from sage.misc.mrange import cartesian_product_iterator - +from sage.structure.sage_object import richcmp from sage.misc.cachefunc import cached_method from copy import copy @@ -1504,7 +1504,7 @@ def __init__(self, parent, x): x = x.element() HeckeModuleElement.__init__(self, parent, parent.free_module()(x)) - def __cmp__(self, other): + def _richcmp_(self, other, op): """ EXAMPLES:: @@ -1522,12 +1522,7 @@ def __cmp__(self, other): sage: loads(dumps(B.0)) == B.0 True """ - if not isinstance(other, BrandtModuleElement): - other = self.parent()(other) - else: - c = cmp(self.parent(), other.parent()) - if c: return c - return cmp(self.element(), other.element()) + return richcmp(self.element(), other.element(), op) def monodromy_pairing(self, x): """ From db20ab51426f8c67b3bfca651e7b7cd41c54e260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Jun 2017 14:02:49 +0200 Subject: [PATCH 102/126] py3: no __cmp__ in sudoku --- src/sage/games/sudoku.py | 100 ++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/src/sage/games/sudoku.py b/src/sage/games/sudoku.py index 9564674371c..dd1cbc8fb23 100644 --- a/src/sage/games/sudoku.py +++ b/src/sage/games/sudoku.py @@ -20,11 +20,10 @@ # The full text of the GPL is available at: # http://www.gnu.org/licenses/ ###################################################################### -from __future__ import print_function -from __future__ import absolute_import +from __future__ import print_function, absolute_import from six.moves import range +from six import string_types -import six from sage.structure.sage_object import SageObject @@ -34,7 +33,7 @@ def sudoku(m): INPUT: - - ``m`` - a square Sage matrix over `\ZZ`, where zeros are blank entries + - ``m`` - a square Sage matrix over `\ZZ`, where zeros are blank entries OUTPUT: @@ -103,7 +102,6 @@ class Sudoku(SageObject): the puzzle. For two-digit entries, a = 10, b = 11, etc. - verify_input - default = ``True``, use ``False`` if you know the input is valid - EXAMPLES:: sage: a = Sudoku('5...8..49...5...3..673....115..........2.8..........187....415..3...2...49..5...3') @@ -136,7 +134,6 @@ class Sudoku(SageObject): |4 9 1|8 5 6|7 2 3| +-----+-----+-----+ """ - def __init__(self, puzzle, verify_input = True): r""" Initialize a Sudoku puzzle, determine its size, sanity-check the inputs. @@ -186,7 +183,7 @@ def __init__(self, puzzle, verify_input = True): if verify_input and not(puzzle.is_square()): raise ValueError('Sudoku puzzle must be a square matrix') self.puzzle = tuple([int(x) for x in puzzle.list()]) - elif isinstance(puzzle, six.string_types): + elif isinstance(puzzle, string_types): puzzle_size = int(round(sqrt(len(puzzle)))) puzzle_numeric = [] for char in puzzle: @@ -207,47 +204,54 @@ def __init__(self, puzzle, verify_input = True): if (x < 0) or (x > self.n*self.n): raise ValueError('Sudoku puzzle has an invalid entry') - - def __cmp__(self, other): + def __eq__(self, other): r""" Compares two Sudoku puzzles, based on the underlying representation of the puzzles as tuples. - A puzzle with fewer entries is considered less than a - puzzle with more entries. For two puzzles of the same - size, their entries are compared lexicographically - based on a row-major order. Since blank entries are - carried as zeros, progressively "more completed" puzzles - are considered larger (but this is not an equivalence). - EXAMPLES:: sage: a = Sudoku('.4..32....14..3.') sage: b = Sudoku('8..6..9.5.............2.31...7318.6.24.....73...........279.1..5...8..36..3......') sage: c = Sudoku('1..6..9.5.............2.31...7318.6.24.....73...........279.1..5...8..36..3......') sage: d = Sudoku('81.6..9.5.............2.31...7318.6.24.....73...........279.1..5...8..36..3......') - sage: a.__cmp__(b) - -1 - sage: b.__cmp__(b) - 0 - sage: b.__cmp__(c) - 1 - sage: b.__cmp__(d) - -1 + + sage: a == b + False + sage: b == b + True + sage: b == c + False + sage: b == d + False """ - left = self.puzzle - right = tuple(other.to_list()) - if left < right: - return -1 - elif left > right: - return 1 - else: - return 0 + return self.puzzle == tuple(other.to_list()) + + def __ne__(self, other): + """ + Check that ``self`` is not equal to ``other``. + + EXAMPLES:: + + sage: a = Sudoku('.4..32....14..3.') + sage: b = Sudoku('8..6..9.5.............2.31...7318.6.24.....73...........279.1..5...8..36..3......') + sage: c = Sudoku('1..6..9.5.............2.31...7318.6.24.....73...........279.1..5...8..36..3......') + sage: d = Sudoku('81.6..9.5.............2.31...7318.6.24.....73...........279.1..5...8..36..3......') + sage: a != b + True + sage: b != b + False + sage: b != c + True + sage: b != d + True + """ + return not (self == other) def _repr_(self): r""" - Returns a concise description of a Sudoku puzzle using a string representation. + Return a concise description of a Sudoku puzzle using a string representation. See the docstring for :func:`to_ascii` for more information on the format. @@ -262,7 +266,7 @@ def _repr_(self): def _latex_(self): r"""nodetex - Returns a `\LaTeX` representation of a Sudoku puzzle as an array environment. + Return a `\LaTeX` representation of a Sudoku puzzle as an array environment. EXAMPLES:: @@ -274,7 +278,7 @@ def _latex_(self): def _matrix_(self, R=None): r""" - Returns the puzzle as a matrix to support Sage's + Return the puzzle as a matrix to support Sage's :func:`~sage.matrix.constructor.matrix` constructor. The base ring will be `\ZZ` if ``None`` is provided, @@ -305,7 +309,7 @@ def _matrix_(self, R=None): def to_string(self): r""" - Constructs a string representing a Sudoku puzzle. + Construct a string representing a Sudoku puzzle. Blank entries are represented as periods, single digits are not converted and two digit entries are @@ -352,10 +356,9 @@ def to_string(self): raise ValueError('Sudoku string representation is only valid for puzzles of size 36 or smaller') return ''.join(encoded) - def to_list(self): r""" - Constructs a list representing a Sudoku puzzle, in row-major order. + Construct a list representing a Sudoku puzzle, in row-major order. EXAMPLES:: @@ -373,10 +376,9 @@ def to_list(self): """ return list(self.puzzle) - def to_matrix(self): r""" - Constructs a Sage matrix over `\ZZ` representing a Sudoku puzzle. + Construct a Sage matrix over `\ZZ` representing a Sudoku puzzle. EXAMPLES:: @@ -402,7 +404,7 @@ def to_matrix(self): def to_ascii(self): r""" - Constructs an ASCII-art version of a Sudoku puzzle. + Construct an ASCII-art version of a Sudoku puzzle. This is a modified version of the ASCII version of a subdivided matrix. EXAMPLES:: @@ -432,7 +434,7 @@ def to_ascii(self): def to_latex(self): r""" - Creates a string of `\LaTeX` code representing a Sudoku puzzle or solution. + Create a string of `\LaTeX` code representing a Sudoku puzzle or solution. EXAMPLES:: @@ -468,7 +470,7 @@ def to_latex(self): def solve(self, algorithm = 'dlx'): r""" - Returns a generator object for the solutions of a Sudoku puzzle. + Return a generator object for the solutions of a Sudoku puzzle. INPUT: @@ -606,10 +608,9 @@ def solve(self, algorithm = 'dlx'): for soln in gen: yield Sudoku(soln, verify_input = 'False') - def backtrack(self): r""" - Returns a generator which iterates through all solutions of a Sudoku puzzle. + Return a generator which iterates through all solutions of a Sudoku puzzle. This function is intended to be called from the :func:`~sage.games.sudoku.Sudoku.solve` method @@ -715,10 +716,9 @@ def backtrack(self): for soln in solutions: yield soln - def dlx(self, count_only=False): r""" - Returns a generator that iterates through all solutions of a Sudoku puzzle. + Return a generator that iterates through all solutions of a Sudoku puzzle. INPUT: @@ -881,9 +881,3 @@ def make_row(row, col, entry): yield solution else: yield None - - - - - - From c0730863ff2f3e06bb8c1b106d44be542683a7b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Jun 2017 14:13:25 +0200 Subject: [PATCH 103/126] trac 23150 adaptation to #23103 --- src/sage/modular/quatalg/brandt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index dda92640404..b99f81cb043 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -207,7 +207,7 @@ class if `I=aJ` for some `a \in A^*`. (Left `\mathcal{O}`-ideals are from sage.modular.dirichlet import TrivialCharacter from sage.matrix.all import MatrixSpace, matrix from sage.misc.mrange import cartesian_product_iterator -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.misc.cachefunc import cached_method from copy import copy From 1af43ac054fdda473b1c694dc5b451e9d317c481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Jun 2017 14:15:51 +0200 Subject: [PATCH 104/126] trac 23148 adaptation to #23103 --- src/sage/rings/pari_ring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/rings/pari_ring.py b/src/sage/rings/pari_ring.py index 5cc2ae53c49..9cacdc34c8f 100644 --- a/src/sage/rings/pari_ring.py +++ b/src/sage/rings/pari_ring.py @@ -19,7 +19,7 @@ import sage.libs.pari.all as pari import sage.rings.ring as ring from sage.structure.element import RingElement -from sage.structure.sage_object import richcmp +from sage.structure.richcmp import richcmp from sage.misc.fast_methods import Singleton From f99393fc110ed6c5f59136717d5fbf1c69c6c7bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Jun 2017 14:26:04 +0200 Subject: [PATCH 105/126] trac 18430 INPUT field has no dot --- .../quadratic_form__local_field_invariants.py | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py index 2350f1c0f15..66de9a5a702 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py +++ b/src/sage/quadratic_forms/quadratic_form__local_field_invariants.py @@ -41,7 +41,7 @@ def rational_diagonal_form(self, return_matrix=False): INPUT: - ``return_matrix`` -- (boolean, default: False) also return the - transformation matrix. + transformation matrix OUTPUT: either ``D`` (if ``return_matrix`` is false) or ``(D,T)`` (if ``return_matrix`` is true) where @@ -388,9 +388,6 @@ def signature(self): return p - n - - - def hasse_invariant(self, p): """ Computes the Hasse invariant at a prime `p` or at infinity, as given on p55 of @@ -405,17 +402,20 @@ def hasse_invariant(self, p): quadratic form must be non-degenerate over `Q_p` for this to make sense. - WARNING: This is different from the O'Meara Hasse invariant, which - allows `i <= j` in the product. That is given by the method - hasse_invariant__OMeara(p). + .. WARNING:: - NOTE: We should really rename this hasse_invariant__Cassels(), and - set hasse_invariant() as a front-end to it. + This is different from the O'Meara Hasse invariant, which + allows `i <= j` in the product. That is given by the method + hasse_invariant__OMeara(p). + .. NOTE:: + + We should really rename this hasse_invariant__Cassels(), and + set hasse_invariant() as a front-end to it. INPUT: - `p` -- a prime number > 0 or `-1` for the infinite place. + - `p` -- a prime number > 0 or `-1` for the infinite place OUTPUT: @@ -496,13 +496,15 @@ def hasse_invariant__OMeara(self, p): where `(a,b)_p` is the Hilbert symbol at `p`. - WARNING: This is different from the (Cassels) Hasse invariant, which - only allows `i < j` in the product. That is given by the method - hasse_invariant(p). + .. WARNING:: + + This is different from the (Cassels) Hasse invariant, which + only allows `i < j` in the product. That is given by the method + hasse_invariant(p). INPUT: - `p` -- a prime number > 0 or `-1` for the infinite place. + - `p` -- a prime number > 0 or `-1` for the infinite place OUTPUT: @@ -581,7 +583,7 @@ def is_hyperbolic(self, p): INPUT: - `p` -- a prime number > 0 or `-1` for the infinite place. + - `p` -- a prime number > 0 or `-1` for the infinite place OUTPUT: @@ -633,7 +635,7 @@ def is_anisotropic(self, p): INPUT: - `p` -- a prime number > 0 or `-1` for the infinite place. + - `p` -- a prime number > 0 or `-1` for the infinite place OUTPUT: @@ -701,7 +703,7 @@ def is_isotropic(self, p): INPUT: - `p` -- a prime number > 0 or `-1` for the infinite place. + - `p` -- a prime number > 0 or `-1` for the infinite place OUTPUT: From a2728da53723ce5fdbff35458f2962891649cedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Jun 2017 15:47:32 +0200 Subject: [PATCH 106/126] trac 23137 reviewer's comments --- src/sage/combinat/binary_tree.py | 14 +++++++------- src/sage/combinat/free_dendriform_algebra.py | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/sage/combinat/binary_tree.py b/src/sage/combinat/binary_tree.py index d371fca8ce5..2728a790733 100644 --- a/src/sage/combinat/binary_tree.py +++ b/src/sage/combinat/binary_tree.py @@ -643,7 +643,7 @@ def node_to_str(bt): t_repr._baseline = t_repr._h - 1 return t_repr - def sort_key(self): + def _sort_key(self): """ Return a tuple of nonnegative integers encoding the binary tree ``self``. @@ -660,16 +660,16 @@ def sort_key(self): sage: x = BinaryTree([]) sage: y = (x.under(x)).over(x) - sage: y.sort_key() + sage: y._sort_key() (2, 2, 0, 0, 2, 0, 0) sage: z = (x.over(x)).under(x) - sage: z.sort_key() + sage: z._sort_key() (2, 2, 0, 2, 0, 0, 0) """ l = len(self) if l == 0: return (0,) - resu = [l] + [u for t in self for u in t.sort_key()] + resu = [l] + [u for t in self for u in t._sort_key()] return tuple(resu) def is_empty(self): @@ -4265,7 +4265,7 @@ def _repr_(self): else: return "%s%s" % (self._label, self[:]) - def sort_key(self): + def _sort_key(self): """ Return a tuple encoding the labelled binary tree ``self``. @@ -4284,13 +4284,13 @@ def sort_key(self): sage: L2 = LabelledBinaryTree([], label='a') sage: L3 = LabelledBinaryTree([], label='b') sage: T23 = LabelledBinaryTree([L2, L3], label='c') - sage: T23.sort_key() + sage: T23._sort_key() ((2, 'c'), (2, 'a'), (0,), (0,), (2, 'b'), (0,), (0,)) """ l = len(self) if l == 0: return ((0,),) - resu = [(l, self.label())] + [u for t in self for u in t.sort_key()] + resu = [(l, self.label())] + [u for t in self for u in t._sort_key()] return tuple(resu) def binary_search_insert(self, letter): diff --git a/src/sage/combinat/free_dendriform_algebra.py b/src/sage/combinat/free_dendriform_algebra.py index 633bd4c79b8..026db2caf43 100644 --- a/src/sage/combinat/free_dendriform_algebra.py +++ b/src/sage/combinat/free_dendriform_algebra.py @@ -149,10 +149,10 @@ def __init__(self, R, names=None): """ if names.cardinality() == 1: Trees = BinaryTrees() - key = BinaryTree.sort_key + key = BinaryTree._sort_key else: Trees = LabelledBinaryTrees() - key = LabelledBinaryTree.sort_key + key = LabelledBinaryTree._sort_key # Here one would need LabelledBinaryTrees(names) # so that one can restrict the labels to some fixed set self._alphabet = names @@ -196,11 +196,11 @@ def _repr_(self): def gen(self, i): r""" - Return the `i`-th generator of the algebra. + Return the ``i``-th generator of the algebra. INPUT: - - `i` -- an integer + - ``i`` -- an integer EXAMPLES:: @@ -356,7 +356,7 @@ def product_on_basis(self, x, y): def succ_product_on_basis(self, x, y): r""" - Return the `>` dendriform product of two trees. + Return the `\succ` dendriform product of two trees. This is the sum over all possible ways to identify the rightmost path in `x` and the leftmost path in `y`, with the additional condition @@ -403,7 +403,7 @@ def succ_product_on_basis(self, x, y): @lazy_attribute def succ(self): """ - Return the `>` dendriform product. + Return the `\succ` dendriform product. This is the sum over all possible ways of identifying the rightmost path in `x` and the leftmost path in `y`, with the @@ -431,7 +431,7 @@ def succ(self): def prec_product_on_basis(self, x, y): r""" - Return the `<` dendriform product of two trees. + Return the `\prec` dendriform product of two trees. This is the sum over all possible ways of identifying the rightmost path in `x` and the leftmost path in `y`, with the @@ -478,7 +478,7 @@ def prec_product_on_basis(self, x, y): @lazy_attribute def prec(self): """ - Return the `<` dendriform product. + Return the `\prec` dendriform product. This is the sum over all possible ways to identify the rightmost path in `x` and the leftmost path in `y`, with the additional condition From 8c823208f6305337954d5c1b6f90f3ee655bcb6a Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Wed, 7 Jun 2017 05:11:49 +0000 Subject: [PATCH 107/126] Change to node for degree=1, based on bugfix in mpmath: https://github.com/fredrik-johansson/mpmath/commit/a851518a4e30ca1dc67c008472f03bd6c4c8f02f --- src/sage/numerical/gauss_legendre.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/numerical/gauss_legendre.pyx b/src/sage/numerical/gauss_legendre.pyx index c919de55490..348ed3ad544 100644 --- a/src/sage/numerical/gauss_legendre.pyx +++ b/src/sage/numerical/gauss_legendre.pyx @@ -83,7 +83,7 @@ def nodes(degree,prec): rnd=R.rnd epsilon=R(1)>>(prec+8) if degree == 1: - x=R(3)/5 + x=(R(3)/5).sqrt() w=R(5)/18 nodes = [((1-x)/2,w),(HALF,R(4)/9),((1+x)/2,w)] else: From 22b3a6fd4754d86cbe7cb340d2a42cce540adbc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Wed, 7 Jun 2017 16:19:23 +0200 Subject: [PATCH 108/126] trac 23137 adding r""" at some methods --- src/sage/combinat/free_dendriform_algebra.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sage/combinat/free_dendriform_algebra.py b/src/sage/combinat/free_dendriform_algebra.py index 026db2caf43..78dd10cec71 100644 --- a/src/sage/combinat/free_dendriform_algebra.py +++ b/src/sage/combinat/free_dendriform_algebra.py @@ -314,7 +314,7 @@ def some_elements(self): @cached_method def one(self): - """ + r""" Return the element `1` of ``self``. This is the unit for the associative dendriform product `*`. @@ -332,7 +332,7 @@ def one(self): return self._monomial(Trees(None)) def product_on_basis(self, x, y): - """ + r""" Return the `*` associative dendriform product of two trees. This is the sum over all possible ways of identifying the @@ -402,7 +402,7 @@ def succ_product_on_basis(self, x, y): @lazy_attribute def succ(self): - """ + r""" Return the `\succ` dendriform product. This is the sum over all possible ways of identifying the @@ -477,7 +477,7 @@ def prec_product_on_basis(self, x, y): @lazy_attribute def prec(self): - """ + r""" Return the `\prec` dendriform product. This is the sum over all possible ways to identify the rightmost path @@ -505,7 +505,7 @@ def prec(self): @lazy_attribute def over(self): - """ + r""" Return the over product. The over product `x/y` is the binary tree obtained by From a455f3e4532f4b642543aaa88aa701b1b3b8d490 Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Wed, 7 Jun 2017 07:47:10 -0700 Subject: [PATCH 109/126] some PEP8, reviewer comments; rationalized "degree" parameter for "nodes" --- src/sage/numerical/gauss_legendre.pyx | 79 ++++++++++++++------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/src/sage/numerical/gauss_legendre.pyx b/src/sage/numerical/gauss_legendre.pyx index 348ed3ad544..858d6ae3194 100644 --- a/src/sage/numerical/gauss_legendre.pyx +++ b/src/sage/numerical/gauss_legendre.pyx @@ -31,6 +31,7 @@ optimized routine to compute the nodes. #want to we can optimize this further, probably to a point where #we don't have to bother with node computation routines that have a better order #than this naive approach (which is quadratic) +from __future__ import absolute_import, division, print_function from sage.libs.mpfr cimport * import math from sage.rings.real_mpfr import RealField @@ -44,54 +45,57 @@ def nodes(degree,prec): INPUT: - - ``degree`` -- integer. A measure for how many nodes to compute. + - ``degree`` -- integer. The number of nodes. Must be 3 or even. - ``prec`` -- integer (minimal value 53). Binary precision with which the nodes and weights are computed. OUTPUT: - A list of (node,weight) pairs, of length 3*2**(degree-1). + A list of (node,weight) pairs. EXAMPLE: The nodes for the Gauss-Legendre scheme are roots of Legendre polynomials. The weights can be computed by a straightforward formula (note that evaluating - a derivative of a Legendre polynomial isn't particularly numerically stable):: + a derivative of a Legendre polynomial isn't particularly numerically stable, so the results + from this routine are actually more accurate than what the values the closed formula produces):: sage: from sage.numerical.gauss_legendre import nodes - sage: L1=nodes(4,53) + sage: L1=nodes(24,53) sage: P=RR['x'](sage.functions.orthogonal_polys.legendre_P(24,x)) sage: Pdif=P.diff() sage: L2=[( (r+1)/2,1/(1-r^2)/Pdif(r)^2) for r,_ in RR['x'](P).roots()] sage: all((a[0]-b[0]).abs() < 10^-15 and (a[1]-b[1]).abs() < 10^-9 for a,b in zip(L1,L2)) True """ - cdef int j,j1,n + cdef long j,j1,n cdef RealNumber r,t1,t2,t3,t4,a,w cdef mpfr_t u,v cdef RealField_class R if prec < 53: prec = 53 - R=RealField(int(prec*3/2)) - Rout=RealField(prec) + if degree !=3 and degree % 2 !=0: + raise ValueError("degree=%s not supported (degree must be 3 or even)"%degree) + R = RealField(int(prec*3/2)) + Rout = RealField(prec) mpfr_init2(u,R.__prec) mpfr_init2(v,R.__prec) - ZERO=R.zero() - ONE=R.one() - HALF=ONE/2 - TWO=2*ONE - rnd=R.rnd - epsilon=R(1)>>(prec+8) + ZERO = R.zero() + ONE = R.one() + HALF = ONE/2 + TWO = 2*ONE + rnd = R.rnd + epsilon = R(1)>>(prec+8) if degree == 1: - x=(R(3)/5).sqrt() - w=R(5)/18 + x = (R(3)/5).sqrt() + w = R(5)/18 nodes = [((1-x)/2,w),(HALF,R(4)/9),((1+x)/2,w)] else: - nodes=[] - n=3*2**(degree-1) + nodes = [] + n = degree upto = n//2+1 for j in xrange(1,upto): - r=R(math.cos(math.pi*(j-0.25)/(n+0.5))) + r = R(math.cos(math.pi*(j-0.25)/(n+0.5))) while True: t1,t2=ONE,ZERO for j1 in xrange(1,n+1): @@ -103,12 +107,12 @@ def nodes(degree,prec): t2=t1 t1=R._new() mpfr_set(t1.value,u,rnd) - t4=R(n)*(r*t1-t2)/(r**2-ONE) - a=t1/t4 - r=r-a + t4 = R(n)*(r*t1-t2)/(r**2-ONE) + a = t1/t4 + r = r-a if a.abs() 1: - err= estimate_error(results,prec,epsilon) + if degree > 3: + err = estimate_error(results,prec,epsilon) if err <= epsilon: return I - degree +=1 + #double the degree to double expected precision + degree *= 2 From 33b2ccac753c58ee4e5a0946bdb177576390ca2a Mon Sep 17 00:00:00 2001 From: Lokesh Jain Date: Wed, 7 Jun 2017 21:41:57 +0530 Subject: [PATCH 110/126] trac #7675: added vertex presence check for shortest_path and shortest_path_length --- src/sage/graphs/generic_graph.py | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 3f71ce24565..13f0a7523cc 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -15074,7 +15074,23 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, Traceback (most recent call last): ... ValueError: The 'BFS_Bid' algorithm does not work on weighted graphs. + + If vertex is not in the graph:: + + sage: G.shortest_path(0, 5) + Traceback (most recent call last): + ... + ValueError: vertex '5' is not in the (di)graph + sage: G.shortest_path(6, 5) + Traceback (most recent call last): + ... + ValueError: vertex '6' is not in the (di)graph """ # TODO- multiple edges?? + if not self.has_vertex(u): + raise ValueError("vertex '{}' is not in the (di)graph".format(u)) + if not self.has_vertex(v): + raise ValueError("vertex '{}' is not in the (di)graph".format(v)) + if weight_function is not None: by_weight = True @@ -15238,7 +15254,25 @@ def shortest_path_length(self, u, v, by_weight=False, algorithm=None, -1000 sage: G.shortest_path_length(0, 2, by_weight=True) 2 + + TESTS: + + If vertex is not in the graph:: + + sage: G.shortest_path(0, 5) + Traceback (most recent call last): + ... + ValueError: vertex '5' is not in the (di)graph + sage: G.shortest_path(6, 5) + Traceback (most recent call last): + ... + ValueError: vertex '6' is not in the (di)graph """ + if not self.has_vertex(u): + raise ValueError("vertex '{}' is not in the (di)graph".format(u)) + if not self.has_vertex(v): + raise ValueError("vertex '{}' is not in the (di)graph".format(v)) + if weight_sum is not None: deprecation(18938, "Now weight_sum is replaced by by_weight.") From 4e3a75186e5641979dcd9698c4cdf321ee95110d Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Wed, 7 Jun 2017 18:32:50 +0200 Subject: [PATCH 111/126] Added keywork 'algorithm' --- .../padics/padic_capped_absolute_element.pyx | 156 ++++------------- .../padics/padic_capped_relative_element.pyx | 158 ++++-------------- .../rings/padics/padic_fixed_mod_element.pyx | 110 ++++-------- .../rings/padics/padic_generic_element.pyx | 139 +++++++++++---- src/sage/rings/padics/transcendantal.c | 43 ++--- 5 files changed, 216 insertions(+), 390 deletions(-) diff --git a/src/sage/rings/padics/padic_capped_absolute_element.pyx b/src/sage/rings/padics/padic_capped_absolute_element.pyx index 63af00cbcea..cfde5727d41 100644 --- a/src/sage/rings/padics/padic_capped_absolute_element.pyx +++ b/src/sage/rings/padics/padic_capped_absolute_element.pyx @@ -284,156 +284,72 @@ cdef class pAdicCappedAbsoluteElement(CAElement): mpz_clear(ppow_minus_one) return infinity - def log(self, p_branch=None, aprec=None, change_frac=False): + def _log_binary_splitting(self, aprec, mina=0): r""" - Compute the `p`-adic logarithm of this element. - - The usual power series for the logarithm with values in the additive - group of a `p`-adic ring only converges for 1-units (units congruent to - 1 modulo `p`). However, there is a unique extension of the logarithm - to a homomorphism defined on all the units: If `u = a \cdot v` is a - unit with `v \equiv 1 \pmod{p}` and `a` a Teichmuller representative, - then we define `log(u) = log(v)`. This is the correct extension - because the units `U` split as a product `U = V \times \langle w - \rangle`, where `V` is the subgroup of 1-units and `w` is a fundamental - root of unity. The `\langle w \rangle` factor is torsion, so must go - to 0 under any homomorphism to the fraction field, which is a torsion - free group. + Return ``\log(self)`` for ``self`` equal to 1 in the residue field - INPUT: - - - ``p_branch`` -- an element in the base ring or its fraction - field; the implementation will choose the branch of the - logarithm which sends `p` to ``branch``. - - - ``aprec`` -- an integer or ``None`` (default: ``None``) if not - ``None``, then the result will only be correct to precision - ``aprec``. + This is a helper method for :meth:`log`. + It uses a fast binary splitting algorithm. - - ``change_frac`` -- In general the codomain of the logarithm should be - in the `p`-adic field, however, for most neighborhoods of 1, it lies - in the ring of integers. This flag decides if the codomain should be - the same as the input (default) or if it should change to the - fraction field of the input. - - NOTES: + INPUT: - What some other systems do: + - ``aprec`` -- an integer, the precision to which the result is + correct. ``aprec`` must not exceed the precision cap of the ring over + which this element is defined. + - ``mina`` -- an integer (default: 0), the series will check `n` up to + this valuation (and beyond) to see if they can contribute to the + series. - - PARI: Seems to define the logarithm for units not congruent - to 1 as we do. + NOTE:: - - MAGMA: Only implements logarithm for 1-units (as of version 2.19-2) + The function does not check that its argument ``self`` is + 1 in the residue field. If this assumption is not fullfiled + the behaviour of the function is not specified. ALGORITHM: - 1. Take the unit part `u` of the input. - - 2. Raise `u` to the power `p-1` to obtain a 1-unit. - - 3. Raise `u` to the power `p^v` for a suitable `v` in order + 1. Raise `u` to the power `p^v` for a suitable `v` in order to make it closer to 1. (`v` is chosen such that `p^v` is close to the precision.) - 4. Write + 2. Write .. MATH:: u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{(v+1)*2^i}) - with `0 \leq a_i < p^{(v+1)*2^i}` and compute + with `0 \leq a_i < p^{(v+1)*2^i}` and compute `\log(1 - a_i p^{(v+1)*2^i})` using the standard Taylor expansion .. MATH:: \log(1 - x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots - together with a binary spliting method. - - 5. Divide the result by `p^v*(p-1)` + together with a binary splitting method. + 3. Divide the result by `p^v*(p-1)` and multiply by ``self.valuation()*log(p)`` The complexity of this algorithm is quasi-linear. EXAMPLES:: - sage: Z13 = ZpCA(13, 10) - sage: a = Z13(14); a - 1 + 13 + O(13^10) - sage: a.log() - 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) - - Note that the relative precision decreases when we take log. - Precisely the absolute precision on ``\log(a)`` agrees with the relative - precision on ``a`` thanks to the relation ``d\log(a) = da/a``. - - The logarithm is not only defined for 1-units:: - - sage: R = ZpCA(5,10) - sage: a = R(2) - sage: a.log() - 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + sage: r = Qp(5,prec=4)(6) + sage: r._log_binary_splitting(2) + 5 + O(5^2) + sage: r._log_binary_splitting(4) + 5 + 3*5^2 + 4*5^3 + O(5^4) + sage: r._log_binary_splitting(100) + 5 + 3*5^2 + 4*5^3 + O(5^5) - If you want to take the logarithm of a non-unit you must specify either - ``p_branch`` or ``pi_branch`` (observe the precision as well):: + sage: r = Zp(5,prec=4,type='fixed-mod')(6) + sage: r._log_binary_splitting(5) + 5 + 3*5^2 + 4*5^3 + O(5^4) - sage: b = R(5) - sage: b.log() - Traceback (most recent call last): - ... - ValueError: You must specify a branch of the logarithm for non-units - sage: b.log(p_branch=4) - 4 + O(5^9) - sage: c = R(10) - sage: c.log(p_branch=4) - 4 + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + O(5^9) - - The branch parameters are only relevant for elements of non-zero - valuation:: - - sage: a.log(p_branch=0) - 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) - sage: a.log(p_branch=1) - 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) - - We illustrate the effect of the precision argument:: - - sage: R = ZpCA(7,10) - sage: x = R(41152263); x - 5 + 3*7^2 + 4*7^3 + 3*7^4 + 5*7^5 + 6*7^6 + 7^9 + O(7^10) - sage: x.log(aprec = 5) - 7 + 3*7^2 + 4*7^3 + 3*7^4 + O(7^5) - sage: x.log(aprec = 7) - 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + O(7^7) - sage: x.log() - 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + 7^7 + 3*7^8 + 4*7^9 + O(7^10) - - The logarithm is not defined for zero:: - - sage: R.zero().log() - Traceback (most recent call last): - ... - ValueError: logarithm is not defined at zero - - TESTS:: - - sage: Z17 = ZpCA(17, 2^20) - sage: a = Z17(18) - sage: b = a.log() # should be rather fast """ cdef unsigned long p = self.prime_pow.prime - cdef unsigned long val, prec + cdef unsigned long val, prec = aprec cdef pAdicCappedAbsoluteElement ans, unit - if self.is_zero(): - raise ValueError('logarithm is not defined at zero') - - val = self.valuation_c() - if aprec is None: - prec = self.absprec - val - else: - prec = min(aprec, self.absprec - val) - ans = self._new_c() ans.absprec = prec unit = self.unit_part() @@ -441,16 +357,6 @@ cdef class pAdicCappedAbsoluteElement(CAElement): padiclog(ans.value, unit.value, p, prec, self.prime_pow.pow_mpz_t_tmp(prec)) sig_off() - if val != 0: - if p_branch is None: - raise ValueError("You must specify a branch of the logarithm for non-units") - ans += val * p_branch - - if not change_frac: - R = self.parent() - if ans.valuation() < 0 and not R.is_field(): - raise ValueError("logarithm is not integral, use change_frac=True to obtain a result in the fraction field") - ans = R(ans) return ans diff --git a/src/sage/rings/padics/padic_capped_relative_element.pyx b/src/sage/rings/padics/padic_capped_relative_element.pyx index de6cace44d9..ed3488ab182 100644 --- a/src/sage/rings/padics/padic_capped_relative_element.pyx +++ b/src/sage/rings/padics/padic_capped_relative_element.pyx @@ -335,58 +335,35 @@ cdef class pAdicCappedRelativeElement(CRElement): mpz_mul(selfvalue.value, self.prime_pow.pow_mpz_t_tmp(self.ordp), self.unit) return Mod(selfvalue, modulus) - def log(self, p_branch=None, aprec=None, change_frac=False): + def _log_binary_splitting(self, aprec, mina=0): r""" - Compute the `p`-adic logarithm of this element. - - The usual power series for the logarithm with values in the additive - group of a `p`-adic ring only converges for 1-units (units congruent to - 1 modulo `p`). However, there is a unique extension of the logarithm - to a homomorphism defined on all the units: If `u = a \cdot v` is a - unit with `v \equiv 1 \pmod{p}` and `a` a Teichmuller representative, - then we define `log(u) = log(v)`. This is the correct extension - because the units `U` split as a product `U = V \times \langle w - \rangle`, where `V` is the subgroup of 1-units and `w` is a fundamental - root of unity. The `\langle w \rangle` factor is torsion, so must go - to 0 under any homomorphism to the fraction field, which is a torsion - free group. + Return ``\log(self)`` for ``self`` equal to 1 in the residue field - INPUT: - - - ``p_branch`` -- an element in the base ring or its fraction - field; the implementation will choose the branch of the - logarithm which sends `p` to ``branch``. - - - ``aprec`` -- an integer or ``None`` (default: ``None``) if not - ``None``, then the result will only be correct to precision - ``aprec``. + This is a helper method for :meth:`log`. + It uses a fast binary splitting algorithm. - - ``change_frac`` -- In general the codomain of the logarithm should be - in the `p`-adic field, however, for most neighborhoods of 1, it lies - in the ring of integers. This flag decides if the codomain should be - the same as the input (default) or if it should change to the - fraction field of the input. - - NOTES: + INPUT: - What some other systems do: + - ``aprec`` -- an integer, the precision to which the result is + correct. ``aprec`` must not exceed the precision cap of the ring over + which this element is defined. + - ``mina`` -- an integer (default: 0), the series will check `n` up to + this valuation (and beyond) to see if they can contribute to the + series. - - PARI: Seems to define the logarithm for units not congruent - to 1 as we do. + NOTE:: - - MAGMA: Only implements logarithm for 1-units (as of version 2.19-2) + The function does not check that its argument ``self`` is + 1 in the residue field. If this assumption is not fullfiled + the behaviour of the function is not specified. ALGORITHM: - 1. Take the unit part `u` of the input. - - 2. Raise `u` to the power `p-1` to obtain a 1-unit. - - 3. Raise `u` to the power `p^v` for a suitable `v` in order + 1. Raise `u` to the power `p^v` for a suitable `v` in order to make it closer to 1. (`v` is chosen such that `p^v` is close to the precision.) - 4. Write + 2. Write .. MATH:: @@ -399,96 +376,31 @@ cdef class pAdicCappedRelativeElement(CRElement): \log(1 - x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots - together with a binary spliting method. - - 5. Divide the result by `p^v*(p-1)` + together with a binary splitting method. + 3. Divide the result by `p^v*(p-1)` and multiply by ``self.valuation()*log(p)`` The complexity of this algorithm is quasi-linear. EXAMPLES:: - sage: Z13 = ZpCA(13, 10) - sage: a = Z13(14); a - 1 + 13 + O(13^10) - sage: a.log() - 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) - - sage: Q13 = Qp(13, 10) - sage: a = Q13(14); a - 1 + 13 + O(13^10) - sage: a.log() - 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) - - Note that the relative precision decreases when we take log. - Precisely the absolute precision on ``\log(a)`` agrees with the relative - precision on ``a`` thanks to the relation ``d\log(a) = da/a``. - - The logarithm is not only defined for 1-units:: + sage: r = Qp(5,prec=4)(6) + sage: r._log_binary_splitting(2) + 5 + O(5^2) + sage: r._log_binary_splitting(4) + 5 + 3*5^2 + 4*5^3 + O(5^4) + sage: r._log_binary_splitting(100) + 5 + 3*5^2 + 4*5^3 + O(5^5) - sage: R = Zp(5,10) - sage: a = R(2) - sage: a.log() - 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + sage: r = Zp(5,prec=4,type='fixed-mod')(6) + sage: r._log_binary_splitting(5) + 5 + 3*5^2 + 4*5^3 + O(5^4) - If you want to take the logarithm of a non-unit you must specify either - ``p_branch`` or ``pi_branch``:: - - sage: b = R(5) - sage: b.log() - Traceback (most recent call last): - ... - ValueError: You must specify a branch of the logarithm for non-units - sage: b.log(p_branch=4) - 4 + O(5^10) - sage: c = R(10) - sage: c.log(p_branch=4) - 4 + 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) - - The branch parameters are only relevant for elements of non-zero - valuation:: - - sage: a.log(p_branch=0) - 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) - sage: a.log(p_branch=1) - 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) - - We illustrate the effect of the precision argument:: - - sage: R = Zp(7,10) - sage: x = R(41152263); x - 5 + 3*7^2 + 4*7^3 + 3*7^4 + 5*7^5 + 6*7^6 + 7^9 + O(7^10) - sage: x.log(aprec = 5) - 7 + 3*7^2 + 4*7^3 + 3*7^4 + O(7^5) - sage: x.log(aprec = 7) - 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + O(7^7) - sage: x.log() - 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + 7^7 + 3*7^8 + 4*7^9 + O(7^10) - - The logarithm is not defined for zero:: - - sage: R.zero().log() - Traceback (most recent call last): - ... - ValueError: logarithm is not defined at zero - - TESTS:: - - sage: Z17 = Zp(17, 2^20) - sage: a = Z17(18) - sage: b = a.log() # should be rather fast """ cdef unsigned long p = self.prime_pow.prime - cdef unsigned long prec + cdef unsigned long prec = aprec cdef pAdicCappedRelativeElement ans - if self.is_zero(): - raise ValueError('logarithm is not defined at zero') - if aprec is None: - prec = self.relprec - else: - prec = min(aprec, self.relprec) - ans = self._new_c() ans.ordp = 0 ans.relprec = prec @@ -497,16 +409,6 @@ cdef class pAdicCappedRelativeElement(CRElement): sig_off() ans._normalize() - if self.valuation() != 0: - if p_branch is None: - raise ValueError("You must specify a branch of the logarithm for non-units") - ans += self.valuation() * p_branch - - if not change_frac: - R = self.parent() - if ans.valuation() < 0 and not R.is_field(): - raise ValueError("logarithm is not integral, use change_frac=True to obtain a result in the fraction field") - ans = R(ans) return ans def unpickle_pcre_v1(R, unit, ordp, relprec): diff --git a/src/sage/rings/padics/padic_fixed_mod_element.pyx b/src/sage/rings/padics/padic_fixed_mod_element.pyx index add97be0c6d..cbba3a4d521 100644 --- a/src/sage/rings/padics/padic_fixed_mod_element.pyx +++ b/src/sage/rings/padics/padic_fixed_mod_element.pyx @@ -357,48 +357,35 @@ cdef class pAdicFixedModElement(FMElement): mpz_clear(tmp) return infinity - def log(self, aprec=None): + def _log_binary_splitting(self, aprec, mina=0): r""" - Compute the `p`-adic logarithm of this element. - - The usual power series for the logarithm with values in the additive - group of a `p`-adic ring only converges for 1-units (units congruent to - 1 modulo `p`). However, there is a unique extension of the logarithm - to a homomorphism defined on all the units: If `u = a \cdot v` is a - unit with `v \equiv 1 \pmod{p}` and `a` a Teichmuller representative, - then we define `log(u) = log(v)`. This is the correct extension - because the units `U` split as a product `U = V \times \langle w - \rangle`, where `V` is the subgroup of 1-units and `w` is a fundamental - root of unity. The `\langle w \rangle` factor is torsion, so must go - to 0 under any homomorphism to the fraction field, which is a torsion - free group. + Return ``\log(self)`` for ``self`` equal to 1 in the residue field - INPUT: - - - ``aprec`` -- an integer or ``None`` (default: ``None``) if not - ``None``, then the result will only be correct to precision - ``aprec``. + This is a helper method for :meth:`log`. + It uses a fast binary splitting algorithm. - NOTES: + INPUT: - What some other systems do: + - ``aprec`` -- an integer, the precision to which the result is + correct. ``aprec`` must not exceed the precision cap of the ring over + which this element is defined. + - ``mina`` -- an integer (default: 0), the series will check `n` up to + this valuation (and beyond) to see if they can contribute to the + series. - - PARI: Seems to define the logarithm for units not congruent - to 1 as we do. + NOTE:: - - MAGMA: Only implements logarithm for 1-units (as of version 2.19-2) + The function does not check that its argument ``self`` is + 1 in the residue field. If this assumption is not fullfiled + the behaviour of the function is not specified. ALGORITHM: - 1. Take the unit part `u` of the input. - - 2. Raise `u` to the power `p-1` to obtain a 1-unit. - - 3. Raise `u` to the power `p^v` for a suitable `v` in order + 1. Raise `u` to the power `p^v` for a suitable `v` in order to make it closer to 1. (`v` is chosen such that `p^v` is close to the precision.) - 4. Write + 2. Write .. MATH:: @@ -411,68 +398,31 @@ cdef class pAdicFixedModElement(FMElement): \log(1 - x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots - together with a binary spliting method. - - 5. Divide the result by `p^v*(p-1)` + together with a binary splitting method. + 3. Divide the result by `p^v*(p-1)` and multiply by ``self.valuation()*log(p)`` The complexity of this algorithm is quasi-linear. EXAMPLES:: - sage: Z13 = ZpFM(13, 10) - sage: a = Z13(14); a - 1 + 13 + O(13^10) - sage: a.log() - 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) - - The logarithm is not only defined for 1-units:: - - sage: R = ZpFM(5,10) - sage: a = R(2) - sage: a.log() - 2*5 + 3*5^2 + 2*5^3 + 4*5^4 + 2*5^6 + 2*5^7 + 4*5^8 + 2*5^9 + O(5^10) + sage: r = Qp(5,prec=4)(6) + sage: r._log_binary_splitting(2) + 5 + O(5^2) + sage: r._log_binary_splitting(4) + 5 + 3*5^2 + 4*5^3 + O(5^4) + sage: r._log_binary_splitting(100) + 5 + 3*5^2 + 4*5^3 + O(5^5) - However, note that the logarithm is not defined for non-units in the fixed - modulus framework. The reason is that the absolute precision decreases when - taking a logarithm of a non-unit:: + sage: r = Zp(5,prec=4,type='fixed-mod')(6) + sage: r._log_binary_splitting(5) + 5 + 3*5^2 + 4*5^3 + O(5^4) - sage: R = ZpFM(5,10) - sage: a = 5 * R.random_element() - sage: a.log() - Traceback (most recent call last): - ... - ValueError: Logarithm of non-units are not defined in the fixed modulus framework - - We illustrate the behaviour of ``aprec``:: - - sage: R = ZpFM(7,10) - sage: x = R(41152263); x - 5 + 3*7^2 + 4*7^3 + 3*7^4 + 5*7^5 + 6*7^6 + 7^9 + O(7^10) - sage: x.log(aprec = 5) - 7 + 3*7^2 + 4*7^3 + 3*7^4 + O(7^10) - sage: x.log(aprec = 7) - 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + O(7^10) - sage: x.log() - 7 + 3*7^2 + 4*7^3 + 3*7^4 + 7^5 + 3*7^6 + 7^7 + 3*7^8 + 4*7^9 + O(7^10) - - TESTS:: - - sage: Z17 = ZpFM(17, 2^20) - sage: a = Z17(18) - sage: b = a.log() # should be rather fast """ cdef unsigned long p = self.prime_pow.prime - cdef unsigned long prec + cdef unsigned long prec = aprec cdef pAdicFixedModElement ans - val = self.valuation_c() - if val > 0: - raise ValueError('Logarithm of non-units are not defined in the fixed modulus framework') ans = self._new_c() - if aprec is None: - prec = self.prime_pow.prec_cap - else: - prec = min(aprec, self.prime_pow.prec_cap) sig_on() padiclog(ans.value, self.value, p, prec, self.prime_pow.pow_mpz_t_tmp(prec)) sig_off() diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 1be79e5d07a..f2b3c9fe5f1 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -1521,9 +1521,9 @@ cdef class pAdicGenericElement(LocalGenericElement): r = rational_reconstruction(alpha, m) return (Rational(p)**self.valuation())*r - def _shifted_log(self, aprec, mina=0): + def _log_generic(self, aprec, mina=0): r""" - Return ``-\log(1-self)`` for elements of positive valuation. + Return ``\log(self)`` for ``self`` equal to 1 in the residue field This is a helper method for :meth:`log`. @@ -1543,7 +1543,7 @@ cdef class pAdicGenericElement(LocalGenericElement): .. MATH:: - -\log(1-x)=\sum_{n=1}^\infty \frac{x^n}{n}. + \log(1-x)=\sum_{n=1}^\infty \frac{x^n}{n}. For the result to be correct to precision ``aprec``, we sum all terms for which the valuation of `x^n/n` is stricly smaller than ``aprec``. @@ -1551,27 +1551,27 @@ cdef class pAdicGenericElement(LocalGenericElement): EXAMPLES:: sage: r = Qp(5,prec=4)(5) - sage: r._shifted_log(2) + sage: r._log(2) 5 + O(5^2) - sage: r._shifted_log(4) + sage: r._log_generic(4) 5 + 3*5^2 + 4*5^3 + O(5^4) - sage: r._shifted_log(100) + sage: r._log_generic(100) 5 + 3*5^2 + 4*5^3 + O(5^5) sage: r = Zp(5,prec=4,type='fixed-mod')(5) - sage: r._shifted_log(5) + sage: r._log_generic(5) 5 + 3*5^2 + 4*5^3 + O(5^4) Only implemented for elements of positive valuation:: sage: r = Zp(5,prec=4,type='fixed-mod')(1) - sage: r._shifted_log(5) + sage: r._log_generic(5) Traceback (most recent call last): ... ValueError: Input value (=1 + O(5^4)) must have strictly positive valuation """ - x = self + x = 1-self R = self.parent() # to get the precision right over capped-absolute rings, we have to # work over the capped-relative fraction field @@ -1581,7 +1581,7 @@ cdef class pAdicGenericElement(LocalGenericElement): alpha=x.valuation() if alpha<=0: - raise ValueError('Input value (=%s) must have strictly positive valuation' % self) + raise ValueError('Input value (=%s) must be 1 in the residue field' % self) e=R.ramification_index() p=R.prime() @@ -1638,7 +1638,7 @@ cdef class pAdicGenericElement(LocalGenericElement): else: inner_sum = (inner_sum+new_term)*(x2p_p**a)*(x**(p2a-a*p)) - total += inner_sum + total -= inner_sum # Now increase the power of p a += 1 @@ -1647,7 +1647,73 @@ cdef class pAdicGenericElement(LocalGenericElement): return total.add_bigoh(aprec) - def log(self, p_branch=None, pi_branch=None, aprec=None, change_frac=False): + def _log_binary_splitting(self, aprec, mina=0): + r""" + Return ``\log(self)`` for ``self`` equal to 1 in the residue field + + This is a helper method for :meth:`log`. + It uses a fast binary splitting algorithm. + + INPUT: + + - ``aprec`` -- an integer, the precision to which the result is + correct. ``aprec`` must not exceed the precision cap of the ring over + which this element is defined. + + - ``mina`` -- an integer (default: 0), the series will check `n` up to + this valuation (and beyond) to see if they can contribute to the + series. + + NOTE:: + + The function does not check that its argument ``self`` is + 1 in the residue field. If this assumption is not fullfiled + the behaviour of the function is not specified. + + ALGORITHM: + + 1. Raise `u` to the power `p^v` for a suitable `v` in order + to make it closer to 1. (`v` is chosen such that `p^v` is + close to the precision.) + + 2. Write + + .. MATH:: + + u^{p-1} = \prod_{i=1}^\infty (1 - a_i p^{(v+1)*2^i}) + + with `0 \leq a_i < p^{(v+1)*2^i}` and compute + `\log(1 - a_i p^{(v+1)*2^i})` using the standard Taylor expansion + + .. MATH:: + + \log(1 - x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots + + together with a binary splitting method. + + 3. Divide the result by `p^v*(p-1)` + and multiply by ``self.valuation()*log(p)`` + + The complexity of this algorithm is quasi-linear. + + EXAMPLES:: + + sage: r = Qp(5,prec=4)(6) + sage: r._log_binary_splitting(2) + 5 + O(5^2) + sage: r._log_binary_splitting(4) + 5 + 3*5^2 + 4*5^3 + O(5^4) + sage: r._log_binary_splitting(100) + 5 + 3*5^2 + 4*5^3 + O(5^5) + + sage: r = Zp(5,prec=4,type='fixed-mod')(6) + sage: r._log_binary_splitting(5) + 5 + 3*5^2 + 4*5^3 + O(5^4) + + """ + raise NotImplementedError + + def log(self, p_branch=None, pi_branch=None, aprec=None, change_frac=False, algorithm=None): r""" Compute the `p`-adic logarithm of this element. @@ -1685,6 +1751,21 @@ cdef class pAdicGenericElement(LocalGenericElement): the same as the input (default) or if it should change to the fraction field of the input. + - ``algorithm`` -- ``generic``, ``binary_splitting`` or ``None`` (default) + The generic algorithm evaluates naively the series defining the log, + namely + + .. MATH:: + + \log(1-x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots + + Its binary complexity is quadratic with respect to the precision. + + The binary splitting algorithm is faster, it has a quasi-linear + complexity. + By default, we use the binary splitting if it is available. Otherwise + we switch to the generic algorithm. + NOTES: What some other systems do: @@ -1700,23 +1781,6 @@ cdef class pAdicGenericElement(LocalGenericElement): by Dan Berstein at http://cr.yp.to/lineartime/multapps-20041007.pdf - ALGORITHM: - - 1. Take the unit part `u` of the input. - - 2. Raise `u` to `q-1` where `q` is the inertia degree of the ring - extension, to obtain a 1-unit. - - 3. Use the series expansion - - .. MATH:: - - \log(1-x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots - - to compute the logarithm `\log(u)`. - - 4. Divide the result by ``q-1`` and multiply by ``self.valuation()*log(pi)`` - EXAMPLES:: sage: Z13 = Zp(13, 10) @@ -1934,7 +1998,7 @@ cdef class pAdicGenericElement(LocalGenericElement): generic `p`-adic rings. - Soroosh Yazdani (2013-02-1): Fixed a precision issue in - :meth:`_shifted_log`. This should really fix the issue with + :meth:`_log_gene`. This should really fix the issue with divisions. - Julian Rueth (2013-02-14): Added doctests, some changes for @@ -1995,7 +2059,20 @@ cdef class pAdicGenericElement(LocalGenericElement): if aprec is None or aprec > minaprec: aprec=minaprec - retval = total - x._shifted_log(aprec, minn)*R(denom).inverse_of_unit() + if algorithm is None: + try: + # The binary splitting algorithm is supposed to be faster + log_unit = y._log_binary_splitting(aprec, minn) + except NotImplementedError: + log_unit = y._log_generic(aprec, minn) + elif algorithm == "generic": + log_unit = y._log_generic(aprec, minn) + elif algorithm == "binary_splitting": + log_unit = y._log_binary_splitting(aprec, minn) + else: + raise ValueError("Algorithm must be either 'generic', 'binary_splitting' or None") + + retval = total + log_unit*R(denom).inverse_of_unit() if not change_frac: if retval.valuation() < 0 and not R.is_field(): raise ValueError("logarithm is not integral, use change_frac=True to obtain a result in the fraction field") diff --git a/src/sage/rings/padics/transcendantal.c b/src/sage/rings/padics/transcendantal.c index b645dafb3da..4dc587336c6 100644 --- a/src/sage/rings/padics/transcendantal.c +++ b/src/sage/rings/padics/transcendantal.c @@ -12,36 +12,29 @@ /* p-adic logarithm */ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, const mpz_t modulo) { /* Compute the p-adic logarithm of a, - which is supposed to be a unit + which is supposed to be congruent to 1 mod p - Algorithm: If a = 1 (mod p): + Algorithm: 1. we raise a at the power p^(v-1) (for a suitable v) in order to make it closer to 1 2. we write the new a as a product 1/a = (1 - a_0*p^v) (1 - a_1*p^(2*v) (1 - a_2*p^(4*v) ... with 0 <= a_i < p^(v*2^i). 3. we compute each log(1 - a_i*p^(v*2^i)) using Taylor expansion - and a binary spliting strategy. + and a binary spliting strategy. */ - For general a, compute log(a^(p-1)) and then divide by p-1 */ - - char congruent_to_one; unsigned long i, v, e, N, saveN, Np, tmp, trunc, step; double den = log(p); - mpz_t f, arg, trunc_mod, h, hpow, mpz_tmp, d, inv; + mpz_t f, arg, trunc_mod, h, hpow, mpz_tmp, mpz_tmp2, d, inv, mod2; mpz_t *num, *denom; mpz_init(mpz_tmp); + mpz_init(mpz_tmp2); mpz_init(arg); mpz_set_ui(ans, 0); mpz_fdiv_r_ui(mpz_tmp, a, p); - congruent_to_one = (mpz_cmp_ui(mpz_tmp, 1) == 0); - if (congruent_to_one) { - mpz_set(arg, a); - } else { - mpz_powm_ui(arg, a, p-1, modulo); - } + mpz_set(arg, a); /* First we make the argument closer to 1 by raising it to the p^(v-1) */ if (prec < p) { @@ -55,17 +48,16 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con } /* Where do we need to truncate the Taylor expansion */ - N = saveN = (prec+v)/++v; // note the ++v + N = Np = (prec+v)/++v; // note the ++v den *= v; while(1) { - tmp = saveN + (unsigned long)(log(N)/den); + tmp = Np + (unsigned long)(log(N)/den); if (tmp == N) break; N = tmp; } - saveN = N; /* We allocate memory and initialize variables */ - mpz_init(f); + mpz_init(f); mpz_init(mod2); mpz_init(h); mpz_init(hpow); mpz_init(d); mpz_init(inv); num = (mpz_t*)malloc(N*sizeof(mpz_t)); @@ -99,8 +91,8 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con mpz_set(hpow, h); while(step < N) { for (i = 0; i < N - step; i += step << 1) { - mpz_mul(mpz_tmp, hpow, num[i+step]); - mpz_mul(mpz_tmp, mpz_tmp, denom[i]); + mpz_mul(mpz_tmp2, hpow, num[i+step]); + mpz_mul(mpz_tmp, mpz_tmp2, denom[i]); mpz_mul(num[i], num[i], denom[i+step]); mpz_add(num[i], num[i], mpz_tmp); mpz_mul(denom[i], denom[i], denom[i+step]); @@ -133,15 +125,13 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con /* We update the variables for the next step */ mpz_mul(trunc_mod, trunc_mod, trunc_mod); trunc <<= 1; + for (i = N >> 1; i < N; i++) { + mpz_clear(num[i]); + mpz_clear(denom[i]); + } N >>= 1; } - if (! congruent_to_one) { - mpz_set_ui(mpz_tmp, p-1); - mpz_gcdext(d, inv, NULL, mpz_tmp, modulo); - mpz_mul(ans, ans, inv); - } - mpz_fdiv_r(ans, ans, modulo); /* We clear memory */ @@ -153,7 +143,8 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con mpz_clear(mpz_tmp); mpz_clear(d); mpz_clear(inv); - for (i = 0; i < saveN; i++) { + mpz_clear(mod2); + for (i = 0; i < N; i++) { mpz_clear(num[i]); mpz_clear(denom[i]); } From 13b1316569eebd9795f50926748e6dd4d1dcc4ec Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Wed, 7 Jun 2017 18:36:55 +0200 Subject: [PATCH 112/126] Switch to generic algorithm when p does not fit in a long --- src/sage/rings/padics/padic_capped_absolute_element.pyx | 6 +++++- src/sage/rings/padics/padic_capped_relative_element.pyx | 6 +++++- src/sage/rings/padics/padic_fixed_mod_element.pyx | 7 ++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/sage/rings/padics/padic_capped_absolute_element.pyx b/src/sage/rings/padics/padic_capped_absolute_element.pyx index cfde5727d41..712a6f78d07 100644 --- a/src/sage/rings/padics/padic_capped_absolute_element.pyx +++ b/src/sage/rings/padics/padic_capped_absolute_element.pyx @@ -346,10 +346,14 @@ cdef class pAdicCappedAbsoluteElement(CAElement): 5 + 3*5^2 + 4*5^3 + O(5^4) """ - cdef unsigned long p = self.prime_pow.prime + cdef unsigned long p cdef unsigned long val, prec = aprec cdef pAdicCappedAbsoluteElement ans, unit + if mpz_fits_slong_p(self.prime_pow.prime) != 0: + raise NotImplementedError("The prime %s does not fit in a long" % p) + p = self.prime_pow.prime + ans = self._new_c() ans.absprec = prec unit = self.unit_part() diff --git a/src/sage/rings/padics/padic_capped_relative_element.pyx b/src/sage/rings/padics/padic_capped_relative_element.pyx index ed3488ab182..eebf64b732c 100644 --- a/src/sage/rings/padics/padic_capped_relative_element.pyx +++ b/src/sage/rings/padics/padic_capped_relative_element.pyx @@ -397,10 +397,14 @@ cdef class pAdicCappedRelativeElement(CRElement): 5 + 3*5^2 + 4*5^3 + O(5^4) """ - cdef unsigned long p = self.prime_pow.prime + cdef unsigned long p cdef unsigned long prec = aprec cdef pAdicCappedRelativeElement ans + if mpz_fits_slong_p(self.prime_pow.prime) != 0: + raise NotImplementedError("The prime %s does not fit in a long" % p) + p = self.prime_pow.prime + ans = self._new_c() ans.ordp = 0 ans.relprec = prec diff --git a/src/sage/rings/padics/padic_fixed_mod_element.pyx b/src/sage/rings/padics/padic_fixed_mod_element.pyx index cbba3a4d521..6f8dc655647 100644 --- a/src/sage/rings/padics/padic_fixed_mod_element.pyx +++ b/src/sage/rings/padics/padic_fixed_mod_element.pyx @@ -419,9 +419,14 @@ cdef class pAdicFixedModElement(FMElement): 5 + 3*5^2 + 4*5^3 + O(5^4) """ - cdef unsigned long p = self.prime_pow.prime + cdef unsigned long p cdef unsigned long prec = aprec cdef pAdicFixedModElement ans + + if mpz_fits_slong_p(self.prime_pow.prime) != 0: + raise NotImplementedError("The prime %s does not fit in a long" % p) + p = self.prime_pow.prime + ans = self._new_c() sig_on() padiclog(ans.value, self.value, p, prec, self.prime_pow.pow_mpz_t_tmp(prec)) From 7472fc1c6d296d7a844b385cfa5770454c2169d6 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Wed, 7 Jun 2017 21:29:38 +0200 Subject: [PATCH 113/126] Switch to generic algorithm when p does not fit in a long (second try) + clean doctests --- .../padics/padic_capped_absolute_element.pyx | 18 ++++++------- .../padics/padic_capped_relative_element.pyx | 18 ++++++------- .../rings/padics/padic_fixed_mod_element.pyx | 16 +++++------ .../rings/padics/padic_generic_element.pyx | 27 +++++++++---------- 4 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/sage/rings/padics/padic_capped_absolute_element.pyx b/src/sage/rings/padics/padic_capped_absolute_element.pyx index 712a6f78d07..5d6973572cf 100644 --- a/src/sage/rings/padics/padic_capped_absolute_element.pyx +++ b/src/sage/rings/padics/padic_capped_absolute_element.pyx @@ -326,8 +326,8 @@ cdef class pAdicCappedAbsoluteElement(CAElement): \log(1 - x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots together with a binary splitting method. - 3. Divide the result by `p^v*(p-1)` - and multiply by ``self.valuation()*log(p)`` + + 3. Divide the result by `p^v` The complexity of this algorithm is quasi-linear. @@ -337,22 +337,22 @@ cdef class pAdicCappedAbsoluteElement(CAElement): sage: r._log_binary_splitting(2) 5 + O(5^2) sage: r._log_binary_splitting(4) - 5 + 3*5^2 + 4*5^3 + O(5^4) + 5 + 2*5^2 + 4*5^3 + O(5^4) sage: r._log_binary_splitting(100) - 5 + 3*5^2 + 4*5^3 + O(5^5) + 5 + 2*5^2 + 4*5^3 + O(5^4) sage: r = Zp(5,prec=4,type='fixed-mod')(6) sage: r._log_binary_splitting(5) - 5 + 3*5^2 + 4*5^3 + O(5^4) + 5 + 2*5^2 + 4*5^3 + O(5^4) """ cdef unsigned long p - cdef unsigned long val, prec = aprec + cdef unsigned long prec = min(aprec, self.absprec) cdef pAdicCappedAbsoluteElement ans, unit - if mpz_fits_slong_p(self.prime_pow.prime) != 0: - raise NotImplementedError("The prime %s does not fit in a long" % p) - p = self.prime_pow.prime + if mpz_fits_slong_p(self.prime_pow.prime.value) == 0: + raise NotImplementedError("The prime %s does not fit in a long" % self.prime_pow.prime) + p = self.prime_pow.prime ans = self._new_c() ans.absprec = prec diff --git a/src/sage/rings/padics/padic_capped_relative_element.pyx b/src/sage/rings/padics/padic_capped_relative_element.pyx index eebf64b732c..8206656f334 100644 --- a/src/sage/rings/padics/padic_capped_relative_element.pyx +++ b/src/sage/rings/padics/padic_capped_relative_element.pyx @@ -377,8 +377,8 @@ cdef class pAdicCappedRelativeElement(CRElement): \log(1 - x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots together with a binary splitting method. - 3. Divide the result by `p^v*(p-1)` - and multiply by ``self.valuation()*log(p)`` + + 3. Divide the result by `p^v` The complexity of this algorithm is quasi-linear. @@ -388,22 +388,22 @@ cdef class pAdicCappedRelativeElement(CRElement): sage: r._log_binary_splitting(2) 5 + O(5^2) sage: r._log_binary_splitting(4) - 5 + 3*5^2 + 4*5^3 + O(5^4) + 5 + 2*5^2 + 4*5^3 + O(5^4) sage: r._log_binary_splitting(100) - 5 + 3*5^2 + 4*5^3 + O(5^5) + 5 + 2*5^2 + 4*5^3 + O(5^4) sage: r = Zp(5,prec=4,type='fixed-mod')(6) sage: r._log_binary_splitting(5) - 5 + 3*5^2 + 4*5^3 + O(5^4) + 5 + 2*5^2 + 4*5^3 + O(5^4) """ cdef unsigned long p - cdef unsigned long prec = aprec + cdef unsigned long prec = min(aprec, self.relprec) cdef pAdicCappedRelativeElement ans - if mpz_fits_slong_p(self.prime_pow.prime) != 0: - raise NotImplementedError("The prime %s does not fit in a long" % p) - p = self.prime_pow.prime + if mpz_fits_slong_p(self.prime_pow.prime.value) == 0: + raise NotImplementedError("The prime %s does not fit in a long" % self.prime_pow.prime) + p = self.prime_pow.prime ans = self._new_c() ans.ordp = 0 diff --git a/src/sage/rings/padics/padic_fixed_mod_element.pyx b/src/sage/rings/padics/padic_fixed_mod_element.pyx index 6f8dc655647..d97c9fa350e 100644 --- a/src/sage/rings/padics/padic_fixed_mod_element.pyx +++ b/src/sage/rings/padics/padic_fixed_mod_element.pyx @@ -399,8 +399,8 @@ cdef class pAdicFixedModElement(FMElement): \log(1 - x) = -x - 1/2 x^2 - 1/3 x^3 - 1/4 x^4 - 1/5 x^5 - \cdots together with a binary splitting method. - 3. Divide the result by `p^v*(p-1)` - and multiply by ``self.valuation()*log(p)`` + + 3. Divide the result by `p^v` The complexity of this algorithm is quasi-linear. @@ -410,21 +410,21 @@ cdef class pAdicFixedModElement(FMElement): sage: r._log_binary_splitting(2) 5 + O(5^2) sage: r._log_binary_splitting(4) - 5 + 3*5^2 + 4*5^3 + O(5^4) + 5 + 2*5^2 + 4*5^3 + O(5^4) sage: r._log_binary_splitting(100) - 5 + 3*5^2 + 4*5^3 + O(5^5) + 5 + 2*5^2 + 4*5^3 + O(5^4) sage: r = Zp(5,prec=4,type='fixed-mod')(6) sage: r._log_binary_splitting(5) - 5 + 3*5^2 + 4*5^3 + O(5^4) + 5 + 2*5^2 + 4*5^3 + O(5^4) """ cdef unsigned long p - cdef unsigned long prec = aprec + cdef unsigned long prec = min(aprec, self.prime_pow.prec_cap) cdef pAdicFixedModElement ans - if mpz_fits_slong_p(self.prime_pow.prime) != 0: - raise NotImplementedError("The prime %s does not fit in a long" % p) + if mpz_fits_slong_p(self.prime_pow.prime.value) == 0: + raise NotImplementedError("The prime %s does not fit in a long" % self.prime_pow.prime) p = self.prime_pow.prime ans = self._new_c() diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index f2b3c9fe5f1..893b09e05e7 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -1550,25 +1550,25 @@ cdef class pAdicGenericElement(LocalGenericElement): EXAMPLES:: - sage: r = Qp(5,prec=4)(5) - sage: r._log(2) + sage: r = Qp(5,prec=4)(6) + sage: r._log_generic(2) 5 + O(5^2) sage: r._log_generic(4) - 5 + 3*5^2 + 4*5^3 + O(5^4) + 5 + 2*5^2 + 4*5^3 + O(5^4) sage: r._log_generic(100) - 5 + 3*5^2 + 4*5^3 + O(5^5) + 5 + 2*5^2 + 4*5^3 + O(5^4) - sage: r = Zp(5,prec=4,type='fixed-mod')(5) + sage: r = Zp(5,prec=4,type='fixed-mod')(6) sage: r._log_generic(5) - 5 + 3*5^2 + 4*5^3 + O(5^4) + 5 + 2*5^2 + 4*5^3 + O(5^4) - Only implemented for elements of positive valuation:: + Only implemented for elements congruent to 1 modulo the maximal ideal:: - sage: r = Zp(5,prec=4,type='fixed-mod')(1) + sage: r = Zp(5,prec=4,type='fixed-mod')(2) sage: r._log_generic(5) Traceback (most recent call last): ... - ValueError: Input value (=1 + O(5^4)) must have strictly positive valuation + ValueError: Input value (=2 + O(5^4)) must be 1 in the residue field """ x = 1-self @@ -1691,8 +1691,7 @@ cdef class pAdicGenericElement(LocalGenericElement): together with a binary splitting method. - 3. Divide the result by `p^v*(p-1)` - and multiply by ``self.valuation()*log(p)`` + 3. Divide the result by `p^v` The complexity of this algorithm is quasi-linear. @@ -1702,13 +1701,13 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: r._log_binary_splitting(2) 5 + O(5^2) sage: r._log_binary_splitting(4) - 5 + 3*5^2 + 4*5^3 + O(5^4) + 5 + 2*5^2 + 4*5^3 + O(5^4) sage: r._log_binary_splitting(100) - 5 + 3*5^2 + 4*5^3 + O(5^5) + 5 + 2*5^2 + 4*5^3 + O(5^4) sage: r = Zp(5,prec=4,type='fixed-mod')(6) sage: r._log_binary_splitting(5) - 5 + 3*5^2 + 4*5^3 + O(5^4) + 5 + 2*5^2 + 4*5^3 + O(5^4) """ raise NotImplementedError From 145da3c337e803644c73322eab4e267c13ac7fab Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Wed, 7 Jun 2017 21:44:50 +0200 Subject: [PATCH 114/126] More doctests --- .../rings/padics/padic_generic_element.pyx | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 893b09e05e7..c515de1157a 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -1798,6 +1798,13 @@ cdef class pAdicGenericElement(LocalGenericElement): Precisely the absolute precision on ``\log(a)`` agrees with the relative precision on ``a`` thanks to the relation ``d\log(a) = da/a``. + The call `log(a)` works as well:: + + sage: log(a) + 13 + 6*13^2 + 2*13^3 + 5*13^4 + 10*13^6 + 13^7 + 11*13^8 + 8*13^9 + O(13^10) + sage: log(a) == a.log() + True + The logarithm is not only defined for 1-units:: sage: R = Zp(5,10) @@ -1925,6 +1932,32 @@ cdef class pAdicGenericElement(LocalGenericElement): TESTS: + Check multiplicativity:: + + sage: p = 11 + sage: R = Zp(p, prec=1000) + + sage: a = 1 + p*R.random_element() + sage: b = 1 + p*R.random_element() + sage: log(a*b) == log(a) + log(b) + True + + sage: a = R.random_element() + sage: b = R.random_element() + sage: branch = R.random_element() + sage: (a*b).log(p_branch=branch) == a.log(p_branch=branch) + b.log(p_branch=branch) + True + + Check that log is the inverse of exp:: + + sage: a = 1 + p*R.random_element() + sage: exp(log(a)) == a + True + + sage: a = p*R.random_element() + sage: log(exp(a)) == a + True + Check that results are consistent over a range of precision:: sage: max_prec = 40 @@ -1997,12 +2030,15 @@ cdef class pAdicGenericElement(LocalGenericElement): generic `p`-adic rings. - Soroosh Yazdani (2013-02-1): Fixed a precision issue in - :meth:`_log_gene`. This should really fix the issue with + :meth:`_log_generic`. This should really fix the issue with divisions. - Julian Rueth (2013-02-14): Added doctests, some changes for capped-absolute implementations. + - Xavier Caruso (2017-06): Added binary splitting type algorithms + over Qp + """ if self.is_zero(): raise ValueError('logarithm is not defined at zero') From 3d74661ce4e1bc9cdb1abeb248f884ff5690a635 Mon Sep 17 00:00:00 2001 From: David Roe Date: Wed, 7 Jun 2017 21:50:01 +0000 Subject: [PATCH 115/126] Adding conversion from rational function fields to their ring of integers --- .../rings/function_field/function_field.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/sage/rings/function_field/function_field.py b/src/sage/rings/function_field/function_field.py index 6190ed360d6..852b66d5e2a 100644 --- a/src/sage/rings/function_field/function_field.py +++ b/src/sage/rings/function_field/function_field.py @@ -1427,6 +1427,9 @@ def __init__(self, constant_field, names, self._ring = R self._field = R.fraction_field() self._populate_coercion_lists_(coerce_list=[self._field]) + from sage.categories.sets_with_partial_maps import SetsWithPartialMaps + from sage.categories.morphism import SetMorphism + R.register_conversion(SetMorphism(self.Hom(R, SetsWithPartialMaps()), self._to_polynomial)) self._gen = self(R.gen()) def __reduce__(self): @@ -1562,6 +1565,25 @@ def _to_constant_base_field(self, f): return K(f.numerator()) / K(f.denominator()) raise ValueError("only constants can be converted into the constant base field but %r is not a constant"%(f,)) + def _to_polynomial(self, f): + """ + If ``f`` is integral, return it as a polynomial. + + INPUT: + + - ``f`` -- an element of this rational function field whose denominator is a constant. + + EXAMPLES:: + + sage: K. = FunctionField(QQ) + sage: K._ring(x) # indirect doctest + x + """ + K = f.parent().constant_base_field() + if f.denominator() in K: + return f.numerator()/K(f.denominator()) + raise ValueError("Only polynomials can be converted to the underlying polynomial ring") + def _to_bivariate_polynomial(self, f): """ Convert ``f`` from a univariate polynomial over the rational function From 630ad0290ce6b6438b365ee9ade2b5bbd81d7105 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Thu, 8 Jun 2017 00:40:08 +0200 Subject: [PATCH 116/126] Added TestSuite for p-adic logarithm --- src/sage/rings/padics/padic_generic.py | 46 ++++++++ .../rings/padics/padic_generic_element.pyx | 108 ++++++++++++------ 2 files changed, 119 insertions(+), 35 deletions(-) diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 079d2cd6cba..839a2530b84 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -707,6 +707,52 @@ def _test_neg(self, **options): tester.assertEqual(x.is_zero(),y.is_zero()) tester.assertEqual(x.is_unit(),y.is_unit()) + def _test_log(self, **options): + """ + Test the log operator on elements of this ring. + + INPUT: + + - ``options`` -- any keyword arguments accepted by :meth:`_tester`. + + EXAMPLES:: + + sage: Zp(3)._test_log() + + .. SEEALSO:: + + :class:`TestSuite` + """ + tester = self._tester(**options) + for x in tester.some_elements(): + if x.is_zero(): continue + l = x.log(p_branch=0) + tester.assertIs(l.parent(), self) + tester.assertGreater(l.valuation(), 0) + if self.is_capped_absolute() or self.is_capped_relative(): + tester.assertEqual(x.precision_relative(), l.precision_absolute()) + + if self.is_capped_absolute() or self.is_capped_relative(): + # In the fixed modulus setting, rounding errors may occur + elements = list(tester.some_elements()) + for x, y, b in some_tuples(elements, 3, tester._max_runs): + if x.is_zero() or y.is_zero(): continue + r1 = x.log(pi_branch=b) + y.log(pi_branch=b) + r2 = (x*y).log(pi_branch=b) + tester.assertEqual(r1, r2) + + p = self.prime() + for x in tester.some_elements(): + if x.is_zero(): continue + if p == 2: + a = 4 * x.unit_part() + else: + a = p * x.unit_part() + b = a.exp().log() + c = (1+a).log().exp() + tester.assertEqual(a, b) + tester.assertEqual(1+a, c) + def _test_teichmuller(self, **options): """ Test Teichmuller lifts. diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index c515de1157a..87937100c28 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -1590,7 +1590,10 @@ cdef class pAdicGenericElement(LocalGenericElement): total=R.zero() # pre-compute x^p/p into x2p_p - if R.is_capped_relative(): + if mina == 0 and alpha*p - e > aprec: + # The value of x^p/p is not needed in that case + x2p_p = R(0) + elif R.is_capped_relative(): if p*alpha >= e: x2p_p = x**p/p else: @@ -1610,40 +1613,44 @@ cdef class pAdicGenericElement(LocalGenericElement): # Two sum over these terms, we run two nested loops, the outer one # iterates over the possible values for a, the inner one iterates over # the possible values for u. - a=0 - p2a=1 # p^a - x2pa = x # x^(p^a) + upper_u = (aprec/alpha).floor() + if mina > 0 or upper_u > 0: + a=0 + p2a=1 # p^a + x2pa = x # x^(p^a) - while True: - upper_u = ((aprec+a*e)/(alpha*p2a)).floor() # In the unramified case, we can stop summing terms as soon as # there are no u for a given a to sum over. In the ramified case, # it can happen that for some initial a there are no such u but # later in the series there are such u again. mina can be set to # take care of this by summing at least to a=mina-1 - if a >= mina and upper_u<=0: - break - # we compute the sum for the possible values for u using Horner's method - inner_sum = R.zero() - for u in xrange(upper_u,0,-1): - # We want u to be a p-adic unit - if u%p==0: - new_term = R.zero() - else: - new_term = ~R(u) - - # This hack is to deal with rings that don't lift to fields - if u>1 or x2p_p.is_zero(): - inner_sum = (inner_sum+new_term)*x2pa - else: - inner_sum = (inner_sum+new_term)*(x2p_p**a)*(x**(p2a-a*p)) - - total -= inner_sum - - # Now increase the power of p - a += 1 - p2a = p2a*p - x2pa = x2pa**p + while True: + # we compute the sum for the possible values for u using Horner's method + inner_sum = R.zero() + for u in xrange(upper_u,0,-1): + # We want u to be a p-adic unit + if u%p==0: + new_term = R.zero() + else: + new_term = ~R(u) + + # This hack is to deal with rings that don't lift to fields + if u > 1 or x2p_p.is_zero(): + inner_sum = (inner_sum+new_term)*x2pa + else: + inner_sum = (inner_sum+new_term)*(x2p_p**a)*(x**(p2a-a*p)) + + total -= inner_sum + + # Now increase a and check if a new iteration of the loop is needed + a += 1 + p2a = p2a*p + upper_u = ((aprec+a*e)/(alpha*p2a)).floor() + if a >= mina and upper_u <= 0: break + + # We perform this last operation after the test + # because it is costly and may raise OverflowError + x2pa = x2pa**p return total.add_bigoh(aprec) @@ -1932,24 +1939,49 @@ cdef class pAdicGenericElement(LocalGenericElement): TESTS: + Check that the generic algorithm and the binary splitting algorithm + returns the same answers:: + + sage: p = 17 + sage: R = Zp(p) + sage: a = 1 + p*R.random_element() + sage: l1 = a.log(algorithm='generic') + sage: l2 = a.log(algorithm='binary_splitting') + sage: l1 == l2 + True + sage: l1.precision_absolute() == l2.precision_absolute() + True + Check multiplicativity:: sage: p = 11 sage: R = Zp(p, prec=1000) - sage: a = 1 + p*R.random_element() - sage: b = 1 + p*R.random_element() - sage: log(a*b) == log(a) + log(b) + sage: x = 1 + p*R.random_element() + sage: y = 1 + p*R.random_element() + sage: log(x*y) == log(x) + log(y) True - sage: a = R.random_element() - sage: b = R.random_element() + sage: x = y = 0 + sage: while x == 0: + ....: x = R.random_element() + sage: while y == 0: + ....: y = R.random_element() sage: branch = R.random_element() - sage: (a*b).log(p_branch=branch) == a.log(p_branch=branch) + b.log(p_branch=branch) + sage: (x*y).log(p_branch=branch) == x.log(p_branch=branch) + y.log(p_branch=branch) True + Note that multiplicativity may fail in the fixed modulus setting + due to rounding errors:: + + sage: R = ZpFM(2, prec=5) + sage: R(180).log(p_branch=0) == R(30).log(p_branch=0) + R(6).log(p_branch=0) + False + Check that log is the inverse of exp:: + sage: p = 11 + sage: R = Zp(p, prec=1000) sage: a = 1 + p*R.random_element() sage: exp(log(a)) == a True @@ -2017,6 +2049,12 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: z.log().precision_relative() 250 + Performances:: + + sage: R = Zp(17, prec=10^6) + sage: a = R.random_element() + sage: b = a.log(p_branch=0) # should be rather fast + AUTHORS: - William Stein: initial version From ce2cfdb336f6e6ced9372e157724e6df9fd624cc Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Wed, 7 Jun 2017 15:54:42 -0700 Subject: [PATCH 117/126] trac15104: some special cased modn_dense matrix operations for improved performance changes rebased on 8.0b9 --- src/sage/matrix/matrix1.pyx | 7 +- src/sage/matrix/matrix2.pyx | 2 +- .../matrix/matrix_modn_dense_template.pxi | 423 +++++++++++++++++- src/sage/matrix/matrix_space.py | 18 + 4 files changed, 441 insertions(+), 9 deletions(-) diff --git a/src/sage/matrix/matrix1.pyx b/src/sage/matrix/matrix1.pyx index b9c35be1aed..ecfa78bcd39 100644 --- a/src/sage/matrix/matrix1.pyx +++ b/src/sage/matrix/matrix1.pyx @@ -2364,8 +2364,11 @@ cdef class Matrix(matrix0.Matrix): Full MatrixSpace of 2 by 3 dense matrices over Real Field with 53 bits of precision """ - if self._nrows == nrows and self._ncols == ncols and (sparse is None or self.is_sparse() == sparse): - return self._parent(entries=entries, coerce=coerce, copy=copy) + if (sparse is None or self.is_sparse() == sparse): + if self._nrows == nrows and self._ncols == ncols: + return self._parent(entries=entries, coerce=coerce, copy=copy) + elif self._nrows == ncols and self._ncols == nrows: + return self._parent.transposed(entries=entries, coerce=coerce, copy=copy) return self.matrix_space(nrows, ncols, sparse=sparse)(entries=entries, coerce=coerce, copy=copy) def block_sum(self, Matrix other): diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index a5ff439817b..649b9e761d2 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -3692,7 +3692,7 @@ cdef class Matrix(matrix1.Matrix): sage: matrix(Integers(6), 2, 2).right_kernel_matrix(algorithm='generic') Traceback (most recent call last): ... - ValueError: 'generic' matrix kernel algorithm only available over a field, not over Ring of integers modulo 6 + NotImplementedError: Echelon form not implemented over 'Ring of integers modulo 6'. sage: matrix(QQ, 2, 2).right_kernel_matrix(algorithm='pluq') Traceback (most recent call last): ... diff --git a/src/sage/matrix/matrix_modn_dense_template.pxi b/src/sage/matrix/matrix_modn_dense_template.pxi index 5b12c64c133..f2078a322f1 100644 --- a/src/sage/matrix/matrix_modn_dense_template.pxi +++ b/src/sage/matrix/matrix_modn_dense_template.pxi @@ -569,7 +569,6 @@ cdef class Matrix_modn_dense_template(Matrix_dense): raise IndexError("The vector of entries has the wrong length.") k = 0 - cdef celement n cdef long tmp for i in range(self._nrows): @@ -590,7 +589,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): elif coerce: v[j] = R(entries[k]) else: - v[j] = (entries[k]) + v[j] = (entries[k]) k = k + 1 def __hash__(self): @@ -2099,6 +2098,114 @@ cdef class Matrix_modn_dense_template(Matrix_dense): self.cache('pivots', tuple(pivots)) self.cache('in_echelon_form',True) + def right_kernel_matrix(self,algorithm='linbox',basis='echelon'): + r""" + Returns a matrix whose rows form a basis for the right kernel + of ``self``, where ``self`` is a matrix over a (small) finite field. + + INPUT: + + - ``algorithm`` -- default: 'linbox' - a parameter that is passed on to + ``self.echelon_form``, if computation of an echelon form is required. + See that routine for allowable values. + + - ``basis`` -- default: 'echelon' - a keyword that describes the format + of the basis returned. Allowable values are: + + - 'echelon': the basis matrix is in echelon form + - 'pivot': the basis matrix is such that the submatrix obtained by + taking the columns that in ``self`` contain no pivots, is the + identity matrix. + - 'computed': no work is done to transform the basis. In the current + implementation the result is the negative of that returned by + 'pivot'. + + OUTPUT: + + A matrix ``X`` whose rows are a basis for the right kernel of ``self``. + This means that ``self*X.transpose()`` is a zero matrix. + + The result is not cached, but the routine benefits when ``self`` is + known to be in echelon form already. + + EXAMPLES:: + + sage: M=matrix(GF(5),6,6,range(36)) + sage: M.right_kernel_matrix(basis='computed') + [4 2 4 0 0 0] + [3 3 0 4 0 0] + [2 4 0 0 4 0] + [1 0 0 0 0 4] + sage: M.right_kernel_matrix(basis='pivot') + [1 3 1 0 0 0] + [2 2 0 1 0 0] + [3 1 0 0 1 0] + [4 0 0 0 0 1] + sage: M.right_kernel_matrix() + [1 0 0 0 0 4] + [0 1 0 0 1 3] + [0 0 1 0 2 2] + [0 0 0 1 3 1] + sage: M*M.right_kernel_matrix().transpose() + [0 0 0 0] + [0 0 0 0] + [0 0 0 0] + [0 0 0 0] + [0 0 0 0] + [0 0 0 0] + + """ + if self.fetch('in_echelon_form') is None: + self = self.echelon_form(algorithm=algorithm) + + cdef Py_ssize_t r = self.rank() + cdef Py_ssize_t nrows= self._nrows + cdef Py_ssize_t ncols= self._ncols + cdef Py_ssize_t i,j,k + + cdef Py_ssize_t* nonpivots = sig_malloc(sizeof(Py_ssize_t)*(ncols-r)) + cdef Py_ssize_t* pivots = sig_malloc(sizeof(Py_ssize_t)*(r)) + cdef tuple pivot_tuple = self.pivots() + + for i in range(r): + pivots[i] = pivot_tuple[i] + j = 0 + k = 0 + for i in range(ncols): + if j < r and i == pivots[j]: + j+=1 + else: + nonpivots[k]=i + k+=1 + + from matrix_space import MatrixSpace + F = self.base_ring() + MS = MatrixSpace(F, ncols-r, ncols) + cdef Matrix_modn_dense_template M + M = self.__class__.__new__(self.__class__, MS, 0,0,0) + M.p = self.p + cdef celement pm1 = self.p-1 + + k=0 + for i in range(ncols-r): + for j in range(ncols-r): + M._entries[nonpivots[i]+j*ncols]=0 + M._entries[nonpivots[i]+k*ncols]=pm1 + k+=1 + for j in range(r): + M._entries[i*ncols+pivots[j]]=self._entries[nonpivots[i]+j*ncols] + + sig_free(pivots) + sig_free(nonpivots) + if basis == 'computed': + return M + elif basis == 'pivot': + return -M + elif basis != 'echelon': + raise ValueError("matrix kernel basis format not recognized") + M.echelonize(algorithm=algorithm) + return M + def hessenbergize(self): """ Transforms self in place to its Hessenberg form. @@ -2228,7 +2335,8 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef celement p, t p = self.p - # Replace self by its Hessenberg form, and set H to this form + # Replace self + by its Hessenberg form, and set H to this form # for notation below. cdef Matrix_modn_dense_template H H = self.__copy__() @@ -2976,6 +3084,312 @@ cdef class Matrix_modn_dense_template(Matrix_dense): L.subdivide(self.subdivisions()) return L + def transpose(self): + """ + Returns the transpose of ``self``, without changing ``self``. + + EXAMPLES: + + We create a matrix, compute its transpose, and note that + the original matrix is not changed. :: + + sage: M = MatrixSpace(GF(41), 2) + sage: A = M([1,2,3,4]) + sage: B = A.transpose() + sage: print B + [1 3] + [2 4] + sage: print A + [1 2] + [3 4] + + ``.T`` is a convenient shortcut for the transpose:: + + sage: A.T + [1 3] + [2 4] + + :: + + sage: A.subdivide(None, 1); A + [1|2] + [3|4] + sage: A.transpose() + [1 3] + [---] + [2 4] + """ + + cdef Py_ssize_t nrows = self._nrows + cdef Py_ssize_t ncols = self._ncols + + from matrix_space import MatrixSpace + F = self.base_ring() + MS = MatrixSpace(F, self._ncols, self._nrows) + cdef Matrix_modn_dense_template M + M = self.__class__.__new__(self.__class__, MS, 0,0,0) + M.p = self.p + cdef Py_ssize_t i,j + + for i from 0 <= i < ncols: + for j from 0 <= j < nrows: + M._entries[j+i*nrows] = self._entries[i+j*ncols] + + if self._subdivisions is not None: + row_divs, col_divs = self.subdivisions() + M.subdivide(col_divs, row_divs) + + return M + + def stack(self, bottom, subdivide=False): + r""" + Return a new matrix formed by appending the matrix (or vector) ``bottom`` beneath ``self``. + + INPUT: + + - ``bottom`` -- a matrix, vector or free module element, whose + dimensions are compatible with ``self``. + + - ``subdivide`` -- default: ``False`` - request the resulting + matrix to have a new subdivision, separating ``self`` from ``bottom``. + + OUTPUT: + + A new matrix formed by appending ``bottom`` beneath ``self``. + If ``bottom`` is a vector (or free module element) then in this context + it is appropriate to consider it as a row vector. (The code first + converts a vector to a 1-row matrix.) + + If ``subdivide`` is ``True`` then any row subdivisions for + the two matrices are preserved, and a new subdivision is added + between ``self`` and ``bottom``. If the column divisions are + identical, then they are preserved, otherwise they are discarded. + When ``subdivide`` is ``False`` there is no subdivision information + in the result. + + .. WARNING:: + If ``subdivide`` is ``True`` then unequal column subdivisions + will be discarded, since it would be ambiguous how to interpret + them. If the subdivision behavior is not what you need, + you can manage subdivisions yourself with methods like + :meth:`~sage.matrix.matrix2.Matrix.subdivisions` + and + :meth:`~sage.matrix.matrix2.Matrix.subdivide`. + You might also find :func:`~sage.matrix.constructor.block_matrix` + or + :func:`~sage.matrix.constructor.block_diagonal_matrix` + useful and simpler in some instances. + + + EXAMPLES: + + Stacking with a matrix:: + + sage: A = matrix(GF(41), 4, 3, range(12)) + sage: B = matrix(GF(41), 3, 3, range(9)) + sage: A.stack(B) + [ 0 1 2] + [ 3 4 5] + [ 6 7 8] + [ 9 10 11] + [ 0 1 2] + [ 3 4 5] + [ 6 7 8] + + Stacking with a vector:: + + sage: A = matrix(GF(41), 3, 2, [0, 2, 4, 6, 8, 10]) + sage: v = vector(GF(41), 2, [100, 200]) + sage: A.stack(v) + [ 0 2] + [ 4 6] + [ 8 10] + [18 36] + + Errors are raised if the sizes are incompatible:: + + sage: A = matrix(GF(41), [[1, 2],[3, 4]]) + sage: B = matrix(GF(41), [[10, 20, 30], [40, 50, 60]]) + sage: A.stack(B) + Traceback (most recent call last): + ... + TypeError: number of columns must be the same + + sage: v = vector(GF(41), [100, 200, 300]) + sage: A.stack(v) + Traceback (most recent call last): + ... + TypeError: number of columns must be the same + + Setting ``subdivide`` to ``True`` will, in its simplest form, + add a subdivision between ``self`` and ``bottom``:: + + sage: A = matrix(GF(41), 2, 5, range(10)) + sage: B = matrix(GF(41), 3, 5, range(15)) + sage: A.stack(B, subdivide=True) + [ 0 1 2 3 4] + [ 5 6 7 8 9] + [--------------] + [ 0 1 2 3 4] + [ 5 6 7 8 9] + [10 11 12 13 14] + + Row subdivisions are preserved by stacking, and enriched, + if subdivisions are requested. (So multiple stackings can + be recorded) :: + + sage: A = matrix(GF(41), 2, 4, range(8)) + sage: A.subdivide([1], None) + sage: B = matrix(GF(41), 3, 4, range(12)) + sage: B.subdivide([2], None) + sage: A.stack(B, subdivide=True) + [ 0 1 2 3] + [-----------] + [ 4 5 6 7] + [-----------] + [ 0 1 2 3] + [ 4 5 6 7] + [-----------] + [ 8 9 10 11] + + Column subdivisions can be preserved, but only if they are identical. + Otherwise, this information is discarded and must be managed + separately. :: + + sage: A = matrix(GF(41), 2, 5, range(10)) + sage: A.subdivide(None, [2,4]) + sage: B = matrix(GF(41), 3, 5, range(15)) + sage: B.subdivide(None, [2,4]) + sage: A.stack(B, subdivide=True) + [ 0 1| 2 3| 4] + [ 5 6| 7 8| 9] + [-----+-----+--] + [ 0 1| 2 3| 4] + [ 5 6| 7 8| 9] + [10 11|12 13|14] + + sage: A.subdivide(None, [1,2]) + sage: A.stack(B, subdivide=True) + [ 0 1 2 3 4] + [ 5 6 7 8 9] + [--------------] + [ 0 1 2 3 4] + [ 5 6 7 8 9] + [10 11 12 13 14] + + The result retains the base ring of ``self`` by coercing + the elements of ``bottom`` into the base ring of ``self``:: + + sage: A = matrix(GF(41), 1, 2, [1,2]) + sage: B = matrix(ZZ, 1, 2, [100, 100]) + sage: C = A.stack(B); C + [ 1 2] + [18 18] + + sage: C.parent() + Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 41 + + sage: D = B.stack(A); D + [18 18] + [ 1 2] + + sage: D.parent() + Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 41 + + """ + if hasattr(bottom, '_vector_'): + bottom = bottom.row() + if self._ncols != bottom.ncols(): + raise TypeError("number of columns must be the same") + if not (self._base_ring is bottom.base_ring()): + bottom = bottom.change_ring(self._base_ring) + cdef Matrix_modn_dense_template other = bottom.dense_matrix() + cdef Matrix_modn_dense_template M + from matrix_space import MatrixSpace + F = self.base_ring() + MS = MatrixSpace(F, self._nrows+other._nrows,self._ncols) + M = self.__class__.__new__(self.__class__, MS, 0,0,0) + M.p = self.p + cdef Py_ssize_t selfsize = self._ncols*self._nrows + memcpy(M._entries, self._entries, sizeof(celement)*selfsize) + memcpy(M._entries+selfsize, other._entries, sizeof(celement)*other._ncols*other._nrows) + if subdivide: + M._subdivide_on_stack(self, other) + return M + + def submatrix(self, Py_ssize_t row=0, Py_ssize_t col=0, + Py_ssize_t nrows=-1, Py_ssize_t ncols=-1): + + r""" + Return the matrix constructed from self using the specified + range of rows and columns. + + INPUT: + + - ``row``, ``col`` -- index of the starting row and column. + Indices start at zero + + - ``nrows``, ``ncols`` -- (optional) number of rows and columns to + take. If not provided, take all rows below and all columns to + the right of the starting entry + + .. SEEALSO: + + The functions :func:`matrix_from_rows`, + :func:`matrix_from_columns`, and + :func:`matrix_from_rows_and_columns` allow one to select + arbitrary subsets of rows and/or columns. + + EXAMPLES: + + Take the `3 \times 3` submatrix starting from entry (1,1) in a + `4 \times 4` matrix:: + + sage: m = matrix(GF(17),4, [1..16]) + sage: m.submatrix(1, 1) + [ 6 7 8] + [10 11 12] + [14 15 16] + + Same thing, except take only two rows:: + + sage: m.submatrix(1, 1, 2) + [ 6 7 8] + [10 11 12] + + And now take only one column:: + + sage: m.submatrix(1, 1, 2, 1) + [ 6] + [10] + + You can take zero rows or columns if you want:: + + sage: m.submatrix(0, 0, 0) + [] + sage: parent(m.submatrix(0, 0, 0)) + Full MatrixSpace of 0 by 4 dense matrices over Finite Field of size 17 + """ + if ncols == -1: + ncols = self._ncols - col + + if nrows == -1: + nrows = self._nrows - row + + if col !=0 or ncols != self._ncols: + return self.matrix_from_rows_and_columns(range(row, row+nrows), range(col, col+ncols)) + + if nrows < 0 or row < 0 or row+nrows > self._nrows: + raise IndexError, "rows out of range" + + from matrix_space import MatrixSpace + F = self.base_ring() + MS = MatrixSpace(F, nrows,self._ncols) + cdef Matrix_modn_dense_template M + M = self.__class__.__new__(self.__class__, MS, 0,0,0) + M.p = self.p + memcpy(M._entries,self._entries+row*ncols,sizeof(celement)*ncols*nrows) + return M def _matrices_from_rows(self, Py_ssize_t nrows, Py_ssize_t ncols): """ @@ -3064,6 +3478,3 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef celement *_from = self._entries+(i*self._ncols) for j in range(self._ncols): to[j] = _from[j] - - - diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index e2f79d33f40..8b6c6c4093f 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -381,6 +381,24 @@ def full_category_initialisation(self): " as a matrix space now has its category" " systematically fully initialized") + @lazy_attribute + def transposed(self): + """ + The transposed matrix space, having the same base ring and sparseness, + but number of columns and rows is swapped. + + EXAMPLES:: + + sage: MS = MatrixSpace(GF(3), 7, 10) + sage: MS.transposed + Full MatrixSpace of 10 by 7 dense matrices over Finite Field of size 3 + sage: MS = MatrixSpace(GF(3), 7, 7) + sage: MS.transposed is MS + True + + """ + return MatrixSpace(self._base, self.__ncols, self.__nrows, self.__is_sparse) + @lazy_attribute def _copy_zero(self): """ From 10fa935c280469669333a64b63686d5bcf197538 Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Wed, 7 Jun 2017 18:32:01 -0500 Subject: [PATCH 118/126] Cleanup doc and fix typo. --- .../matrix/matrix_modn_dense_template.pxi | 84 +++++++++---------- 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/src/sage/matrix/matrix_modn_dense_template.pxi b/src/sage/matrix/matrix_modn_dense_template.pxi index f2078a322f1..e326d71dd78 100644 --- a/src/sage/matrix/matrix_modn_dense_template.pxi +++ b/src/sage/matrix/matrix_modn_dense_template.pxi @@ -2098,32 +2098,32 @@ cdef class Matrix_modn_dense_template(Matrix_dense): self.cache('pivots', tuple(pivots)) self.cache('in_echelon_form',True) - def right_kernel_matrix(self,algorithm='linbox',basis='echelon'): + def right_kernel_matrix(self, algorithm='linbox', basis='echelon'): r""" Returns a matrix whose rows form a basis for the right kernel of ``self``, where ``self`` is a matrix over a (small) finite field. INPUT: - - ``algorithm`` -- default: 'linbox' - a parameter that is passed on to - ``self.echelon_form``, if computation of an echelon form is required. - See that routine for allowable values. + - ``algorithm`` -- (default: ``'linbox'``) a parameter that is + passed on to ``self.echelon_form``, if computation of an echelon + form is required; see that routine for allowable values - - ``basis`` -- default: 'echelon' - a keyword that describes the format - of the basis returned. Allowable values are: + - ``basis`` -- (default: ``'echelon'``) a keyword that describes the + format of the basis returned, allowable values are: - - 'echelon': the basis matrix is in echelon form - - 'pivot': the basis matrix is such that the submatrix obtained by - taking the columns that in ``self`` contain no pivots, is the - identity matrix. - - 'computed': no work is done to transform the basis. In the current - implementation the result is the negative of that returned by - 'pivot'. + - ``'echelon'``: the basis matrix is in echelon form + - ``'pivot'``: the basis matrix is such that the submatrix obtained + by taking the columns that in ``self`` contain no pivots, is the + identity matrix + - ``'computed'``: no work is done to transform the basis; in + the current implementation the result is the negative of + that returned by ``'pivot'`` OUTPUT: - A matrix ``X`` whose rows are a basis for the right kernel of ``self``. - This means that ``self*X.transpose()`` is a zero matrix. + A matrix ``X`` whose rows are a basis for the right kernel of + ``self``. This means that ``self * X.transpose()`` is a zero matrix. The result is not cached, but the routine benefits when ``self`` is known to be in echelon form already. @@ -2153,14 +2153,13 @@ cdef class Matrix_modn_dense_template(Matrix_dense): [0 0 0 0] [0 0 0 0] [0 0 0 0] - """ if self.fetch('in_echelon_form') is None: self = self.echelon_form(algorithm=algorithm) cdef Py_ssize_t r = self.rank() - cdef Py_ssize_t nrows= self._nrows - cdef Py_ssize_t ncols= self._ncols + cdef Py_ssize_t nrows = self._nrows + cdef Py_ssize_t ncols = self._ncols cdef Py_ssize_t i,j,k cdef Py_ssize_t* nonpivots = sig_malloc(sizeof(Py_ssize_t)*(ncols-r)) @@ -2182,18 +2181,18 @@ cdef class Matrix_modn_dense_template(Matrix_dense): F = self.base_ring() MS = MatrixSpace(F, ncols-r, ncols) cdef Matrix_modn_dense_template M - M = self.__class__.__new__(self.__class__, MS, 0,0,0) + M = self.__class__.__new__(self.__class__, MS, 0, 0, 0) M.p = self.p cdef celement pm1 = self.p-1 k=0 for i in range(ncols-r): for j in range(ncols-r): - M._entries[nonpivots[i]+j*ncols]=0 - M._entries[nonpivots[i]+k*ncols]=pm1 + M._entries[nonpivots[i]+j*ncols] = 0 + M._entries[nonpivots[i]+k*ncols] = pm1 k+=1 for j in range(r): - M._entries[i*ncols+pivots[j]]=self._entries[nonpivots[i]+j*ncols] + M._entries[i*ncols+pivots[j]] = self._entries[nonpivots[i]+j*ncols] sig_free(pivots) sig_free(nonpivots) @@ -2335,8 +2334,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef celement p, t p = self.p - # Replace self - by its Hessenberg form, and set H to this form + # Replace self by its Hessenberg form, and set H to this form # for notation below. cdef Matrix_modn_dense_template H H = self.__copy__() @@ -3086,7 +3084,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): def transpose(self): """ - Returns the transpose of ``self``, without changing ``self``. + Return the transpose of ``self``, without changing ``self``. EXAMPLES: @@ -3119,7 +3117,6 @@ cdef class Matrix_modn_dense_template(Matrix_dense): [---] [2 4] """ - cdef Py_ssize_t nrows = self._nrows cdef Py_ssize_t ncols = self._ncols @@ -3143,22 +3140,23 @@ cdef class Matrix_modn_dense_template(Matrix_dense): def stack(self, bottom, subdivide=False): r""" - Return a new matrix formed by appending the matrix (or vector) ``bottom`` beneath ``self``. + Return a new matrix formed by appending the matrix (or vector) + ``bottom`` beneath ``self``. INPUT: - ``bottom`` -- a matrix, vector or free module element, whose - dimensions are compatible with ``self``. + dimensions are compatible with ``self`` - - ``subdivide`` -- default: ``False`` - request the resulting - matrix to have a new subdivision, separating ``self`` from ``bottom``. + - ``subdivide`` -- (default: ``False``) request the resulting matrix + to have a new subdivision, separating ``self`` from ``bottom`` OUTPUT: A new matrix formed by appending ``bottom`` beneath ``self``. - If ``bottom`` is a vector (or free module element) then in this context - it is appropriate to consider it as a row vector. (The code first - converts a vector to a 1-row matrix.) + If ``bottom`` is a vector (or free module element) then in this + context it is appropriate to consider it as a row vector. + (The code first converts a vector to a 1-row matrix.) If ``subdivide`` is ``True`` then any row subdivisions for the two matrices are preserved, and a new subdivision is added @@ -3168,6 +3166,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): in the result. .. WARNING:: + If ``subdivide`` is ``True`` then unequal column subdivisions will be discarded, since it would be ambiguous how to interpret them. If the subdivision behavior is not what you need, @@ -3180,7 +3179,6 @@ cdef class Matrix_modn_dense_template(Matrix_dense): :func:`~sage.matrix.constructor.block_diagonal_matrix` useful and simpler in some instances. - EXAMPLES: Stacking with a matrix:: @@ -3236,7 +3234,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): Row subdivisions are preserved by stacking, and enriched, if subdivisions are requested. (So multiple stackings can - be recorded) :: + be recorded.) :: sage: A = matrix(GF(41), 2, 4, range(8)) sage: A.subdivide([1], None) @@ -3295,7 +3293,6 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: D.parent() Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 41 - """ if hasattr(bottom, '_vector_'): bottom = bottom.row() @@ -3319,7 +3316,6 @@ cdef class Matrix_modn_dense_template(Matrix_dense): def submatrix(self, Py_ssize_t row=0, Py_ssize_t col=0, Py_ssize_t nrows=-1, Py_ssize_t ncols=-1): - r""" Return the matrix constructed from self using the specified range of rows and columns. @@ -3333,16 +3329,16 @@ cdef class Matrix_modn_dense_template(Matrix_dense): take. If not provided, take all rows below and all columns to the right of the starting entry - .. SEEALSO: + .. SEEALSO:: - The functions :func:`matrix_from_rows`, - :func:`matrix_from_columns`, and - :func:`matrix_from_rows_and_columns` allow one to select - arbitrary subsets of rows and/or columns. + The functions :func:`matrix_from_rows`, + :func:`matrix_from_columns`, and + :func:`matrix_from_rows_and_columns` allow one to select + arbitrary subsets of rows and/or columns. EXAMPLES: - Take the `3 \times 3` submatrix starting from entry (1,1) in a + Take the `3 \times 3` submatrix starting from entry `(1,1)` in a `4 \times 4` matrix:: sage: m = matrix(GF(17),4, [1..16]) @@ -3388,7 +3384,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef Matrix_modn_dense_template M M = self.__class__.__new__(self.__class__, MS, 0,0,0) M.p = self.p - memcpy(M._entries,self._entries+row*ncols,sizeof(celement)*ncols*nrows) + memcpy(M._entries, self._entries+row*ncols,sizeof(celement)*ncols*nrows) return M def _matrices_from_rows(self, Py_ssize_t nrows, Py_ssize_t ncols): From 27f9467b3530468668522e310ce239870d0d023a Mon Sep 17 00:00:00 2001 From: Nils Bruin Date: Wed, 7 Jun 2017 23:25:57 -0700 Subject: [PATCH 119/126] faster construction of new parents --- .../matrix/matrix_modn_dense_template.pxi | 43 +++---------------- 1 file changed, 7 insertions(+), 36 deletions(-) diff --git a/src/sage/matrix/matrix_modn_dense_template.pxi b/src/sage/matrix/matrix_modn_dense_template.pxi index e326d71dd78..564b3e6251a 100644 --- a/src/sage/matrix/matrix_modn_dense_template.pxi +++ b/src/sage/matrix/matrix_modn_dense_template.pxi @@ -407,15 +407,13 @@ cpdef __matrix_from_rows_of_matrices(X): ## v = sum([y.list() for y in X],[]) ## return matrix(K, len(X), X[0].nrows()*X[0].ncols(), v) - from matrix_space import MatrixSpace - cdef Matrix_modn_dense_template A, T + cdef Matrix_modn_dense_template T cdef Py_ssize_t i, n, m n = len(X) T = X[0] m = T._nrows * T._ncols - A = T.__class__.__new__(T.__class__, MatrixSpace(X[0].base_ring(), n, m), 0, 0, 0) - A.p = T.p + cdef Matrix_modn_dense_template A = T.new_matrix(nrows = n, ncols = m) for i from 0 <= i < n: T = X[i] @@ -2177,12 +2175,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): nonpivots[k]=i k+=1 - from matrix_space import MatrixSpace - F = self.base_ring() - MS = MatrixSpace(F, ncols-r, ncols) - cdef Matrix_modn_dense_template M - M = self.__class__.__new__(self.__class__, MS, 0, 0, 0) - M.p = self.p + cdef Matrix_modn_dense_template M = self.new_matrix(nrows = ncols-r, ncols = ncols) cdef celement pm1 = self.p-1 k=0 @@ -3120,12 +3113,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef Py_ssize_t nrows = self._nrows cdef Py_ssize_t ncols = self._ncols - from matrix_space import MatrixSpace - F = self.base_ring() - MS = MatrixSpace(F, self._ncols, self._nrows) - cdef Matrix_modn_dense_template M - M = self.__class__.__new__(self.__class__, MS, 0,0,0) - M.p = self.p + cdef Matrix_modn_dense_template M = self.new_matrix(nrows = ncols, ncols = nrows) cdef Py_ssize_t i,j for i from 0 <= i < ncols: @@ -3301,12 +3289,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): if not (self._base_ring is bottom.base_ring()): bottom = bottom.change_ring(self._base_ring) cdef Matrix_modn_dense_template other = bottom.dense_matrix() - cdef Matrix_modn_dense_template M - from matrix_space import MatrixSpace - F = self.base_ring() - MS = MatrixSpace(F, self._nrows+other._nrows,self._ncols) - M = self.__class__.__new__(self.__class__, MS, 0,0,0) - M.p = self.p + cdef Matrix_modn_dense_template M = self.new_matrix(nrows = self._nrows+other._nrows, ncols = self._ncols) cdef Py_ssize_t selfsize = self._ncols*self._nrows memcpy(M._entries, self._entries, sizeof(celement)*selfsize) memcpy(M._entries+selfsize, other._entries, sizeof(celement)*other._ncols*other._nrows) @@ -3378,12 +3361,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): if nrows < 0 or row < 0 or row+nrows > self._nrows: raise IndexError, "rows out of range" - from matrix_space import MatrixSpace - F = self.base_ring() - MS = MatrixSpace(F, nrows,self._ncols) - cdef Matrix_modn_dense_template M - M = self.__class__.__new__(self.__class__, MS, 0,0,0) - M.p = self.p + cdef Matrix_modn_dense_template M = self.new_matrix(nrows = nrows, ncols = self._ncols) memcpy(M._entries, self._entries+row*ncols,sizeof(celement)*ncols*nrows) return M @@ -3420,19 +3398,12 @@ cdef class Matrix_modn_dense_template(Matrix_dense): if nrows * ncols != self._ncols: raise ValueError("nrows * ncols must equal self's number of columns") - from matrix_space import MatrixSpace - F = self.base_ring() - MS = MatrixSpace(F, nrows, ncols) - cdef Matrix_modn_dense_template M cdef Py_ssize_t i cdef Py_ssize_t n = nrows * ncols ans = [] for i from 0 <= i < self._nrows: - # Quickly construct a new mod-p matrix - M = self.__class__.__new__(self.__class__, MS, 0,0,0) - M.p = self.p - # Set the entries + M = self.new_matrix(nrows = nrows, ncols = ncols) memcpy(M._entries, self._entries+i*n, sizeof(celement)*n) ans.append(M) return ans From 5c878c728cf05071490446e5e56b3d32d109cb5b Mon Sep 17 00:00:00 2001 From: Travis Scrimshaw Date: Thu, 8 Jun 2017 02:51:28 -0500 Subject: [PATCH 120/126] Use _stack_impl for the work and leave the checks for stack. --- .../matrix/matrix_modn_dense_template.pxi | 92 ++++++------------- 1 file changed, 28 insertions(+), 64 deletions(-) diff --git a/src/sage/matrix/matrix_modn_dense_template.pxi b/src/sage/matrix/matrix_modn_dense_template.pxi index 564b3e6251a..b697f6ac0a5 100644 --- a/src/sage/matrix/matrix_modn_dense_template.pxi +++ b/src/sage/matrix/matrix_modn_dense_template.pxi @@ -2128,7 +2128,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): EXAMPLES:: - sage: M=matrix(GF(5),6,6,range(36)) + sage: M = matrix(GF(5),6,6,range(36)) sage: M.right_kernel_matrix(basis='computed') [4 2 4 0 0 0] [3 3 0 4 0 0] @@ -2144,7 +2144,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): [0 1 0 0 1 3] [0 0 1 0 2 2] [0 0 0 1 3 1] - sage: M*M.right_kernel_matrix().transpose() + sage: M * M.right_kernel_matrix().transpose() [0 0 0 0] [0 0 0 0] [0 0 0 0] @@ -2158,7 +2158,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef Py_ssize_t r = self.rank() cdef Py_ssize_t nrows = self._nrows cdef Py_ssize_t ncols = self._ncols - cdef Py_ssize_t i,j,k + cdef Py_ssize_t i, j, k cdef Py_ssize_t* nonpivots = sig_malloc(sizeof(Py_ssize_t)*(ncols-r)) cdef Py_ssize_t* pivots = sig_malloc(sizeof(Py_ssize_t)*(r)) @@ -2170,20 +2170,20 @@ cdef class Matrix_modn_dense_template(Matrix_dense): k = 0 for i in range(ncols): if j < r and i == pivots[j]: - j+=1 + j += 1 else: - nonpivots[k]=i - k+=1 + nonpivots[k] = i + k += 1 - cdef Matrix_modn_dense_template M = self.new_matrix(nrows = ncols-r, ncols = ncols) - cdef celement pm1 = self.p-1 + cdef Matrix_modn_dense_template M = self.new_matrix(nrows=ncols-r, ncols=ncols) + cdef celement pm1 = self.p - 1 - k=0 + k = 0 for i in range(ncols-r): for j in range(ncols-r): M._entries[nonpivots[i]+j*ncols] = 0 M._entries[nonpivots[i]+k*ncols] = pm1 - k+=1 + k += 1 for j in range(r): M._entries[i*ncols+pivots[j]] = self._entries[nonpivots[i]+j*ncols] @@ -3126,46 +3126,17 @@ cdef class Matrix_modn_dense_template(Matrix_dense): return M - def stack(self, bottom, subdivide=False): + cdef _stack_impl(self, bottom): r""" - Return a new matrix formed by appending the matrix (or vector) - ``bottom`` beneath ``self``. - - INPUT: + Implementation of :meth:`stack` by returning a new matrix + formed by appending the matrix ``bottom`` beneath ``self``. - - ``bottom`` -- a matrix, vector or free module element, whose - dimensions are compatible with ``self`` + Assume that ``self`` and ``other`` are compatible in the sense + that they have the same base ring and that both are dense. - - ``subdivide`` -- (default: ``False``) request the resulting matrix - to have a new subdivision, separating ``self`` from ``bottom`` - - OUTPUT: + INPUT: - A new matrix formed by appending ``bottom`` beneath ``self``. - If ``bottom`` is a vector (or free module element) then in this - context it is appropriate to consider it as a row vector. - (The code first converts a vector to a 1-row matrix.) - - If ``subdivide`` is ``True`` then any row subdivisions for - the two matrices are preserved, and a new subdivision is added - between ``self`` and ``bottom``. If the column divisions are - identical, then they are preserved, otherwise they are discarded. - When ``subdivide`` is ``False`` there is no subdivision information - in the result. - - .. WARNING:: - - If ``subdivide`` is ``True`` then unequal column subdivisions - will be discarded, since it would be ambiguous how to interpret - them. If the subdivision behavior is not what you need, - you can manage subdivisions yourself with methods like - :meth:`~sage.matrix.matrix2.Matrix.subdivisions` - and - :meth:`~sage.matrix.matrix2.Matrix.subdivide`. - You might also find :func:`~sage.matrix.constructor.block_matrix` - or - :func:`~sage.matrix.constructor.block_diagonal_matrix` - useful and simpler in some instances. + - ``bottom`` -- a matrix compatible with ``self`` EXAMPLES: @@ -3199,13 +3170,13 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: A.stack(B) Traceback (most recent call last): ... - TypeError: number of columns must be the same + TypeError: number of columns must be the same, not 2 and 3 sage: v = vector(GF(41), [100, 200, 300]) sage: A.stack(v) Traceback (most recent call last): ... - TypeError: number of columns must be the same + TypeError: number of columns must be the same, not 2 and 3 Setting ``subdivide`` to ``True`` will, in its simplest form, add a subdivision between ``self`` and ``bottom``:: @@ -3282,19 +3253,12 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: D.parent() Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 41 """ - if hasattr(bottom, '_vector_'): - bottom = bottom.row() - if self._ncols != bottom.ncols(): - raise TypeError("number of columns must be the same") - if not (self._base_ring is bottom.base_ring()): - bottom = bottom.change_ring(self._base_ring) - cdef Matrix_modn_dense_template other = bottom.dense_matrix() - cdef Matrix_modn_dense_template M = self.new_matrix(nrows = self._nrows+other._nrows, ncols = self._ncols) - cdef Py_ssize_t selfsize = self._ncols*self._nrows + cdef Matrix_modn_dense_template other = bottom + cdef Matrix_modn_dense_template M = self.new_matrix(nrows=self._nrows+other._nrows, + ncols=self._ncols) + cdef Py_ssize_t selfsize = self._ncols * self._nrows memcpy(M._entries, self._entries, sizeof(celement)*selfsize) memcpy(M._entries+selfsize, other._entries, sizeof(celement)*other._ncols*other._nrows) - if subdivide: - M._subdivide_on_stack(self, other) return M def submatrix(self, Py_ssize_t row=0, Py_ssize_t col=0, @@ -3355,14 +3319,14 @@ cdef class Matrix_modn_dense_template(Matrix_dense): if nrows == -1: nrows = self._nrows - row - if col !=0 or ncols != self._ncols: + if col != 0 or ncols != self._ncols: return self.matrix_from_rows_and_columns(range(row, row+nrows), range(col, col+ncols)) - if nrows < 0 or row < 0 or row+nrows > self._nrows: - raise IndexError, "rows out of range" + if nrows < 0 or row < 0 or row + nrows > self._nrows: + raise IndexError("rows out of range") - cdef Matrix_modn_dense_template M = self.new_matrix(nrows = nrows, ncols = self._ncols) - memcpy(M._entries, self._entries+row*ncols,sizeof(celement)*ncols*nrows) + cdef Matrix_modn_dense_template M = self.new_matrix(nrows=nrows, ncols=self._ncols) + memcpy(M._entries, self._entries+row*ncols, sizeof(celement)*ncols*nrows) return M def _matrices_from_rows(self, Py_ssize_t nrows, Py_ssize_t ncols): From b47597412e0db06fd2a21d70736efef8c97866c9 Mon Sep 17 00:00:00 2001 From: Xavier Caruso Date: Thu, 8 Jun 2017 13:51:38 +0200 Subject: [PATCH 121/126] Disable signal handling while memory allocation --- src/sage/rings/padics/transcendantal.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/padics/transcendantal.c b/src/sage/rings/padics/transcendantal.c index 4dc587336c6..3796cfb6e4c 100644 --- a/src/sage/rings/padics/transcendantal.c +++ b/src/sage/rings/padics/transcendantal.c @@ -6,8 +6,8 @@ #include #include -#include #include +#include /* cysignals library */ /* p-adic logarithm */ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, const mpz_t modulo) { @@ -48,7 +48,8 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con } /* Where do we need to truncate the Taylor expansion */ - N = Np = (prec+v)/++v; // note the ++v + N = prec+v; N /= ++v; // note the ++v + Np = N; den *= v; while(1) { tmp = Np + (unsigned long)(log(N)/den); @@ -60,8 +61,10 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con mpz_init(f); mpz_init(mod2); mpz_init(h); mpz_init(hpow); mpz_init(d); mpz_init(inv); + sig_block(); num = (mpz_t*)malloc(N*sizeof(mpz_t)); denom = (mpz_t*)malloc(N*sizeof(mpz_t)); + sig_unblock(); for (i = 0; i < N; i++) { mpz_init(num[i]); mpz_init(denom[i]); @@ -148,6 +151,8 @@ void padiclog(mpz_t ans, const mpz_t a, unsigned long p, unsigned long prec, con mpz_clear(num[i]); mpz_clear(denom[i]); } + sig_block(); free(num); free(denom); + sig_unblock(); } From c79b903d66c13ac26ce88bf2aee67693b9304479 Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Thu, 8 Jun 2017 15:20:22 +0000 Subject: [PATCH 122/126] Make it an error to build with SAGE_FAT_BINARY=yes if 'as' is outdated --- build/pkgs/mpir/spkg-install | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/build/pkgs/mpir/spkg-install b/build/pkgs/mpir/spkg-install index 36d896f67af..26e7bae77b7 100755 --- a/build/pkgs/mpir/spkg-install +++ b/build/pkgs/mpir/spkg-install @@ -172,9 +172,11 @@ if [ "$UNAME" = Linux ]; then if [ $as_version_major -lt 2 ] || \ [ $as_version_major -eq 2 -a $as_version_minor -lt 24 ]; then echo "Disable use of assembly because of GNU as < 2.23." - echo "This also disables SAGE_FAT_BINARY=yes." export MPN_PATH=generic - SAGE_FAT_BINARY=no + if [ "$SAGE_FAT_BINARY" = "yes" ]; then + echo "Cannot build with SAGE_FAT_BINARY=yes." + exit 1 + fi fi fi From 8d25401676bd431373153b10cd9d701062ca499b Mon Sep 17 00:00:00 2001 From: "Erik M. Bray" Date: Thu, 8 Jun 2017 15:26:14 +0000 Subject: [PATCH 123/126] Fix error message accuracy --- build/pkgs/mpir/spkg-install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/pkgs/mpir/spkg-install b/build/pkgs/mpir/spkg-install index 26e7bae77b7..a3a403653e0 100755 --- a/build/pkgs/mpir/spkg-install +++ b/build/pkgs/mpir/spkg-install @@ -171,7 +171,7 @@ if [ "$UNAME" = Linux ]; then as_version_minor=${as_version_rest%%.*} if [ $as_version_major -lt 2 ] || \ [ $as_version_major -eq 2 -a $as_version_minor -lt 24 ]; then - echo "Disable use of assembly because of GNU as < 2.23." + echo "Disable use of assembly because of GNU as <= 2.23." export MPN_PATH=generic if [ "$SAGE_FAT_BINARY" = "yes" ]; then echo "Cannot build with SAGE_FAT_BINARY=yes." From bebe033c977e86716c5a794a2d9946493670cbf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Thu, 8 Jun 2017 15:58:15 -0700 Subject: [PATCH 124/126] polynomial's is_squarefree() calls _is_squarefree_univariate_polynomial when implemented --- .../rings/polynomial/polynomial_element.pyx | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 00e4f94176d..015e61ec071 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -8207,11 +8207,50 @@ cdef class Polynomial(CommutativeAlgebraElement): Traceback (most recent call last): ... TypeError: is_squarefree() is not defined for polynomials over Ring of integers modulo 9 + + TESTS: + + If the base ring implements `_is_squarefree_univariate_polynomial`, + then this method gets used instead of the generic algorithm in + :meth:`_is_squarefree_generic`:: + + sage: R. = QQbar[] + sage: (x^2).is_squarefree() + False + sage: hasattr(QQbar, '_is_squarefree_univariate_polynomial') + False + sage: QQbar._is_squarefree_univariate_polynomial = lambda self: True + sage: (x^2).is_squarefree() + True + sage: del(QQbar._is_squarefree_univariate_polynomial) + """ B = self.parent().base_ring() if B not in sage.categories.integral_domains.IntegralDomains(): raise TypeError("is_squarefree() is not defined for polynomials over {}".format(B)) + B = self.parent().base_ring() + if hasattr(B, '_is_squarefree_univariate_polynomial'): + return B._is_squarefree_univariate_polynomial(self) + + return self._is_squarefree_generic() + + def _is_squarefree_generic(self): + r""" + Return False if this polynomial is not square-free, i.e., if there is a + non-unit `g` in the polynomial ring such that `g^2` divides ``self``. + + EXAMPLES:: + + sage: R. = QQbar[] + sage: (x^2*(x + 1)).is_squarefree() # indirect doctest + False + sage: (x*(x+1)).is_squarefree() # indirect doctest + True + + """ + B = self.parent().base_ring() + # a square-free polynomial has a square-free content if not B.is_field(): content = self.content() From 16d8757c92dccab7cb8164700217c6710905cc95 Mon Sep 17 00:00:00 2001 From: David Roe Date: Fri, 9 Jun 2017 00:40:58 +0000 Subject: [PATCH 125/126] Adding limits to long tests in padic_extension_leaves, fix typo --- src/sage/rings/padics/padic_extension_leaves.py | 16 ++++++++-------- src/sage/rings/padics/padic_generic_element.pyx | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sage/rings/padics/padic_extension_leaves.py b/src/sage/rings/padics/padic_extension_leaves.py index 90fbc31a8a3..0ac45bdc9d2 100644 --- a/src/sage/rings/padics/padic_extension_leaves.py +++ b/src/sage/rings/padics/padic_extension_leaves.py @@ -95,7 +95,7 @@ class UnramifiedExtensionRingCappedRelative(UnramifiedExtensionGeneric, pAdicCap TESTS:: sage: R. = ZqCR(27,10000) - sage: TestSuite(R).run() + sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): """ @@ -155,7 +155,7 @@ class UnramifiedExtensionFieldCappedRelative(UnramifiedExtensionGeneric, pAdicCa TESTS:: sage: R. = QqCR(27,10000) - sage: TestSuite(R).run() + sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): """ @@ -226,7 +226,7 @@ class UnramifiedExtensionRingCappedAbsolute(UnramifiedExtensionGeneric, pAdicCap TESTS:: sage: R. = ZqCA(27,10000) - sage: TestSuite(R).run() + sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): """ @@ -287,7 +287,7 @@ class UnramifiedExtensionRingFixedMod(UnramifiedExtensionGeneric, pAdicFixedModR TESTS:: sage: R. = ZqFM(27,10000) - sage: TestSuite(R).run() + sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): """ @@ -353,7 +353,7 @@ class EisensteinExtensionRingCappedRelative(EisensteinExtensionGeneric, pAdicCap sage: R = Zp(3, 10000, print_pos=False); S. = ZZ[]; f = x^3 + 9*x - 3 sage: W. = R.ext(f) - sage: TestSuite(R).run() + sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): """ @@ -411,7 +411,7 @@ class EisensteinExtensionFieldCappedRelative(EisensteinExtensionGeneric, pAdicCa sage: R = Qp(3, 10000, print_pos=False); S. = ZZ[]; f = x^3 + 9*x - 3 sage: W. = R.ext(f) - sage: TestSuite(R).run() + sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): """ @@ -480,7 +480,7 @@ class EisensteinExtensionRingCappedAbsolute(EisensteinExtensionGeneric, pAdicCap sage: R = ZpCA(3, 10000, print_pos=False); S. = ZZ[]; f = x^3 + 9*x - 3 sage: W. = R.ext(f) - sage: TestSuite(R).run() + sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation): """ @@ -538,7 +538,7 @@ class EisensteinExtensionRingFixedMod(EisensteinExtensionGeneric, pAdicFixedModR sage: R = ZpFM(3, 10000, print_pos=False); S. = ZZ[]; f = x^3 + 9*x - 3 sage: W. = R.ext(f) - sage: TestSuite(R).run() + sage: TestSuite(R).run(skip='_test_log',max_runs=4) """ def __init__(self, prepoly, poly, prec, halt, print_mode, shift_seed, names, implementation='NTL'): """ diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 87937100c28..caf5f0c6912 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -1543,7 +1543,7 @@ cdef class pAdicGenericElement(LocalGenericElement): .. MATH:: - \log(1-x)=\sum_{n=1}^\infty \frac{x^n}{n}. + -\log(1-x)=\sum_{n=1}^\infty \frac{x^n}{n}. For the result to be correct to precision ``aprec``, we sum all terms for which the valuation of `x^n/n` is stricly smaller than ``aprec``. From ffc8eff2656d3d197e711b7d80b4e7eaafe3be49 Mon Sep 17 00:00:00 2001 From: Volker Braun Date: Sun, 11 Jun 2017 13:07:13 +0200 Subject: [PATCH 126/126] Updated SageMath version to 8.0.beta10 --- VERSION.txt | 2 +- build/pkgs/configure/checksums.ini | 6 +++--- build/pkgs/configure/package-version.txt | 2 +- src/bin/sage-banner | 2 +- src/bin/sage-version.sh | 4 ++-- src/sage/version.py | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index d01f871103c..f001902c9fd 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 8.0.beta9, Release Date: 2017-05-31 +SageMath version 8.0.beta10, Release Date: 2017-06-11 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 289e7d03321..13cf41a1d16 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=1468ff678f41a3552bce2ba952af0795127d64d8 -md5=931c98793b007e28874089c17c40e53d -cksum=1227610551 +sha1=4fa024947bd555ae00d155c022d52f5fddad045f +md5=35c48d9ed0328cc92e2100a7721a996e +cksum=2690821246 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 5f277ae787b..20c90807cc9 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -223 +224 diff --git a/src/bin/sage-banner b/src/bin/sage-banner index e29022a5da0..97412eb77ae 100644 --- a/src/bin/sage-banner +++ b/src/bin/sage-banner @@ -1,5 +1,5 @@ ┌────────────────────────────────────────────────────────────────────┐ -│ SageMath version 8.0.beta9, Release Date: 2017-05-31 │ +│ SageMath version 8.0.beta10, Release Date: 2017-06-11 │ │ Type "notebook()" for the browser-based notebook interface. │ │ Type "help()" for help. │ └────────────────────────────────────────────────────────────────────┘ diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 2317480273c..e582d343200 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -1,4 +1,4 @@ # Sage version information for shell scripts # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='8.0.beta9' -SAGE_RELEASE_DATE='2017-05-31' +SAGE_VERSION='8.0.beta10' +SAGE_RELEASE_DATE='2017-06-11' diff --git a/src/sage/version.py b/src/sage/version.py index 767e570cba9..9d800484904 100644 --- a/src/sage/version.py +++ b/src/sage/version.py @@ -1,4 +1,4 @@ # Sage version information for Python scripts # This file is auto-generated by the sage-update-version script, do not edit! -version = '8.0.beta9' -date = '2017-05-31' +version = '8.0.beta10' +date = '2017-06-11'