def split_local_cover(self): """ Tries to find subform of the given (positive definite quaternary) quadratic form Q of the form .. MATH:: d*x^2 + T(y,z,w) where `d > 0` is as small as possible. This is done by exhaustive search on small vectors, and then comparing the local conditions of its sum with it's complementary lattice and the original quadratic form Q. INPUT: none OUTPUT: a QuadraticForm over ZZ EXAMPLES:: sage: Q1 = DiagonalQuadraticForm(ZZ, [7,5,3]) sage: Q1.split_local_cover() Quadratic form in 3 variables over Integer Ring with coefficients: [ 3 0 0 ] [ * 7 0 ] [ * * 5 ] """ ## 0. If a split local cover already exists, then return it. if hasattr(self, "__split_local_cover"): if is_QuadraticForm(self.__split_local_cover ): ## Here the computation has been done. return self.__split_local_cover elif self.__split_local_cover in ZZ: ## Here it indexes the values already tried! current_length = self.__split_local_cover + 1 Length_Max = current_length + 5 else: current_length = 1 Length_Max = 6 ## 1. Find a range of new vectors all_vectors = self.vectors_by_length(Length_Max) current_vectors = all_vectors[current_length] ## Loop until we find a split local cover... while True: ## 2. Check if any of the primitive ones produce a split local cover for v in current_vectors: Q = QuadraticForm__constructor( ZZ, 1, [current_length]) + self.complementary_subform_to_vector(v) if Q.local_representation_conditions( ) == self.local_representation_conditions(): self.__split_local_cover = Q return Q ## 3. Save what we have checked and get more vectors. self.__split_local_cover = current_length current_length += 1 if current_length >= len(all_vectors): Length_Max += 5 all_vectors = self.vectors_by_length(Length_Max) current_vectors = all_vectors[current_length]
def split_local_cover(self): """ Tries to find subform of the given (positive definite quaternary) quadratic form Q of the form .. math:: d*x^2 + T(y,z,w) where `d > 0` is as small as possible. This is done by exhaustive search on small vectors, and then comparing the local conditions of its sum with it's complementary lattice and the original quadratic form Q. INPUT: none OUTPUT: a QuadraticForm over ZZ EXAMPLES:: sage: Q1 = DiagonalQuadraticForm(ZZ, [7,5,3]) sage: Q1.split_local_cover() Quadratic form in 3 variables over Integer Ring with coefficients: [ 3 0 0 ] [ * 7 0 ] [ * * 5 ] """ ## 0. If a split local cover already exists, then return it. if hasattr(self, "__split_local_cover"): if is_QuadraticForm(self.__split_local_cover): ## Here the computation has been done. return self.__split_local_cover elif isinstance(self.__split_local_cover, Integer): ## Here it indexes the values already tried! current_length = self.__split_local_cover + 1 Length_Max = current_length + 5 else: current_length = 1 Length_Max = 6 ## 1. Find a range of new vectors all_vectors = self.vectors_by_length(Length_Max) current_vectors = all_vectors[current_length] ## Loop until we find a split local cover... while True: ## 2. Check if any of the primitive ones produce a split local cover for v in current_vectors: #print "current length = ", current_length #print "v = ", v Q = QuadraticForm__constructor(ZZ, 1, [current_length]) + self.complementary_subform_to_vector(v) #print Q if Q.local_representation_conditions() == self.local_representation_conditions(): self.__split_local_cover = Q return Q ## 3. Save what we have checked and get more vectors. self.__split_local_cover = current_length current_length += 1 if current_length >= len(all_vectors): Length_Max += 5 all_vectors = self.vectors_by_length(Length_Max) current_vectors = all_vectors[current_length]
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 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 is_globally_equivalent_to(self, other, return_matrix=False): """ Determine if the current quadratic form is equivalent to the given form over ZZ. If ``return_matrix`` is True, then we return the transformation matrix `M` so that ``self(M) == other``. INPUT: - ``self``, ``other`` -- positive definite integral quadratic forms - ``return_matrix`` -- (boolean, default ``False``) return the transformation matrix instead of a boolean OUTPUT: - if ``return_matrix`` is ``False``: a boolean - if ``return_matrix`` is ``True``: either ``False`` or the transformation matrix EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: M = Matrix(ZZ, 4, 4, [1,2,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]) sage: Q1 = Q(M) sage: Q.is_globally_equivalent_to(Q1) True sage: MM = Q.is_globally_equivalent_to(Q1, return_matrix=True) sage: Q(MM) == Q1 True :: sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q2 = QuadraticForm(ZZ, 3, [2, 1, 2, 2, 1, 3]) sage: Q3 = QuadraticForm(ZZ, 3, [8, 6, 5, 3, 4, 2]) sage: Q1.is_globally_equivalent_to(Q2) False sage: Q1.is_globally_equivalent_to(Q2, return_matrix=True) False sage: Q1.is_globally_equivalent_to(Q3) True sage: M = Q1.is_globally_equivalent_to(Q3, True); M [-1 -1 0] [ 1 1 1] [-1 0 0] sage: Q1(M) == Q3 True :: sage: Q = DiagonalQuadraticForm(ZZ, [1, -1]) sage: Q.is_globally_equivalent_to(Q) Traceback (most recent call last): ... ValueError: not a definite form in QuadraticForm.is_globally_equivalent_to() ALGORITHM: this uses the PARI function :pari:`qfisom`, implementing an algorithm by Plesken and Souvignier. TESTS: :trac:`27749` is fixed:: sage: Q = QuadraticForm(ZZ, 2, [2, 3, 5]) sage: P = QuadraticForm(ZZ, 2, [8, 6, 5]) sage: Q.is_globally_equivalent_to(P) False sage: P.is_globally_equivalent_to(Q) False """ ## Check that other is a QuadraticForm if not is_QuadraticForm(other): raise TypeError( "you must compare two quadratic forms, but the argument is not a quadratic form" ) ## only for definite forms if not self.is_definite() or not other.is_definite(): raise ValueError( "not a definite form in QuadraticForm.is_globally_equivalent_to()") mat = other.__pari__().qfisom(self) if not mat: return False if return_matrix: return mat.sage() else: return True