def normalize_coefficients(self, c): r""" If our coefficient ring is the field of fractions over a univariate polynomial ring over the rationals, then we should clear both the numerator and denominator of the denominators of their coefficients. INPUT: - ``self`` -- a Jack basis of the symmetric functions - ``c`` -- a coefficient in the base ring of ``self`` OUTPUT: - divide numerator and denominator by the greatest common divisor EXAMPLES:: sage: JP = SymmetricFunctions(FractionField(QQ['t'])).jack().P() sage: t = JP.base_ring().gen() sage: a = 2/(1/2*t+1/2) sage: JP._normalize_coefficients(a) 4/(t + 1) sage: a = 1/(1/3+1/6*t) sage: JP._normalize_coefficients(a) 6/(t + 2) sage: a = 24/(4*t^2 + 12*t + 8) sage: JP._normalize_coefficients(a) 6/(t^2 + 3*t + 2) """ BR = self.base_ring() if is_FractionField(BR) and BR.base_ring() == QQ: denom = c.denominator() numer = c.numerator() # Clear the denominators a = lcm([i.denominator() for i in denom.coefficients(sparse=False)]) b = lcm([i.denominator() for i in numer.coefficients(sparse=False)]) l = Integer(a).lcm(Integer(b)) denom *= l numer *= l # Divide through by the gcd of the numerators a = gcd([i.numerator() for i in denom.coefficients(sparse=False)]) b = gcd([i.numerator() for i in numer.coefficients(sparse=False)]) l = Integer(a).gcd(Integer(b)) denom = denom // l numer = numer // l return c.parent()(numer, denom) else: return c
def __init__(self, domain, D): """ Initialize the morphism with a domain and dictionary of specializations EXAMPLES:: sage: R.<a,c> = QQ[] sage: S.<x,y> = R[] sage: from sage.rings.polynomial.flatten import FractionSpecializationMorphism sage: phi = FractionSpecializationMorphism(Frac(S), {c:3}) sage: phi Fraction Specialization morphism: From: Fraction Field of Multivariate Polynomial Ring in x, y over Multivariate Polynomial Ring in a, c over Rational Field To: Fraction Field of Multivariate Polynomial Ring in x, y over Univariate Polynomial Ring in a over Rational Field """ if not is_FractionField(domain): raise TypeError("domain must be a fraction field") self._specialization = SpecializationMorphism(domain.base(), D) self._repr_type_str = 'Fraction Specialization' Morphism.__init__(self, domain, self._specialization.codomain().fraction_field())
def _coerce_map_from_patched(self, domain): r""" TESTS:: sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone sage: R.<x> = ZZ[] sage: S.<x> = QQ[] sage: S.quo(x^2 + 1).coerce_map_from(R.quo(x^2 + 1)).is_injective() # indirect doctest True """ from sage.rings.polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing if is_PolynomialQuotientRing(domain) and domain.modulus() == self.modulus(): if self.base().has_coerce_map_from(domain.base()): return DefaultConvertMap_unique_patched3(domain, self) from sage.rings.fraction_field import is_FractionField if is_FractionField(domain): # this should be implemented on a much higher level: # if there is a morphism R -> K then there is a morphism Frac(R) -> K if self.has_coerce_map_from(domain.base()): return True return self._coerce_map_from_original(domain)
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 _reduce_conic(self): r""" Return the reduced form of the conic, i.e. a conic with base field `K=F(t)` and coefficients `a,b,c` such that `a,b,c \in F[t]`, `\gcd(a,b)=\gcd(b,c)=\gcd(c,a)=1` and `abc` is square-free. Assumes `self` is in diagonal form. OUTPUT: A tuple (coefficients, multipliers), the coefficients of the conic in reduced form and multipliers `\lambda, \mu, \nu \in F(t)^*` such that `(x,y,z) \in F(t)` is a solution of the reduced conic if and only if `(\lambda x, \mu y, \nu z)` is a solution of `self`. ALGORITHM: The algorithm used is the algorithm ReduceConic in [HC2006]_. EXAMPLES:: sage: K.<t> = FractionField(PolynomialRing(QQ, 't')) sage: C = Conic(K, [t^2-2, 2*t^3, -2*t^3-13*t^2-2*t+18]) sage: C._reduce_conic() ([t^2 - 2, 2*t, -2*t^3 - 13*t^2 - 2*t + 18], [t, 1, t]) """ # start with removing fractions coeff = [ self.coefficients()[0], self.coefficients()[3], self.coefficients()[5] ] coeff = lcm(lcm(coeff[0].denominator(), coeff[1].denominator()), coeff[2].denominator()) * vector(coeff) # go to base ring of fraction field coeff = [self.base().base()(x) for x in coeff] coeff = vector(coeff) / gcd(coeff) # remove common divisors labda = mu = nu = 1 g1 = g2 = g3 = 0 ca, cb, cc = coeff while g1 != 1 or g2 != 1 or g3 != 1: g1 = gcd(ca, cb) ca = ca / g1 cb = cb / g1 cc = cc * g1 nu = g1 * nu g2 = gcd(ca, cc) ca = ca / g2 cc = cc / g2 cb = cb * g2 mu = g2 * mu g3 = gcd(cb, cc) cb = cb / g3 cc = cc / g3 ca = ca * g3 labda = g3 * labda coeff = [ca, cb, cc] multipliers = [labda, mu, nu] # remove squares for i, x in enumerate(coeff): if is_FractionField(x.parent()): # go to base ring of fraction field x = self.base().base()(x) try: decom = x.squarefree_decomposition() except (NotImplementedError, AttributeError): decom = x.factor() x = decom.unit() x2 = 1 for factor in decom: if factor[1] > 1: if factor[1] % 2 == 0: x2 *= factor[0]**(factor[1] // 2) else: x *= factor[0] x2 *= factor[0]**((factor[1] - 1) // 2) else: x *= factor[0] for j, y in enumerate(multipliers): if j != i: multipliers[j] = y * x2 coeff[i] = self.base_ring().base().coerce(x) return (coeff, multipliers)
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 __init__(self, domain, D): """ The Python constructor EXAMPLES:: sage: S.<x,y> = PolynomialRing(QQ) sage: D = dict({x:1}) sage: from sage.rings.polynomial.flatten import SpecializationMorphism sage: phi = SpecializationMorphism(S, D); phi Specialization morphism: From: Multivariate Polynomial Ring in x, y over Rational Field To: Univariate Polynomial Ring in y over Rational Field sage: phi(x^2 + y^2) y^2 + 1 :: sage: R.<a,b,c> = PolynomialRing(ZZ) sage: S.<x,y,z> = PolynomialRing(R) sage: from sage.rings.polynomial.flatten import SpecializationMorphism sage: xi = SpecializationMorphism(S, {a:1/2}) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer The following was fixed in :trac:`23811`:: sage: R.<c> = RR[] sage: P.<z> = AffineSpace(R, 1) sage: H = End(P) sage: f = H([z^2 + c]) sage: f.specialization({c:1}) Scheme endomorphism of Affine Space of dimension 1 over Real Field with 53 bits of precision Defn: Defined on coordinates by sending (z) to (z^2 + 1.00000000000000) """ if not is_PolynomialRing(domain) and not is_MPolynomialRing(domain): raise TypeError("domain should be a polynomial ring") # use only the generators that are in the stack somewhere, # and ignore the rest all_gens = domain.gens_dict_recursive() new_D = {} for gen in D: if str(gen) in all_gens: new_D[gen] = D[gen] D = new_D # _sub_specialization is a specialization morphism (recursive) # which is applied to the base Fraction field, or None if it's # any other base ring self._sub_specialization = None # We use this composition where "flat" is a flattened # polynomial ring. # # phi D psi # domain → flat → flat → R # │ │ │ # └─────────┴───────────────┘ # _flattening_morph _eval_morph # = phi = psi ∘ D phi = FlatteningMorphism(domain) flat = phi.codomain() base = flat.base_ring() # Change domain of D to "flat" and ensure that the values lie # in the base ring. D = {phi(k): base(D[k]) for k in D} # Construct unflattened codomain R new_vars = [] R = domain while is_PolynomialRing(R) or is_MPolynomialRing( R) or is_FractionField(R): if is_FractionField(R): # We've hit base_ring, so set _sub_specialization and exit the loop field_over = R.base() applicable_vars = { key: val for key, val in D.items() if key not in flat.gens() } # If there are any variables in D to set in _sub_specialization if applicable_vars: # Coerce the generators to be in the right ring # This un-does changing the domain of D to be in the flat base ring tmp = {} for var, val in applicable_vars.items(): for gstr, gen in field_over.gens_dict_recursive( ).items(): if str(var) == gstr: tmp[gen] = val break else: # Should have been caught earlier raise NameError( "argument " + str(var) + " is not a generator anywhere in the polynomial tower" ) applicable_vars = tmp self._sub_specialization = FractionSpecializationMorphism( R, applicable_vars) break # We're still in the polynomials, so keep track of the tower old = R.gens() new = [t for t in old if t not in D] force_multivariate = ((len(old) == 1) and is_MPolynomialRing(R)) new_vars.append((new, force_multivariate, old)) R = R.base_ring() if self._sub_specialization: # The sub_specialization range will be different # if it applied some variables from D R = self._sub_specialization.codomain().fraction_field() # Construct unflattening map psi (only defined on the variables # of "flat" which are not involved in D) psi = dict() # Reconstruct the proper domain of this morphism # based on the sub_specialization domains new_domain = R for new, force_multivariate, old in reversed(new_vars): if self._sub_specialization: if force_multivariate: new_domain = PolynomialRing(new_domain, old, len(old)) else: new_domain = PolynomialRing(new_domain, old) if not new: continue var_names = [str(var) for var in new] if force_multivariate: R = PolynomialRing(R, var_names, len(var_names)) else: R = PolynomialRing(R, var_names) # Map variables in "new" to R psi.update(zip([phi(w) for w in new], R.gens())) # Fix domain of eval_morph # (note: phi's domain is correct) if self._sub_specialization: phi_prime = FlatteningMorphism(new_domain) flat_old = flat flat = phi_prime.codomain() base_prime = flat.base_ring() D = {phi(k): base_prime(D[k]) for k in D} else: # The bottom of our tower has not changed def flat_old(x): return x # Compose D with psi vals = [] for t in flat.gens(): if t in D: vals.append(R.coerce(D[t])) else: # Make sure keys are in the old domain # or else they won't match exactly vals.append(psi[flat_old(t)]) self._flattening_morph = phi self._eval_morph = flat.hom(vals, R) self._repr_type_str = 'Specialization' Morphism.__init__(self, domain, R)
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 :: sage: R.<x,y,z> = QQ[] sage: f = DynamicalSystem_affine([x+y+z, y*z]) Traceback (most recent call last): ... ValueError: Number of polys does not match dimension of Affine Space of dimension 3 over Rational Field :: sage: A.<x,y> = AffineSpace(QQ,2) sage: f = DynamicalSystem_affine([CC.0*x^2, y^2], domain=A) Traceback (most recent call last): ... TypeError: coefficients of polynomial not in Rational Field """ 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] PR = get_coercion_model().common_parent(*polys) fraction_field = any(is_FractionField(poly.parent()) for poly in polys) if fraction_field: K = PR.base_ring().fraction_field() # Replace base ring with its fraction field PR = PR.ring().change_ring(K).fraction_field() polys = [PR(poly) for poly in polys] else: quotient_ring = any( is_QuotientRing(poly.parent()) for poly in polys) # If any of the list entries lies in a quotient ring, we try # to lift all entries to a common polynomial ring. if quotient_ring: polys = [PR(poly).lift() for poly in polys] else: polys = [PR(poly) for poly in polys] if domain is None: if PR is SR: raise TypeError("Symbolic Ring cannot be the base ring") if fraction_field: PR = PR.ring() domain = AffineSpace(PR) else: # Check if we can coerce the given polynomials over the given domain PR = domain.ambient_space().coordinate_ring() try: if fraction_field: PR = PR.fraction_field() polys = [PR(poly) for poly in polys] except TypeError: raise TypeError('coefficients of polynomial not in {}'.format( domain.base_ring())) if len(polys) != domain.ambient_space().coordinate_ring().ngens(): raise ValueError( 'Number of polys does not match dimension of {}'.format( domain)) 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 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 __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 mandelbrot_plot(f=None, **kwds): r""" Plot of the Mandelbrot set for a one parameter family of polynomial maps. The family `f_c(z)` must have parent ``R`` of the form ``R.<z,c> = CC[]``. REFERENCE: [Dev2005]_ INPUT: - ``f`` -- map (optional - default: ``z^2 + c``), polynomial family used to plot the Mandelbrot set. - ``parameter`` -- variable (optional - default: ``c``), parameter variable used to plot the Mandelbrot set. - ``x_center`` -- double (optional - default: ``-1.0``), Real part of center point. - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of center point. - ``image_width`` -- double (optional - default: ``4.0``), width of image in the complex plane. - ``max_iteration`` -- long (optional - default: ``500``), maximum number of iterations the map ``f_c(z)``. - ``pixel_count`` -- long (optional - default: ``500``), side length of image in number of pixels. - ``base_color`` -- RGB color (optional - default: ``[40, 40, 40]``) color used to determine the coloring of set. - ``level_sep`` -- long (optional - default: 1) number of iterations between each color level. - ``number_of_colors`` -- long (optional - default: 30) number of colors used to plot image. - ``interact`` -- boolean (optional - default: ``False``), controls whether plot will have interactive functionality. OUTPUT: 24-bit RGB image of the Mandelbrot set in the complex plane. EXAMPLES: :: sage: mandelbrot_plot() 500x500px 24-bit RGB image :: sage: mandelbrot_plot(pixel_count=1000) 1000x1000px 24-bit RGB image :: sage: mandelbrot_plot(x_center=-1.11, y_center=0.2283, image_width=1/128, # long time ....: max_iteration=2000, number_of_colors=500, base_color=[40, 100, 100]) 500x500px 24-bit RGB image To display an interactive plot of the Mandelbrot in the Notebook, set ``interact`` to ``True``. (This is only implemented for ``z^2 + c``):: sage: mandelbrot_plot(interact=True) interactive(children=(FloatSlider(value=0.0, description=u'Real center', max=1.0, min=-1.0, step=1e-05), FloatSlider(value=0.0, description=u'Imag center', max=1.0, min=-1.0, step=1e-05), FloatSlider(value=4.0, description=u'Width', max=4.0, min=1e-05, step=1e-05), IntSlider(value=500, description=u'Iterations', max=1000), IntSlider(value=500, description=u'Pixels', max=1000, min=10), IntSlider(value=1, description=u'Color sep', max=20, min=1), IntSlider(value=30, description=u'# Colors', min=1), ColorPicker(value='#ff6347', description=u'Base color'), Output()), _dom_classes=(u'widget-interact',)) :: sage: mandelbrot_plot(interact=True, x_center=-0.75, y_center=0.25, ....: image_width=1/2, number_of_colors=75) interactive(children=(FloatSlider(value=-0.75, description=u'Real center', max=1.0, min=-1.0, step=1e-05), FloatSlider(value=0.25, description=u'Imag center', max=1.0, min=-1.0, step=1e-05), FloatSlider(value=0.5, description=u'Width', max=4.0, min=1e-05, step=1e-05), IntSlider(value=500, description=u'Iterations', max=1000), IntSlider(value=500, description=u'Pixels', max=1000, min=10), IntSlider(value=1, description=u'Color sep', max=20, min=1), IntSlider(value=75, description=u'# Colors', min=1), ColorPicker(value='#ff6347', description=u'Base color'), Output()), _dom_classes=(u'widget-interact',)) Polynomial maps can be defined over a multivariate polynomial ring or a univariate polynomial ring tower:: sage: R.<z,c> = CC[] sage: f = z^2 + c sage: mandelbrot_plot(f) 500x500px 24-bit RGB image :: sage: B.<c> = CC[] sage: R.<z> = B[] sage: f = z^5 + c sage: mandelbrot_plot(f) 500x500px 24-bit RGB image When the polynomial is defined over a multivariate polynomial ring it is necessary to specify the parameter variable (default parameter is ``c``):: sage: R.<a,b> = CC[] sage: f = a^2 + b^3 sage: mandelbrot_plot(f, parameter=b) 500x500px 24-bit RGB image Interact functionality is not implemented for general polynomial maps:: sage: R.<z,c> = CC[] sage: f = z^3 + c sage: mandelbrot_plot(f, interact=True) Traceback (most recent call last): ... NotImplementedError: Interact only implemented for z^2 + c """ parameter = kwds.pop("parameter", None) x_center = kwds.pop("x_center", 0.0) y_center = kwds.pop("y_center", 0.0) image_width = kwds.pop("image_width", 4.0) max_iteration = kwds.pop("max_iteration", None) pixel_count = kwds.pop("pixel_count", 500) level_sep = kwds.pop("level_sep", 1) number_of_colors = kwds.pop("number_of_colors", 30) interacts = kwds.pop("interact", False) base_color = kwds.pop("base_color", Color('tomato')) # Check if user specified maximum number of iterations given_iterations = True if max_iteration is None: # Set default to 500 for z^2 + c map max_iteration = 500 given_iterations = False from ipywidgets.widgets import FloatSlider, IntSlider, ColorPicker, interact widgets = dict( x_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=x_center, description="Real center"), y_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=y_center, description="Imag center"), image_width=FloatSlider(min=EPS, max=4.0, step=EPS, value=image_width, description="Width"), max_iteration=IntSlider(min=0, max=1000, value=max_iteration, description="Iterations"), pixel_count=IntSlider(min=10, max=1000, value=pixel_count, description="Pixels"), level_sep=IntSlider(min=1, max=20, value=level_sep, description="Color sep"), color_num=IntSlider(min=1, max=100, value=number_of_colors, description="# Colors"), base_color=ColorPicker(value=Color(base_color).html_color(), description="Base color"), ) if f is None: # Quadratic map f = z^2 + c if interacts: return interact(**widgets).widget(fast_mandelbrot_plot) else: return fast_mandelbrot_plot(x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color) else: if parameter is None: c = var('c') parameter = c P = f.parent() if P.base_ring() is CC or P.base_ring() is CDF: if is_FractionField(P): raise NotImplementedError( "coefficients must be polynomials in the parameter") gen_list = list(P.gens()) parameter = gen_list.pop(gen_list.index(parameter)) variable = gen_list.pop() elif P.base_ring().base_ring() is CC or P.base_ring().base_ring( ) is CDF: if is_FractionField(P.base_ring()): raise NotImplementedError( "coefficients must be polynomials in the parameter") phi = P.flattening_morphism() f = phi(f) gen_list = list(f.parent().gens()) parameter = gen_list.pop(gen_list.index(parameter)) variable = gen_list.pop() elif P.base_ring() in FunctionFields(): raise NotImplementedError( "coefficients must be polynomials in the parameter") else: raise ValueError("base ring must be a complex field") if f == variable**2 + parameter: # Quadratic map f = z^2 + c if interacts: return interact(**widgets).widget(fast_mandelbrot_plot) else: return fast_mandelbrot_plot(x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color) else: if interacts: raise NotImplementedError( "Interact only implemented for z^2 + c") else: # Set default of max_iteration to 50 for general polynomial maps # This prevents the function from being very slow by default if not given_iterations: max_iteration = 50 # Mandelbrot of General Polynomial Map return polynomial_mandelbrot(f, parameter, x_center, y_center, \ image_width, max_iteration, pixel_count, level_sep, \ number_of_colors, base_color)
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 __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 :: sage: R.<x,y,z> = QQ[] sage: f = DynamicalSystem_affine([x+y+z, y*z]) Traceback (most recent call last): ... ValueError: Number of polys does not match dimension of Affine Space of dimension 3 over Rational Field :: sage: A.<x,y> = AffineSpace(QQ,2) sage: f = DynamicalSystem_affine([CC.0*x^2, y^2], domain=A) Traceback (most recent call last): ... TypeError: coefficients of polynomial not in Rational Field """ 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] PR = get_coercion_model().common_parent(*polys) fraction_field = any(is_FractionField(poly.parent()) for poly in polys) if fraction_field: K = PR.base_ring().fraction_field() # Replace base ring with its fraction field PR = PR.ring().change_ring(K).fraction_field() polys = [PR(poly) for poly in polys] else: quotient_ring = any(is_QuotientRing(poly.parent()) for poly in polys) # If any of the list entries lies in a quotient ring, we try # to lift all entries to a common polynomial ring. if quotient_ring: polys = [PR(poly).lift() for poly in polys] else: polys = [PR(poly) for poly in polys] if domain is None: if PR is SR: raise TypeError("Symbolic Ring cannot be the base ring") if fraction_field: PR = PR.ring() domain = AffineSpace(PR) else: # Check if we can coerce the given polynomials over the given domain PR = domain.ambient_space().coordinate_ring() try: if fraction_field: PR = PR.fraction_field() polys = [PR(poly) for poly in polys] except TypeError: raise TypeError('coefficients of polynomial not in {}'.format(domain.base_ring())) if len(polys) != domain.ambient_space().coordinate_ring().ngens(): raise ValueError('Number of polys does not match dimension of {}'.format(domain)) 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 _reduce_conic(self): r""" Return the reduced form of the conic, i.e. a conic with base field `K=F(t)` and coefficients `a,b,c` such that `a,b,c \in F[t]`, `\gcd(a,b)=\gcd(b,c)=\gcd(c,a)=1` and `abc` is square-free. Assumes `self` is in diagonal form. OUTPUT: A tuple (coefficients, multipliers), the coefficients of the conic in reduced form and multipliers `\lambda, \mu, \nu \in F(t)^*` such that `(x,y,z) \in F(t)` is a solution of the reduced conic if and only if `(\lambda x, \mu y, \nu z)` is a solution of `self`. ALGORITMH: The algorithm used is the algorithm ReduceConic in [HC2006]_. EXAMPLES:: sage: K.<t> = FractionField(PolynomialRing(QQ, 't')) sage: C = Conic(K, [t^2-2, 2*t^3, -2*t^3-13*t^2-2*t+18]) sage: C._reduce_conic() ([t^2 - 2, 2*t, -2*t^3 - 13*t^2 - 2*t + 18], [t, 1, t]) """ # start with removing fractions coeff = [self.coefficients()[0], self.coefficients()[3], self.coefficients()[5]] coeff = lcm(lcm(coeff[0].denominator(), coeff[1].denominator()), coeff[2].denominator()) * vector(coeff) # go to base ring of fraction field coeff = [self.base().base()(x) for x in coeff] coeff = vector(coeff) / gcd(coeff) # remove common divisors labda = mu = nu = 1 g1 = g2 = g3 = 0 ca, cb, cc = coeff while g1 != 1 or g2 != 1 or g3 != 1: g1 = gcd(ca,cb); ca = ca/g1; cb = cb/g1; cc = cc*g1; nu = g1*nu g2 = gcd(ca,cc); ca = ca/g2; cc = cc/g2; cb = cb*g2; mu = g2*mu g3 = gcd(cb,cc); cb = cb/g3; cc = cc/g3; ca = ca*g3; labda = g3*labda coeff = [ca, cb, cc] multipliers = [labda, mu, nu] # remove squares for i, x in enumerate(coeff): if is_FractionField(x.parent()): # go to base ring of fraction field x = self.base().base()(x) try: decom = x.squarefree_decomposition() except (NotImplementedError, AttributeError): decom = x.factor() x = decom.unit(); x2 = 1 for factor in decom: if factor[1] > 1: if factor[1] % 2 == 0: x2 = x2 * factor[0] ** (factor[1] / 2) else: x = x * factor[0] x2 = x2 * factor[0] ** ((factor[1]-1) / 2) else: x = x * factor[0] for j, y in enumerate(multipliers): if j != i: multipliers[j] = y * x2 coeff[i] = self.base_ring().base().coerce(x); return (coeff, multipliers)