Repository: sagemath/sage

Issue:
normalize_coordinates for projective morphisms gcd failure
### Is there an existing issue for this?

- [X] I have searched the existing issues for a bug report that matches the one I want to file, without success.

### Did you read the documentation and troubleshoot guide?

- [X] I have read the documentation and troubleshoot guide

### Environment

```markdown
- **OS**: Ubuntu 20.04
- **Sage Version**: 10.0
```


### Steps To Reproduce

```
K.<a> = NumberField(3*x^2 + 1)
P.<z,w> = ProjectiveSpace(K, 1)
phi = DynamicalSystem_projective([a*(z^2 + w^2),z*w])
phi.normalize_coordinates()
```

### Expected Behavior

Should return a version of the point with normalized coordinates

### Actual Behavior

the gcd step fails since it assumes clearing denominators gives back points in the ring of integers.

### Additional Information

_No response_


Discussion:
Putting the "Steps to reproduce" into `sage` gives syntax errors, because it is not displaying properly. Please surround the code block with triple backticks.

Also, please delete "&lt;title&gt;" from the end of the title.

Resolving patch:
diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py
--- 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.
@@ -915,8 +914,33 @@ 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)
+
+        Check that #35797 is fixed::
+
+            sage: R.<x> = QQ[]
+            sage: K.<a> = NumberField(3*x^2 + 1)
+            sage: P.<z,w> = 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/2*a + 1/2)*z^2 + (-3/2*a + 1/2)*w^2 : (-3/2*a - 3/2)*z*w)
+
+        ::
+
+            sage: R.<a,b> = QQ[]
+            sage: P.<x,y,z> = 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
+        # 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
@@ -948,6 +972,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
@@ -967,13 +992,21 @@ def normalize_coordinates(self, **kwds):
             self.scale_by(uniformizer**(-1 * min_val))
             return
 
-        # clear any denominators from the coefficients
         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()
 
+        # Clear any denominators from the coefficients
+        if R in NumberFields():
+            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()
+
+            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
         # where R is a NumberField of class number > 1.
@@ -993,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):
@@ -1008,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)


Test patch: