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
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()
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))
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
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
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 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()])
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)
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)
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)
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)
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
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]
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
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)
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 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())
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)
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)
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()
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())
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 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)
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)
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
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)
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)
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
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
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)
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
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)