Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" PolyDict engine for generic multivariate polynomial rings
This module provides an implementation of the underlying arithmetic for multi-variate polynomial rings using Python dicts.
This class is not meant for end users, but instead for implementing multivariate polynomial rings over a completely general base. It does not do strong type checking or have parents, etc. For speed, it has been implemented in Cython.
The functions in this file use the 'dictionary representation' of multivariate polynomials
``{(e1,...,er):c1,...} <-> c1*x1^e1*...*xr^er+...``,
which we call a polydict. The exponent tuple ``(e1,...,er)`` in this representation is an instance of the class :class:`ETuple`. This class behaves like a normal Python tuple but also offers advanced access methods for sparse monomials like positions of non-zero exponents etc.
AUTHORS:
- William Stein - David Joyner - Martin Albrecht (ETuple) - Joel B. Mohler (2008-03-17) -- ETuple rewrite as sparse C array """
#***************************************************************************** # Copyright (C) 2005 William Stein <wstein@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import print_function, absolute_import
from 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 from sage.arith.power import generic_power from pprint import pformat
from sage.misc.misc import cputime from sage.misc.latex import latex from sage.misc.superseded import deprecation
cdef class PolyDict: def __init__(PolyDict self, pdict, zero=0, remove_zero=False, force_int_exponents=True, force_etuples=True): """ INPUT:
- ``pdict`` -- list, which represents a multi-variable polynomial with the distribute representation (a copy is not made)
- ``zero`` -- (optional) zero in the base ring
- ``force_int_exponents`` -- bool (optional) arithmetic with int exponents is much faster than some of the alternatives, so this is True by default.
- ``force_etuples`` -- bool (optional) enforce that the exponent tuples are instances of ETuple class
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: PolyDict({(2,3):2, (1,2):3, (2,1):4}) PolyDict with representation {(1, 2): 3, (2, 1): 4, (2, 3): 2}
# I've removed fractional exponent support in ETuple when moving to a sparse C integer array #sage: PolyDict({(2/3,3,5):2, (1,2,1):3, (2,1):4}, force_int_exponents=False) #PolyDict with representation {(2, 1): 4, (1, 2, 1): 3, (2/3, 3, 5): 2}
sage: PolyDict({(2,3):0, (1,2):3, (2,1):4}, remove_zero=True) PolyDict with representation {(1, 2): 3, (2, 1): 4}
sage: PolyDict({(0,0):RIF(-1,1)}, remove_zero=True) PolyDict with representation {(0, 0): 0.?} """ if isinstance(pdict, list): v = {} for w in pdict: if w[0] != 0: v[ETuple(w[1])] = w[0] remove_zero = False pdict = v else: raise TypeError("pdict must be a list.")
else: else:
def __hash__(self): """ Return the hash.
The hash of two PolyDicts is the same whether or not they use ETuples for their keys since that's just an implementation detail.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: PD1 = PolyDict({(2,3):0, (1,2):3, (2,1):4}) sage: PD2 = PolyDict({(2,3):0, (1,2):3, (2,1):4}, remove_zero=True) sage: PD3 = PolyDict({(2,3):0, (1,2):3, (2,1):4}, ....: force_etuples=False, force_int_exponents=False) sage: PD4 = PolyDict({(2,3):0, (1,2):3, (2,1):4}, zero=4) sage: hash(PD1) == hash(PD2) False sage: hash(PD1) == hash(PolyDict({(2,3):0, (1,2):3, (2,1):4})) True sage: hash(PD1) == hash(PD3) True sage: hash(PD3) == hash(PolyDict({(2,3):0, (1,2):3, (2,1):4}, ....: force_etuples=False)) True sage: hash(PD1) == hash(PD4) False sage: hash(PD4) == hash(PolyDict({(2,3):0, (1,2):3, (2,1):4}, ....: zero=4)) True """
def __richcmp__(PolyDict self, PolyDict right, int op):
def compare(PolyDict self, PolyDict other, key=None): # start with biggest else: # in despair, do that raise ValueError('no key provided')
# first compare the leading monomials
# same leading monomial, compare their coefficients
# try next pair except StopIteration: return 0 # both have no terms
def list(PolyDict self): """ Return a list that defines ``self``. It is safe to change this.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.list() [[3, [1, 2]], [2, [2, 3]], [4, [2, 1]]] """
def dict(PolyDict self): """ Return a copy of the dict that defines self. It is safe to change this. For a reference, use dictref.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.dict() {(1, 2): 3, (2, 1): 4, (2, 3): 2} """
def coefficients(PolyDict self): """ Return the coefficients of self.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.coefficients() [3, 2, 4] """
def exponents(PolyDict self): """ Return the exponents of self.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.exponents() [(1, 2), (2, 3), (2, 1)] """
def __len__(PolyDict self): """ Return the number of terms of the polynomial.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: len(f) 3 """
def __getitem__(PolyDict self, e): """ Return a coefficient of the polynomial.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f[1,2] 3 sage: f[(2,1)] 4 """
def __repr__(PolyDict self):
def degree(PolyDict self, PolyDict x=None): raise TypeError("x must be one of the generators of the parent.") raise TypeError("x must be one of the generators of the parent.") raise TypeError("x must be one of the generators of the parent.")
def valuation(PolyDict self, PolyDict x=None): L = x.__repn.keys() if x is None: _min = [] negative = False for k in self.__repn.keys(): _sum = 0 for m in self.__repn[k].nonzero_values(sort=False): if m < 0: negative = True break _sum += m if negative: break _min.append(_sum) else: return min(_min) for k in self.__repn.keys(): _min.append(sum(m for m in self.__repn[k].nonzero_values(sort=False) if m < 0)) return min(_min) L = x.__repn.keys() if len(L) != 1: raise TypeError("x must be one of the generators of the parent.") L = L[0] nonzero_positions = L.nonzero_positions() if len(nonzero_positions) != 1: raise TypeError("x must be one of the generators of the parent.") i = nonzero_positions[0] if L[i] != 1: raise TypeError("x must be one of the generators of the parent.") _min = [] for v in self.__repn.keys(): _min.append(v[i]) return min(_min)
def total_degree(PolyDict self):
def monomial_coefficient(PolyDict self, mon): """ INPUT:
a PolyDict with a single key
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.monomial_coefficient(PolyDict({(2,1):1}).dict()) 4 """
def polynomial_coefficient(PolyDict self, degrees): """ Return a polydict that defines the coefficient in the current polynomial viewed as a tower of polynomial extensions.
INPUT:
- ``degrees`` -- a list of degree restrictions; list elements are None if the variable in that position should be unrestricted
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.polynomial_coefficient([2,None]) PolyDict with representation {(0, 1): 4, (0, 3): 2} sage: f = PolyDict({(0,3):2, (0,2):3, (2,1):4}) sage: f.polynomial_coefficient([0,None]) PolyDict with representation {(0, 2): 3, (0, 3): 2} """ cdef int i
def coefficient(PolyDict self, mon): """ Return a polydict that defines a polynomial in 1 less number of variables that gives the coefficient of mon in this polynomial.
The coefficient is defined as follows. If f is this polynomial, then the coefficient is the sum T/mon where the sum is over terms T in f that are exactly divisible by mon. """
def is_homogeneous(PolyDict self): # A polynomial is homogeneous if the number of different # exponent sums is at most 1.
def homogenize(PolyDict self, var):
def latex(PolyDict self, vars, atomic_exponents=True, atomic_coefficients=True, sortkey=None): r""" Return a nice polynomial latex representation of this PolyDict, where the vars are substituted in.
INPUT:
- ``vars`` -- list - ``atomic_exponents`` -- bool (default: ``True``) - ``atomic_coefficients`` -- bool (default: ``True``)
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.latex(['a', 'WW']) '2 a^{2} WW^{3} + 4 a^{2} WW + 3 a WW^{2}'
When ``atomic_exponents`` is False, the exponents are surrounded in parenthesis, since ^ has such high precedence::
# I've removed fractional exponent support in ETuple when moving to a sparse C integer array #sage: f = PolyDict({(2/3,3,5):2, (1,2,1):3, (2,1,1):4}, force_int_exponents=False) #sage: f.latex(['a', 'b', 'c'], atomic_exponents=False) #'4 a^{2}bc + 3 ab^{2}c + 2 a^{2/3}b^{3}c^{5}'
TESTS:
We check that the issue on :trac:`9478` is resolved::
sage: R2.<a> = QQ[] sage: R3.<xi, x> = R2[] sage: print(latex(xi*x)) \xi x """ else: # probably self.__zero is not a ring element # First determine the multinomial: # Next determine coefficient of multinomial # handle -1 specially because it's a pain else: c = latex(c) if c.find("+") != -1 or c.find("-") != -1 or c.find(" ") != -1: c = "(%s)" % c
# Now add on coefficiented multinomials else: return "0"
def poly_repr(PolyDict self, vars, atomic_exponents=True, atomic_coefficients=True, sortkey=None): """ Return a nice polynomial string representation of this PolyDict, where the vars are substituted in.
INPUT:
- ``vars`` -- list - ``atomic_exponents`` -- bool (default: ``True``) - ``atomic_coefficients`` -- bool (default: ``True``)
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.poly_repr(['a', 'WW']) '2*a^2*WW^3 + 4*a^2*WW + 3*a*WW^2'
When atomic_exponents is ``False``, the exponents are surrounded in parenthesis, since ^ has such high precedence. ::
# I've removed fractional exponent support in ETuple when moving to a sparse C integer array #sage: f = PolyDict({(2/3,3,5):2, (1,2,1):3, (2,1,1):4}, force_int_exponents=False) #sage: f.poly_repr(['a', 'b', 'c'], atomic_exponents=False) #'4*a^(2)*b*c + 3*a*b^(2)*c + 2*a^(2/3)*b^(3)*c^(5)'
We check to make sure that when we are in characteristic two, we don't put negative signs on the generators. ::
sage: Integers(2)['x, y'].gens() (x, y)
We make sure that intervals are correctly represented. ::
sage: f = PolyDict({(2,3):RIF(1/2,3/2), (1,2):RIF(-1,1)}) sage: f.poly_repr(['x', 'y']) '1.?*x^2*y^3 + 0.?*x*y^2' """ else: # probably self.__zero is not a ring element
# First determine the multinomial: else: multi = multi + "^(%s)" % e[j] # Next determine coefficient of multinomial # handle -1 specially because it's a pain else:
# Now add on coefficiented multinomials else:
def __add__(PolyDict self, PolyDict other): """ Add two PolyDict's in the same number of variables.
EXAMPLES:
We add two polynomials in 2 variables::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: g = PolyDict({(1,5):-3, (2,3):-2, (1,1):3}) sage: f + g PolyDict with representation {(1, 1): 3, (1, 2): 3, (1, 5): -3, (2, 1): 4}
Next we add two polynomials with fractional exponents in 3 variables::
# I've removed fractional exponent support in ETuple when moving to a sparse C integer array #sage: f = PolyDict({(2/3,3,5):2, (1,2,1):3, (2,1,1):4}, force_int_exponents=False) #sage: g = PolyDict({(2/3,3,5):3}, force_int_exponents=False) #sage: f+g #PolyDict with representation {(1, 2, 1): 3, (2/3, 3, 5): 5, (2, 1, 1): 4} """ # D = copy.copy(self.__repn)
def __mul__(PolyDict self, PolyDict right): """ Multiply two PolyDict's in the same number of variables.
EXAMPLES: We multiply two polynomials in 2 variables::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: g = PolyDict({(1,5):-3, (2,3):-2, (1,1):3}) sage: f*g PolyDict with representation {(2, 3): 9, (2, 7): -9, (3, 2): 12, (3, 4): 6, (3, 5): -6, (3, 6): -12, (3, 8): -6, (4, 4): -8, (4, 6): -4} """ cdef PyObject *cc else:
def scalar_rmult(PolyDict self, s): """ Right Scalar Multiplication
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! sage: f = PolyDict({(2,3):x}) sage: f.scalar_rmult(y) PolyDict with representation {(2, 3): x*y} sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.scalar_rmult(-2) PolyDict with representation {(1, 2): -6, (2, 1): -8, (2, 3): -4} sage: f.scalar_rmult(RIF(-1,1)) PolyDict with representation {(1, 2): 0.?e1, (2, 1): 0.?e1, (2, 3): 0.?e1} """ # if s is 0, then all the products will be zero
def scalar_lmult(PolyDict self, s): """ Left Scalar Multiplication
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: x, y = FreeMonoid(2, 'x, y').gens() # a strange object to live in a polydict, but non-commutative! sage: f = PolyDict({(2,3):x}) sage: f.scalar_lmult(y) PolyDict with representation {(2, 3): y*x} sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.scalar_lmult(-2) PolyDict with representation {(1, 2): -6, (2, 1): -8, (2, 3): -4} sage: f.scalar_lmult(RIF(-1,1)) PolyDict with representation {(1, 2): 0.?e1, (2, 1): 0.?e1, (2, 3): 0.?e1} """ # if s is 0, then all the products will be zero
def __sub__(PolyDict self, PolyDict other): """ Subtract two PolyDict's.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: g = PolyDict({(2,3):2, (1,1):-10}) sage: f - g PolyDict with representation {(1, 1): 10, (1, 2): 3, (2, 1): 4} sage: g - f PolyDict with representation {(1, 1): -10, (1, 2): -3, (2, 1): -4} """
# TODO: should refactor add, make abstract operator, so can do both +/-; or copy code.
def __one(PolyDict self): else:
def __pow__(PolyDict self, n, ignored): """ Return the n-th nonnegative power of this PolyDict.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f**2 PolyDict with representation {(2, 4): 9, (3, 3): 24, (3, 5): 12, (4, 2): 16, (4, 4): 16, (4, 6): 4} sage: f**0 PolyDict with representation {(0, 0): 1} sage: (f-f)**0 PolyDict with representation {0: 1} """
def lcmt(PolyDict self, greater_etuple): """ Provides functionality of lc, lm, and lt by calling the tuple compare function on the provided term order T.
INPUT:
- ``greater_etuple`` -- a term order """ except KeyError: raise ArithmeticError("%s not supported", greater_etuple)
def __reduce__(PolyDict self): """
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: loads(dumps(f)) == f True """
def min_exp(self): """ Returns an ETuple containing the minimum exponents appearing. If there are no terms at all in the PolyDict, it returns None.
The nvars parameter is necessary because a PolyDict doesn't know it from the data it has (and an empty PolyDict offers no clues).
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.min_exp() (1, 1) sage: PolyDict({}).min_exp() # returns None """ cdef ETuple r else:
def max_exp(self): """ Returns an ETuple containing the maximum exponents appearing. If there are no terms at all in the PolyDict, it returns None.
The nvars parameter is necessary because a PolyDict doesn't know it from the data it has (and an empty PolyDict offers no clues).
EXAMPLES::
sage: from sage.rings.polynomial.polydict import PolyDict sage: f = PolyDict({(2,3):2, (1,2):3, (2,1):4}) sage: f.max_exp() (2, 3) sage: PolyDict({}).max_exp() # returns None """ cdef ETuple r else:
cdef class ETupleIter: cdef int _i cdef int _length cdef object _data
def __init__(self, data, length):
def __next__(self):
cdef inline bint dual_etuple_iter(ETuple self, ETuple other, size_t *ind1, size_t *ind2, size_t *index, int *exp1, int *exp2): """ This function is a crucial helper function for a number of methods of the ETuple class.
This is a rather fragile function. Perhaps some Cython guru could make it appear a little less stilted -- a principal difficulty is passing C types by reference. In any case, the complicated features of looping through two ETuple _data members is all packaged up right here and shouldn't be allowed to spread. """ else: else:
cdef class ETuple: """ Representation of the exponents of a polydict monomial. If (0,0,3,0,5) is the exponent tuple of x_2^3*x_4^5 then this class only stores {2:3, 4:5} instead of the full tuple. This sparse information may be obtained by provided methods.
The index/value data is all stored in the _data C int array member variable. For the example above, the C array would contain 2,3,4,5. The indices are interlaced with the values.
This data structure is very nice to work with for some functions implemented in this class, but tricky for others. One reason that I really like the format is that it requires a single memory allocation for all of the values. A hash table would require more allocations and presumably be slower. I didn't benchmark this question (although, there is no question that this is much faster than the prior use of python dicts). """ cdef ETuple _new(ETuple self): """ Quickly creates a new initialized ETuple with the same length as self. """
def __init__(ETuple self, data=None, length=None): """ - ``ETuple()`` -> an empty ETuple - ``ETuple(sequence)`` -> ETuple initialized from sequence's items
If the argument is an ETuple, the return value is the same object.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: ETuple([1,1,0]) (1, 1, 0) sage: ETuple({int(1):int(2)}, int(3)) (0, 2, 0)
TESTS:
Iterators are not accepted::
sage: ETuple(iter([2,3,4])) Traceback (most recent call last): ... TypeError: Error in ETuple((),<listiterator object at ...>,None) """ return cdef size_t ind cdef int v else:
def __cinit__(ETuple self):
def __dealloc__(self):
# methods to simulate tuple
def __add__(ETuple self, ETuple other): """ x.__add__(n) <==> x+n
concatenates two ETuples
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: ETuple([1,1,0]) + ETuple({int(1):int(2)}, int(3)) (1, 1, 0, 0, 2, 0) """
def __mul__(ETuple self, factor): """ x.__mul__(n) <==> x*n
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: ETuple([1,2,3])*2 (1, 2, 3, 1, 2, 3) """ result._length = 0 result._nonzero = 0 return result cdef size_t index cdef size_t f
def __getitem__(ETuple self, i): """ EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: m = ETuple([1,2,0,3]) sage: m[2] 0 sage: m[1] 2 sage: e = ETuple([1,2,3]) sage: e[1:] (2, 3) sage: e[:1] (1,) """ cdef size_t ind start = start % self._length start = self._length
stop = stop % self._length
# this is not particularly fast, but I doubt many people care # if you do, feel free to tweak! else: # the indices are sorted in _data, we are beyond, so quit
def __hash__(ETuple self): """ x.__hash__() <==> hash(x) """ cdef int i
def __len__(ETuple self): """ x.__len__() <==> len(x)
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e=ETuple([1,0,2,0,3]) sage: len(e) 5 """
def __contains__(ETuple self, elem): """ x.__contains__(n) <==> n in x
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple({int(1):int(2)}, int(3)); e (0, 2, 0) sage: 1 in e False sage: 2 in e True """ return self._length > self._nonzero
def __richcmp__(ETuple self, ETuple other, op): """ EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: ETuple([1,1,0])<ETuple([1,1,0]) False sage: ETuple([1,1,0])<ETuple([1,0,0]) False sage: ETuple([1,1,0])<ETuple([1,2,0]) True sage: ETuple([1,1,0])<ETuple([1,-1,0]) False sage: ETuple([0,-2,0])<ETuple([1,-1,0]) True sage: ETuple([1,1,0])>ETuple([1,1,0]) False sage: ETuple([1,1,0])>ETuple([1,0,0]) True sage: ETuple([1,1,0])>ETuple([1,2,0]) False sage: ETuple([1,1,0])>ETuple([1,-1,0]) True sage: ETuple([0,-2,0])>ETuple([1,-1,0]) False """
# the rest of these are not particularly fast
if op == Py_LE: # <= return tuple(self) <= tuple(other)
if op == Py_NE: # != return tuple(self) != tuple(other)
if op == Py_GE: # >= return tuple(self) >= tuple(other)
def __iter__(ETuple self): """ x.__iter__() <==> iter(x) """ cdef size_t ind # this is not particularly fast, but I doubt many people care # if you do, feel free to tweak!
def __str__(ETuple self):
def __repr__(ETuple self):
def __reduce__(ETuple self): """ EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,1,0]) sage: bool(e == loads(dumps(e))) True """ cdef size_t ind # this is not particularly fast, but I doubt many people care # if you do, feel free to tweak!
# additional methods
cpdef ETuple eadd(ETuple self, ETuple other): """ Vector addition of ``self`` with ``other``.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,0,2]) sage: f = ETuple([0,1,1]) sage: e.eadd(f) (1, 1, 3)
Verify that :trac:`6428` has been addressed::
sage: R.<y, z> = Frac(QQ['x'])[] sage: type(y) <class 'sage.rings.polynomial.multi_polynomial_element.MPolynomial_polydict'> sage: y^(2^32) Traceback (most recent call last): ... OverflowError: exponent overflow (2147483648) """ raise ArithmeticError
cdef size_t index cdef int exp1 cdef int exp2 cdef int s # sum # Check for overflow and underflow
cpdef ETuple eadd_p(ETuple self, int other, int pos): """ Add ``other`` to ``self`` at position ``pos``.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,0,2]) sage: e.eadd_p(5, 1) (1, 5, 2) sage: e = ETuple([0]*7) sage: e.eadd_p(5,4) (0, 0, 0, 0, 5, 0, 0)
sage: ETuple([0,1]).eadd_p(1, 0) == ETuple([1,1]) True
""" cdef int new_value raise ValueError("pos must be between 0 and %s" % self._length)
new_value = self._data[2*index+1] + other if new_value != 0: result._data[2*rindex] = pos result._data[2*rindex+1] = new_value else: result._nonzero -= 1 rindex -= 1 need_to_add = 0 else:
cpdef ETuple esub(ETuple self, ETuple other): """ Vector subtraction of ``self`` with ``other``.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,0,2]) sage: f = ETuple([0,1,1]) sage: e.esub(f) (1, -1, 1) """ raise ArithmeticError
cdef size_t index cdef int exp1 cdef int exp2 cdef int d # difference # Check for overflow and underflow raise OverflowError("Exponent overflow (%s)." % (int(exp1)-int(exp2)))
cpdef ETuple emul(ETuple self, int factor): """ Scalar Vector multiplication of ``self``.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,0,2]) sage: e.emul(2) (2, 0, 4) """ cdef size_t ind else:
cpdef ETuple emax(ETuple self, ETuple other): """ Vector of maximum of components of ``self`` and ``other``.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,0,2]) sage: f = ETuple([0,1,1]) sage: e.emax(f) (1, 1, 2) sage: e = ETuple((1,2,3,4)) sage: f = ETuple((4,0,2,1)) sage: f.emax(e) (4, 2, 3, 4) sage: e = ETuple((1,-2,-2,4)) sage: f = ETuple((4,0,0,0)) sage: f.emax(e) (4, 0, 0, 4) sage: f.emax(e).nonzero_positions() [0, 3] """ raise ArithmeticError
cdef size_t index cdef int exp1 cdef int exp2
cpdef ETuple emin(ETuple self, ETuple other): """ Vector of minimum of components of ``self`` and ``other``.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,0,2]) sage: f = ETuple([0,1,1]) sage: e.emin(f) (0, 0, 1) sage: e = ETuple([1,0,-1]) sage: f = ETuple([0,-2,1]) sage: e.emin(f) (0, -2, -1) """ raise ArithmeticError
cdef size_t index cdef int exp1 cdef int exp2
cpdef bint is_constant(ETuple self): """ Return if all exponents are zero in the tuple.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,0,2]) sage: e.is_constant() False sage: e = ETuple([0,0]) sage: e.is_constant() True """
cpdef list nonzero_positions(ETuple self, bint sort=False): """ Return the positions of non-zero exponents in the tuple.
INPUT:
- ``sort`` -- (default: ``False``) if ``True`` a sorted list is returned; if ``False`` an unsorted list is returned
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,0,2]) sage: e.nonzero_positions() [0, 2] """ cdef size_t ind
cpdef common_nonzero_positions(ETuple self, ETuple other, bint sort=False): """ Returns an optionally sorted list of non zero positions either in self or other, i.e. the only positions that need to be considered for any vector operation.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,0,2]) sage: f = ETuple([0,0,1]) sage: e.common_nonzero_positions(f) {0, 2} sage: e.common_nonzero_positions(f, sort=True) [0, 2] """ # TODO: we should probably make a fast version of this! else:
cpdef list nonzero_values(ETuple self, bint sort=True): """ Return the non-zero values of the tuple.
INPUT:
- ``sort`` -- (default: ``True``) if ``True`` the values are sorted by their indices; otherwise the values are returned unsorted
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([2,0,1]) sage: e.nonzero_values() [2, 1] sage: f = ETuple([0,-1,1]) sage: f.nonzero_values(sort=True) [-1, 1] """ cdef size_t ind
cpdef ETuple reversed(ETuple self): """ Return the reversed ETuple of ``self``.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,2,3]) sage: e.reversed() (3, 2, 1) """ cdef size_t ind
def sparse_iter(ETuple self): """ Iterator over the elements of ``self`` where the elements are returned as ``(i, e)`` where ``i`` is the position of ``e`` in the tuple.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([1,0,2,0,3]) sage: list(e.sparse_iter()) [(0, 1), (2, 2), (4, 3)] """ cdef size_t ind
def combine_to_positives(ETuple self, ETuple other): """ Given a pair of ETuples (self, other), returns a triple of ETuples (a, b, c) so that self = a + b, other = a + c and b and c have all positive entries.
EXAMPLES::
sage: from sage.rings.polynomial.polydict import ETuple sage: e = ETuple([-2,1,-5, 3, 1,0]) sage: f = ETuple([1,-3,-3,4,0,2]) sage: e.combine_to_positives(f) ((-2, -3, -5, 3, 0, 0), (0, 4, 0, 0, 1, 0), (3, 0, 2, 1, 0, 2)) """
def make_PolyDict(data):
def make_ETuple(data, length): |