From 8493ce2dbcd2ec4dff360d9a5612298388f3d803 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Thu, 22 Jun 2023 19:50:39 +0000 Subject: [PATCH 1/8] projective_morphism.py: First impl for LCM in `normalize_coordinates` --- .../schemes/projective/projective_morphism.py | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index cd484292859..e2f443a8f35 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -915,6 +915,18 @@ def normalize_coordinates(self, **kwds): 3-adic Field with capped relative precision 20 Defn: Defined on coordinates by sending (x : y) to (x^2 + (2 + O(3^20))*y^2 : (3 + O(3^21))*x*y) + + :: + + sage: R. = QQ[] + sage: K. = NumberField(3*x^2 + 1) + sage: P. = ProjectiveSpace(K, 1) + sage: f = DynamicalSystem_projective([a*(z^2 + w^2), z*w]) + sage: f.normalize_coordinates(); f + Dynamical System of Projective Space of dimension 1 over + Number Field in a with defining polynomial 3*x^2 + 1 + Defn: Defined on coordinates by sending (z : w) to + ((3*a)*z^2 + (3*a)*w^2 : z*w) """ # if ideal or valuation is specified, we scale according the norm defined by the ideal/valuation ideal = kwds.pop('ideal', None) @@ -967,12 +979,32 @@ def normalize_coordinates(self, **kwds): self.scale_by(uniformizer**(-1 * min_val)) return - # clear any denominators from the coefficients + R = self.domain().base_ring() + K = self.base_ring() N = self.codomain().ambient_space().dimension_relative() + 1 - LCM = lcm([self[i].denominator() for i in range(N)]) - self.scale_by(LCM) - R = self.domain().base_ring() + # Only clear denominators from the coefficients in the ring of integers + if R in NumberFields(): + denom_list = [] + + for entry in self: + if entry == 0: + continue + + O = R.maximal_order() + + if O is ZZ: + denom_list.append(entry.denominator()) + elif is_NumberFieldOrder(O): + frac_ideal = O.fractional_ideal(entry) + if K.is_relative(): + frac_ideal_norm = frac_ideal.absolute_norm() + else: + frac_ideal_norm = frac_ideal.norm() + + denom_list.append(frac_ideal_norm.denominator()) + + self.scale_by(lcm(denom_list)) # There are cases, such as the example above over GF(7), # where we want to compute GCDs, but NOT in the case From 6467855ae3fb0e3552b6fa29f955db40b6aab68d Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Thu, 22 Jun 2023 20:08:28 +0000 Subject: [PATCH 2/8] projective_morphism.py: Simplify LCM of `normalize_coordinates` --- .../schemes/projective/projective_morphism.py | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index e2f443a8f35..6b22c6b3c02 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -985,26 +985,14 @@ def normalize_coordinates(self, **kwds): # Only clear denominators from the coefficients in the ring of integers if R in NumberFields(): - denom_list = [] - - for entry in self: - if entry == 0: - continue - - O = R.maximal_order() - - if O is ZZ: - denom_list.append(entry.denominator()) - elif is_NumberFieldOrder(O): - frac_ideal = O.fractional_ideal(entry) - if K.is_relative(): - frac_ideal_norm = frac_ideal.absolute_norm() - else: - frac_ideal_norm = frac_ideal.norm() + O = R.maximal_order() - denom_list.append(frac_ideal_norm.denominator()) + if O is ZZ: + denom = lcm([self[i].denominator() for i in range(len(list(self)))]) + else: + denom = R.ideal(list(self)).absolute_norm().denominator() - self.scale_by(lcm(denom_list)) + self.scale_by(denom) # There are cases, such as the example above over GF(7), # where we want to compute GCDs, but NOT in the case From 50205e192b9f2ebd114f80694770b7cdb4ed651f Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Sat, 24 Jun 2023 13:10:02 +0000 Subject: [PATCH 3/8] projective_morphism.py: Format doc --- src/sage/schemes/projective/projective_morphism.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 6b22c6b3c02..2d786a3db39 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -928,7 +928,8 @@ def normalize_coordinates(self, **kwds): Defn: Defined on coordinates by sending (z : w) to ((3*a)*z^2 + (3*a)*w^2 : z*w) """ - # if ideal or valuation is specified, we scale according the norm defined by the ideal/valuation + # If ideal or valuation is specified, we scale according the norm + # defined by the ideal/valuation ideal = kwds.pop('ideal', None) if ideal is not None: from sage.rings.number_field.number_field_ideal import NumberFieldFractionalIdeal @@ -960,6 +961,7 @@ def normalize_coordinates(self, **kwds): min_val = min(valuations) self.scale_by(uniformizer**(-1 * min_val)) return + valuation = kwds.pop('valuation', None) if valuation is not None: from sage.rings.padics.padic_valuation import pAdicValuation_base @@ -980,8 +982,6 @@ def normalize_coordinates(self, **kwds): return R = self.domain().base_ring() - K = self.base_ring() - N = self.codomain().ambient_space().dimension_relative() + 1 # Only clear denominators from the coefficients in the ring of integers if R in NumberFields(): @@ -1007,6 +1007,8 @@ def normalize_coordinates(self, **kwds): GCD = gcd(self[0], self[1]) index = 2 + N = self.codomain().ambient_space().dimension_relative() + 1 + while GCD != 1 and index < N: GCD = gcd(GCD, self[index]) index += +1 From 89fde7a23be75ddd334f5ba9d73c9fd4a05f081a Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Mon, 26 Jun 2023 17:30:47 +0000 Subject: [PATCH 4/8] projective_morphism.py: Restore LCM for elts not in number fields and create the right ideals for a list of polys --- .../schemes/projective/projective_morphism.py | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 2d786a3db39..916d63d27c3 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -926,7 +926,19 @@ def normalize_coordinates(self, **kwds): Dynamical System of Projective Space of dimension 1 over Number Field in a with defining polynomial 3*x^2 + 1 Defn: Defined on coordinates by sending (z : w) to - ((3*a)*z^2 + (3*a)*w^2 : z*w) + ((-3/2*a + 1/2)*z^2 + (-3/2*a + 1/2)*w^2 : (-3/2*a - 3/2)*z*w) + + :: + + sage: R. = QQ[] + sage: P. = ProjectiveSpace(FractionField(R), 2) + sage: H = End(P) + sage: f = H([a/b*(x*z + y^2)*x^2, a*b*(x*z + y^2)*y^2, a*(x*z + y^2)*z^2]) + sage: f.normalize_coordinates(); f + Scheme endomorphism of Projective Space of dimension 2 over Fraction + Field of Multivariate Polynomial Ring in a, b over Rational Field + Defn: Defined on coordinates by sending (x : y : z) to + (x^2 : (b^2)*y^2 : b*z^2) """ # If ideal or valuation is specified, we scale according the norm # defined by the ideal/valuation @@ -981,18 +993,22 @@ def normalize_coordinates(self, **kwds): self.scale_by(uniformizer**(-1 * min_val)) return + N = self.codomain().ambient_space().dimension_relative() + 1 + R = self.domain().base_ring() - # Only clear denominators from the coefficients in the ring of integers + # Clear any denominators from the coefficients if R in NumberFields(): O = R.maximal_order() if O is ZZ: - denom = lcm([self[i].denominator() for i in range(len(list(self)))]) + denom = lcm([self[i].denominator() for i in range(N)]) else: - denom = R.ideal(list(self)).absolute_norm().denominator() + denom = R.ideal([c for poly in self for c in poly.coefficients()]).norm().denominator() self.scale_by(denom) + else: + self.scale_by(lcm([self[i].denominator() for i in range(N)])) # There are cases, such as the example above over GF(7), # where we want to compute GCDs, but NOT in the case @@ -1007,8 +1023,6 @@ def normalize_coordinates(self, **kwds): GCD = gcd(self[0], self[1]) index = 2 - N = self.codomain().ambient_space().dimension_relative() + 1 - while GCD != 1 and index < N: GCD = gcd(GCD, self[index]) index += +1 From 5ca23a5d96970831d0041bcb0d53c91a8dccc72d Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Mon, 26 Jun 2023 17:33:53 +0000 Subject: [PATCH 5/8] projective_morphism.py: Simplify code --- src/sage/schemes/projective/projective_morphism.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 916d63d27c3..c01b9c14c40 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -999,9 +999,7 @@ def normalize_coordinates(self, **kwds): # Clear any denominators from the coefficients if R in NumberFields(): - O = R.maximal_order() - - if O is ZZ: + if R.maximal_order() is ZZ: denom = lcm([self[i].denominator() for i in range(N)]) else: denom = R.ideal([c for poly in self for c in poly.coefficients()]).norm().denominator() From aaacb9c3e545154272676813d1a7a8c1dde56dc2 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Tue, 27 Jun 2023 09:37:56 +0000 Subject: [PATCH 6/8] projective_morphis.py: Reformat some docstrings and comments --- .../schemes/projective/projective_morphism.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index c01b9c14c40..fd11fcab728 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -792,25 +792,24 @@ def scale_by(self, t): def normalize_coordinates(self, **kwds): """ - Ensures that this morphism has integral coefficients, and, - if the coordinate ring has a GCD, then it ensures that the + Ensures that this morphism has integral coefficients. + If the coordinate ring has a GCD, then it ensures that the coefficients have no common factor. - Also, makes the leading coefficients of the first polynomial + It also makes the leading coefficients of the first polynomial positive (if positive has meaning in the coordinate ring). This is done in place. - When ``ideal`` or ``valuation`` is specified, - normalization occurs with respect to the absolute value - defined by the ``ideal`` or ``valuation``. That is, the - coefficients are scaled such that one coefficient has - absolute value 1 while the others have absolute value - less than or equal to 1. Only supported when the base - ring is a number field. + When ``ideal`` or ``valuation`` is specified, normalization occurs + with respect to the absolute value defined by the ``ideal`` or + ``valuation``. That is, the coefficients are scaled such that + one coefficient has absolute value 1 while the others have + absolute value less than or equal to 1. + Only supported when the base ring is a number field. INPUT: - keywords: + kwds: - ``ideal`` -- (optional) a prime ideal of the base ring of this morphism. @@ -926,7 +925,7 @@ def normalize_coordinates(self, **kwds): Dynamical System of Projective Space of dimension 1 over Number Field in a with defining polynomial 3*x^2 + 1 Defn: Defined on coordinates by sending (z : w) to - ((-3/2*a + 1/2)*z^2 + (-3/2*a + 1/2)*w^2 : (-3/2*a - 3/2)*z*w) + ((-3/2*a + 1/2)*z^2 + (-3/2*a + 1/2)*w^2 : (-3/2*a - 3/2)*z*w) :: @@ -1027,7 +1026,7 @@ def normalize_coordinates(self, **kwds): if GCD != 1: self.scale_by(R(1) / GCD) - # scales by 1/gcd of the coefficients. + # Scale by 1/GCD of the coefficients. if R in _NumberFields: O = R.maximal_order() elif isinstance(R, FiniteField): @@ -1042,8 +1041,9 @@ def normalize_coordinates(self, **kwds): if GCD != 1: self.scale_by(1 / GCD) + + # If R is not p-adic, we make the first coordinate positive from sage.rings.padics.padic_base_generic import pAdicGeneric - # if R is not padic, we make the first coordinate positive if not isinstance(R, pAdicGeneric): if self[0].lc() < 0: self.scale_by(-1) From fbefbc5bf32f3450ab24734890ed1214d74ea448 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Tue, 27 Jun 2023 09:42:37 +0000 Subject: [PATCH 7/8] projective_morphism.py: Remove trailing whitespaces --- src/sage/schemes/projective/projective_morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index fd11fcab728..9e6123f83ce 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -800,7 +800,7 @@ def normalize_coordinates(self, **kwds): positive (if positive has meaning in the coordinate ring). This is done in place. - When ``ideal`` or ``valuation`` is specified, normalization occurs + When ``ideal`` or ``valuation`` is specified, normalization occurs with respect to the absolute value defined by the ``ideal`` or ``valuation``. That is, the coefficients are scaled such that one coefficient has absolute value 1 while the others have From 6425e9e7b5b4b5f4cc420782c59ca60b99dea792 Mon Sep 17 00:00:00 2001 From: Jing Guo Date: Tue, 27 Jun 2023 18:41:30 +0000 Subject: [PATCH 8/8] projective_morphism.py: Add `check #35797 is fixed` to docstring --- src/sage/schemes/projective/projective_morphism.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 9e6123f83ce..ddbaa072962 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -915,7 +915,7 @@ def normalize_coordinates(self, **kwds): Defn: Defined on coordinates by sending (x : y) to (x^2 + (2 + O(3^20))*y^2 : (3 + O(3^21))*x*y) - :: + Check that #35797 is fixed:: sage: R. = QQ[] sage: K. = NumberField(3*x^2 + 1)