Exemple #1
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
        """
        self._matrix = coxeter_matrix
        self._index_set = index_set
        n = ZZ(coxeter_matrix.nrows())
        MS = MatrixSpace(base_ring, n, sparse=True)
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        if base_ring is UniversalCyclotomicField():
            val = lambda x: base_ring.gen(2*x) + ~base_ring.gen(2*x) if x != -1 else base_ring(2)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: base_ring(2*cos(pi / x)) if x != -1 else base_ring(2)
        gens = [MS.one() + MS({(i, j): val(coxeter_matrix[i, j])
                               for j in range(n)})
                for i in range(n)]
        FinitelyGeneratedMatrixGroup_generic.__init__(self, n, base_ring,
                                                      gens,
                                                      category=CoxeterGroups())
Exemple #2
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
        """
        self._matrix = coxeter_matrix
        self._index_set = index_set
        n = ZZ(coxeter_matrix.nrows())
        MS = MatrixSpace(base_ring, n, sparse=True)
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        if base_ring is UniversalCyclotomicField():
            val = lambda x: base_ring.gen(2*x) + ~base_ring.gen(2*x) if x != -1 else base_ring(2)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: base_ring(2*cos(pi / x)) if x != -1 else base_ring(2)
        gens = [MS.one() + MS({(i, j): val(coxeter_matrix[i, j])
                               for j in range(n)})
                for i in range(n)]
        FinitelyGeneratedMatrixGroup_generic.__init__(self, n, base_ring,
                                                      gens,
                                                      category=CoxeterGroups())
 def _create_prod_set(self, image, n, p):
     """
     A helper function. Creates all products of matrices up to and including length `p`.
     """
     import itertools
     M = MatrixSpace(self.base_field().algebraic_closure(), n, sparse=True)
     for i in range(1, p + 1):
         for matrices in itertools.product(image, repeat=i):
             result = M.one()
             for m in matrices:
                 result = result * M(m)
             yield result
    def is_irred_rep(self, image, n, force=False):
        """
        Returns `True` if the map generated by mapping the generators to the matrices defined in
        `image` is an `n`-dimensional irreducible representation of `self`, and `False` otherwise.
        Like above, the entries of `image` must be `n`-by-`n` matrices with entries in the
        algebraic closure of the base field of `self`. Its length must match the number of
        generators of `self.`

        Use `force=True` if the function does not recognize the base field as computable, but the
        field is computable.
        """
        if (not force and self.base_field() not in NumberFields
                and self.base_field() not in FiniteFields):
            raise TypeError(
                'Base field must be computable. If %s is computable' %
                self.base_field() + ' then use force=True to bypass this.')

        if n not in ZZ or n < 1:
            raise ValueError('Dimension must be a positive integer.')

        if not self.is_rep(image, n): return False

        from sage.matrix.all import Matrix
        from sage.rings.number_field.number_field import is_NumberField
        import math

        M = MatrixSpace(self.base_field().algebraic_closure(), n, sparse=True)
        image = [M(image[i]).list() for i in range(len(image))]

        if n <= 6 and is_NumberField(self.base_field()): p = 2 * n
        else:
            p = int(
                math.floor(n *
                           math.sqrt(2 * n**2 / float(n - 1) + 1 / float(4)) +
                           n / float(2) - 3))

        prod_set = list(self._create_prod_set(image, n, p))
        prod_set.append(M.one())
        vector = [mat.list() for mat in prod_set]
        return 0 not in Matrix(vector).echelon_form().diagonal()
Exemple #5
0
def HS_minimal(f, return_transformation=False, D=None):
    r"""
    Compute a minimal model for the given projective dynamical system.

    This function implements the algorithm in Hutz-Stoll [HS2018]_.
    A representative with minimal resultant in the conjugacy class
    of ``f`` returned.

    INPUT:

    - ``f`` -- dynamical system on the projective line with minimal resultant

    - ``return_transformation`` -- (default: ``False``) boolean; this
      signals a return of the `PGL_2` transformation to conjugate
      this map to the calculated models

    - ``D`` -- a list of primes, in case one only wants to check minimality
      at those specific primes

    OUTPUT:

    - a dynamical system
    - (optional) a `2 \times 2` matrix

    EXAMPLES::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 6^2*y^3, x^2*y])
        sage: m = matrix(QQ,2,2,[5,1,0,1])
        sage: g = f.conjugate(m)
        sage: g.normalize_coordinates()
        sage: g.resultant().factor()
        2^4 * 3^4 * 5^12
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import HS_minimal
        sage: HS_minimal(g).resultant().factor()
        2^4 * 3^4
        sage: HS_minimal(g, D=[2]).resultant().factor()
        2^4 * 3^4 * 5^12
        sage: F,m = HS_minimal(g, return_transformation=True)
        sage: g.conjugate(m) == F
        True
    """
    F = copy(f)
    d = F.degree()
    F.normalize_coordinates()
    MS = MatrixSpace(ZZ, 2, 2)
    m = MS.one()
    prev = copy(m)
    res = ZZ(F.resultant())
    if D is None:
        D = res.prime_divisors()

    # minimize for each prime
    for p in D:
        vp = res.valuation(p)
        minimal = False
        while not minimal:
            if (d % 2 == 0 and vp < d) or (d % 2 == 1 and vp < 2 * d):
                # must be minimal
                minimal = True
                break
            minimal = True
            t = MS([1, 0, 0, p])
            F1 = F.conjugate(t)
            F1.normalize_coordinates()
            res1 = F1.resultant()
            vp1 = res1.valuation(p)
            if vp1 < vp:  # check if smaller
                F = F1
                vp = vp1
                m = m * t  # keep track of conjugation
                minimal = False
            else:
                # still search for smaller
                for b in range(p):
                    t = matrix(ZZ, 2, 2, [p, b, 0, 1])
                    F1 = F.conjugate(t)
                    F1.normalize_coordinates()
                    res1 = ZZ(F1.resultant())
                    vp1 = res1.valuation(p)
                    if vp1 < vp:  # check if smaller
                        F = F1
                        m = m * t  # keep track of transformation
                        minimal = False
                        vp = vp1
                        break  # exit for loop
    if return_transformation:
        return F, m
    return F
Exemple #6
0
def BM_all_minimal(vp, return_transformation=False, D=None):
    r"""
    Determine a representative in each `SL(2,\ZZ)` orbit with minimal
    resultant.

    This function modifies the Bruin-Molnar algorithm ([BM2012]_) to solve
    in the inequalities as ``<=`` instead of ``<``. Among the list of
    solutions is all conjugations that preserve the resultant. From that
    list the `SL(2,\ZZ)` orbits are identified and one representative from
    each orbit is returned. This function assumes that the given model is
    a minimal model.

    INPUT:

    - ``vp`` -- a minimal model of a dynamical system on the projective line

    - ``return_transformation`` -- (default: ``False``) boolean; this
      signals a return of the ``PGL_2`` transformation to conjugate ``vp``
      to the calculated minimal model

    - ``D`` -- a list of primes, in case one only wants to check minimality
      at those specific primes

    OUTPUT:

    List of pairs ``[f, m]`` where ``f`` is a dynamical system and ``m`` is a
    `2 \times 2` matrix.

    EXAMPLES::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 13^2*y^3, x*y^2])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import BM_all_minimal
        sage: BM_all_minimal(f)
        [Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (x^3 - 169*y^3 : x*y^2),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (13*x^3 - y^3 : x*y^2)]

    ::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 6^2*y^3, x*y^2])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import BM_all_minimal
        sage: BM_all_minimal(f, D=[3])
        [Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (x^3 - 36*y^3 : x*y^2),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (3*x^3 - 4*y^3 : x*y^2)]

    ::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 4^2*y^3, x*y^2])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import BM_all_minimal
        sage: cl = BM_all_minimal(f, return_transformation=True)
        sage: all(f.conjugate(m) == g for g, m in cl)
        True
    """
    mp = copy(vp)
    mp.normalize_coordinates()
    BR = mp.domain().base_ring()
    MS = MatrixSpace(QQ, 2)
    M_Id = MS.one()
    d = mp.degree()
    F, G = list(mp)  #coordinate polys
    aff_map = mp.dehomogenize(1)
    f, g = aff_map[0].numerator(), aff_map[0].denominator()
    z = aff_map.domain().gen(0)
    dg = f.parent()(g).degree()
    Res = mp.resultant()

    ##### because of how the bound is compute in lemma 3.3
    from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine
    h = f - z * g
    A = AffineSpace(BR, 1, h.parent().variable_name())
    res = DynamicalSystem_affine([h / g], domain=A).homogenize(1).resultant()

    if D is None:
        D = ZZ(Res).prime_divisors()

    # get the conjugations for each prime independently
    # these are returning (p,k,b) so that the matrix is [p^k,b,0,1]
    all_pM = []
    for p in D:
        # all_orbits used to scale inequalities to equalities
        all_pM.append(Min(mp, p, res, M_Id, all_orbits=True))
        # need the identity for each prime
        if [p, 0, 0] not in all_pM[-1]:
            all_pM[-1].append([p, 0, 0])

    #combine conjugations for all primes
    all_M = [M_Id]
    for prime_data in all_pM:
        #these are (p,k,b) so that the matrix is [p^k,b,0,1]
        new_M = []
        if prime_data:
            p = prime_data[0][0]
            for m in prime_data:
                mat = MS([m[0]**m[1], m[2], 0, 1])
                new_map = mp.conjugate(mat)
                new_map.normalize_coordinates()
                # make sure the resultant didn't change and that it is a different SL(2,ZZ) orbit
                if (mat == M_Id) or (new_map.resultant().valuation(p)
                                     == Res.valuation(p)
                                     and mat.det() not in [1, -1]):
                    new_M.append(m)
        if new_M:
            all_M = [
                m1 * MS([m[0]**m[1], m[2], 0, 1]) for m1 in all_M
                for m in new_M
            ]

    #get all models with same resultant
    all_maps = []
    for M in all_M:
        new_map = mp.conjugate(M)
        new_map.normalize_coordinates()
        if not [new_map, M] in all_maps:
            all_maps.append([new_map, M])

    #Split into conjugacy classes
    #We just keep track of the two matrices that come from
    #the original to get the conjugation that goes between these!!
    classes = []
    for funct, mat in all_maps:
        if not classes:
            classes.append([funct, mat])
        else:
            found = False
            for Func, Mat in classes:
                #get conjugation
                M = mat.inverse() * Mat
                assert funct.conjugate(M) == Func
                if M.det() in [1, -1]:
                    #same SL(2,Z) orbit
                    found = True
                    break
            if found is False:
                classes.append([funct, mat])

    if return_transformation:
        return classes
    else:
        return [funct for funct, matr in classes]
Exemple #7
0
def HS_all_minimal(f, return_transformation=False, D=None):
    r"""
    Determine a representative in each `SL(2,\ZZ)` orbit with minimal resultant.

    This function implements the algorithm in Hutz-Stoll [HS2018]_.
    A representative in each distinct `SL(2,\ZZ)` orbit is returned.
    The input ``f`` must have minimal resultant in its conguacy class.

    INPUT:

    - ``f`` -- dynamical system on the projective line with minimal resultant

    - ``return_transformation`` -- (default: ``False``) boolean; this
      signals a return of the ``PGL_2`` transformation to conjugate ``vp``
      to the calculated minimal model

    - ``D`` -- a list of primes, in case one only wants to check minimality
      at those specific primes

    OUTPUT:

    List of pairs ``[f, m]``, where ``f`` is a dynamical system and ``m``
    is a `2 \times 2` matrix.

    EXAMPLES::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 6^2*y^3, x^2*y])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import HS_all_minimal
        sage: HS_all_minimal(f)
        [Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (x^3 - 36*y^3 : x^2*y),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (9*x^3 - 12*y^3 : 9*x^2*y),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (4*x^3 - 18*y^3 : 4*x^2*y),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (36*x^3 - 6*y^3 : 36*x^2*y)]
        sage: HS_all_minimal(f, D=[3])
        [Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (x^3 - 36*y^3 : x^2*y),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (9*x^3 - 12*y^3 : 9*x^2*y)]

    ::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 6^2*y^3, x*y^2])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import HS_all_minimal
        sage: cl = HS_all_minimal(f, return_transformation=True)
        sage: all([f.conjugate(m) == g for g,m in cl])
        True
    """
    MS = MatrixSpace(ZZ, 2)
    m = MS.one()
    F = copy(f)
    F.normalize_coordinates()
    if F.degree() == 1:
        raise ValueError("function must be degree at least 2")
    if f.degree() % 2 == 0:
        #there is only one orbit for even degree
        if return_transformation:
            return [[f, m]]
        else:
            return [f]
    if D is None:
        res = ZZ(F.resultant())
        D = res.prime_divisors()
    M = [[F, m]]
    for p in D:
        # get p-orbits
        Mp = HS_all_minimal_p(p, F, m, return_transformation=True)
        # combine with previous orbits representatives
        M = [[g.conjugate(t), t*s] for g,s in M for G,t in Mp]

    if return_transformation:
        return M
    else:
        return [funct for funct, matr in M]
Exemple #8
0
def HS_all_minimal_p(p, f, m=None, return_transformation=False):
    r"""
    Find a representative in each distinct `SL(2,\ZZ)` orbit with
    minimal `p`-resultant.

    This function implements the algorithm in Hutz-Stoll [HS2018]_.
    A representatives in each distinct `SL(2,\ZZ)` orbit with minimal
    valuation with respect to the prime ``p`` is returned. The input
    ``f`` must have minimal resultant in its conguacy class.

    INPUT:

    - ``p`` -- a prime

    - ``f`` -- dynamical system on the projective line with minimal resultant

    - ``m`` -- (optional) `2 \times 2` matrix associated with ``f``

    - ``return_transformation`` -- (default: ``False``) boolean; this
      signals a return of the ``PGL_2`` transformation to conjugate ``vp``
      to the calculated minimal model

    OUTPUT:

    List of pairs ``[f, m]`` where ``f`` is a dynamical system and ``m`` is a
    `2 \times 2` matrix.

    EXAMPLES::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^5 - 6^4*y^5, x^2*y^3])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import HS_all_minimal_p
        sage: HS_all_minimal_p(2, f)
        [Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (x^5 - 1296*y^5 : x^2*y^3),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (4*x^5 - 162*y^5 : x^2*y^3)]
        sage: cl = HS_all_minimal_p(2, f, return_transformation=True)
        sage: all([f.conjugate(m) == g for g,m in cl])
        True
    """
    count = 0
    prev = 0 # no exclusions
    F = copy(f)
    res = ZZ(F.resultant())
    vp = res.valuation(p)
    MS = MatrixSpace(ZZ, 2)
    if m is None:
        m = MS.one()
    if f.degree() % 2 == 0 or vp == 0:
        # there is only one orbit for even degree
        # nothing to do if the prime doesn't divide the resultant
        if return_transformation:
            return [[f, m]]
        else:
            return [f]
    to_do = [[F, m, prev]] # repns left to check
    reps = [[F, m]] # orbit representatives for f
    while to_do:
        F, m, prev = to_do.pop()
        # there are at most two directions preserving the resultant
        if prev == 0:
            count = 0
        else:
            count = 1
        if prev != 2: # [p,a,0,1]
            t = MS([1, 0, 0, p])
            F1 = F.conjugate(t)
            F1.normalize_coordinates()
            res1 = ZZ(F1.resultant())
            vp1 = res1.valuation(p)
            if vp1 == vp:
                count += 1
                # we have a new representative
                reps.append([F1, m*t])
                # need to check if it has any neighbors
                to_do.append([F1, m*t, 1])
        for b in range(p):
            if not (b == 0 and prev == 1):
                t = MS([p, b, 0, 1])
                F1 = F.conjugate(t)
                F1.normalize_coordinates()
                res1 = ZZ(F1.resultant())
                vp1 = res1.valuation(p)
                if vp1 == vp:
                    count += 1
                    # we have a new representative
                    reps.append([F1, m*t])
                    # need to check if it has any neighbors
                    to_do.append([F1, m*t, 2])
            if count >= 2: # at most two neighbors
                break

    if return_transformation:
        return reps
    else:
        return [funct for funct, matr in reps]
Exemple #9
0
def HS_minimal(f, return_transformation=False, D=None):
    r"""
    Compute a minimal model for the given projective dynamical system.

    This function implements the algorithm in Hutz-Stoll [HS2018]_.
    A representative with minimal resultant in the conjugacy class
    of ``f`` returned.

    INPUT:

    - ``f`` -- dynamical system on the projective line with minimal resultant

    - ``return_transformation`` -- (default: ``False``) boolean; this
      signals a return of the `PGL_2` transformation to conjugate
      this map to the calculated models

    - ``D`` -- a list of primes, in case one only wants to check minimality
      at those specific primes

    OUTPUT:

    - a dynamical system
    - (optional) a `2 \times 2` matrix

    EXAMPLES::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 6^2*y^3, x^2*y])
        sage: m = matrix(QQ,2,2,[5,1,0,1])
        sage: g = f.conjugate(m)
        sage: g.normalize_coordinates()
        sage: g.resultant().factor()
        2^4 * 3^4 * 5^12
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import HS_minimal
        sage: HS_minimal(g).resultant().factor()
        2^4 * 3^4
        sage: HS_minimal(g, D=[2]).resultant().factor()
        2^4 * 3^4 * 5^12
        sage: F,m = HS_minimal(g, return_transformation=True)
        sage: g.conjugate(m) == F
        True
    """
    F = copy(f)
    d = F.degree()
    F.normalize_coordinates()
    MS = MatrixSpace(ZZ, 2, 2)
    m = MS.one()
    prev = copy(m)
    res = ZZ(F.resultant())
    if D is None:
        D = res.prime_divisors()

    # minimize for each prime
    for p in D:
        vp = res.valuation(p)
        minimal = False
        while not minimal:
            if (d % 2 == 0 and vp < d) or (d % 2 == 1 and vp < 2 * d):
                # must be minimal
                minimal = True
                break
            minimal = True
            t = MS([1, 0, 0, p])
            F1 = F.conjugate(t)
            F1.normalize_coordinates()
            res1 = F1.resultant()
            vp1 = res1.valuation(p)
            if vp1 < vp: # check if smaller
                F = F1
                vp = vp1
                m = m * t # keep track of conjugation
                minimal = False
            else:
                # still search for smaller
                for b in range(p):
                    t = matrix(ZZ,2,2,[p, b, 0, 1])
                    F1 = F.conjugate(t)
                    F1.normalize_coordinates()
                    res1 = ZZ(F1.resultant())
                    vp1 = res1.valuation(p)
                    if vp1 < vp: # check if smaller
                        F = F1
                        m = m * t # keep track of transformation
                        minimal = False
                        vp = vp1
                        break # exit for loop
    if return_transformation:
        return F, m
    return F
Exemple #10
0
def BM_all_minimal(vp, return_transformation=False, D=None):
    r"""
    Determine a representative in each `SL(2,\ZZ)` orbit with minimal
    resultant.

    This function modifies the Bruin-Molnar algorithm ([BM2012]_) to solve
    in the inequalities as ``<=`` instead of ``<``. Among the list of
    solutions is all conjugations that preserve the resultant. From that
    list the `SL(2,\ZZ)` orbits are identified and one representative from
    each orbit is returned. This function assumes that the given model is
    a minimal model.

    INPUT:

    - ``vp`` -- a minimal model of a dynamical system on the projective line

    - ``return_transformation`` -- (default: ``False``) boolean; this
      signals a return of the ``PGL_2`` transformation to conjugate ``vp``
      to the calculated minimal model

    - ``D`` -- a list of primes, in case one only wants to check minimality
      at those specific primes

    OUTPUT:

    List of pairs ``[f, m]`` where ``f`` is a dynamical system and ``m`` is a
    `2 \times 2` matrix.

    EXAMPLES::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 13^2*y^3, x*y^2])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import BM_all_minimal
        sage: BM_all_minimal(f)
        [Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (x^3 - 169*y^3 : x*y^2),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (13*x^3 - y^3 : x*y^2)]

    ::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 6^2*y^3, x*y^2])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import BM_all_minimal
        sage: BM_all_minimal(f, D=[3])
        [Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (x^3 - 36*y^3 : x*y^2),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (3*x^3 - 4*y^3 : x*y^2)]

    ::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 4^2*y^3, x*y^2])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import BM_all_minimal
        sage: cl = BM_all_minimal(f, return_transformation=True)
        sage: all([f.conjugate(m) == g for g,m in cl])
        True
    """
    mp = copy(vp)
    mp.normalize_coordinates()
    BR = mp.domain().base_ring()
    MS = MatrixSpace(QQ, 2)
    M_Id = MS.one()
    d = mp.degree()
    F, G = list(mp)  #coordinate polys
    aff_map = mp.dehomogenize(1)
    f, g = aff_map[0].numerator(), aff_map[0].denominator()
    z = aff_map.domain().gen(0)
    dg = f.parent()(g).degree()
    Res = mp.resultant()

    ##### because of how the bound is compute in lemma 3.3
    from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine
    h = f - z*g
    A = AffineSpace(BR, 1, h.parent().variable_name())
    res = DynamicalSystem_affine([h/g], domain=A).homogenize(1).resultant()

    if D is None:
        D = ZZ(Res).prime_divisors()

    # get the conjugations for each prime independently
    # these are returning (p,k,b) so that the matrix is [p^k,b,0,1]
    all_pM = []
    for p in D:
        # all_orbits used to scale inequalities to equalities
        all_pM.append(Min(mp, p, res, M_Id, all_orbits=True))
        # need the identity for each prime
        if [p, 0, 0] not in all_pM[-1]:
            all_pM[-1].append([p, 0, 0])

    #combine conjugations for all primes
    all_M = [M_Id]
    for prime_data in all_pM:
        #these are (p,k,b) so that the matrix is [p^k,b,0,1]
        new_M = []
        if prime_data:
            p = prime_data[0][0]
            for m in prime_data:
                mat = MS([m[0]**m[1], m[2], 0, 1])
                new_map = mp.conjugate(mat)
                new_map.normalize_coordinates()
                # make sure the resultant didn't change and that it is a different SL(2,ZZ) orbit
                if (mat == M_Id) or (new_map.resultant().valuation(p) == Res.valuation(p)
                                     and mat.det() not in [1,-1]):
                    new_M.append(m)
        if new_M:
            all_M = [m1 * MS([m[0]**m[1], m[2], 0, 1])
                     for m1 in all_M for m in new_M]

    #get all models with same resultant
    all_maps = []
    for M in all_M:
        new_map = mp.conjugate(M)
        new_map.normalize_coordinates()
        if not [new_map, M] in all_maps:
            all_maps.append([new_map, M])

    #Split into conjugacy classes
    #We just keep track of the two matrices that come from
    #the original to get the conjugation that goes between these!!
    classes = []
    for funct, mat in all_maps:
        if not classes:
            classes.append([funct, mat])
        else:
            found = False
            for Func, Mat in classes:
                #get conjugation
                M = mat.inverse() * Mat
                assert funct.conjugate(M) == Func
                if M.det() in [1,-1]:
                    #same SL(2,Z) orbit
                    found = True
                    break
            if found is False:
                classes.append([funct, mat])

    if return_transformation:
        return classes
    else:
        return [funct for funct, matr in classes]
Exemple #11
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time

        We check that :trac:`16630` is fixed::

            sage: CoxeterGroup(['D',4], base_ring=QQ).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['H',4], base_ring=QQbar).category()
            Category of finite coxeter groups
            sage: F = CoxeterGroups().Finite()
            sage: all(CoxeterGroup([letter,i]) in F
            ....:     for i in range(2,5) for letter in ['A','B','D'])
            True
            sage: all(CoxeterGroup(['E',i]) in F for i in range(6,9))
            True
            sage: CoxeterGroup(['F',4]).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['G',2]).category()
            Category of finite coxeter groups
            sage: all(CoxeterGroup(['H',i]) in F for i in range(3,5))
            True
            sage: all(CoxeterGroup(['I',i]) in F for i in range(2,5))
            True
        """
        self._matrix = coxeter_matrix
        n = coxeter_matrix.rank()
        # Compute the matrix with entries `2 \cos( \pi / m_{ij} )`.
        MS = MatrixSpace(base_ring, n, sparse=True)
        MC = MS._get_matrix_class()
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        if base_ring is UniversalCyclotomicField():
            val = lambda x: base_ring.gen(2*x) + ~base_ring.gen(2*x) if x != -1 else base_ring(2)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: base_ring(2*cos(pi / x)) if x != -1 else base_ring(2)
        gens = [MS.one() + MC(MS, entries={(i, j): val(coxeter_matrix[index_set[i], index_set[j]])
                                           for j in range(n)},
                              coerce=True, copy=True)
                for i in range(n)]
        category = CoxeterGroups()
        # Now we shall see if the group is finite, and, if so, refine
        # the category to ``category.Finite()``. Otherwise the group is
        # infinite and we refine the category to ``category.Infinite()``.
        if self._matrix.is_finite():
            category = category.Finite()
        else:
            category = category.Infinite()
        FinitelyGeneratedMatrixGroup_generic.__init__(self, ZZ(n), base_ring,
                                                      gens, category=category)
Exemple #12
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time

        We check that :trac:`16630` is fixed::

            sage: CoxeterGroup(['D',4], base_ring=QQ).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['H',4], base_ring=QQbar).category()
            Category of finite coxeter groups
            sage: F = CoxeterGroups().Finite()
            sage: all(CoxeterGroup([letter,i]) in F
            ....:     for i in range(2,5) for letter in ['A','B','D'])
            True
            sage: all(CoxeterGroup(['E',i]) in F for i in range(6,9))
            True
            sage: CoxeterGroup(['F',4]).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['G',2]).category()
            Category of finite coxeter groups
            sage: all(CoxeterGroup(['H',i]) in F for i in range(3,5))
            True
            sage: all(CoxeterGroup(['I',i]) in F for i in range(2,5))
            True
        """
        self._matrix = coxeter_matrix
        n = coxeter_matrix.rank()
        # Compute the matrix with entries `2 \cos( \pi / m_{ij} )`.
        MS = MatrixSpace(base_ring, n, sparse=True)
        MC = MS._get_matrix_class()
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        E = UniversalCyclotomicField().gen
        if base_ring is UniversalCyclotomicField():

            def val(x):
                if x == -1:
                    return 2
                else:
                    return E(2 * x) + ~E(2 * x)
        elif is_QuadraticField(base_ring):

            def val(x):
                if x == -1:
                    return 2
                else:
                    return base_ring(
                        (E(2 * x) + ~E(2 * x)).to_cyclotomic_field())
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi

            def val(x):
                if x == -1:
                    return 2
                else:
                    return base_ring(2 * cos(pi / x))

        gens = [
            MS.one() +
            MC(MS,
               entries={(i, j): val(coxeter_matrix[index_set[i], index_set[j]])
                        for j in range(n)},
               coerce=True,
               copy=True) for i in range(n)
        ]
        # Make the generators dense matrices for consistency and speed
        gens = [g.dense_matrix() for g in gens]
        category = CoxeterGroups()
        # Now we shall see if the group is finite, and, if so, refine
        # the category to ``category.Finite()``. Otherwise the group is
        # infinite and we refine the category to ``category.Infinite()``.
        if self._matrix.is_finite():
            category = category.Finite()
        else:
            category = category.Infinite()
        self._index_set_inverse = {
            i: ii
            for ii, i in enumerate(self._matrix.index_set())
        }
        FinitelyGeneratedMatrixGroup_generic.__init__(self,
                                                      ZZ(n),
                                                      base_ring,
                                                      gens,
                                                      category=category)
Exemple #13
0
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

    The authors can be reached at: [email protected] and
    [email protected].

    ====================================================================

"""

from sage.all import QQ
from sage.matrix.matrix_space import MatrixSpace
from sage.matrix.special import block_diagonal_matrix

M = MatrixSpace(QQ, 2)
one = M.one()
matrices = [M.random_element() for i in range(2000)]


def test_m_tensor_one():
    for m in matrices:
        m.tensor_product(one, subdivide=False)


def test_one_tensor_m():
    for m in matrices:
        one.tensor_product(m, subdivide=False)


def test_m_tensor_one_subdivide():
    for m in matrices:
Exemple #14
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time

        We check that :trac:`16630` is fixed::

            sage: CoxeterGroup(['D',4], base_ring=QQ).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['H',4], base_ring=QQbar).category()
            Category of finite coxeter groups
            sage: F = CoxeterGroups().Finite()
            sage: all(CoxeterGroup([letter,i]) in F
            ....:     for i in range(2,5) for letter in ['A','B','D'])
            True
            sage: all(CoxeterGroup(['E',i]) in F for i in range(6,9))
            True
            sage: CoxeterGroup(['F',4]).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['G',2]).category()
            Category of finite coxeter groups
            sage: all(CoxeterGroup(['H',i]) in F for i in range(3,5))
            True
            sage: all(CoxeterGroup(['I',i]) in F for i in range(2,5))
            True
        """
        self._matrix = coxeter_matrix
        self._index_set = index_set
        n = ZZ(coxeter_matrix.nrows())
        # Compute the matrix with entries `2 \cos( \pi / m_{ij} )`.
        MS = MatrixSpace(base_ring, n, sparse=True)
        MC = MS._get_matrix_class()
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        if base_ring is UniversalCyclotomicField():
            val = lambda x: base_ring.gen(2 * x) + ~base_ring.gen(2 * x) if x != -1 else base_ring(2)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi

            val = lambda x: base_ring(2 * cos(pi / x)) if x != -1 else base_ring(2)
        gens = [
            MS.one() + MC(MS, entries={(i, j): val(coxeter_matrix[i, j]) for j in range(n)}, coerce=True, copy=True)
            for i in range(n)
        ]
        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        # This describes the bilinear form corresponding to this
        # Coxeter system, and might lead us out of our base ring.
        base_field = base_ring.fraction_field()
        MS2 = MatrixSpace(base_field, n, sparse=True)
        MC2 = MS2._get_matrix_class()
        self._bilinear = MC2(
            MS2,
            entries={
                (i, j): val(coxeter_matrix[i, j]) / base_field(-2)
                for i in range(n)
                for j in range(n)
                if coxeter_matrix[i, j] != 2
            },
            coerce=True,
            copy=True,
        )
        self._bilinear.set_immutable()
        category = CoxeterGroups()
        # Now we shall see if the group is finite, and, if so, refine
        # the category to ``category.Finite()``. Otherwise the group is
        # infinite and we refine the category to ``category.Infinite()``.
        is_finite = self._finite_recognition()
        if is_finite:
            category = category.Finite()
        else:
            category = category.Infinite()
        FinitelyGeneratedMatrixGroup_generic.__init__(self, n, base_ring, gens, category=category)
Exemple #15
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time

        We check that :trac:`16630` is fixed::

            sage: CoxeterGroup(['D',4], base_ring=QQ).category()
            Category of finite irreducible coxeter groups
            sage: CoxeterGroup(['H',4], base_ring=QQbar).category()
            Category of finite irreducible coxeter groups
            sage: F = CoxeterGroups().Finite()
            sage: all(CoxeterGroup([letter,i]) in F
            ....:     for i in range(2,5) for letter in ['A','B','D'])
            True
            sage: all(CoxeterGroup(['E',i]) in F for i in range(6,9))
            True
            sage: CoxeterGroup(['F',4]).category()
            Category of finite irreducible coxeter groups
            sage: CoxeterGroup(['G',2]).category()
            Category of finite irreducible coxeter groups
            sage: all(CoxeterGroup(['H',i]) in F for i in range(3,5))
            True
            sage: all(CoxeterGroup(['I',i]) in F for i in range(2,5))
            True
        """
        self._matrix = coxeter_matrix
        n = coxeter_matrix.rank()
        # Compute the matrix with entries `2 \cos( \pi / m_{ij} )`.
        MS = MatrixSpace(base_ring, n, sparse=True)
        one = MS.one()
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        E = UniversalCyclotomicField().gen
        if base_ring is UniversalCyclotomicField():

            def val(x):
                if x == -1:
                    return 2
                else:
                    return E(2 * x) + ~E(2 * x)
        elif is_QuadraticField(base_ring):

            def val(x):
                if x == -1:
                    return 2
                else:
                    return base_ring((E(2 * x) + ~E(2 * x)).to_cyclotomic_field())
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi

            def val(x):
                if x == -1:
                    return 2
                else:
                    return base_ring(2 * cos(pi / x))
        gens = [one + MS([SparseEntry(i, j, val(coxeter_matrix[index_set[i], index_set[j]]))
                          for j in range(n)])
                for i in range(n)]
        # Make the generators dense matrices for consistency and speed
        gens = [g.dense_matrix() for g in gens]
        category = CoxeterGroups()
        # Now we shall see if the group is finite, and, if so, refine
        # the category to ``category.Finite()``. Otherwise the group is
        # infinite and we refine the category to ``category.Infinite()``.
        if self._matrix.is_finite():
            category = category.Finite()
        else:
            category = category.Infinite()
        if all(self._matrix._matrix[i, j] == 2
               for i in range(n) for j in range(i)):
            category = category.Commutative()
        if self._matrix.is_irreducible():
            category = category.Irreducible()
        self._index_set_inverse = {i: ii
                                   for ii, i in enumerate(self._matrix.index_set())}
        FinitelyGeneratedMatrixGroup_generic.__init__(self, ZZ(n), base_ring,
                                                      gens, category=category)
Exemple #16
0
def HS_all_minimal_p(p, f, m=None, return_transformation=False):
    r"""
    Find a representative in each distinct `SL(2,\ZZ)` orbit with
    minimal `p`-resultant.

    This function implements the algorithm in Hutz-Stoll [HS2018]_.
    A representatives in each distinct `SL(2,\ZZ)` orbit with minimal
    valuation with respect to the prime ``p`` is returned. The input
    ``f`` must have minimal resultant in its conjugacy class.

    INPUT:

    - ``p`` -- a prime

    - ``f`` -- dynamical system on the projective line with minimal resultant

    - ``m`` -- (optional) `2 \times 2` matrix associated with ``f``

    - ``return_transformation`` -- (default: ``False``) boolean; this
      signals a return of the ``PGL_2`` transformation to conjugate ``vp``
      to the calculated minimal model

    OUTPUT:

    List of pairs ``[f, m]`` where ``f`` is a dynamical system and ``m`` is a
    `2 \times 2` matrix.

    EXAMPLES::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^5 - 6^4*y^5, x^2*y^3])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import HS_all_minimal_p
        sage: HS_all_minimal_p(2, f)
        [Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (x^5 - 1296*y^5 : x^2*y^3),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (4*x^5 - 162*y^5 : x^2*y^3)]
        sage: cl = HS_all_minimal_p(2, f, return_transformation=True)
        sage: all(f.conjugate(m) == g for g, m in cl)
        True
    """
    count = 0
    prev = 0  # no exclusions
    F = copy(f)
    res = ZZ(F.resultant())
    vp = res.valuation(p)
    MS = MatrixSpace(ZZ, 2)
    if m is None:
        m = MS.one()
    if f.degree() % 2 == 0 or vp == 0:
        # there is only one orbit for even degree
        # nothing to do if the prime doesn't divide the resultant
        if return_transformation:
            return [[f, m]]
        else:
            return [f]
    to_do = [[F, m, prev]]  # repns left to check
    reps = [[F, m]]  # orbit representatives for f
    while to_do:
        F, m, prev = to_do.pop()
        # there are at most two directions preserving the resultant
        if prev == 0:
            count = 0
        else:
            count = 1
        if prev != 2:  # [p,a,0,1]
            t = MS([1, 0, 0, p])
            F1 = F.conjugate(t)
            F1.normalize_coordinates()
            res1 = ZZ(F1.resultant())
            vp1 = res1.valuation(p)
            if vp1 == vp:
                count += 1
                # we have a new representative
                reps.append([F1, m * t])
                # need to check if it has any neighbors
                to_do.append([F1, m * t, 1])
        for b in range(p):
            if not (b == 0 and prev == 1):
                t = MS([p, b, 0, 1])
                F1 = F.conjugate(t)
                F1.normalize_coordinates()
                res1 = ZZ(F1.resultant())
                vp1 = res1.valuation(p)
                if vp1 == vp:
                    count += 1
                    # we have a new representative
                    reps.append([F1, m * t])
                    # need to check if it has any neighbors
                    to_do.append([F1, m * t, 2])
            if count >= 2:  # at most two neighbors
                break

    if return_transformation:
        return reps
    else:
        return [funct for funct, matr in reps]
Exemple #17
0
def HS_all_minimal(f, return_transformation=False, D=None):
    r"""
    Determine a representative in each `SL(2,\ZZ)` orbit with minimal resultant.

    This function implements the algorithm in Hutz-Stoll [HS2018]_.
    A representative in each distinct `SL(2,\ZZ)` orbit is returned.
    The input ``f`` must have minimal resultant in its conjugacy class.

    INPUT:

    - ``f`` -- dynamical system on the projective line with minimal resultant

    - ``return_transformation`` -- (default: ``False``) boolean; this
      signals a return of the ``PGL_2`` transformation to conjugate ``vp``
      to the calculated minimal model

    - ``D`` -- a list of primes, in case one only wants to check minimality
      at those specific primes

    OUTPUT:

    List of pairs ``[f, m]``, where ``f`` is a dynamical system and ``m``
    is a `2 \times 2` matrix.

    EXAMPLES::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 6^2*y^3, x^2*y])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import HS_all_minimal
        sage: HS_all_minimal(f)
        [Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (x^3 - 36*y^3 : x^2*y),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (9*x^3 - 12*y^3 : 9*x^2*y),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (4*x^3 - 18*y^3 : 4*x^2*y),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (36*x^3 - 6*y^3 : 36*x^2*y)]
        sage: HS_all_minimal(f, D=[3])
        [Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (x^3 - 36*y^3 : x^2*y),
         Dynamical System of Projective Space of dimension 1 over Rational Field
           Defn: Defined on coordinates by sending (x : y) to
                 (9*x^3 - 12*y^3 : 9*x^2*y)]

    ::

        sage: P.<x,y> = ProjectiveSpace(QQ,1)
        sage: f = DynamicalSystem([x^3 - 6^2*y^3, x*y^2])
        sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import HS_all_minimal
        sage: cl = HS_all_minimal(f, return_transformation=True)
        sage: all(f.conjugate(m) == g for g, m in cl)
        True
    """
    MS = MatrixSpace(ZZ, 2)
    m = MS.one()
    F = copy(f)
    F.normalize_coordinates()
    if F.degree() == 1:
        raise ValueError("function must be degree at least 2")
    if f.degree() % 2 == 0:
        #there is only one orbit for even degree
        if return_transformation:
            return [[f, m]]
        else:
            return [f]
    if D is None:
        res = ZZ(F.resultant())
        D = res.prime_divisors()
    M = [[F, m]]
    for p in D:
        # get p-orbits
        Mp = HS_all_minimal_p(p, F, m, return_transformation=True)
        # combine with previous orbits representatives
        M = [[g.conjugate(t), t * s] for g, s in M for G, t in Mp]

    if return_transformation:
        return M
    else:
        return [funct for funct, matr in M]
Exemple #18
0
    def __init__(self, coxeter_matrix, base_ring, index_set):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: W = CoxeterGroup([[1,3,2],[3,1,3],[2,3,1]])
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,4],[2,4,1]], base_ring=QQbar)
            sage: TestSuite(W).run() # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,6],[2,6,1]])
            sage: TestSuite(W).run(max_runs=30) # long time
            sage: W = CoxeterGroup([[1,3,2],[3,1,-1],[2,-1,1]])
            sage: TestSuite(W).run(max_runs=30) # long time

        We check that :trac:`16630` is fixed::

            sage: CoxeterGroup(['D',4], base_ring=QQ).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['H',4], base_ring=QQbar).category()
            Category of finite coxeter groups
            sage: F = CoxeterGroups().Finite()
            sage: all(CoxeterGroup([letter,i]) in F
            ....:     for i in range(2,5) for letter in ['A','B','D'])
            True
            sage: all(CoxeterGroup(['E',i]) in F for i in range(6,9))
            True
            sage: CoxeterGroup(['F',4]).category()
            Category of finite coxeter groups
            sage: CoxeterGroup(['G',2]).category()
            Category of finite coxeter groups
            sage: all(CoxeterGroup(['H',i]) in F for i in range(3,5))
            True
            sage: all(CoxeterGroup(['I',i]) in F for i in range(2,5))
            True
        """
        self._matrix = coxeter_matrix
        self._index_set = index_set
        n = ZZ(coxeter_matrix.nrows())
        # Compute the matrix with entries `2 \cos( \pi / m_{ij} )`.
        MS = MatrixSpace(base_ring, n, sparse=True)
        MC = MS._get_matrix_class()
        # FIXME: Hack because there is no ZZ \cup \{ \infty \}: -1 represents \infty
        if base_ring is UniversalCyclotomicField():
            val = lambda x: base_ring.gen(2 * x) + ~base_ring.gen(
                2 * x) if x != -1 else base_ring(2)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi
            val = lambda x: base_ring(2 * cos(pi / x)
                                      ) if x != -1 else base_ring(2)
        gens = [
            MS.one() + MC(MS,
                          entries={(i, j): val(coxeter_matrix[i, j])
                                   for j in range(n)},
                          coerce=True,
                          copy=True) for i in range(n)
        ]
        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        # This describes the bilinear form corresponding to this
        # Coxeter system, and might lead us out of our base ring.
        base_field = base_ring.fraction_field()
        MS2 = MatrixSpace(base_field, n, sparse=True)
        MC2 = MS2._get_matrix_class()
        self._bilinear = MC2(MS2,
                             entries={
                                 (i, j):
                                 val(coxeter_matrix[i, j]) / base_field(-2)
                                 for i in range(n) for j in range(n)
                                 if coxeter_matrix[i, j] != 2
                             },
                             coerce=True,
                             copy=True)
        self._bilinear.set_immutable()
        category = CoxeterGroups()
        # Now we shall see if the group is finite, and, if so, refine
        # the category to ``category.Finite()``. Otherwise the group is
        # infinite and we refine the category to ``category.Infinite()``.
        is_finite = self._finite_recognition()
        if is_finite:
            category = category.Finite()
        else:
            category = category.Infinite()
        FinitelyGeneratedMatrixGroup_generic.__init__(self,
                                                      n,
                                                      base_ring,
                                                      gens,
                                                      category=category)