Exemple #1
0
def _get_base_ring(ring, var_name="d"):
    r"""
    Return the base ring of the given ``ring``:

    If ``ring`` is of the form ``FractionField(PolynomialRing(R,'d'))``:
    Return ``R``.

    If ``ring`` is of the form ``FractionField(R)``:
    Return ``R``.

    If ``ring`` is of the form ``PolynomialRing(R,'d')``:
    Return ``R``.

    Otherwise return ``ring``.

    The base ring is used in the construction of the correponding
    ``FormsRing`` or ``FormsSpace``. In particular in the construction
    of holomorphic forms of degree (0, 1). For (binary)
    operations a general ring element is considered (coerced to)
    a (constant) holomorphic form of degree (0, 1)
    whose construction should be based on the returned base ring
    (and not on ``ring``!).

    If ``var_name`` (default: "d") is specified then this variable
    name is used for the polynomial ring.

    EXAMPLES::

        sage: from sage.modular.modform_hecketriangle.functors import _get_base_ring
        sage: _get_base_ring(ZZ) == ZZ
        True
        sage: _get_base_ring(QQ) == ZZ
        True
        sage: _get_base_ring(PolynomialRing(CC, 'd')) == CC
        True
        sage: _get_base_ring(PolynomialRing(QQ, 'd')) == ZZ
        True
        sage: _get_base_ring(FractionField(PolynomialRing(CC, 'd'))) == CC
        True
        sage: _get_base_ring(FractionField(PolynomialRing(QQ, 'd'))) == ZZ
        True
        sage: _get_base_ring(PolynomialRing(QQ, 'x')) == PolynomialRing(QQ, 'x')
        True
    """

    #from sage.rings.fraction_field import is_FractionField
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    from sage.categories.pushout import FractionField as FractionFieldFunctor

    base_ring = ring
    #if (is_FractionField(base_ring)):
    #    base_ring = base_ring.base()
    if (base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor()):
        base_ring = base_ring.construction()[1]
    if (is_PolynomialRing(base_ring) and base_ring.ngens()==1 and base_ring.variable_name()==var_name):
        base_ring = base_ring.base()
    if (base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor()):
        base_ring = base_ring.construction()[1]

    return base_ring
Exemple #2
0
    def residue_ring(self):
        r"""
        Return the residue field of this valuation.

        EXAMPLES::

            sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone
            sage: K = QQ
            sage: R.<t> = K[]
            sage: L.<t> = K.extension(t^2 + 1)
            sage: v = pAdicValuation(QQ, 2)
            sage: w = v.extension(L)
            sage: w.residue_ring()
            Finite Field of size 2

        """
        R = self._initial_approximation.residue_ring()
        from sage.categories.fields import Fields
        if R in Fields():
            # the approximation ends in v(phi)=infty
            return R
        else:
            from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
            assert(is_PolynomialRing(R))
            return R.base_ring()
Exemple #3
0
def _get_base_ring(ring, var_name="d"):
    r"""
    Return the base ring of the given ``ring``:

    If ``ring`` is of the form ``FractionField(PolynomialRing(R,'d'))``:
    Return ``R``.

    If ``ring`` is of the form ``FractionField(R)``:
    Return ``R``.

    If ``ring`` is of the form ``PolynomialRing(R,'d')``:
    Return ``R``.

    Otherwise return ``ring``.

    The base ring is used in the construction of the corresponding
    ``FormsRing`` or ``FormsSpace``. In particular in the construction
    of holomorphic forms of degree (0, 1). For (binary)
    operations a general ring element is considered (coerced to)
    a (constant) holomorphic form of degree (0, 1)
    whose construction should be based on the returned base ring
    (and not on ``ring``!).

    If ``var_name`` (default: "d") is specified then this variable
    name is used for the polynomial ring.

    EXAMPLES::

        sage: from sage.modular.modform_hecketriangle.functors import _get_base_ring
        sage: _get_base_ring(ZZ) == ZZ
        True
        sage: _get_base_ring(QQ) == ZZ
        True
        sage: _get_base_ring(PolynomialRing(CC, 'd')) == CC
        True
        sage: _get_base_ring(PolynomialRing(QQ, 'd')) == ZZ
        True
        sage: _get_base_ring(FractionField(PolynomialRing(CC, 'd'))) == CC
        True
        sage: _get_base_ring(FractionField(PolynomialRing(QQ, 'd'))) == ZZ
        True
        sage: _get_base_ring(PolynomialRing(QQ, 'x')) == PolynomialRing(QQ, 'x')
        True
    """

    #from sage.rings.fraction_field import is_FractionField
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    from sage.categories.pushout import FractionField as FractionFieldFunctor

    base_ring = ring
    #if (is_FractionField(base_ring)):
    #    base_ring = base_ring.base()
    if (base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor()):
        base_ring = base_ring.construction()[1]
    if (is_PolynomialRing(base_ring) and base_ring.ngens()==1 and base_ring.variable_name()==var_name):
        base_ring = base_ring.base()
    if (base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor()):
        base_ring = base_ring.construction()[1]

    return base_ring
    def create_key(self, domain, v = None):
        r"""
        Normalize and check the parameters to create a Gauss valuation.

        TESTS::

            sage: v = QQ.valuation(2)
            sage: R.<x> = ZZ[]
            sage: GaussValuation.create_key(R, v)
            Traceback (most recent call last):
            ...
            ValueError: the domain of v must be the base ring of domain but 2-adic valuation is not defined over Integer Ring but over Rational Field

        """
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if not is_PolynomialRing(domain):
            raise TypeError("GaussValuations can only be created over polynomial rings but %r is not a polynomial ring"%(domain,))
        if not domain.ngens() == 1:
            raise NotImplementedError("domain must be univariate but %r is not univariate"%(domain,))

        if v is None:
            v = domain.base_ring().valuation()

        if not v.domain() is domain.base_ring():
            raise ValueError("the domain of v must be the base ring of domain but %r is not defined over %r but over %r"%(v, domain.base_ring(), v.domain()))
        if not v.is_discrete_valuation():
            raise ValueError("v must be a discrete valuation but %r is not"%(v,))

        return (domain, v)
    def __init__(self, coeff_ring=ZZ, group='Sp(4,Z)', weights='even', degree=2, default_prec=SMF_DEFAULT_PREC):
        r"""
        Initialize an algebra of Siegel modular forms of degree ``degree`` 
        with coefficients in ``coeff_ring``, on the group ``group``.  
        If ``weights`` is 'even', then only forms of even weights are 
        considered; if ``weights`` is 'all', then all forms are 
        considered.

        EXAMPLES::

            sage: A = SiegelModularFormsAlgebra(QQ)
            sage: B = SiegelModularFormsAlgebra(ZZ)
            sage: A._coerce_map_from_(B)
            True                                                                                                      
            sage: B._coerce_map_from_(A)
            False                                                                                                                                            
            sage: A._coerce_map_from_(ZZ)
            True   
        """
        self.__coeff_ring = coeff_ring
        self.__group = group
        self.__weights = weights
        self.__degree = degree
        self.__default_prec = default_prec
        R = coeff_ring
        from sage.algebras.all import GroupAlgebra
        if isinstance(R, GroupAlgebra):
            R = R.base_ring()
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(R):
            self.__base_ring = R.base_ring()
        else:
            self.__base_ring = R
        from sage.categories.all import Algebras
        Algebra.__init__(self, base=self.__base_ring, category=Algebras(self.__base_ring))
Exemple #6
0
    def __init__(self, parent, phi):
        r"""
        TESTS::

            sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone
            sage: R.<x> = QQ[]
            sage: v = GaussValuation(R, pAdicValuation(QQ, 7))
            sage: isinstance(v, DevelopingValuation)
            True

        """
        DiscretePseudoValuation.__init__(self, parent)

        domain = parent.domain()
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if not is_PolynomialRing(domain) or not domain.ngens() == 1:
            raise TypeError(
                "domain must be a univariate polynomial ring but %r is not" %
                (domain, ))

        phi = domain.coerce(phi)
        if phi.is_constant() or not phi.is_monic():
            raise ValueError(
                "phi must be a monic non-constant polynomial but %r is not" %
                (phi, ))

        self._phi = phi
Exemple #7
0
    def _coerce_map_from_(self, S):
        """
        A coercion from `S` exists, if `S` coerces into ``self``'s base ring,
        or if `S` is a univariate polynomial or power series ring with the
        same variable name as self, defined over a base ring that coerces into
        ``self``'s base ring.

        EXAMPLES::

            sage: A = GF(17)[['x']]
            sage: A.has_coerce_map_from(ZZ)  # indirect doctest
            True
            sage: A.has_coerce_map_from(ZZ['x'])
            True
            sage: A.has_coerce_map_from(ZZ['y'])
            False
            sage: A.has_coerce_map_from(ZZ[['x']])
            True

        """
        if self.base_ring().has_coerce_map_from(S):
            return True
        if (is_PolynomialRing(S) or is_PowerSeriesRing(S)) and self.base_ring().has_coerce_map_from(S.base_ring()) \
           and self.variable_names()==S.variable_names():
            return True
    def _coerce_map_from_(self, P):
        """
        Return a coercion map from `P` to ``self``, or True, or None.

        The following rings admit a coercion map to the Laurent series
        ring `A((t))`:

        - any ring that admits a coercion map to `A` (including `A`
          itself);

        - any Laurent series ring, power series ring or polynomial
          ring in the variable `t` over a ring admitting a coercion
          map to `A`.

        EXAMPLES::

            sage: S.<t> = LaurentSeriesRing(ZZ)
            sage: S.has_coerce_map_from(ZZ)
            True
            sage: S.has_coerce_map_from(PolynomialRing(ZZ, 't'))
            True
            sage: S.has_coerce_map_from(LaurentPolynomialRing(ZZ, 't'))
            True
            sage: S.has_coerce_map_from(PowerSeriesRing(ZZ, 't'))
            True
            sage: S.has_coerce_map_from(S)
            True

            sage: S.has_coerce_map_from(QQ)
            False
            sage: S.has_coerce_map_from(PolynomialRing(QQ, 't'))
            False
            sage: S.has_coerce_map_from(LaurentPolynomialRing(QQ, 't'))
            False
            sage: S.has_coerce_map_from(PowerSeriesRing(QQ, 't'))
            False
            sage: S.has_coerce_map_from(LaurentSeriesRing(QQ, 't'))
            False

            sage: R.<t> = LaurentSeriesRing(QQ['x'])
            sage: R.has_coerce_map_from(QQ[['t']])
            True
            sage: R.has_coerce_map_from(QQ['t'])
            True
            sage: R.has_coerce_map_from(ZZ['x']['t'])
            True
            sage: R.has_coerce_map_from(ZZ['t']['x'])
            False
            sage: R.has_coerce_map_from(ZZ['x'])
            True
        """
        A = self.base_ring()
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        from sage.rings.power_series_ring import is_PowerSeriesRing
        from sage.rings.polynomial.laurent_polynomial_ring import is_LaurentPolynomialRing
        if ((is_LaurentSeriesRing(P) or is_LaurentPolynomialRing(P)
             or is_PowerSeriesRing(P) or is_PolynomialRing(P))
                and P.variable_name() == self.variable_name()
                and A.has_coerce_map_from(P.base_ring())):
            return True
Exemple #9
0
    def _coerce_map_from_(self, S):
        """
        A coercion from `S` exists, if `S` coerces into ``self``'s base ring,
        or if `S` is a univariate polynomial or power series ring with the
        same variable name as self, defined over a base ring that coerces into
        ``self``'s base ring.

        EXAMPLES::

            sage: A = GF(17)[['x']]
            sage: A.has_coerce_map_from(ZZ)  # indirect doctest
            True
            sage: A.has_coerce_map_from(ZZ['x'])
            True
            sage: A.has_coerce_map_from(ZZ['y'])
            False
            sage: A.has_coerce_map_from(ZZ[['x']])
            True

        """
        if self.base_ring().has_coerce_map_from(S):
            return True
        if (is_PolynomialRing(S) or is_PowerSeriesRing(S)) and self.base_ring().has_coerce_map_from(S.base_ring()) \
           and self.variable_names()==S.variable_names():
            return True
    def __init__(self, parent, phi):
        r"""
        TESTS::

            sage: R.<x> = QQ[]
            sage: v = GaussValuation(R, QQ.valuation(7))
            sage: from sage.rings.valuation.developing_valuation import DevelopingValuation
            sage: isinstance(v, DevelopingValuation)
            True

        """
        DiscretePseudoValuation.__init__(self, parent)

        domain = parent.domain()
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if not is_PolynomialRing(domain) or not domain.ngens() == 1:
            raise TypeError(
                "domain must be a univariate polynomial ring but %r is not" %
                (domain, ))

        phi = domain.coerce(phi)
        if phi.is_constant() or not phi.is_monic():
            raise ValueError(
                "phi must be a monic non-constant polynomial but %r is not" %
                (phi, ))

        self._phi = phi
Exemple #11
0
    def create_key(self, domain, v = None):
        r"""
        Normalize and check the parameters to create a Gauss valuation.

        TESTS::

            sage: v = QQ.valuation(2)
            sage: R.<x> = ZZ[]
            sage: GaussValuation.create_key(R, v)
            Traceback (most recent call last):
            ...
            ValueError: the domain of v must be the base ring of domain but 2-adic valuation is not defined over Integer Ring but over Rational Field

        """
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if not is_PolynomialRing(domain):
            raise TypeError("GaussValuations can only be created over polynomial rings but %r is not a polynomial ring"%(domain,))
        if not domain.ngens() == 1:
            raise NotImplementedError("domain must be univariate but %r is not univariate"%(domain,))

        if v is None:
            v = domain.base_ring().valuation()

        if not v.domain() is domain.base_ring():
            raise ValueError("the domain of v must be the base ring of domain but %r is not defined over %r but over %r"%(v, domain.base_ring(), v.domain()))
        if not v.is_discrete_valuation():
            raise ValueError("v must be a discrete valuation but %r is not"%(v,))

        return (domain, v)
Exemple #12
0
    def extensions(self, ring):
        r"""
        Return the extensions of this valuation to ``ring``.

        EXAMPLES::

            sage: v = GaussianIntegers().valuation(2)
            sage: u = v._base_valuation
            sage: u.extensions(QQ['x'])
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 , … ]]

        """
        if self.domain() is ring:
            return [self]
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and self.domain().base_ring().is_subring(
                ring.base_ring()):
            if self.domain().base_ring().fraction_field() is ring.base_ring():
                return [
                    LimitValuation(
                        self._initial_approximation.change_domain(ring),
                        self._G.change_ring(ring.base_ring()))
                ]
            else:
                # we need to recompute the mac lane approximants over this base
                # ring because it could split differently
                pass
        return super(MacLaneLimitValuation, self).extensions(ring)
    def _coerce_impl(self, f):
        """
        Return the canonical coercion of ``f`` into this multivariate power
        series ring, if one is defined, or raise a TypeError.

        The rings that canonically coerce to this multivariate power series
        ring are:

            - this ring itself

            - a polynomial or power series ring in the same variables or a
              subset of these variables (possibly empty), over any base
              ring that canonically coerces into the base ring of this ring

        EXAMPLES::

            sage: R.<t,u,v> = PowerSeriesRing(QQ); R
            Multivariate Power Series Ring in t, u, v over Rational Field
            sage: S1.<t,v> = PolynomialRing(ZZ); S1
            Multivariate Polynomial Ring in t, v over Integer Ring
            sage: f1 = -t*v + 2*v^2 + v; f1
            -t*v + 2*v^2 + v
            sage: R(f1)
            v - t*v + 2*v^2
            sage: S2.<u,v> = PowerSeriesRing(ZZ); S2
            Multivariate Power Series Ring in u, v over Integer Ring
            sage: f2 = -2*v^2 + 5*u*v^2 + S2.O(6); f2
            -2*v^2 + 5*u*v^2 + O(u, v)^6
            sage: R(f2)
            -2*v^2 + 5*u*v^2 + O(t, u, v)^6

            sage: R2 = R.change_ring(GF(2))
            sage: R2(f1)
            v + t*v
            sage: R2(f2)
            u*v^2 + O(t, u, v)^6

        TESTS::

            sage: R.<t,u,v> = PowerSeriesRing(QQ)
            sage: S1.<t,v> = PolynomialRing(ZZ)
            sage: f1 = S1.random_element()
            sage: g1 = R._coerce_impl(f1)
            sage: f1.parent() == R
            False
            sage: g1.parent() == R
            True

        """

        P = f.parent()
        if is_MPolynomialRing(P) or is_MPowerSeriesRing(P) \
               or is_PolynomialRing(P) or is_PowerSeriesRing(P):
            if set(P.variable_names()).issubset(set(self.variable_names())):
                if self.has_coerce_map_from(P.base_ring()):
                    return self(f)
        else:
            return self._coerce_try(f,[self.base_ring()])
    def _coerce_impl(self, f):
        """
        Return the canonical coercion of ``f`` into this multivariate power
        series ring, if one is defined, or raise a TypeError.

        The rings that canonically coerce to this multivariate power series
        ring are:

            - this ring itself

            - a polynomial or power series ring in the same variables or a
              subset of these variables (possibly empty), over any base
              ring that canonically coerces into the base ring of this ring

        EXAMPLES::

            sage: R.<t,u,v> = PowerSeriesRing(QQ); R
            Multivariate Power Series Ring in t, u, v over Rational Field
            sage: S1.<t,v> = PolynomialRing(ZZ); S1
            Multivariate Polynomial Ring in t, v over Integer Ring
            sage: f1 = -t*v + 2*v^2 + v; f1
            -t*v + 2*v^2 + v
            sage: R(f1)
            v - t*v + 2*v^2
            sage: S2.<u,v> = PowerSeriesRing(ZZ); S2
            Multivariate Power Series Ring in u, v over Integer Ring
            sage: f2 = -2*v^2 + 5*u*v^2 + S2.O(6); f2
            -2*v^2 + 5*u*v^2 + O(u, v)^6
            sage: R(f2)
            -2*v^2 + 5*u*v^2 + O(t, u, v)^6

            sage: R2 = R.change_ring(GF(2))
            sage: R2(f1)
            v + t*v
            sage: R2(f2)
            u*v^2 + O(t, u, v)^6

        TESTS::

            sage: R.<t,u,v> = PowerSeriesRing(QQ)
            sage: S1.<t,v> = PolynomialRing(ZZ)
            sage: f1 = S1.random_element()
            sage: g1 = R._coerce_impl(f1)
            sage: f1.parent() == R
            False
            sage: g1.parent() == R
            True

        """

        P = f.parent()
        if is_MPolynomialRing(P) or is_MPowerSeriesRing(P) \
               or is_PolynomialRing(P) or is_PowerSeriesRing(P):
            if set(P.variable_names()).issubset(set(self.variable_names())):
                if self.has_coerce_map_from(P.base_ring()):
                    return self(f)
        else:
            return self._coerce_try(f, [self.base_ring()])
Exemple #15
0
def AffineSpace(n, R=None, names='x'):
    r"""
    Return affine space of dimension ``n`` over the ring ``R``.

    EXAMPLES:

    The dimension and ring can be given in either order::

        sage: AffineSpace(3, QQ, 'x')
        Affine Space of dimension 3 over Rational Field
        sage: AffineSpace(5, QQ, 'x')
        Affine Space of dimension 5 over Rational Field
        sage: A = AffineSpace(2, QQ, names='XY'); A
        Affine Space of dimension 2 over Rational Field
        sage: A.coordinate_ring()
        Multivariate Polynomial Ring in X, Y over Rational Field

    Use the divide operator for base extension::

        sage: AffineSpace(5, names='x')/GF(17)
        Affine Space of dimension 5 over Finite Field of size 17

    The default base ring is `\ZZ`::

        sage: AffineSpace(5, names='x')
        Affine Space of dimension 5 over Integer Ring

    There is also an affine space associated to each polynomial ring::

        sage: R = GF(7)['x, y, z']
        sage: A = AffineSpace(R); A
        Affine Space of dimension 3 over Finite Field of size 7
        sage: A.coordinate_ring() is R
        True
    """
    if (is_MPolynomialRing(n) or is_PolynomialRing(n)) and R is None:
        R = n
        A = AffineSpace(R.ngens(), R.base_ring(), R.variable_names())
        A._coordinate_ring = R
        return A
    if isinstance(R, integer_types + (Integer, )):
        n, R = R, n
    if R is None:
        R = ZZ  # default is the integers
    if names is None:
        if n == 0:
            names = ''
        else:
            raise TypeError(
                "you must specify the variables names of the coordinate ring")
    names = normalize_names(n, names)
    if R in _Fields:
        if is_FiniteField(R):
            return AffineSpace_finite_field(n, R, names)
        else:
            return AffineSpace_field(n, R, names)
    return AffineSpace_generic(n, R, names)
Exemple #16
0
def _tower_variables(parent):
    result = []
    n_vars = 0
    while(is_PolynomialRing(parent) or is_MPolynomialRing(parent)):
        result += [str(gen) for gen in parent.gens()]
        n_vars += parent.ngens()
        parent = parent.base()

    return (parent,result, n_vars)
Exemple #17
0
def AffineSpace(n, R=None, names='x'):
    r"""
    Return affine space of dimension ``n`` over the ring ``R``.

    EXAMPLES:

    The dimension and ring can be given in either order::

        sage: AffineSpace(3, QQ, 'x')
        Affine Space of dimension 3 over Rational Field
        sage: AffineSpace(5, QQ, 'x')
        Affine Space of dimension 5 over Rational Field
        sage: A = AffineSpace(2, QQ, names='XY'); A
        Affine Space of dimension 2 over Rational Field
        sage: A.coordinate_ring()
        Multivariate Polynomial Ring in X, Y over Rational Field

    Use the divide operator for base extension::

        sage: AffineSpace(5, names='x')/GF(17)
        Affine Space of dimension 5 over Finite Field of size 17

    The default base ring is `\ZZ`::

        sage: AffineSpace(5, names='x')
        Affine Space of dimension 5 over Integer Ring

    There is also an affine space associated to each polynomial ring::

        sage: R = GF(7)['x, y, z']
        sage: A = AffineSpace(R); A
        Affine Space of dimension 3 over Finite Field of size 7
        sage: A.coordinate_ring() is R
        True
    """
    if (is_MPolynomialRing(n) or is_PolynomialRing(n)) and R is None:
        R = n
        A = AffineSpace(R.ngens(), R.base_ring(), R.variable_names())
        A._coordinate_ring = R
        return A
    if isinstance(R, integer_types + (Integer,)):
        n, R = R, n
    if R is None:
        R = ZZ  # default is the integers
    if names is None:
        if n == 0:
            names = ''
        else:
            raise TypeError("you must specify the variables names of the coordinate ring")
    names = normalize_names(n, names)
    if R in _Fields:
        if is_FiniteField(R):
            return AffineSpace_finite_field(n, R, names)
        else:
            return AffineSpace_field(n, R, names)
    return AffineSpace_generic(n, R, names)
Exemple #18
0
def multivariate_division_with_remainder(f, fs):
    """
    Performs multivariate division with remainder, that is, returns quotients q_1, ..., q_s and a remainder r such that
    q_1 * f_1 + ... + q_s * f_s + r = f, and no monomial in r is divisible by any of lt(f_i). Both f and all fs must
    belong to the same multivariate polynomial ring.

    Parameters
    ----------
    f : the numerator.
    fs : the list of denominators.

    Returns
    -------
    qs: the quotients.
    r: the remainder, f rem (f1, ..., fs).
    """
    poly_ring = f.parent()

    if (not is_PolynomialRing(poly_ring)) and (
            not is_MPolynomialRing(poly_ring)):
        raise TypeError('f and the fs should belong to a polynomial ring')

    base_field = poly_ring.base_ring()

    if not base_field.is_field():
        raise TypeError(
            'f and the fs should belong to a polynomial ring over a field')

    if not all([poly_ring == g.parent()] for g in fs):
        raise ValueError("All polynomials must belong to the same ring")

    r = poly_ring(0)
    p = f
    q = [poly_ring(0)] * len(fs)

    while not p.is_zero():
        any_divides = False

        for i in range(len(fs)):
            fi = fs[i]

            if fi.lt().divides(p.lt()):
                div, _ = p.lt().quo_rem(fi.lt())
                q[i] += div
                p -= div * fi

                any_divides = True
                break

        if not any_divides:
            r += p.lt()
            p -= p.lt()

    return q, r
def buchberger_algorithm(I):
    """
    Buchberger algorithm for the computation of a Groebner basis.

    Returns a list of polynomials that form a Groebner basis of the given ideal.

    Parameters
    ----------
    I: an ideal of a multivariate polynomial ring over a field.

    Returns
    -------
    The list of polynomials forming a Groebner basis.
    """
    if not is_Ideal(I):
        raise TypeError('Argument should be an ideal')

    poly_ring = I.ring()

    if (not is_PolynomialRing(poly_ring)) and (
            not is_MPolynomialRing(poly_ring)):
        raise TypeError('The ideal should be of a polynomial ring')

    base_field = I.base_ring()

    if not base_field.is_field():
        raise TypeError(
            'The ideal should be of a polynomial ring over a field')

    # Idea of the algorithm: we will check if the basis is already Groebner by checking that
    # S(gi, gj) rem (g1, ..., gs) = 0 for each pair (gi, gj). If it is not, we add that S(gi, gj) to the basis to force
    # it to be true.

    # Initialize G with the generators of the ideal
    G = list(I.basis)

    # It will finish by construction of the algorithm
    while True:
        S = []
        G.sort(reverse=True)  # Sorts with the polynomial ring ordering

        for (g1, g2) in __unordered_pairs(G):
            r = __s_polynomial(g1, g2)
            _, r = multivariate_division_with_remainder(r, G)

            if r != 0:
                S.append(r)

        # If S is empty, we already have a Groebner basis
        if not S:
            return G

        G.extend(S)
Exemple #20
0
def normalized_extended_euclidean_algorithm(f, g, normal=None):
    """
    Normalized extended euclidean Algorithm.

    Parameters
    ----------
    f : the first element, belonging to the euclidean domain R.
    g : the second element, belonging to the euclidean domain R.
    normal : a function R -> R, that returns a normal form for a given element. That is, given a, it returns a value
            normal(a) such that there exists a unit u such that a = u * normal(a). If set to None, an adequate normal
            will be generated if possible, and else a ValueError will be thrown.

    Returns
    -------
    r : a list whose nth element is the remainder of the nth step of the algorithm.
    s : a list that verifies that s[i] * f + t[i] * g = r[i].
    t : a list that verifies that s[i] * f + t[i] * g = r[i].
    q : a list whose nth element is the quotient of the nth step of the algorithm. q[0] is a dummy element.
    """

    if f.parent() is not g.parent():
        raise ValueError("Arguments should belong to the same ring")

    domain = f.parent()

    if not domain.is_euclidean_domain():
        raise ValueError("Arguments should belong to an euclidean domain")

    if normal is None:
        if domain is ZZ:
            normal = lambda z: z.abs()
        elif is_PolynomialRing(domain) and domain.base().is_field():
            normal = lambda f: f.parent().zero() if f.is_zero() else f.quo_rem(f.lc())[0]
        else:
            raise ValueError("No default implementation for normal found, a value must be provided")

    q = [domain.zero()]
    rho = [__lu(f, normal), __lu(g, normal)]
    r = [normal(f), normal(g)]
    s = [domain.one().quo_rem(rho[0])[0], domain.zero()]
    t = [domain.zero(), domain.one().quo_rem(rho[1])[0]]

    i = 1
    while r[i] != domain.zero():
        q.append(r[i - 1].quo_rem(r[i])[0])
        rho.append(__lu(r[i - 1] - q[i] * r[i], normal))
        r.append((r[i - 1] - q[i] * r[i]).quo_rem(rho[-1])[0])
        s.append((s[i - 1] - q[i] * s[i]).quo_rem(rho[-1])[0])
        t.append((t[i - 1] - q[i] * t[i]).quo_rem(rho[-1])[0])
        i += 1

    return r, s, t, q
def gcd_ufd(f, g):
    """
    GCD computing.

    Returns one gcd of two elements f, g belonging to a ring whose base ring is an Euclidean domain.

    Parameters
    ----------
    f : the first element.
    g : the second element.

    Returns
    -------
    The gcd.
    """

    if f.parent() is not g.parent():
        raise ValueError("Arguments should belong to the same ring")

    domain = f.parent()

    if not is_PolynomialRing(domain):
        raise ValueError("Arguments should be polynomials")

    base_domain = domain.base()

    if not base_domain.is_euclidean_domain():
        raise ValueError(
            "The base ring for the polynomial ring must be an Euclidean domain"
        )

    # gcd(f, 0) = f, gcd(0, g) = g
    if f == domain.zero():
        if g == domain.zero():
            return domain.zero()
        else:
            return g
    else:
        if g == domain.zero():
            return f

    # We use the well known equalities: c(gcd(f, g)) = gcd(c(f), c(g)), pp(gcd(f, g)) = gcd(pp(f), pp(g)).

    cont_f, cont_g = __poly_content(f), __poly_content(g)
    cont_result = euclidean_algorithm(cont_f, cont_g)

    pp_f, _ = f.quo_rem(cont_f)
    pp_g, _ = g.quo_rem(cont_g)
    pp_result = __gcd_ufd_primitive_polynomial(pp_f, pp_g)

    return cont_result * pp_result
Exemple #22
0
def get_integer_roots(element):
    if(not is_PolynomialRing(element.parent())):
        raise TypeError("Incompatible element to compute integer roots")
    base,deep_vars,_ = _tower_variables(element.parent().base())
    gen = str(element.parent().gens()[0])
    
    ring = element.parent().change_ring(base)
    deg = element.degree()
    p = ring.one()
    while(p.degree() < deg):
        new_ev = {var : base.random_element() for var in deep_vars}
        p = ring(element(**new_ev))
    
    pos_roots = [ZZ(root) for root in p.roots(multiplicities=False) if (root in ZZ)]
    return [rt for rt in pos_roots if element(**{gen : rt}) == 0]
Exemple #23
0
    def __reduce_solution(self, solution, syzygy):
        r'''
            Method to compute the "smallest" solution of the system.
        '''
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing 
        if(is_PolynomialRing(self.parent()) and syzygy.ncols() == 1):
            d = max(el.degree() for el in syzygy.column(0))
            p = max(el.degree() for el in solution)
            while(p >= d):
                i = 0
                while(solution[i].degree() < p): i += 1
                q,_ = self.__euclidean(solution[i], syzygy[0][i])
                solution -= syzygy*vector([q])
                p = max(el.degree() for el in solution)

        return (solution, syzygy)
    def _coerce_map_from_(self, P):
        """
        Return a coercion map from `P` to ``self``, or True, or None.

        The following rings admit a coercion map to the Laurent series
        ring `A((t))`:

        - any ring that admits a coercion map to `A` (including `A`
          itself);

        - any Laurent series ring, power series ring or polynomial
          ring in the variable `t` over a ring admitting a coercion
          map to `A`.

        EXAMPLES::

            sage: R.<t> = LaurentSeriesRing(ZZ)
            sage: S.<t> = PowerSeriesRing(QQ)
            sage: R.has_coerce_map_from(S) # indirect doctest
            False
            sage: R.has_coerce_map_from(R)
            True
            sage: R.<t> = LaurentSeriesRing(QQ['x'])
            sage: R.has_coerce_map_from(S)
            True
            sage: R.has_coerce_map_from(QQ['t'])
            True
            sage: R.has_coerce_map_from(ZZ['x']['t'])
            True
            sage: R.has_coerce_map_from(ZZ['t']['x'])
            False
            sage: R.has_coerce_map_from(ZZ['x'])
            True
        """
        A = self.base_ring()
        if A is P:
            return True
        f = A.coerce_map_from(P)
        if f is not None:
            return self.coerce_map_from(A) * f

        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        from sage.rings.power_series_ring import is_PowerSeriesRing
        if ((is_LaurentSeriesRing(P) or is_PowerSeriesRing(P) or is_PolynomialRing(P))
            and P.variable_name() == self.variable_name()
            and A.has_coerce_map_from(P.base_ring())):
            return True
Exemple #25
0
    def change_domain(self, ring):
        r"""
        Return this valuation as a valuation over ``ring``.

        EXAMPLES::

            sage: v = ZZ.valuation(2)
            sage: R.<x> = ZZ[]
            sage: w = GaussValuation(R, v)
            sage: w.change_domain(QQ['x'])
            Gauss valuation induced by 2-adic valuation

        """
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and ring.ngens() == 1:
            base_valuation = self._base_valuation.change_domain(ring.base_ring())
            return GaussValuation(self.domain().change_ring(ring.base_ring()), base_valuation)
        return super(GaussValuation_generic, self).change_domain(ring)
    def extensions(self, ring):
        r"""
        Return the extensions of this valuation to ``ring``.

        EXAMPLES::

            sage: v = ZZ.valuation(2)
            sage: R.<x> = ZZ[]
            sage: w = GaussValuation(R, v)
            sage: w.extensions(GaussianIntegers()['x'])
            [Gauss valuation induced by 2-adic valuation]

        """
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and ring.ngens() == 1:
            if self.domain().is_subring(ring):
                return [GaussValuation(ring, w) for w in self._base_valuation.extensions(ring.base_ring())]
        return super(GaussValuation_generic, self).extensions(ring)
Exemple #27
0
    def extensions(self, ring):
        r"""
        Return the extensions of this valuation to ``ring``.

        EXAMPLES::

            sage: v = ZZ.valuation(2)
            sage: R.<x> = ZZ[]
            sage: w = GaussValuation(R, v)
            sage: w.extensions(GaussianIntegers()['x'])
            [Gauss valuation induced by 2-adic valuation]

        """
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and ring.ngens() == 1:
            if self.domain().is_subring(ring):
                return [GaussValuation(ring, w) for w in self._base_valuation.extensions(ring.base_ring())]
        return super(GaussValuation_generic, self).extensions(ring)
    def change_domain(self, ring):
        r"""
        Return this valuation as a valuation over ``ring``.

        EXAMPLES::

            sage: v = ZZ.valuation(2)
            sage: R.<x> = ZZ[]
            sage: w = GaussValuation(R, v)
            sage: w.change_domain(QQ['x'])
            Gauss valuation induced by 2-adic valuation

        """
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and ring.ngens() == 1:
            base_valuation = self._base_valuation.change_domain(ring.base_ring())
            return GaussValuation(self.domain().change_ring(ring.base_ring()), base_valuation)
        return super(GaussValuation_generic, self).change_domain(ring)
Exemple #29
0
    def is_injective(self):
        r"""
        TESTS::

            sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone
            sage: QQ.coerce_map_from(ZZ).is_injective() # indirect doctest
            True

            sage: Hom(ZZ,QQ['x']).natural_map().is_injective()
            True

            sage: R.<x> = ZZ[]
            sage: R.<xbar> = R.quo(x^2+x+1)
            sage: Hom(ZZ,R).natural_map().is_injective()
            True

            sage: R.<x> = QQbar[]
            sage: R.coerce_map_from(QQbar).is_injective()
            True

        """
        from sage.categories.all import Fields, IntegralDomains
        from sage.rings.number_field.order import AbsoluteOrder
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        # this should be implemented as far down as possible
        if self.domain() in Fields(): return True
        if self.domain() == sage.all.ZZ and self.codomain().characteristic() == 0: return True
        if isinstance(self.domain(), AbsoluteOrder) and self(self.domain().gen()) != 0 and self.codomain() in IntegralDomains(): return True
        # this should be implemented somewhere else
        if is_PolynomialRing(self.codomain()) and self.codomain().base_ring() is self.domain():
            return True
        coercion = self.codomain().coerce_map_from(self.domain())
        if coercion is not None:
            try:
                return coercion.is_injective()
            except NotImplementedError:
                # PolynomialBaseringInjection does not implement is_surjective/is_injective
                if isinstance(coercion, sage.categories.map.FormalCompositeMap):
                    if all([f.is_injective() for f in list(coercion)]):
                        return True
            except AttributeError: # DefaultConvertMap_unique does not implement is_injective/surjective at all
                pass

        raise NotImplementedError
    def __init__(self,
                 coeff_ring=ZZ,
                 group='Sp(4,Z)',
                 weights='even',
                 degree=2,
                 default_prec=SMF_DEFAULT_PREC):
        r"""
        Initialize an algebra of Siegel modular forms of degree ``degree`` 
        with coefficients in ``coeff_ring``, on the group ``group``.  
        If ``weights`` is 'even', then only forms of even weights are 
        considered; if ``weights`` is 'all', then all forms are 
        considered.

        EXAMPLES::

            sage: A = SiegelModularFormsAlgebra(QQ)
            sage: B = SiegelModularFormsAlgebra(ZZ)
            sage: A._coerce_map_from_(B)
            True                                                                                                      
            sage: B._coerce_map_from_(A)
            False                                                                                                                                            
            sage: A._coerce_map_from_(ZZ)
            True   
        """
        self.__coeff_ring = coeff_ring
        self.__group = group
        self.__weights = weights
        self.__degree = degree
        self.__default_prec = default_prec
        R = coeff_ring
        from sage.algebras.all import GroupAlgebra
        if isinstance(R, GroupAlgebra):
            R = R.base_ring()
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(R):
            self.__base_ring = R.base_ring()
        else:
            self.__base_ring = R
        from sage.categories.all import Algebras
        Algebra.__init__(self,
                         base=self.__base_ring,
                         category=Algebras(self.__base_ring))
Exemple #31
0
    def restriction(self, ring):
        r"""
        Return the restriction of this valuation to ``ring``.

        EXAMPLES::

            sage: v = ZZ.valuation(2)
            sage: R.<x> = ZZ[]
            sage: w = GaussValuation(R, v)
            sage: w.restriction(ZZ)
            2-adic valuation

        """
        if ring.is_subring(self.domain().base_ring()):
            return self._base_valuation.restriction(ring)
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and ring.ngens() == 1:
            if ring.base().is_subring(self.domain().base()):
                return GaussValuation(ring, self._base_valuation.restriction(ring.base()))
        return super(GaussValuation_generic, self).restriction(ring)
    def restriction(self, ring):
        r"""
        Return the restriction of this valuation to ``ring``.

        EXAMPLES::

            sage: v = ZZ.valuation(2)
            sage: R.<x> = ZZ[]
            sage: w = GaussValuation(R, v)
            sage: w.restriction(ZZ)
            2-adic valuation

        """
        if ring.is_subring(self.domain().base_ring()):
            return self._base_valuation.restriction(ring)
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and ring.ngens() == 1:
            if ring.base().is_subring(self.domain().base()):
                return GaussValuation(ring, self._base_valuation.restriction(ring.base()))
        return super(GaussValuation_generic, self).restriction(ring)
    def base_extend(self, R):
        r"""
        Extends the base ring of the algebra ``self`` to ``R``.

        EXAMPLES::

            sage: S = SiegelModularFormsAlgebra(coeff_ring=QQ)
            sage: S.base_extend(RR)
            Algebra of Siegel modular forms of degree 2 and even weights on Sp(4,Z) over Real Field with 53 bits of precision
        """
        #B = self.base_ring()
        S = self.coeff_ring()
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(S):
            xS = S.base_extend(R)
        elif R.has_coerce_map_from(S):
            xS = R
        else:
            raise TypeError, "cannot extend to %s" %R
        return SiegelModularFormsAlgebra(coeff_ring=xS, group=self.group(), weights=self.weights(), degree=self.degree(), default_prec=self.default_prec())
Exemple #34
0
    def change_domain(self, ring):
        r"""
        Return this valuation as a valuation over ``ring``.

        EXAMPLES::

            sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone
            sage: v = pAdicValuation(ZZ, 2)
            sage: R.<x> = ZZ[]
            sage: w = GaussValuation(R, v)
            sage: w.change_domain(QQ['x'])
            Gauss valuation induced by 2-adic valuation

        """
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and ring.ngens() == 1:
            base_valuation = self._base_valuation.change_domain(
                ring.base_ring())
            return GaussValuation(self.domain().change_ring(ring.base_ring()),
                                  base_valuation)
        return super(GaussValuation_generic, self).change_domain(ring)
Exemple #35
0
    def restriction(self, ring):
        r"""
        Return the restriction of this valuation to ``ring``.

        EXAMPLES::

            sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone
            sage: v = pAdicValuation(ZZ, 2)
            sage: R.<x> = ZZ[]
            sage: w = GaussValuation(R, v)
            sage: w.restriction(ZZ)
            2-adic valuation

        """
        if ring.is_subring(self.domain().base_ring()):
            return self._base_valuation.restriction(ring)
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and ring.ngens() == 1:
            if ring.base().is_subring(self.domain().base()):
                return GaussValuation(
                    ring, self._base_valuation.restriction(ring.base()))
        return super(GaussValuation_generic, self).restriction(ring)
Exemple #36
0
    def extensions(self, ring):
        r"""
        Return the extensions of this valuation to ``ring``.

        EXAMPLES::

            sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone
            sage: v = pAdicValuation(ZZ, 2)
            sage: R.<x> = ZZ[]
            sage: w = GaussValuation(R, v)
            sage: w.extensions(GaussianIntegers()['x'])
            [Gauss valuation induced by 2-adic valuation]

        """
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and ring.ngens() == 1:
            if self.domain().is_subring(ring):
                return [
                    GaussValuation(ring, w)
                    for w in self._base_valuation.extensions(ring.base_ring())
                ]
        return super(GaussValuation_generic, self).extensions(ring)
    def __init__(self, parent, phi):
        r"""
        TESTS::

            sage: R.<x> = QQ[]
            sage: v = GaussValuation(R, QQ.valuation(7))
            sage: from sage.rings.valuation.developing_valuation import DevelopingValuation
            sage: isinstance(v, DevelopingValuation)
            True

        """
        DiscretePseudoValuation.__init__(self, parent)

        domain = parent.domain()
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if not is_PolynomialRing(domain) or not domain.ngens() == 1:
            raise TypeError("domain must be a univariate polynomial ring but %r is not"%(domain,))

        phi = domain.coerce(phi)
        if phi.is_constant() or not phi.is_monic():
            raise ValueError("phi must be a monic non-constant polynomial but %r is not"%(phi,))

        self._phi = phi
def field_format(field):
    """Print a nice representation of the given field object. This works
    correctly for number fields, but for fraction fields of polynomial
    rings we just pretend the base field are the complex numbers (for
    now)."""
    # print("debug field = {0}".format(field))
    if field == QQ:
        return ll("\\Q")
    elif is_NumberField(field):
        minpoly = field.defining_polynomial()
        g, = field.gens()
        # G, = minpoly.parent().gens()
        return (ll("K = \\Q(", g, ")") + ", where " +
                ll(g) + " has minimal polynomial " + ll(minpoly))
    elif is_FractionField(field):
        ring = field.ring_of_integers()
        if is_PolynomialRing(ring):
            return ll("\\C(", ring.gens()[0], ")")
        else:
            print("debug ring =  {0}".format(ring))
            raise UnknownField()
    else:
        raise UnknownField()
Exemple #39
0
def is_member(f, I):
    """
    Determines if the polynomial f is a member of the ideal I.

    Parameters
    ----------
    f: a polynomial of a multivariate polynomial ring over a field.
    I: an ideal of the same polynomial ring.

    Returns
    -------
    True if f is a member of the ideal I, False otherwise.
    """

    if not is_Ideal(I):
        raise TypeError('Argument should be an ideal')

    poly_ring = I.ring()

    if not f.parent() == poly_ring:
        raise ValueError('f must belong to the same polynomial ring that the ideal belongs to')

    if (not is_PolynomialRing(poly_ring)) and (not is_MPolynomialRing(poly_ring)):
        raise TypeError('The ideal should be of a polynomial ring')

    base_field = I.base_ring()

    if not base_field.is_field():
        raise TypeError('The ideal should be of a polynomial ring over a field')

    # Computation of a groebner basis
    G = buchberger_algorithm(I)

    # Since groebner basis have a unique remainder with multivariate division, f belongs to I <=> f rem G == 0
    # Formalized on theorem 21.28 of Modern Computer Algebra
    _, rem = multivariate_division_with_remainder(f, G)
    return rem == 0
    def residue_ring(self):
        r"""
        Return the residue ring of this valuation, which is always a field.

        EXAMPLES::

            sage: K = QQ
            sage: R.<t> = K[]
            sage: L.<t> = K.extension(t^2 + 1)
            sage: v = QQ.valuation(2)
            sage: w = v.extension(L)
            sage: w.residue_ring()
            Finite Field of size 2

        """
        R = self._initial_approximation.residue_ring()
        from sage.categories.fields import Fields
        if R in Fields():
            # the approximation ends in v(phi)=infty
            return R
        else:
            from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
            assert(is_PolynomialRing(R))
            return R.base_ring()
    def base_extend(self, R):
        r"""
        Extends the base ring of the algebra ``self`` to ``R``.

        EXAMPLES::

            sage: S = SiegelModularFormsAlgebra(coeff_ring=QQ)
            sage: S.base_extend(RR)
            Algebra of Siegel modular forms of degree 2 and even weights on Sp(4,Z) over Real Field with 53 bits of precision
        """
        #B = self.base_ring()
        S = self.coeff_ring()
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(S):
            xS = S.base_extend(R)
        elif R.has_coerce_map_from(S):
            xS = R
        else:
            raise TypeError, "cannot extend to %s" % R
        return SiegelModularFormsAlgebra(coeff_ring=xS,
                                         group=self.group(),
                                         weights=self.weights(),
                                         degree=self.degree(),
                                         default_prec=self.default_prec())
Exemple #42
0
    def residue_ring(self):
        r"""
        Return the residue ring of this valuation, which is always a field.

        EXAMPLES::

            sage: K = QQ
            sage: R.<t> = K[]
            sage: L.<t> = K.extension(t^2 + 1)
            sage: v = QQ.valuation(2)
            sage: w = v.extension(L)
            sage: w.residue_ring()
            Finite Field of size 2

        """
        R = self._initial_approximation.residue_ring()
        from sage.categories.fields import Fields
        if R in Fields():
            # the approximation ends in v(phi)=infty
            return R
        else:
            from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
            assert(is_PolynomialRing(R))
            return R.base_ring()
    def extensions(self, ring):
        r"""
        Return the extensions of this valuation to ``ring``.

        EXAMPLES::

            sage: v = GaussianIntegers().valuation(2)
            sage: u = v._base_valuation
            sage: u.extensions(QQ['x'])
            [[ Gauss valuation induced by 2-adic valuation, v(x + 1) = 1/2 , … ]]

        """
        if self.domain() is ring:
            return [self]
        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if is_PolynomialRing(ring) and self.domain().base_ring().is_subring(ring.base_ring()):
            if self.domain().base_ring().fraction_field() is ring.base_ring():
                return [LimitValuation(self._initial_approximation.change_domain(ring),
                        self._G.change_ring(ring.base_ring()))]
            else:
                # we need to recompute the mac lane approximants over this base
                # ring because it could split differently
                pass
        return super(MacLaneLimitValuation, self).extensions(ring)
Exemple #44
0
def weak_popov_form(M,ascend=True):
    """
    This function computes a weak Popov form of a matrix over a rational
    function field `k(x)`, for `k` a field.
    
    INPUT:
        
     - `M` - matrix
     
     - `ascend` - if True, rows of output matrix `W` are sorted so
       degree (= the maximum of the degrees of the elements in
       the row) increases monotonically, and otherwise degrees decrease.
     
    OUTPUT:
    
    A 3-tuple `(W,N,d)` consisting of two matrices over `k(x)` and a list
    of integers:
        
    1. `W` - matrix giving a weak the Popov form of M
    2. `N` - matrix representing row operations used to transform
       `M` to `W`
    3. `d` - degree of respective columns of W; the degree of a column is
       the maximum of the degree of its elements
    
    `N` is invertible over `k(x)`. These matrices satisfy the relation
    `N*M = W`.
    
    EXAMPLES:
        
    The routine expects matrices over the rational function field, but
    other examples below show how one can provide matrices over the ring
    of polynomials (whose quotient field is the rational function field).

    ::
            
        sage: R.<t> = GF(3)['t']
        sage: K = FractionField(R)
        sage: import sage.matrix.matrix_misc
        sage: sage.matrix.matrix_misc.weak_popov_form(matrix([[(t-1)^2/t],[(t-1)]]))
        (
        [          0]  [      t 2*t + 1]                
        [(2*t + 1)/t], [      1       2], [-Infinity, 0]
        )

    NOTES:

    See docstring for weak_popov_form method of matrices for
    more information.
    """
    # determine whether M has polynomial or rational function coefficients
    R0 = M.base_ring()

    from sage.rings.ring import is_Field

    #Compute the base polynomial ring

    if is_Field(R0):
        R = R0.base()
    else:
        R = R0
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    if not is_PolynomialRing(R):
        raise TypeError("the coefficients of M must lie in a univariate polynomial ring")

    t = R.gen()

    # calculate least-common denominator of matrix entries and clear
    # denominators. The result lies in R
    from sage.rings.arith import lcm
    from sage.matrix.constructor import matrix
    from sage.misc.functional import numerator
    if is_Field(R0):
        den = lcm([a.denominator() for a in M.list()])
        num = matrix([(lambda x : map(numerator,  x))(v) for v in map(list,(M*den).rows())])
    else:
        # No need to clear denominators
        den = R.one_element()
        num = M

    r = [list(v) for v in num.rows()]

    N = matrix(num.nrows(), num.nrows(), R(1)).rows()

    from sage.rings.infinity import Infinity
    if M.is_zero():
        return (M, matrix(N), [-Infinity for i in range(num.nrows())])

    rank = 0
    num_zero = 0            
    while rank != len(r) - num_zero:
        # construct matrix of leading coefficients
        v = []
        for w in map(list, r):
            # calculate degree of row (= max of degree of entries)
            d = max([e.numerator().degree() for e in w])

            # extract leading coefficients from current row
            x = []
            for y in w:
                if y.degree() >= d and d >= 0:   x.append(y.coeffs()[d])
                else:                            x.append(0)
            v.append(x)
        l = matrix(v)
        
        # count number of zero rows in leading coefficient matrix
        # because they do *not* contribute interesting relations
        num_zero = 0
        for v in l.rows():
            is_zero = 1
            for w in v:
                if w != 0:
                    is_zero = 0
            if is_zero == 1:
                num_zero += 1
        
        # find non-trivial relations among the columns of the
        # leading coefficient matrix
        kern = l.kernel().basis()
        rank = num.nrows() - len(kern)

        # do a row operation if there's a non-trivial relation        
        if not rank == len(r) - num_zero:
            for rel in kern:
                # find the row of num involved in the relation and of
                # maximal degree            
                indices = []
                degrees = []
                for i in range(len(rel)):
                    if rel[i] != 0:
                        indices.append(i)
                        degrees.append(max([e.degree() for e in r[i]]))
                
                # find maximum degree among rows involved in relation        
                max_deg = max(degrees)
                
                # check if relation involves non-zero rows
                if max_deg != -1:
                    i = degrees.index(max_deg)
                    rel /= rel[indices[i]]
            
                    for j in range(len(indices)):
                        if j != i:
                            # do row operation and record it
                            v = []
                            for k in range(len(r[indices[i]])):
                                v.append(r[indices[i]][k] + rel[indices[j]] * t**(max_deg-degrees[j]) * r[indices[j]][k])
                            r[indices[i]] = v

                            v = []
                            for k in range(len(N[indices[i]])):
                                v.append(N[indices[i]][k] + rel[indices[j]] * t**(max_deg-degrees[j]) * N[indices[j]][k])
                            N[indices[i]] = v
                    
                    # remaining relations (if any) are no longer valid,
                    # so continue onto next step of algorithm
                    break

    # sort the rows in order of degree
    d = []
    from sage.rings.all import infinity
    for i in range(len(r)):
        d.append(max([e.degree() for e in r[i]]))
        if d[i] < 0:
            d[i] = -infinity
        else:
            d[i] -= den.degree()
        
    for i in range(len(r)):
        for j in range(i+1,len(r)):
            if (ascend and d[i] > d[j]) or (not ascend and d[i] < d[j]):
                (r[i], r[j]) = (r[j], r[i])
                (d[i], d[j]) = (d[j], d[i])
                (N[i], N[j]) = (N[j], N[i])
                            
    # return reduced matrix and operations matrix
    return (matrix(r)/den, matrix(N), d)
Exemple #45
0
def Conic(base_field, F=None, names=None, unique=True):
    r"""
    Return the plane projective conic curve defined by ``F``
    over ``base_field``.

    The input form ``Conic(F, names=None)`` is also accepted,
    in which case the fraction field of the base ring of ``F``
    is used as base field.

    INPUT:

    - ``base_field`` -- The base field of the conic.

    - ``names`` -- a list, tuple, or comma separated string
      of three variable names specifying the names
      of the coordinate functions of the ambient
      space `\Bold{P}^3`. If not specified or read
      off from ``F``, then this defaults to ``'x,y,z'``.

    - ``F`` -- a polynomial, list, matrix, ternary quadratic form,
      or list or tuple of 5 points in the plane.

                   If ``F`` is a polynomial or quadratic form,
                   then the output is the curve in the projective plane
                   defined by ``F = 0``.

                   If ``F`` is a polynomial, then it must be a polynomial
                   of degree at most 2 in 2 variables, or a homogeneous
                   polynomial in of degree 2 in 3 variables.

                   If ``F`` is a matrix, then the output is the zero locus
                   of `(x,y,z) F (x,y,z)^t`.

                   If ``F`` is a list of coefficients, then it has
                   length 3 or 6 and gives the coefficients of
                   the monomials `x^2, y^2, z^2` or all 6 monomials
                   `x^2, xy, xz, y^2, yz, z^2` in lexicographic order.

                   If ``F`` is a list of 5 points in the plane, then the output
                   is a conic through those points.

    - ``unique`` -- Used only if ``F`` is a list of points in the plane.
      If the conic through the points is not unique, then
      raise ``ValueError`` if and only if ``unique`` is True

    OUTPUT:

    A plane projective conic curve defined by ``F`` over a field.

    EXAMPLES:

    Conic curves given by polynomials ::

        sage: X,Y,Z = QQ['X,Y,Z'].gens()
        sage: Conic(X^2 - X*Y + Y^2 - Z^2)
        Projective Conic Curve over Rational Field defined by X^2 - X*Y + Y^2 - Z^2
        sage: x,y = GF(7)['x,y'].gens()
        sage: Conic(x^2 - x + 2*y^2 - 3, 'U,V,W')
        Projective Conic Curve over Finite Field of size 7 defined by U^2 + 2*V^2 - U*W - 3*W^2

    Conic curves given by matrices ::

        sage: Conic(matrix(QQ, [[1, 2, 0], [4, 0, 0], [7, 0, 9]]), 'x,y,z')
        Projective Conic Curve over Rational Field defined by x^2 + 6*x*y + 7*x*z + 9*z^2

        sage: x,y,z = GF(11)['x,y,z'].gens()
        sage: C = Conic(x^2+y^2-2*z^2); C
        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2
        sage: Conic(C.symmetric_matrix(), 'x,y,z')
        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2

    Conics given by coefficients ::

        sage: Conic(QQ, [1,2,3])
        Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + 3*z^2
        sage: Conic(GF(7), [1,2,3,4,5,6], 'X')
        Projective Conic Curve over Finite Field of size 7 defined by X0^2 + 2*X0*X1 - 3*X1^2 + 3*X0*X2 - 2*X1*X2 - X2^2

    The conic through a set of points ::

        sage: C = Conic(QQ, [[10,2],[3,4],[-7,6],[7,8],[9,10]]); C
        Projective Conic Curve over Rational Field defined by x^2 + 13/4*x*y - 17/4*y^2 - 35/2*x*z + 91/4*y*z - 37/2*z^2
        sage: C.rational_point()
        (10 : 2 : 1)
        sage: C.point([3,4])
        (3 : 4 : 1)

        sage: a=AffineSpace(GF(13),2)
        sage: Conic([a([x,x^2]) for x in range(5)])
        Projective Conic Curve over Finite Field of size 13 defined by x^2 - y*z
    """
    if not (base_field is None or isinstance(base_field, IntegralDomain)):
        if names is None:
            names = F
        F = base_field
        base_field = None
    if isinstance(F, (list,tuple)):
        if len(F) == 1:
            return Conic(base_field, F[0], names)
        if names is None:
            names = 'x,y,z'
        if len(F) == 5:
            L=[]
            for f in F:
                if isinstance(f, SchemeMorphism_point_affine):
                    C = Sequence(f, universe = base_field)
                    if len(C) != 2:
                        raise TypeError("points in F (=%s) must be planar"%F)
                    C.append(1)
                elif isinstance(f, SchemeMorphism_point_projective_field):
                    C = Sequence(f, universe = base_field)
                elif isinstance(f, (list, tuple)):
                    C = Sequence(f, universe = base_field)
                    if len(C) == 2:
                        C.append(1)
                else:
                    raise TypeError("F (=%s) must be a sequence of planar " \
                                      "points" % F)
                if len(C) != 3:
                    raise TypeError("points in F (=%s) must be planar" % F)
                P = C.universe()
                if not isinstance(P, IntegralDomain):
                    raise TypeError("coordinates of points in F (=%s) must " \
                                     "be in an integral domain" % F)
                L.append(Sequence([C[0]**2, C[0]*C[1], C[0]*C[2], C[1]**2,
                                   C[1]*C[2], C[2]**2], P.fraction_field()))
            M=Matrix(L)
            if unique and M.rank() != 5:
                raise ValueError("points in F (=%s) do not define a unique " \
                                   "conic" % F)
            con = Conic(base_field, Sequence(M.right_kernel().gen()), names)
            con.point(F[0])
            return con
        F = Sequence(F, universe = base_field)
        base_field = F.universe().fraction_field()
        temp_ring = PolynomialRing(base_field, 3, names)
        (x,y,z) = temp_ring.gens()
        if len(F) == 3:
            return Conic(F[0]*x**2 + F[1]*y**2 + F[2]*z**2)
        if len(F) == 6:
            return Conic(F[0]*x**2 + F[1]*x*y + F[2]*x*z + F[3]*y**2 + \
                         F[4]*y*z + F[5]*z**2)
        raise TypeError("F (=%s) must be a sequence of 3 or 6" \
                         "coefficients" % F)
    if is_QuadraticForm(F):
        F = F.matrix()
    if is_Matrix(F) and F.is_square() and F.ncols() == 3:
        if names is None:
            names = 'x,y,z'
        temp_ring = PolynomialRing(F.base_ring(), 3, names)
        F = vector(temp_ring.gens()) * F * vector(temp_ring.gens())

    if not is_MPolynomial(F):
        raise TypeError("F (=%s) must be a three-variable polynomial or " \
                         "a sequence of points or coefficients" % F)

    if F.total_degree() != 2:
        raise TypeError("F (=%s) must have degree 2" % F)

    if base_field is None:
        base_field = F.base_ring()
    if not isinstance(base_field, IntegralDomain):
        raise ValueError("Base field (=%s) must be a field" % base_field)
    base_field = base_field.fraction_field()
    if names is None:
        names = F.parent().variable_names()
    pol_ring = PolynomialRing(base_field, 3, names)

    if F.parent().ngens() == 2:
        (x,y,z) = pol_ring.gens()
        F = pol_ring(F(x/z,y/z)*z**2)

    if F == 0:
        raise ValueError("F must be nonzero over base field %s" % base_field)

    if F.total_degree() != 2:
        raise TypeError("F (=%s) must have degree 2 over base field %s" % \
                          (F, base_field))

    if F.parent().ngens() == 3:
        P2 = ProjectiveSpace(2, base_field, names)
        if is_PrimeFiniteField(base_field):
            return ProjectiveConic_prime_finite_field(P2, F)
        if is_FiniteField(base_field):
            return ProjectiveConic_finite_field(P2, F)
        if is_RationalField(base_field):
            return ProjectiveConic_rational_field(P2, F)
        if is_NumberField(base_field):
            return ProjectiveConic_number_field(P2, F)
        if is_FractionField(base_field) and (is_PolynomialRing(base_field.ring()) or is_MPolynomialRing(base_field.ring())):
            return ProjectiveConic_rational_function_field(P2, F)
            
        return ProjectiveConic_field(P2, F)

    raise TypeError("Number of variables of F (=%s) must be 2 or 3" % F)
Exemple #46
0
def row_reduced_form(M,transformation=False):
    """
    This function computes a row reduced form of a matrix over a rational
    function field `k(x)`, for `k` a field.

    INPUT:

     - `M` - a matrix over `k(x)` or `k[x]` for `k` a field.
     - `transformation` - A boolean (default: `False`). If this boolean is set to `True` a second matrix is output (see OUTPUT).
     
    OUTPUT:

    If `transformation` is `False`, the output is `W`, a row reduced form of `M`.
    
    If `transformation` is `True`, this function will output a pair `(W,N)` consisting of two matrices over `k(x)`:

    1. `W` - a row reduced form of `M`.
    2. `N` - an invertible matrix over `k(x)` satisfying `NW = M`.

    EXAMPLES:

    The fuction expects matrices over the rational function field, but
    other examples below show how one can provide matrices over the ring
    of polynomials (whose quotient field is the rational function field).

    ::

        sage: R.<t> = GF(3)['t']
        sage: K = FractionField(R)
        sage: import sage.matrix.matrix_misc
        sage: sage.matrix.matrix_misc.row_reduced_form(matrix([[(t-1)^2/t],[(t-1)]]))
        [(2*t + 1)/t]
        [          0]

    The last example shows the usage of the transformation parameter.
        
    ::
        sage: Fq.<a> = GF(2^3)
        sage: Fx.<x> = Fq[]
        sage: A = matrix(Fx,[[x^2+a,x^4+a],[x^3,a*x^4]])
        sage: from sage.matrix.matrix_misc import row_reduced_form
        sage: row_reduced_form(A,transformation=True)
        (
        [(a^2 + 1)*x^3 + x^2 + a                       a]  [      1 a^2 + 1]
        [                    x^3                   a*x^4], [      0                 1]
        )
            
    NOTES:

    See docstring for row_reduced_form method of matrices for
    more information.
    """

    # determine whether M has polynomial or rational function coefficients
    R0 = M.base_ring()

    #Compute the base polynomial ring
    if R0 in _Fields:
        R = R0.base()
    else:
        R = R0
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    if not is_PolynomialRing(R) or not R.base_ring().is_field():
        raise TypeError("the coefficients of M must lie in a univariate polynomial ring over a field")

    t = R.gen()

    # calculate least-common denominator of matrix entries and clear
    # denominators. The result lies in R
    from sage.arith.all import lcm
    from sage.matrix.constructor import matrix
    from sage.misc.functional import numerator
    if R0 in _Fields:
        den = lcm([a.denominator() for a in M.list()])
        num = matrix([[numerator(_) for _ in v] for v in (M*den).rows()])
    else:
        # No need to clear denominators
        num = M

    r = [list(v) for v in num.rows()]

    if transformation:
        N = matrix(num.nrows(), num.nrows(), R(1)).rows()


    rank = 0
    num_zero = 0
    if M.is_zero():
        num_zero = len(r)
    while rank != len(r) - num_zero:
        # construct matrix of leading coefficients
        v = []
        for w in map(list, r):
            # calculate degree of row (= max of degree of entries)
            d = max([e.numerator().degree() for e in w])

            # extract leading coefficients from current row
            x = []
            for y in w:
                if y.degree() >= d and d >= 0:   x.append(y.coefficients(sparse=False)[d])
                else:                            x.append(0)
            v.append(x)
        l = matrix(v)

        # count number of zero rows in leading coefficient matrix
        # because they do *not* contribute interesting relations
        num_zero = 0
        for v in l.rows():
            is_zero = 1
            for w in v:
                if w != 0:
                    is_zero = 0
            if is_zero == 1:
                num_zero += 1

        # find non-trivial relations among the columns of the
        # leading coefficient matrix
        kern = l.kernel().basis()
        rank = num.nrows() - len(kern)

        # do a row operation if there's a non-trivial relation
        if not rank == len(r) - num_zero:
            for rel in kern:
                # find the row of num involved in the relation and of
                # maximal degree
                indices = []
                degrees = []
                for i in range(len(rel)):
                    if rel[i] != 0:
                        indices.append(i)
                        degrees.append(max([e.degree() for e in r[i]]))

                # find maximum degree among rows involved in relation
                max_deg = max(degrees)

                # check if relation involves non-zero rows
                if max_deg != -1:
                    i = degrees.index(max_deg)
                    rel /= rel[indices[i]]

                    for j in range(len(indices)):
                        if j != i:
                            # do the row operation
                            v = []
                            for k in range(len(r[indices[i]])):
                                v.append(r[indices[i]][k] + rel[indices[j]] * t**(max_deg-degrees[j]) * r[indices[j]][k])
                            r[indices[i]] = v

                            if transformation:
                                # If the user asked for it, record the row operation 
                                v = []
                                for k in range(len(N[indices[i]])):
                                    v.append(N[indices[i]][k] + rel[indices[j]] * t**(max_deg-degrees[j]) * N[indices[j]][k])
                                N[indices[i]] = v

                    # remaining relations (if any) are no longer valid,
                    # so continue onto next step of algorithm
                    break
    if is_PolynomialRing(R0):
        A = matrix(R, r)
    else:
        A = matrix(R, r)/den
    if transformation:
        return (A, matrix(N))
    else:
        return A
Exemple #47
0
    def __classcall_private__(cls, morphism_or_polys, domain=None):
        r"""
        Return the appropriate dynamical system on an affine scheme.

        TESTS::

            sage: A.<x> = AffineSpace(ZZ,1)
            sage: A1.<z> = AffineSpace(CC,1)
            sage: H = End(A1)
            sage: f2 = H([z^2+1])
            sage: f = DynamicalSystem_affine(f2, A)
            sage: f.domain() is A
            False

        ::

            sage: P1.<x,y> = ProjectiveSpace(QQ,1)
            sage: DynamicalSystem_affine([y, 2*x], domain=P1)
            Traceback (most recent call last):
            ...
            ValueError: "domain" must be an affine scheme
            sage: H = End(P1)
            sage: DynamicalSystem_affine(H([y, 2*x]))
            Traceback (most recent call last):
            ...
            ValueError: "domain" must be an affine scheme
        """
        if isinstance(morphism_or_polys, SchemeMorphism_polynomial):
            morphism = morphism_or_polys
            R = morphism.base_ring()
            polys = list(morphism)
            domain = morphism.domain()
            if not is_AffineSpace(domain) and not isinstance(domain, AlgebraicScheme_subscheme_affine):
                raise ValueError('"domain" must be an affine scheme')
            if domain != morphism_or_polys.codomain():
                raise ValueError('domain and codomain do not agree')
            if R not in Fields():
                return typecall(cls, polys, domain)
            if is_FiniteField(R):
                return DynamicalSystem_affine_finite_field(polys, domain)
            return DynamicalSystem_affine_field(polys, domain)
        elif isinstance(morphism_or_polys,(list, tuple)):
            polys = list(morphism_or_polys)
        else:
            polys = [morphism_or_polys]

        # We now arrange for all of our list entries to lie in the same ring
        # Fraction field case first
        fraction_field = False
        for poly in polys:
            P = poly.parent()
            if is_FractionField(P):
                fraction_field = True
                break
        if fraction_field:
            K = P.base_ring().fraction_field()
            # Replace base ring with its fraction field
            P = P.ring().change_ring(K).fraction_field()
            polys = [P(poly) for poly in polys]
        else:
            # If any of the list entries lies in a quotient ring, we try
            # to lift all entries to a common polynomial ring.
            quotient_ring = False
            for poly in polys:
                P = poly.parent()
                if is_QuotientRing(P):
                    quotient_ring = True
                    break
            if quotient_ring:
                polys = [P(poly).lift() for poly in polys]
            else:
                poly_ring = False
                for poly in polys:
                    P = poly.parent()
                    if is_PolynomialRing(P) or is_MPolynomialRing(P):
                        poly_ring = True
                        break
                if poly_ring:
                    polys = [P(poly) for poly in polys]

        if domain is None:
            f = polys[0]
            CR = f.parent()
            if CR is SR:
                raise TypeError("Symbolic Ring cannot be the base ring")
            if fraction_field:
                CR = CR.ring()
            domain = AffineSpace(CR)

        R = domain.base_ring()
        if R is SR:
            raise TypeError("Symbolic Ring cannot be the base ring")
        if not is_AffineSpace(domain) and not isinstance(domain, AlgebraicScheme_subscheme_affine):
            raise ValueError('"domain" must be an affine scheme')

        if R not in Fields():
            return typecall(cls, polys, domain)
        if is_FiniteField(R):
                return DynamicalSystem_affine_finite_field(polys, domain)
        return DynamicalSystem_affine_field(polys, domain)
Exemple #48
0
    def __init__(self, base_ring, name=None, default_prec=None, sparse=False,
                 use_lazy_mpoly_ring=False, category=None):
        """
        Initializes a power series ring.

        INPUT:


        -  ``base_ring`` - a commutative ring

        -  ``name`` - name of the indeterminate

        -  ``default_prec`` - the default precision

        -  ``sparse`` - whether or not power series are
           sparse

        - ``use_lazy_mpoly_ring`` - if base ring is a poly ring compute with
          multivariate polynomials instead of a univariate poly over the base
          ring. Only use this for dense power series where you won't do too
          much arithmetic, but the arithmetic you do must be fast. You must
          explicitly call ``f.do_truncation()`` on an element
          for it to truncate away higher order terms (this is called
          automatically before printing).
          
        EXAMPLES:
    
        This base class inherits from :class:`~sage.rings.ring.CommutativeRing`.
        Since :trac:`11900`, it is also initialised as such, and since :trac:`14084`
        it is actually initialised as an integral domain::
    
            sage: R.<x> = ZZ[[]]
            sage: R.category()
            Category of integral domains
            sage: TestSuite(R).run()
    
        When the base ring `k` is a field, the ring `k[[x]]` is not only a
        commutative ring, but also a complete discrete valuation ring (CDVR).
        The appropriate (sub)category is automatically set in this case::
    
            sage: k = GF(11)
            sage: R.<x> = k[[]]
            sage: R.category()
            Category of complete discrete valuation rings
            sage: TestSuite(R).run()
        """
        R = PolynomialRing(base_ring, name, sparse=sparse)
        self.__poly_ring = R
        self.__is_sparse = sparse
        if default_prec is None:
            from sage.misc.defaults import series_precision
            default_prec = series_precision()
        self.__params = (base_ring, name, default_prec, sparse)

        if use_lazy_mpoly_ring and (is_MPolynomialRing(base_ring) or \
                                    is_PolynomialRing(base_ring)):
            K = base_ring
            names = K.variable_names() + (name,)
            self.__mpoly_ring = PolynomialRing(K.base_ring(), names=names)
            assert is_MPolynomialRing(self.__mpoly_ring)
            self.Element = power_series_mpoly.PowerSeries_mpoly
        commutative_ring.CommutativeRing.__init__(self, base_ring, names=name,
                                                  category=getattr(self,'_default_category',
                                                                  _CommutativeRings))
        Nonexact.__init__(self, default_prec)
        self.__generator = self.element_class(self, R.gen(), check=True, is_gen=True)
Exemple #49
0
def gen_lattice(type='modular', n=4, m=8, q=11, seed=None,
                quotient=None, dual=False, ntl=False, lattice=False):
    """
    This function generates different types of integral lattice bases
    of row vectors relevant in cryptography.

    Randomness can be set either with ``seed``, or by using
    :func:`sage.misc.randstate.set_random_seed`.

    INPUT:

    - ``type`` -- one of the following strings
        - ``'modular'`` (default) -- A class of lattices for which
          asymptotic worst-case to average-case connections hold. For
          more refer to [A96]_.
        - ``'random'`` -- Special case of modular (n=1). A dense class
          of lattice used for testing basis reduction algorithms
          proposed by Goldstein and Mayer [GM02]_.
        - ``'ideal'`` -- Special case of modular. Allows for a more
          compact representation proposed by [LM06]_.
        - ``'cyclotomic'`` -- Special case of ideal. Allows for
          efficient processing proposed by [LM06]_.
    - ``n`` -- Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`.
      For ideal lattices this is also the degree of the quotient polynomial.
    - ``m`` -- Lattice dimension, `L \subseteq Z^m`.
    - ``q`` -- Coefficient size, `q-Z^m \subseteq L`.
    - ``seed`` -- Randomness seed.
    - ``quotient`` -- For the type ideal, this determines the quotient
      polynomial. Ignored for all other types.
    - ``dual`` -- Set this flag if you want a basis for `q-dual(L)`, for example
      for Regev's LWE bases [R05]_.
    - ``ntl`` -- Set this flag if you want the lattice basis in NTL readable
      format.
    - ``lattice`` -- Set this flag if you want a
      :class:`FreeModule_submodule_with_basis_integer` object instead
      of an integer matrix representing the basis.

    OUTPUT: ``B`` a unique size-reduced triangular (primal: lower_left,
      dual: lower_right) basis of row vectors for the lattice in question.

    EXAMPLES:

    Modular basis::

        sage: sage.crypto.gen_lattice(m=10, seed=42)
        [11  0  0  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0  0  0]
        [ 2  4  3  5  1  0  0  0  0  0]
        [ 1 -5 -4  2  0  1  0  0  0  0]
        [-4  3 -1  1  0  0  1  0  0  0]
        [-2 -3 -4 -1  0  0  0  1  0  0]
        [-5 -5  3  3  0  0  0  0  1  0]
        [-4 -3  2 -5  0  0  0  0  0  1]

    Random basis::

        sage: sage.crypto.gen_lattice(type='random', n=1, m=10, q=11^4, seed=42)
        [14641     0     0     0     0     0     0     0     0     0]
        [  431     1     0     0     0     0     0     0     0     0]
        [-4792     0     1     0     0     0     0     0     0     0]
        [ 1015     0     0     1     0     0     0     0     0     0]
        [-3086     0     0     0     1     0     0     0     0     0]
        [-5378     0     0     0     0     1     0     0     0     0]
        [ 4769     0     0     0     0     0     1     0     0     0]
        [-1159     0     0     0     0     0     0     1     0     0]
        [ 3082     0     0     0     0     0     0     0     1     0]
        [-4580     0     0     0     0     0     0     0     0     1]

    Ideal bases with quotient x^n-1, m=2*n are NTRU bases::

        sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4-1)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [ 4 -2 -3 -3  1  0  0  0]
        [-3  4 -2 -3  0  1  0  0]
        [-3 -3  4 -2  0  0  1  0]
        [-2 -3 -3  4  0  0  0  1]

    Ideal bases also work with polynomials::

        sage: R.<t> = PolynomialRing(ZZ)
        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=t^4-1)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [ 4  1  4 -3  1  0  0  0]
        [-3  4  1  4  0  1  0  0]
        [ 4 -3  4  1  0  0  1  0]
        [ 1  4 -3  4  0  0  0  1]

    Cyclotomic bases with n=2^k are SWIFFT bases::

        sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [ 4 -2 -3 -3  1  0  0  0]
        [ 3  4 -2 -3  0  1  0  0]
        [ 3  3  4 -2  0  0  1  0]
        [ 2  3  3  4  0  0  0  1]

    Dual modular bases are related to Regev's famous public-key
    encryption [R05]_::

        sage: sage.crypto.gen_lattice(type='modular', m=10, seed=42, dual=True)
        [ 0  0  0  0  0  0  0  0  0 11]
        [ 0  0  0  0  0  0  0  0 11  0]
        [ 0  0  0  0  0  0  0 11  0  0]
        [ 0  0  0  0  0  0 11  0  0  0]
        [ 0  0  0  0  0 11  0  0  0  0]
        [ 0  0  0  0 11  0  0  0  0  0]
        [ 0  0  0  1 -5 -2 -1  1 -3  5]
        [ 0  0  1  0 -3  4  1  4 -3 -2]
        [ 0  1  0  0 -4  5 -3  3  5  3]
        [ 1  0  0  0 -2 -1  4  2  5  4]

    Relation of primal and dual bases::

        sage: B_primal=sage.crypto.gen_lattice(m=10, q=11, seed=42)
        sage: B_dual=sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True)
        sage: B_dual_alt=transpose(11*B_primal.inverse()).change_ring(ZZ)
        sage: B_dual_alt.hermite_form() == B_dual.hermite_form()
        True

    TESTS:

    Test some bad quotient polynomials::

        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x))
        Traceback (most recent call last):
        ...
        TypeError: unable to convert cos(x) to an integer
        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1)
        Traceback (most recent call last):
        ...
        ValueError: ideal basis requires n = quotient.degree()
        sage: R.<u,v> = ZZ[]
        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=u+v)
        Traceback (most recent call last):
        ...
        TypeError: quotient should be a univariate polynomial

    We are testing output format choices::

        sage: sage.crypto.gen_lattice(m=10, q=11, seed=42)
        [11  0  0  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0  0  0]
        [ 2  4  3  5  1  0  0  0  0  0]
        [ 1 -5 -4  2  0  1  0  0  0  0]
        [-4  3 -1  1  0  0  1  0  0  0]
        [-2 -3 -4 -1  0  0  0  1  0  0]
        [-5 -5  3  3  0  0  0  0  1  0]
        [-4 -3  2 -5  0  0  0  0  0  1]

        sage: sage.crypto.gen_lattice(m=10, q=11, seed=42, ntl=True)
        [
        [11 0 0 0 0 0 0 0 0 0]
        [0 11 0 0 0 0 0 0 0 0]
        [0 0 11 0 0 0 0 0 0 0]
        [0 0 0 11 0 0 0 0 0 0]
        [2 4 3 5 1 0 0 0 0 0]
        [1 -5 -4 2 0 1 0 0 0 0]
        [-4 3 -1 1 0 0 1 0 0 0]
        [-2 -3 -4 -1 0 0 0 1 0 0]
        [-5 -5 3 3 0 0 0 0 1 0]
        [-4 -3 2 -5 0 0 0 0 0 1]
        ]

        sage: sage.crypto.gen_lattice(m=10, q=11, seed=42, lattice=True)
        Free module of degree 10 and rank 10 over Integer Ring
        User basis matrix:
        [ 0  0  1  1  0 -1 -1 -1  1  0]
        [-1  1  0  1  0  1  1  0  1  1]
        [-1  0  0  0 -1  1  1 -2  0  0]
        [-1 -1  0  1  1  0  0  1  1 -1]
        [ 1  0 -1  0  0  0 -2 -2  0  0]
        [ 2 -1  0  0  1  0  1  0  0 -1]
        [-1  1 -1  0  1 -1  1  0 -1 -2]
        [ 0  0 -1  3  0  0  0 -1 -1 -1]
        [ 0 -1  0 -1  2  0 -1  0  0  2]
        [ 0  1  1  0  1  1 -2  1 -1 -2]

    REFERENCES:

    .. [A96] Miklos Ajtai.
      Generating hard instances of lattice problems (extended abstract).
      STOC, pp. 99--108, ACM, 1996.

    .. [GM02] Daniel Goldstein and Andrew Mayer.
      On the equidistribution of Hecke points.
      Forum Mathematicum, 15:2, pp. 165--189, De Gruyter, 2003.

    .. [LM06] Vadim Lyubashevsky and Daniele Micciancio.
      Generalized compact knapsacks are collision resistant.
      ICALP, pp. 144--155, Springer, 2006.

    .. [R05] Oded Regev.
      On lattices, learning with errors, random linear codes, and cryptography.
      STOC, pp. 84--93, ACM, 2005.
    """
    from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
    from sage.matrix.constructor import identity_matrix, block_matrix
    from sage.matrix.matrix_space import MatrixSpace
    from sage.rings.integer_ring import IntegerRing
    if seed is not None:
        from sage.misc.randstate import set_random_seed
        set_random_seed(seed)

    if type == 'random':
        if n != 1: raise ValueError('random bases require n = 1')

    ZZ = IntegerRing()
    ZZ_q = IntegerModRing(q)
    A = identity_matrix(ZZ_q, n)

    if type == 'random' or type == 'modular':
        R = MatrixSpace(ZZ_q, m-n, n)
        A = A.stack(R.random_element())

    elif type == 'ideal':
        if quotient is None:
            raise ValueError('ideal bases require a quotient polynomial')
        try:
            quotient = quotient.change_ring(ZZ_q)
        except (AttributeError, TypeError):
            quotient = quotient.polynomial(base_ring=ZZ_q)

        P = quotient.parent()
        # P should be a univariate polynomial ring over ZZ_q
        if not is_PolynomialRing(P):
            raise TypeError("quotient should be a univariate polynomial")
        assert P.base_ring() is ZZ_q

        if quotient.degree() != n:
            raise ValueError('ideal basis requires n = quotient.degree()')
        R = P.quotient(quotient)
        for i in range(m//n):
            A = A.stack(R.random_element().matrix())

    elif type == 'cyclotomic':
        from sage.arith.all import euler_phi
        from sage.misc.functional import cyclotomic_polynomial

        # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n
        found = False
        for k in range(2*n,n,-1):
            if euler_phi(k) == n:
                found = True
                break
        if not found:
            raise ValueError("cyclotomic bases require that n "
                       "is an image of Euler's totient function")

        R = ZZ_q['x'].quotient(cyclotomic_polynomial(k, 'x'), 'x')
        for i in range(m//n):
            A = A.stack(R.random_element().matrix())

    # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2
    def minrep(a):
        if abs(a-q) < abs(a): return a-q
        else: return a
    A_prime = A[n:m].lift().apply_map(minrep)

    if not dual:
        B = block_matrix([[ZZ(q), ZZ.zero()], [A_prime, ZZ.one()] ],
                         subdivide=False)
    else:
        B = block_matrix([[ZZ.one(), -A_prime.transpose()],
            [ZZ.zero(), ZZ(q)]], subdivide=False)
        for i in range(m//2):
            B.swap_rows(i,m-i-1)

    if ntl and lattice:
        raise ValueError("Cannot specify ntl=True and lattice=True "
                         "at the same time")

    if ntl:
        return B._ntl_()
    elif lattice:
        from sage.modules.free_module_integer import IntegerLattice
        return IntegerLattice(B)
    else:
        return B
    def is_totally_ramified(self, G, include_steps=False, assume_squarefree=False):
        r"""
        Return whether ``G`` defines a single totally ramified extension of the
        completion of the domain of this valuation.

        INPUT:

        - ``G`` -- a monic squarefree polynomial over the domain of this valuation

        - ``include_steps`` -- a boolean (default: ``False``); where to include
          the valuations produced during the process of checking whether ``G``
          is totally ramified in the return value

        - ``assume_squarefree`` -- a boolean (default: ``False``); whether to
          assume that ``G`` is square-free over the completion of the domain of
          this valuation. Setting this to ``True`` can significantly improve
          the performance.

        ALGORITHM:

        This is a simplified version of :meth:`sage.rings.valuation.valuation.DiscreteValuation.mac_lane_approximants`.

        EXAMPLES::

            sage: k = Qp(5,4)
            sage: v = k.valuation()
            sage: R.<x> = k[]
            sage: G = x^2 + 1
            sage: v.is_totally_ramified(G)
            False
            sage: G = x + 1
            sage: v.is_totally_ramified(G)
            True
            sage: G = x^2 + 2
            sage: v.is_totally_ramified(G)
            False
            sage: G = x^2 + 5
            sage: v.is_totally_ramified(G)
            True
            sage: v.is_totally_ramified(G, include_steps=True)
            (True, [Gauss valuation induced by 5-adic valuation, [ Gauss valuation induced by 5-adic valuation, v((1 + O(5^4))*x) = 1/2 ]])

        We consider an extension as totally ramified if its ramification index
        matches the degree. Hence, a trivial extension is totally ramified::

            sage: R.<x> = QQ[]
            sage: v = QQ.valuation(2)
            sage: v.is_totally_ramified(x)
            True

        TESTS:

        An example that Sebastian Pauli used at Sage Days 87::

            sage: R = ZpFM(3, 20)
            sage: S.<x> = R[]
            sage: f = x^9 + 9*x^2 + 3
            sage: R.valuation().is_totally_ramified(f)
            True

        """
        R = G.parent()

        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if not is_PolynomialRing(R) or R.base_ring() is not self.domain() or not G.is_monic():
            raise ValueError("G must be a monic univariate polynomial over the domain of this valuation")
        if not assume_squarefree and not G.is_squarefree():
            raise ValueError("G must be squarefree")

        from sage.rings.valuation.gauss_valuation import GaussValuation

        steps = [ GaussValuation(R, self) ]
        while True:
            v = steps[-1]
            if v.F() > 1:
                ret = False
                break
            if v.E() == G.degree():
                ret = True
                break

            assert v(G) is not infinity
            if v.is_key(G):
                ret = False
                break

            next = v.mac_lane_step(G, assume_squarefree=True)
            if len(next)>1:
                ret = False
                break
            steps.append(next[0])

        if include_steps:
            return ret, steps
        else:
            return ret
    def is_unramified(self, G, include_steps=False, assume_squarefree=False):
        r"""
        Return whether ``G`` defines a single unramified extension of the
        completion of the domain of this valuation.

        INPUT:

        - ``G`` -- a monic squarefree polynomial over the domain of this valuation

        - ``include_steps`` -- a boolean (default: ``False``); whether to
          include the approximate valuations that were used to determine the
          result in the return value.

        - ``assume_squarefree`` -- a boolean (default: ``False``); whether to
          assume that ``G`` is square-free over the completion of the domain of
          this valuation. Setting this to ``True`` can significantly improve
          the performance.

        EXAMPLES:

        We consider an extension as unramified if its ramification index is 1.
        Hence, a trivial extension is unramified::

            sage: R.<x> = QQ[]
            sage: v = QQ.valuation(2)
            sage: v.is_unramified(x)
            True

        If ``G`` remains irreducible in reduction, then it defines an
        unramified extension::

            sage: v.is_unramified(x^2 + x + 1)
            True

        However, even if ``G`` factors, it might define an unramified
        extension::

            sage: v.is_unramified(x^2 + 2*x + 4)
            True

        """
        R = G.parent()

        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
        if not is_PolynomialRing(R) or R.base_ring() is not self.domain() or not G.is_monic():
            raise ValueError("G must be a monic univariate polynomial over the domain of this valuation")
        if not assume_squarefree and not G.is_squarefree():
            raise ValueError("G must be squarefree")

        from sage.rings.valuation.gauss_valuation import GaussValuation

        steps = [ GaussValuation(R, self) ]
        while True:
            v = steps[-1]
            if v.E() > 1:
                ret = False
                break
            if v.F() == G.degree():
                ret = True
                break

            assert v(G) is not infinity
            if v.is_key(G):
                ret = True
                break

            next = v.mac_lane_step(G, assume_squarefree=True)
            if len(next)>1:
                ret = False
                break
            steps.append(next[0])

        if include_steps:
            return ret, steps
        else:
            return ret
Exemple #52
0
def LaurentPolynomialRing(base_ring, *args, **kwds):
    r"""
    Return the globally unique univariate or multivariate Laurent polynomial
    ring with given properties and variable name or names.

    There are four ways to call the Laurent polynomial ring constructor:

    1. ``LaurentPolynomialRing(base_ring, name,    sparse=False)``
    2. ``LaurentPolynomialRing(base_ring, names,   order='degrevlex')``
    3. ``LaurentPolynomialRing(base_ring, name, n, order='degrevlex')``
    4. ``LaurentPolynomialRing(base_ring, n, name, order='degrevlex')``

    The optional arguments sparse and order *must* be explicitly
    named, and the other arguments must be given positionally.

    INPUT:

    - ``base_ring`` -- a commutative ring
    - ``name`` -- a string
    - ``names`` -- a list or tuple of names, or a comma separated string
    - ``n`` -- a positive integer
    - ``sparse`` -- bool (default: False), whether or not elements are sparse
    - ``order`` -- string or
      :class:`~sage.rings.polynomial.term_order.TermOrder`, e.g.,

        - ``'degrevlex'`` (default) -- degree reverse lexicographic
        - ``'lex'`` -- lexicographic
        - ``'deglex'`` -- degree lexicographic
        - ``TermOrder('deglex',3) + TermOrder('deglex',3)`` -- block ordering

    OUTPUT:

    ``LaurentPolynomialRing(base_ring, name, sparse=False)`` returns a
    univariate Laurent polynomial ring; all other input formats return a
    multivariate Laurent polynomial ring.

    UNIQUENESS and IMMUTABILITY: In Sage there is exactly one
    single-variate Laurent polynomial ring over each base ring in each choice
    of variable and sparseness.  There is also exactly one multivariate
    Laurent polynomial ring over each base ring for each choice of names of
    variables and term order.

    ::

        sage: R.<x,y> = LaurentPolynomialRing(QQ,2); R
        Multivariate Laurent Polynomial Ring in x, y over Rational Field
        sage: f = x^2 - 2*y^-2

    You can't just globally change the names of those variables.
    This is because objects all over Sage could have pointers to
    that polynomial ring.

    ::

        sage: R._assign_names(['z','w'])
        Traceback (most recent call last):
        ...
        ValueError: variable names cannot be changed after object creation.


    EXAMPLES:

    1. ``LaurentPolynomialRing(base_ring, name, sparse=False)``

       ::

           sage: LaurentPolynomialRing(QQ, 'w')
           Univariate Laurent Polynomial Ring in w over Rational Field

       Use the diamond brackets notation to make the variable
       ready for use after you define the ring::

           sage: R.<w> = LaurentPolynomialRing(QQ)
           sage: (1 + w)^3
           1 + 3*w + 3*w^2 + w^3

       You must specify a name::

           sage: LaurentPolynomialRing(QQ)
           Traceback (most recent call last):
           ...
           TypeError: you must specify the names of the variables

           sage: R.<abc> = LaurentPolynomialRing(QQ, sparse=True); R
           Univariate Laurent Polynomial Ring in abc over Rational Field

           sage: R.<w> = LaurentPolynomialRing(PolynomialRing(GF(7),'k')); R
           Univariate Laurent Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7

       Rings with different variables are different::

           sage: LaurentPolynomialRing(QQ, 'x') == LaurentPolynomialRing(QQ, 'y')
           False

    2. ``LaurentPolynomialRing(base_ring, names,   order='degrevlex')``

       ::

           sage: R = LaurentPolynomialRing(QQ, 'a,b,c'); R
           Multivariate Laurent Polynomial Ring in a, b, c over Rational Field

           sage: S = LaurentPolynomialRing(QQ, ['a','b','c']); S
           Multivariate Laurent Polynomial Ring in a, b, c over Rational Field

           sage: T = LaurentPolynomialRing(QQ, ('a','b','c')); T
           Multivariate Laurent Polynomial Ring in a, b, c over Rational Field

       All three rings are identical.

       ::

           sage: (R is S) and  (S is T)
           True

       There is a unique Laurent polynomial ring with each term order::

           sage: R = LaurentPolynomialRing(QQ, 'x,y,z', order='degrevlex'); R
           Multivariate Laurent Polynomial Ring in x, y, z over Rational Field
           sage: S = LaurentPolynomialRing(QQ, 'x,y,z', order='invlex'); S
           Multivariate Laurent Polynomial Ring in x, y, z over Rational Field
           sage: S is LaurentPolynomialRing(QQ, 'x,y,z', order='invlex')
           True
           sage: R == S
           False


    3. ``LaurentPolynomialRing(base_ring, name, n, order='degrevlex')``

       If you specify a single name as a string and a number of
       variables, then variables labeled with numbers are created.

       ::

           sage: LaurentPolynomialRing(QQ, 'x', 10)
           Multivariate Laurent Polynomial Ring in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 over Rational Field

           sage: LaurentPolynomialRing(GF(7), 'y', 5)
           Multivariate Laurent Polynomial Ring in y0, y1, y2, y3, y4 over Finite Field of size 7

           sage: LaurentPolynomialRing(QQ, 'y', 3, sparse=True)
           Multivariate Laurent Polynomial Ring in y0, y1, y2 over Rational Field

       By calling the
       :meth:`~sage.structure.category_object.CategoryObject.inject_variables`
       method, all those variable names are available for interactive use::

           sage: R = LaurentPolynomialRing(GF(7),15,'w'); R
           Multivariate Laurent Polynomial Ring in w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 over Finite Field of size 7
           sage: R.inject_variables()
           Defining w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14
           sage: (w0 + 2*w8 + w13)^2
           w0^2 + 4*w0*w8 + 4*w8^2 + 2*w0*w13 + 4*w8*w13 + w13^2
    """
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    from sage.rings.polynomial.multi_polynomial_ring_generic import is_MPolynomialRing

    R = PolynomialRing(base_ring, *args, **kwds)
    if R in _cache:
        return _cache[R]  # put () here to re-enable weakrefs

    if is_PolynomialRing(R):
        # univariate case
        P = LaurentPolynomialRing_univariate(R)
    else:
        assert is_MPolynomialRing(R)
        P = LaurentPolynomialRing_mpair(R)

    _cache[R] = P
    return P
Exemple #53
0
def row_reduced_form(M,transformation=False):
    """
    This function computes a row reduced form of a matrix over a rational
    function field `k(x)`, for `k` a field.

    INPUT:

     - `M` - a matrix over `k(x)` or `k[x]` for `k` a field.
     - `transformation` - A boolean (default: `False`). If this boolean is set to `True` a second matrix is output (see OUTPUT).

    OUTPUT:

    If `transformation` is `False`, the output is `W`, a row reduced form of `M`.

    If `transformation` is `True`, this function will output a pair `(W,N)` consisting of two matrices over `k(x)`:

    1. `W` - a row reduced form of `M`.
    2. `N` - an invertible matrix over `k(x)` satisfying `NW = M`.

    EXAMPLES:

    The function expects matrices over the rational function field, but
    other examples below show how one can provide matrices over the ring
    of polynomials (whose quotient field is the rational function field).

    ::

        sage: R.<t> = GF(3)['t']
        sage: K = FractionField(R)
        sage: import sage.matrix.matrix_misc
        sage: sage.matrix.matrix_misc.row_reduced_form(matrix([[(t-1)^2/t],[(t-1)]]))
        doctest:...: DeprecationWarning: Row reduced form will soon be supported only for matrices of polynomials.
        See http://trac.sagemath.org/21024 for details.
        [        0]
        [(t + 2)/t]

    The last example shows the usage of the transformation parameter.

    ::
        sage: Fq.<a> = GF(2^3)
        sage: Fx.<x> = Fq[]
        sage: A = matrix(Fx,[[x^2+a,x^4+a],[x^3,a*x^4]])
        sage: from sage.matrix.matrix_misc import row_reduced_form
        sage: row_reduced_form(A,transformation=True)
        (
        [          x^2 + a           x^4 + a]  [1 0]
        [x^3 + a*x^2 + a^2               a^2], [a 1]
        )

    NOTES:

    See docstring for row_reduced_form method of matrices for
    more information.
    """
    from sage.misc.superseded import deprecation
    deprecation(21024, "Row reduced form will soon be supported only for matrices of polynomials.")

    # determine whether M has polynomial or rational function coefficients
    R0 = M.base_ring()

    #Compute the base polynomial ring
    if R0 in _Fields:
        R = R0.base()
    else:
        R = R0
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    if not is_PolynomialRing(R) or not R.base_ring().is_field():
        raise TypeError("the coefficients of M must lie in a univariate polynomial ring over a field")

    t = R.gen()

    # calculate least-common denominator of matrix entries and clear
    # denominators. The result lies in R
    from sage.arith.all import lcm
    from sage.matrix.constructor import matrix
    from sage.misc.functional import numerator
    if R0 in _Fields:
        den = lcm([a.denominator() for a in M.list()])
        num = matrix([[numerator(_) for _ in v] for v in (M*den).rows()])
    else:
        # No need to clear denominators
        num = M

    if transformation:
        A, N = num.row_reduced_form(transformation=True)
    else:
        A = num.row_reduced_form(transformation=False)

    if not is_PolynomialRing(R0):
        A = ~den * A

    if transformation:
        return (A, N)
    else:
        return A
    def _coerce_map_from_(self, P):
        """
        The rings that canonically coerce to this multivariate power series
        ring are:

            - this ring itself

            - a polynomial or power series ring in the same variables or a
              subset of these variables (possibly empty), over any base
              ring that canonically coerces into this ring

            - any ring that coerces into the foreground polynomial ring of this ring

        EXAMPLES::

            sage: A = GF(17)[['x','y']]
            sage: A.has_coerce_map_from(ZZ)
            True
            sage: A.has_coerce_map_from(ZZ['x'])
            True
            sage: A.has_coerce_map_from(ZZ['y','x'])
            True
            sage: A.has_coerce_map_from(ZZ[['x']])
            True
            sage: A.has_coerce_map_from(ZZ[['y','x']])
            True
            sage: A.has_coerce_map_from(ZZ['x','z'])
            False
            sage: A.has_coerce_map_from(GF(3)['x','y'])
            False
            sage: A.has_coerce_map_from(Frac(ZZ['y','x']))
            False

        TESTS::

            sage: M = PowerSeriesRing(ZZ,3,'x,y,z');
            sage: M._coerce_map_from_(M)
            True
            sage: M._coerce_map_from_(M.remove_var(x))
            True
            sage: M._coerce_map_from_(PowerSeriesRing(ZZ,x))
            True
            sage: M._coerce_map_from_(PolynomialRing(ZZ,'x,z'))
            True
            sage: M._coerce_map_from_(PolynomialRing(ZZ,0,''))
            True
            sage: M._coerce_map_from_(ZZ)
            True

            sage: M._coerce_map_from_(Zmod(13))
            False
            sage: M._coerce_map_from_(PolynomialRing(ZZ,2,'x,t'))
            False
            sage: M._coerce_map_from_(PolynomialRing(Zmod(11),2,'x,y'))
            False

            sage: P = PolynomialRing(ZZ,3,'z')
            sage: H = PowerSeriesRing(P,4,'f'); H
            Multivariate Power Series Ring in f0, f1, f2, f3 over Multivariate Polynomial Ring in z0, z1, z2 over Integer Ring
            sage: H._coerce_map_from_(P)
            True
            sage: H._coerce_map_from_(P.remove_var(P.gen(1)))
            True
            sage: H._coerce_map_from_(PolynomialRing(ZZ,'z2,f0'))
            True

        """
        if is_MPolynomialRing(P) or is_MPowerSeriesRing(P) \
                   or is_PolynomialRing(P) or is_PowerSeriesRing(P):
            if set(P.variable_names()).issubset(set(self.variable_names())):
                if self.has_coerce_map_from(P.base_ring()):
                    return True

        return self._poly_ring().has_coerce_map_from(P)
Exemple #55
0
def parent_to_repr_short(P):
    r"""
    Helper method which generates a short(er) representation string
    out of a parent.

    INPUT:

    - ``P`` -- a parent.

    OUTPUT:

    A string.

    EXAMPLES::

        sage: from sage.rings.asymptotic.misc import parent_to_repr_short
        sage: parent_to_repr_short(ZZ)
        'ZZ'
        sage: parent_to_repr_short(QQ)
        'QQ'
        sage: parent_to_repr_short(SR)
        'SR'
        sage: parent_to_repr_short(ZZ['x'])
        'ZZ[x]'
        sage: parent_to_repr_short(QQ['d, k'])
        'QQ[d, k]'
        sage: parent_to_repr_short(QQ['e'])
        'QQ[e]'
        sage: parent_to_repr_short(SR[['a, r']])
        'SR[[a, r]]'
        sage: parent_to_repr_short(Zmod(3))
        'Ring of integers modulo 3'
        sage: parent_to_repr_short(Zmod(3)['g'])
        'Univariate Polynomial Ring in g over Ring of integers modulo 3'
    """
    from sage.rings.integer_ring import ZZ
    from sage.rings.rational_field import QQ
    from sage.symbolic.ring import SR
    from sage.rings.polynomial.polynomial_ring import is_PolynomialRing
    from sage.rings.polynomial.multi_polynomial_ring_generic import is_MPolynomialRing
    from sage.rings.power_series_ring import is_PowerSeriesRing
    def abbreviate(P):
        if P is ZZ:
            return 'ZZ'
        elif P is QQ:
            return 'QQ'
        elif P is SR:
            return 'SR'
        raise ValueError('Cannot abbreviate %s.' % (P,))

    poly = is_PolynomialRing(P) or is_MPolynomialRing(P)
    from sage.rings import multi_power_series_ring
    power = is_PowerSeriesRing(P) or \
            multi_power_series_ring.is_MPowerSeriesRing(P)

    if poly or power:
        if poly:
            op, cl = ('[', ']')
        else:
            op, cl = ('[[', ']]')
        try:
            s = abbreviate(P.base_ring()) + op + ', '.join(P.variable_names()) + cl
        except ValueError:
            s = str(P)
    else:
        try:
            s = abbreviate(P)
        except ValueError:
            s = str(P)

    return s
Exemple #56
0
    def __init__(self, base_ring, name=None, default_prec=None, sparse=False,
                 use_lazy_mpoly_ring=None, implementation=None,
                 category=None):
        """
        Initializes a power series ring.

        INPUT:


        -  ``base_ring`` - a commutative ring

        -  ``name`` - name of the indeterminate

        -  ``default_prec`` - the default precision

        -  ``sparse`` - whether or not power series are
           sparse

        - ``implementation`` -- either ``'poly'``, ``'mpoly'``, or
          ``'pari'``.  The default is ``'pari'`` if the base field is
          a PARI finite field, and ``'poly'`` otherwise.

        - ``use_lazy_mpoly_ring`` -- This option is deprecated; use
          ``implementation='mpoly'`` instead.

        If the base ring is a polynomial ring, then the option
        ``implementation='mpoly'`` causes computations to be done with
        multivariate polynomials instead of a univariate polynomial
        ring over the base ring.  Only use this for dense power series
        where you won't do too much arithmetic, but the arithmetic you
        do must be fast.  You must explicitly call
        ``f.do_truncation()`` on an element for it to truncate away
        higher order terms (this is called automatically before
        printing).

        EXAMPLES:
    
        This base class inherits from :class:`~sage.rings.ring.CommutativeRing`.
        Since :trac:`11900`, it is also initialised as such, and since :trac:`14084`
        it is actually initialised as an integral domain::

            sage: R.<x> = ZZ[[]]
            sage: R.category()
            Category of integral domains
            sage: TestSuite(R).run()
    
        When the base ring `k` is a field, the ring `k[[x]]` is not only a
        commutative ring, but also a complete discrete valuation ring (CDVR).
        The appropriate (sub)category is automatically set in this case::
    
            sage: k = GF(11)
            sage: R.<x> = k[[]]
            sage: R.category()
            Category of complete discrete valuation rings
            sage: TestSuite(R).run()

        It is checked that the default precision is non-negative
        (see :trac:`19409`)::

            sage: PowerSeriesRing(ZZ, 'x', default_prec=-5)
            Traceback (most recent call last):
            ...
            ValueError: default_prec (= -5) must be non-negative

        """
        if use_lazy_mpoly_ring is not None:
            deprecation(15601, 'The option use_lazy_mpoly_ring is deprecated; use implementation="mpoly" instead')

        from sage.rings.finite_rings.finite_field_pari_ffelt import FiniteField_pari_ffelt

        if implementation is None:
            if isinstance(base_ring, FiniteField_pari_ffelt):
                implementation = 'pari'
            elif use_lazy_mpoly_ring and (is_MPolynomialRing(base_ring) or
                                          is_PolynomialRing(base_ring)):
                implementation = 'mpoly'
            else:
                implementation = 'poly'

        R = PolynomialRing(base_ring, name, sparse=sparse)
        self.__poly_ring = R
        self.__is_sparse = sparse
        if default_prec is None:
            from sage.misc.defaults import series_precision
            default_prec = series_precision()
        elif default_prec < 0:
            raise ValueError("default_prec (= %s) must be non-negative"
                             % default_prec)

        if implementation == 'poly':
            self.Element = power_series_poly.PowerSeries_poly
        elif implementation == 'mpoly':
            K = base_ring
            names = K.variable_names() + (name,)
            self.__mpoly_ring = PolynomialRing(K.base_ring(), names=names)
            assert is_MPolynomialRing(self.__mpoly_ring)
            self.Element = power_series_mpoly.PowerSeries_mpoly
        elif implementation == 'pari':
            self.Element = PowerSeries_pari
        else:
            raise ValueError('unknown power series implementation: %r' % implementation)

        ring.CommutativeRing.__init__(self, base_ring, names=name,
                                      category=getattr(self, '_default_category',
                                                       _CommutativeRings))
        Nonexact.__init__(self, default_prec)
        if self.Element is PowerSeries_pari:
            self.__generator = self.element_class(self, R.gen().__pari__())
        else:
            self.__generator = self.element_class(self, R.gen(), is_gen=True)