示例#1
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]
示例#2
0
################################################################################

from sage.misc.cachefunc import cached_method

from sage.misc.misc import prod
from congroup_generic import is_CongruenceSubgroup
from congroup_gammaH import GammaH_class, is_GammaH, GammaH_constructor
#from congroup_gamma0 import Gamma0_constructor -- circular!
from arithgroup_element import ArithmeticSubgroupElement
from sage.rings.all import ZZ, euler_phi as phi, moebius, divisors
from sage.modular.dirichlet import DirichletGroup

# Just for now until we make an SL_2 group type.
from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
from sage.matrix.matrix_space import MatrixSpace
Mat2Z = MatrixSpace(IntegerModRing(0),2)

def is_Gamma1(x):
    """
    Return True if x is a congruence subgroup of type Gamma1.

    EXAMPLES::

        sage: from sage.modular.arithgroup.all import is_Gamma1
        sage: is_Gamma1(SL2Z)
        False
        sage: is_Gamma1(Gamma1(13))
        True
        sage: is_Gamma1(Gamma0(6))
        False
        sage: is_Gamma1(GammaH(12, [])) # trick question!
def ToricCode(P, F):
    r"""
    Let `P` denote a list of lattice points in
    `\ZZ^d` and let `T` denote the set of all
    points in `(F^x)^d` (ordered in some fixed way). Put
    `n=|T|` and let `k` denote the dimension of the
    vector space of functions `V = \mathrm{Span}\{x^e \ |\ e \in P\}`.
    The associated toric code `C` is the evaluation code which
    is the image of the evaluation map
    
    .. math::
    
        \mathrm{eval_T} : V \rightarrow F^n,     
    
    
    where `x^e` is the multi-index notation
    (`x=(x_1,...,x_d)`, `e=(e_1,...,e_d)`, and
    `x^e = x_1^{e_1}...x_d^{e_d}`), where
    `eval_T (f(x)) = (f(t_1),...,f(t_n))`, and where
    `T=\{t_1,...,t_n\}`. This function returns the toric
    codes discussed in [J]_.
    
    INPUT:
    
    
    -  ``P`` - all the integer lattice points in a polytope
       defining the toric variety.
    
    -  ``F`` - a finite field.
    
    
    OUTPUT: Returns toric code with length n = , dimension k over field
    F.
    
    EXAMPLES::
    
         sage: C = ToricCode([[0,0],[1,0],[2,0],[0,1],[1,1]],GF(7))
         sage: C     
         Linear code of length 36, dimension 5 over Finite Field of size 7
         sage: C.minimum_distance()
         24
         sage: C = ToricCode([[-2,-2],[-1,-2],[-1,-1],[-1,0],[0,-1],[0,0],[0,1],[1,-1],[1,0]],GF(5))
         sage: C
         Linear code of length 16, dimension 9 over Finite Field of size 5
         sage: C.minimum_distance()
         6
         sage: C = ToricCode([ [0,0],[1,1],[1,2],[1,3],[1,4],[2,1],[2,2],[2,3],[3,1],[3,2],[4,1]],GF(8,"a"))
         sage: C
         Linear code of length 49, dimension 11 over Finite Field in a of size 2^3
    
    This is in fact a [49,11,28] code over GF(8). If you type next
    ``C.minimum_distance()`` and wait overnight (!), you
    should get 28.
    
    AUTHOR:

    - David Joyner (07-2006)
    
    REFERENCES:

    .. [J] D. Joyner, Toric codes over finite fields, Applicable
       Algebra in Engineering, Communication and Computing, 15, (2004), p. 63-79.
    """
    from sage.combinat.all import Tuples
    mset = [x for x in F if x != 0]
    d = len(P[0])
    pts = Tuples(mset, d).list()
    n = len(pts)  # (q-1)^d
    k = len(P)
    e = P[0]
    B = []
    for e in P:
        tmpvar = [prod([t[i]**e[i] for i in range(d)]) for t in pts]
        B.append(tmpvar)
    # now B0 *should* be a full rank matrix
    MS = MatrixSpace(F, k, n)
    return LinearCode(MS(B))
示例#4
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)
示例#5
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)
示例#6
0
def higher_level_UpGj(p, N, klist, m, modformsring, bound, extra_data=False):
    r"""
    Return a list ``[A_k]`` of square matrices over ``IntegerRing(p^m)``
    parameterised by the weights k in ``klist``.

    The matrix `A_k` is the finite square matrix which occurs on input
    p, k, N and m in Step 6 of Algorithm 2 in [Lau2011]_.

    Notational change from paper: In Step 1 following Wan we defined
    j by `k = k_0 + j(p-1)` with `0 \le k_0 < p-1`. Here we replace j by
    ``kdiv`` so that we may use j as a column index for matrices.)

    INPUT:

    - ``p`` -- prime at least 5.
    - ``N`` -- integer at least 2 and not divisible by p (level).
    - ``klist`` -- list of integers all congruent modulo (p-1) (the weights).
    - ``m`` -- positive integer.
    - ``modformsring`` -- ``True`` or ``False``.
    - ``bound`` -- (even) positive integer.
    - ``extra_data`` -- (default: ``False``) boolean.

    OUTPUT:

    - list of square matrices. If ``extra_data`` is ``True``, return also
      extra intermediate data, namely the matrix `E` in [Lau2011]_ and
      the integers ``elldash`` and ``mdash``.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import higher_level_UpGj
        sage: higher_level_UpGj(5,3,[4],2,true,6)
        [
        [ 1  0  0  0  0  0]
        [ 0  1  0  0  0  0]
        [ 0  7  0  0  0  0]
        [ 0  5 10 20  0  0]
        [ 0  7 20  0 20  0]
        [ 0  1 24  0 20  0]
        ]
        sage: len(higher_level_UpGj(5,3,[4],2,true,6,extra_data=True))
        4
    """
    t = cputime()
    # Step 1

    k0 = klist[0] % (p - 1)
    n = floor(((p + 1) / (p - 1)) * (m + 1))
    elldash = compute_elldash(p, N, k0, n)
    elldashp = elldash * p
    mdash = m + ceil(n / (p + 1))

    verbose("done step 1", t)
    t = cputime()
    # Steps 2 and 3

    e, Ep1 = higher_level_katz_exp(p, N, k0, m, mdash, elldash, elldashp,
                                   modformsring, bound)
    ell = dimension(transpose(e)[0].parent())
    S = e[0, 0].parent()

    verbose("done steps 2+3", t)
    t = cputime()
    # Step 4

    R = Ep1.parent()
    G = compute_G(p, Ep1)
    Alist = []

    verbose("done step 4a", t)
    t = cputime()
    for k in klist:
        k = ZZ(k)  # convert to sage integer
        kdiv = k // (p - 1)
        Gkdiv = G**kdiv

        T = matrix(S, ell, elldash)
        for i in range(ell):
            ei = R(e[i].list())
            Gkdivei = Gkdiv * ei
            # act by G^kdiv
            for j in range(0, elldash):
                T[i, j] = Gkdivei[p * j]

        verbose("done steps 4b and 5", t)
        t = cputime()

        # Step 6: solve T = AE using fact E is upper triangular.
        # Warning: assumes that T = AE (rather than pT = AE) has
        # a solution over Z/(p^mdash). This has always been the case in
        # examples computed by the author, see Note 3.1.

        A = matrix(S, ell, ell)
        verbose("solving a square matrix problem of dimension %s" % ell)
        verbose("elldash is %s" % elldash)

        for i in range(ell):
            Ti = T[i]
            for j in range(ell):
                ej = Ti.parent()([e[j][l] for l in range(elldash)])
                ejleadpos = ej.nonzero_positions()[0]
                lj = ZZ(ej[ejleadpos])
                A[i, j] = S(ZZ(Ti[j]) / lj)
                Ti = Ti - A[i, j] * ej

        Alist.append(MatrixSpace(Zmod(p**m), ell, ell)(A))
        verbose("done step 6", t)

    if extra_data:
        return Alist, e, elldash, mdash
    else:
        return Alist
def CyclicCodeFromGeneratingPolynomial(n,g,ignore=True):
    r"""
    If g is a polynomial over GF(q) which divides `x^n-1` then
    this constructs the code "generated by g" (ie, the code associated
    with the principle ideal `gR` in the ring
    `R = GF(q)[x]/(x^n-1)` in the usual way).

    The option "ignore" says to ignore the condition that (a) the
    characteristic of the base field does not divide the length (the
    usual assumption in the theory of cyclic codes), and (b) `g`
    must divide `x^n-1`. If ignore=True, instead of returning
    an error, a code generated by `gcd(x^n-1,g)` is created.

    EXAMPLES::

        sage: P.<x> = PolynomialRing(GF(3),"x")
        sage: g = x-1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C
        Linear code of length 4, dimension 3 over Finite Field of size 3
        sage: P.<x> = PolynomialRing(GF(4,"a"),"x")
        sage: g = x^3+1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(9,g); C
        Linear code of length 9, dimension 6 over Finite Field in a of size 2^2
        sage: P.<x> = PolynomialRing(GF(2),"x")
        sage: g = x^3+x+1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(7,g); C
        Linear code of length 7, dimension 4 over Finite Field of size 2
        sage: C.gen_mat()
        [1 1 0 1 0 0 0]
        [0 1 1 0 1 0 0]
        [0 0 1 1 0 1 0]
        [0 0 0 1 1 0 1]
        sage: g = x+1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(4,g); C
        Linear code of length 4, dimension 3 over Finite Field of size 2
        sage: C.gen_mat()
        [1 1 0 0]
        [0 1 1 0]
        [0 0 1 1]

    On the other hand, CyclicCodeFromPolynomial(4,x) will produce a
    ValueError including a traceback error message: "`x` must
    divide `x^4 - 1`". You will also get a ValueError if you
    type

    ::

        sage: P.<x> = PolynomialRing(GF(4,"a"),"x")
        sage: g = x^2+1

    followed by CyclicCodeFromGeneratingPolynomial(6,g). You will also
    get a ValueError if you type

    ::

        sage: P.<x> = PolynomialRing(GF(3),"x")
        sage: g = x^2-1
        sage: C = codes.CyclicCodeFromGeneratingPolynomial(5,g); C
        Linear code of length 5, dimension 4 over Finite Field of size 3

    followed by C = CyclicCodeFromGeneratingPolynomial(5,g,False), with
    a traceback message including "`x^2 + 2` must divide
    `x^5 - 1`".
    """
    P = g.parent()
    x = P.gen()
    F = g.base_ring()
    p = F.characteristic()
    if not(ignore) and p.divides(n):
        raise ValueError('The characteristic %s must not divide %s'%(p,n))
    if not(ignore) and not(g.divides(x**n-1)):
        raise ValueError('%s must divide x^%s - 1'%(g,n))
    gn = GCD([g,x**n-1])
    d = gn.degree()
    coeffs = Sequence(gn.list())
    r1 = Sequence(coeffs+[0]*(n - d - 1))
    Sn = SymmetricGroup(n)
    s = Sn.gens()[0] # assumes 1st gen of S_n is (1,2,...,n)
    rows = [permutation_action(s**(-i),r1) for i in range(n-d)]
    MS = MatrixSpace(F,n-d,n)
    return LinearCode(MS(rows))
示例#8
0
    def __call__(self, A, name='', **kwds):
        r"""
        Create an element of the homspace ``self`` from `A`.

        INPUT:

        - ``A`` -- one of the following:

          - an element of a Hecke algebra

          - a Hecke module morphism

          - a matrix

          - a list of elements of the codomain specifying the images
            of the basis elements of the domain.

        EXAMPLES::

            sage: M = ModularForms(Gamma0(7), 4)
            sage: H = M.Hom(M)
            sage: H(M.hecke_operator(7))
            Hecke module morphism T_7 defined by the matrix
            [ -7   0   0]
            [  0   1 240]
            [  0   0 343]
            Domain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...
            Codomain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...
            sage: H(H(M.hecke_operator(7)))
            Hecke module morphism T_7 defined by the matrix
            [ -7   0   0]
            [  0   1 240]
            [  0   0 343]
            Domain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...
            Codomain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...
            sage: H(matrix(QQ, 3, srange(9)))
            Hecke module morphism defined by the matrix
            [0 1 2]
            [3 4 5]
            [6 7 8]
            Domain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...
            Codomain: Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(7) ...

        TESTS:

        Make sure that the element is created correctly when the codomain is
        not the full module (related to :trac:`21497`)::

            sage: M = ModularSymbols(Gamma0(3),weight=22,sign=1)
            sage: S = M.cuspidal_subspace()
            sage: H = S.Hom(S)
            sage: H(S.gens())
            Hecke module morphism defined by the matrix
            [1 0 0 0 0 0]
            [0 1 0 0 0 0]
            [0 0 1 0 0 0]
            [0 0 0 1 0 0]
            [0 0 0 0 1 0]
            [0 0 0 0 0 1]
            Domain: Modular Symbols subspace of dimension 6 of Modular Symbols space ...
            Codomain: Modular Symbols subspace of dimension 6 of Modular Symbols space ...

            sage: H.zero() in H
            True
            sage: H.one() in H
            True
        """
        try:
            if A.parent() == self:
                A._set_parent(self)
                return A
            A = A.hecke_module_morphism()
            if A.parent() == self:
                A._set_parent(self)
                return A
            else:
                raise TypeError("unable to coerce A to self")
        except AttributeError:
            pass
        side = kwds.get("side", "left")
        if A in self.base_ring():
            dim_dom = self.domain().rank()
            dim_codom = self.codomain().rank()
            if side == "left":
                MS = MatrixSpace(self.base_ring(), dim_dom, dim_codom)
            else:
                MS = MatrixSpace(self.base_ring(), dim_codom, dim_dom)
            if self.domain() == self.codomain():
                A = A * MS.identity_matrix()
            elif A == 0:
                A = MS.zero()
            else:
                raise ValueError('scalars do not coerce to this homspace')
        elif isinstance(A, (list, tuple)):
            A = matrix([self.codomain().coordinate_vector(f) for f in A])
        if side == "right":
            A = A.transpose()
        return HeckeModuleMorphism_matrix(self, A, name, side)
示例#9
0
    def __classcall_private__(cls,
                              data=None,
                              index_set=None,
                              cartan_type=None,
                              cartan_type_check=True):
        """
        Normalize input so we can inherit from sparse integer matrix.

        .. NOTE::

            To disable the Cartan type check, use the optional argument
            ``cartan_type_check = False``.

        EXAMPLES::

            sage: C = CartanMatrix(['A',1,1])
            sage: C2 = CartanMatrix([[2, -2], [-2, 2]])
            sage: C3 = CartanMatrix(matrix([[2, -2], [-2, 2]]), [0, 1])
            sage: C == C2 and C == C3
            True

        TESTS:

        Check that :trac:`15740` is fixed::

            sage: d = DynkinDiagram()
            sage: d.add_edge('a', 'b', 2)
            sage: d.index_set()
            ('a', 'b')
            sage: cm = CartanMatrix(d)
            sage: cm.index_set()
            ('a', 'b')
        """
        # Special case with 0 args and kwds has Cartan type
        if cartan_type is not None and data is None:
            data = CartanType(cartan_type)

        if data is None:
            data = []
            n = 0
            index_set = tuple()
            cartan_type = None
            subdivisions = None
        elif isinstance(data, CartanMatrix):
            if index_set is not None:
                d = {a: index_set[i] for i, a in enumerate(data.index_set())}
                return data.relabel(d)
            return data
        else:
            dynkin_diagram = None
            subdivisions = None

            from sage.combinat.root_system.dynkin_diagram import DynkinDiagram_class
            if isinstance(data, DynkinDiagram_class):
                dynkin_diagram = data
                cartan_type = data._cartan_type
            else:
                try:
                    cartan_type = CartanType(data)
                    dynkin_diagram = cartan_type.dynkin_diagram()
                except (TypeError, ValueError):
                    pass

            if dynkin_diagram is not None:
                n = dynkin_diagram.rank()
                index_set = dynkin_diagram.index_set()
                reverse = {a: i for i, a in enumerate(index_set)}
                data = {(i, i): 2 for i in range(n)}
                for (i, j, l) in dynkin_diagram.edge_iterator():
                    data[(reverse[j], reverse[i])] = -l
            else:
                M = matrix(data)
                if not is_generalized_cartan_matrix(M):
                    raise ValueError(
                        "the input matrix is not a generalized Cartan matrix")
                n = M.ncols()
                data = M.dict()
                subdivisions = M._subdivisions

            if index_set is None:
                index_set = tuple(range(n))
            else:
                index_set = tuple(index_set)

        if len(index_set) != n and len(set(index_set)) != n:
            raise ValueError("the given index set is not valid")

        # We can do the Cartan type initialization later as this is not
        #   a unqiue representation
        mat = typecall(cls, MatrixSpace(ZZ, n, sparse=True), data, False,
                       False)
        # FIXME: We have to initialize the CartanMatrix part separately because
        #   of the __cinit__ of the matrix. We should get rid of this workaround
        mat._CM_init(cartan_type, index_set, cartan_type_check)
        mat._subdivisions = subdivisions
        return mat
示例#10
0
def CongruenceSubgroup_constructor(*args):
    r"""
    Attempt to create a congruence subgroup from the given data.

    The allowed inputs are as follows:

    - A :class:`~sage.groups.matrix_gps.matrix_group.MatrixGroup` object. This
      must be a group of matrices over `\ZZ / N\ZZ` for some `N`, with
      determinant 1, in which case the function will return the group of
      matrices in `SL(2, \ZZ)` whose reduction mod `N` is in the given group.

    - A list of matrices over `\ZZ / N\ZZ` for some `N`. The function will then
      compute the subgroup of `SL(2, \ZZ)` generated by these matrices, and
      proceed as above.

    - An integer `N` and a list of matrices (over any ring coercible to `\ZZ /
      N\ZZ`, e.g. over `\ZZ`). The matrices will then be coerced to `\ZZ /
      N\ZZ`.

    The function checks that the input G is valid. It then tests to see if
    `G` is the preimage mod `N` of some group of matrices modulo a proper
    divisor `M` of `N`, in which case it replaces `G` with this group before
    continuing.

    EXAMPLES::

        sage: from sage.modular.arithgroup.congroup_generic import CongruenceSubgroup_constructor as CS
        sage: CS(2, [[1,1,0,1]])
        Congruence subgroup of SL(2,Z) of level 2, preimage of:
         Matrix group over Ring of integers modulo 2 with 1 generators (
        [1 1]
        [0 1]
        )
        sage: CS([matrix(Zmod(2), 2, [1,1,0,1])])
        Congruence subgroup of SL(2,Z) of level 2, preimage of:
         Matrix group over Ring of integers modulo 2 with 1 generators (
        [1 1]
        [0 1]
        )
        sage: CS(MatrixGroup([matrix(Zmod(2), 2, [1,1,0,1])]))
        Congruence subgroup of SL(2,Z) of level 2, preimage of:
         Matrix group over Ring of integers modulo 2 with 1 generators (
        [1 1]
        [0 1]
        )
        sage: CS(SL(2, 2))
        Modular Group SL(2,Z)

    Some invalid inputs::

        sage: CS(SU(2, 7))
        Traceback (most recent call last):
        ...
        TypeError: Ring of definition must be Z / NZ for some N
    """
    from sage.groups.matrix_gps.matrix_group import is_MatrixGroup
    if is_MatrixGroup(args[0]):
        G = args[0]

    elif isinstance(args[0], list):
        G = MatrixGroup(args[0])

    elif args[0] in ZZ:
        M = MatrixSpace(Zmod(args[0]), 2)
        G = MatrixGroup([M(x) for x in args[1]])

    R = G.matrix_space().base_ring()
    if not hasattr(R, "cover_ring") or R.cover_ring() != ZZ:
        raise TypeError("Ring of definition must be Z / NZ for some N")

    if not all(x.matrix().det() == 1 for x in G.gens()):
        raise ValueError("Group must be contained in SL(2, Z / N)")
    GG = _minimize_level(G)
    if GG in ZZ:
        from .all import Gamma
        return Gamma(GG)
    else:
        return CongruenceSubgroupFromGroup(GG)
示例#11
0
    def get_form(self, connection, cmatrices=None):
        r"""
        Return the form representing ``self`` with respect to the given
        connection ``connection``.

        INPUT:

        - ``connection`` -- connection to which the form should be associated to;
          this can be either a bundle connection as an instance of
          :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection`
          or, in case of the tensor bundle, an affine connection as an instance
          of :class:`~sage.manifolds.differentiable.affine_connection.AffineConnection`
        - ``cmatrices`` -- (default: ``None``) a dictionary of curvature
          matrices with local frames as keys and curvature matrices as items; if
          ``None``, Sage tries to get the curvature matrices from the connection

        OUTPUT:

        - mixed form as an instance of
          :class:`~sage.manifolds.differentiable.mixed_form.MixedForm`
          representing the total characteristic class

        .. NOTE::

            Be aware that depending on the characteristic class and complexity
            of the manifold, computation times may vary a lot. In addition, if
            not done before, the curvature form is computed from the connection,
            here. If this behaviour is not wanted and the curvature form is
            already known, please use the argument ``cmatrices``.

        EXAMPLES:

        Again, consider the Chern character on some 2-dimensional spacetime::

            sage: M = Manifold(2, 'M', structure='Lorentzian')
            sage: X.<t,x> = M.chart()
            sage: E = M.vector_bundle(1, 'E', field='complex'); E
            Differentiable complex vector bundle E -> M of rank 1 over the base
             space 2-dimensional Lorentzian manifold M
            sage: e = E.local_frame('e')

        And again, we define the connection `\nabla^E` in terms of an
        electro-magnetic potential `A(t)`::

            sage: nab = E.bundle_connection('nabla^E', latex_name=r'\nabla^E')
            sage: omega = M.one_form(name='omega')
            sage: A = function('A')
            sage: omega[1] = I*A(t)
            sage: omega.display()
            omega = I*A(t) dx
            sage: nab.set_connection_form(0, 0, omega)

        The Chern character is then given by::

            sage: ch = E.characteristic_class('ChernChar'); ch
            Characteristic class ch of additive type associated to e^x on the
             Differentiable complex vector bundle E -> M of rank 1 over the base
             space 2-dimensional Lorentzian manifold M

        Inserting the connection, the result is a mixed differential form with
        a priori non-zero components in even degrees::

            sage: ch_form = ch.get_form(nab); ch_form
            Mixed differential form ch(E, nabla^E) on the 2-dimensional
             Lorentzian manifold M
            sage: ch_form.display()
            ch(E, nabla^E) = ch_0(E, nabla^E) + zero + ch_1(E, nabla^E)
            sage: ch_form.display_expansion()
            ch(E, nabla^E) = [1] + [0] + [1/2*d(A)/dt/pi dt/\dx]

        Due to long computation times, the form is saved::

            sage: ch_form is ch.get_form(nab)
            True

        """
        from .bundle_connection import BundleConnection
        from .affine_connection import AffineConnection
        if not isinstance(connection, (AffineConnection, BundleConnection)):
            raise TypeError("argument must be an affine connection on the "
                            "manifold or bundle connection on the vector "
                            "bundle")
        if connection not in self._mixed_forms:
            if cmatrices is None:
                if self._class_type == 'Pfaffian':
                    raise NotImplementedError(
                        "At this stage, Pfaffian forms cannot be derived from "
                        "(metric) connections. Please use the argument "
                        "'cmatrices' to insert a dictionary of skew-symmetric "
                        "curvature matrices by hand, instead.")
                cmatrices = {}
                for frame in self._get_min_frames(
                        connection._coefficients.keys()):
                    cmatrix = [[
                        connection.curvature_form(i, j, frame)
                        for j in self._vbundle.irange()
                    ] for i in self._vbundle.irange()]
                    cmatrices[frame] = cmatrix
            # Prepare mixed form:
            name, latex_name = self._name, self._latex_name
            if name is not None and connection._name is not None:
                name += "(" + self._vbundle._name + ", " + connection._name + ")"
            if latex_name is not None and connection._latex_name is not None:
                latex_name += "(" + self._vbundle._latex_name + ", " + \
                              connection._latex_name + ")"
            res = self._base_space.mixed_form(name=name, latex_name=latex_name)
            # BEGIN computation:
            from sage.matrix.matrix_space import MatrixSpace
            for frame, cmatrix in cmatrices.items():
                # Define matrix space:
                dom = frame._domain
                alg = dom.mixed_form_algebra()
                mspace = MatrixSpace(alg, self._rank)
                # Insert "normalized" curvature matrix into polynomial:
                cmatrix = mspace(cmatrix)  # convert curvature matrix
                ncmatrix = self._normalize_matrix(cmatrix)
                rmatrix = self._insert_in_polynomial(ncmatrix)
                # Compute classes:
                if self._class_type == 'additive':
                    rst = rmatrix.trace()  # mixed form
                elif self._class_type == 'multiplicative':
                    rst = rmatrix.det()  # mixed form
                elif self._class_type == 'Pfaffian':
                    rst = rmatrix.pfaffian()  # mixed form
                # Set restriction:
                res.set_restriction(rst)
            # END of computation
            #
            # Preparation to name each homogeneous component; only even (or in
            # the real case, by four divisible) degrees are non-zero:
            if self._class_type == 'Pfaffian':
                deg_dist = self._rank
            elif self._vbundle._field_type == 'real':
                deg_dist = 4
            elif self._vbundle._field_type == 'complex':
                deg_dist = 2
            else:
                # You never know...
                deg_dist = 1
            # Now, define the name for each form:
            for k in res.irange():
                if k % deg_dist != 0 or (self._class_type == 'Pfaffian'
                                         and k == 0):
                    res[k] = 0  # this form is zero anyway
                else:
                    # String representation:
                    if self._name is not None:
                        name = self._name + "_" + str(k // deg_dist) + \
                               "(" + self._vbundle._name
                        if connection._name is not None:
                            name += ", " + connection._name
                        name += ")"
                    # LaTeX name:
                    if self._latex_name is not None:
                        latex_name = self._latex_name + \
                                     r"_{" + str(k // deg_dist) + r"}" + \
                                     r"(" + self._vbundle._latex_name
                        if connection._latex_name is not None:
                            latex_name += r", " + connection._latex_name
                        latex_name += r")"
                    # Set name:
                    res[k].set_name(name=name, latex_name=latex_name)
            # Add the result to the dictionary:
            self._mixed_forms[connection] = res

        return self._mixed_forms[connection]
示例#12
0
    def hecke_matrix(self, L):
        r"""
        Return the `L^{\text{th}}` Hecke matrix.

        INPUT:

        - ``self`` -- SupersingularModule object

        - ``L`` -- integer, positive

        OUTPUT:

        - matrix -- sparse integer matrix

        EXAMPLES:

        This example computes the action of the Hecke operator `T_2`
        on the module of supersingular points on `X_0(1)/F_{37}`::

            sage: S = SupersingularModule(37)
            sage: M = S.hecke_matrix(2)
            sage: M
            [1 1 1]
            [1 0 2]
            [1 2 0]

        This example computes the action of the Hecke operator `T_3`
        on the module of supersingular points on `X_0(1)/F_{67}`::

            sage: S = SupersingularModule(67)
            sage: M = S.hecke_matrix(3)
            sage: M
            [0 0 0 0 2 2]
            [0 0 1 1 1 1]
            [0 1 0 2 0 1]
            [0 1 2 0 1 0]
            [1 1 0 1 0 1]
            [1 1 1 0 1 0]

        .. note::

            The first list --- list_j --- returned by the supersingular_points
            function are the rows *and* column indexes of the above hecke
            matrices and its ordering should be kept in mind when interpreting
            these matrices.

        AUTHORS:

        - David Kohel -- [email protected]

        - Iftikhar Burhanuddin -- [email protected]
        """
        if L in self.__hecke_matrices:
            return self.__hecke_matrices[L]
        SS, II = self.supersingular_points()
        if L == 2:
            # since T_2 gets computed as a side effect of computing the supersingular points
            return self.__hecke_matrices[2]
        Fp2 = self.__finite_field
        h = len(SS)
        R = self.base_ring()
        T_L = MatrixSpace(R, h)(0)
        S, X = Fp2['x'].objgen()

        for i in range(len(SS)):
            ss_i = SS[i]
            phi_L_in_x = Phi_polys(L, X, ss_i)
            rts = phi_L_in_x.roots()
            for r in rts:
                T_L[i, int(II[r[0]])] = r[1]

        self.__hecke_matrices[L] = T_L
        return T_L
示例#13
0
        def matrix(self, base_ring=None, side="left"):
            r"""
            Return the matrix of this morphism in the distinguished
            bases of the domain and codomain.

            INPUT:

            - ``base_ring`` -- a ring (default: ``None``, meaning the
              base ring of the codomain)

            - ``side`` -- "left" or "right" (default: "left")

            If ``side`` is "left", this morphism is considered as
            acting on the left; i.e. each column of the matrix
            represents the image of an element of the basis of the
            domain.

            The order of the rows and columns matches with the order
            in which the bases are enumerated.

            .. SEEALSO:: :func:`Modules.WithBasis.ParentMethods.module_morphism`

            EXAMPLES::

                sage: X = CombinatorialFreeModule(ZZ, [1,2]); x = X.basis()
                sage: Y = CombinatorialFreeModule(ZZ, [3,4]); y = Y.basis()
                sage: phi = X.module_morphism(on_basis = {1: y[3] + 3*y[4], 2: 2*y[3] + 5*y[4]}.__getitem__,
                ....:                         codomain = Y)
                sage: phi.matrix()
                [1 2]
                [3 5]
                sage: phi.matrix(side="right")
                [1 3]
                [2 5]

                sage: phi.matrix().parent()
                Full MatrixSpace of 2 by 2 dense matrices over Integer Ring
                sage: phi.matrix(QQ).parent()
                Full MatrixSpace of 2 by 2 dense matrices over Rational Field

            The resulting matrix is immutable::

                sage: phi.matrix().is_mutable()
                False

            The zero morphism has a zero matrix::

                sage: Hom(X,Y).zero().matrix()
                [0 0]
                [0 0]

            .. TODO::

                Add support for morphisms where the codomain has a
                different base ring than the domain::

                    sage: Y = CombinatorialFreeModule(QQ, [3,4]); y = Y.basis()
                    sage: phi = X.module_morphism(on_basis = {1: y[3] + 3*y[4], 2: 2*y[3] + 5/2*y[4]}.__getitem__,
                    ....:                         codomain = Y)
                    sage: phi.matrix().parent()          # todo: not implemented
                    Full MatrixSpace of 2 by 2 dense matrices over Rational Field

                This currently does not work because, in this case,
                the morphism is just in the category of commutative
                additive groups (i.e. the intersection of the
                categories of modules over `\ZZ` and over `\QQ`)::

                    sage: phi.parent().homset_category()
                    Category of commutative additive semigroups
                    sage: phi.parent().homset_category() # todo: not implemented
                    Category of finite dimensional modules with basis over Integer Ring

            TESTS:

            Check that :trac:`23216` is fixed::

                sage: X = CombinatorialFreeModule(QQ, [])
                sage: Y = CombinatorialFreeModule(QQ, [1,2,3])
                sage: Hom(X,Y).zero().matrix()
                []
                sage: Hom(X,Y).zero().matrix().parent()
                Full MatrixSpace of 3 by 0 dense matrices over Rational Field
            """
            if base_ring is None:
                base_ring = self.codomain().base_ring()

            on_basis = self.on_basis()
            basis_keys = self.domain().basis().keys()
            from sage.matrix.matrix_space import MatrixSpace
            if isinstance(basis_keys, list):
                nrows = len(basis_keys)
            else:
                nrows = basis_keys.cardinality()
            MS = MatrixSpace(base_ring, nrows, self.codomain().dimension())
            m = MS([on_basis(x)._vector_() for x in basis_keys])
            if side == "left":
                m = m.transpose()
            m.set_immutable()
            return m
示例#14
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]
示例#15
0
def QuaternionMatrixGroupGF3():
    r"""
    The quaternion group as a set of `2\times 2` matrices over `GF(3)`.

    OUTPUT:

    A matrix group consisting of `2\times 2` matrices with
    elements from the finite field of order 3.  The group is
    the quaternion group, the nonabelian group of order 8 that
    is not isomorphic to the group of symmetries of a square
    (the dihedral group `D_4`).

    .. note::
        This group is most easily available via ``groups.matrix.QuaternionGF3()``.

    EXAMPLES:

    The generators are the matrix representations of the
    elements commonly called `I` and `J`, while `K`
    is the product of `I` and `J`. ::

        sage: from sage.groups.matrix_gps.finitely_generated import QuaternionMatrixGroupGF3
        sage: Q = QuaternionMatrixGroupGF3()
        sage: Q.order()
        8
        sage: aye = Q.gens()[0]; aye
        [1 1]
        [1 2]
        sage: jay = Q.gens()[1]; jay
        [2 1]
        [1 1]
        sage: kay = aye*jay; kay
        [0 2]
        [1 0]

    TESTS::

        sage: groups.matrix.QuaternionGF3()
        Matrix group over Finite Field of size 3 with 2 generators (
        [1 1]  [2 1]
        [1 2], [1 1]
        )

        sage: Q = QuaternionMatrixGroupGF3()
        sage: QP = Q.as_permutation_group()
        sage: QP.is_isomorphic(QuaternionGroup())
        True
        sage: H = DihedralGroup(4)
        sage: H.order()
        8
        sage: QP.is_abelian(), H.is_abelian()
        (False, False)
        sage: QP.is_isomorphic(H)
        False
    """
    from sage.rings.finite_rings.finite_field_constructor import FiniteField
    from sage.matrix.matrix_space import MatrixSpace
    MS = MatrixSpace(FiniteField(3), 2)
    aye = MS([1,1,1,2])
    jay = MS([2,1,1,1])
    return MatrixGroup([aye, jay])
示例#16
0
    def __init__(self, type="shuffle"):
        self.type = type
        MS34 = MatrixSpace(SR,3,4)
        minimog_modulo11 = MS34([[0,3,infinity,2],[5,9,8,10],[4,1,6,7]])
        minimog_shuffle = MS34([[6,3,0,9],[5,2,7,10],[4,1,8,11]])
        if type == "shuffle":
            self.minimog = minimog_shuffle
        elif type == "modulo11":
            self.minimog = minimog_modulo11
        else:
            raise ValueError("That Minimog type is not implemented.")
        # This initializes the variables in the game.
        MS34 = MatrixSpace(SR,3,4)
        A = self.minimog
        MS33 = MatrixSpace(SR,3,3)
        self.picture00 = MS33([[A[(1,0)],A[(2,3)],A[(0,1)]],[A[(2,2)],A[(1,1)],A[(2,0)]],[A[(0,3)],A[(1,3)],A[(1,2)]]])
        #######     self.picture00 is the "picture at 6"
        self.picture02 = MS33([[A[(1,0)],A[(2,3)],A[(0,1)]],[A[(1,1)],A[(2,0)],A[(2,2)]],[A[(1,2)],A[(0,3)],A[(1,3)]]])
        #######     self.picture02 is the "picture at 1"
        self.picture21 = MS33([[A[(2,2)],A[(1,3)],A[(0,1)]],[A[(0,3)],A[(2,3)],A[(2,0)]],[A[(1,0)],A[(1,1)],A[(1,2)]]])
        #######     self.picture21 is the "picture at 0"

        self.line = [set([]) for i in range(12)]
        self.line[0] = set([(0,0),(0,1),(0,2)])
        self.line[1] = set([(1,0),(1,1),(1,2)])
        self.line[2] = set([(2,0),(2,1),(2,2)])
        self.line[3] = set([(0,2),(1,2),(2,2)])
        self.line[4] = set([(0,1),(1,1),(2,1)])
        self.line[5] = set([(0,0),(1,0),(2,0)])
        self.line[6] = set([(0,0),(1,1),(2,2)])
        self.line[7] = set([(2,0),(0,1),(1,2)])
        self.line[8] = set([(0,2),(1,0),(2,1)])
        self.line[9] = set([(2,0),(1,1),(0,2)])
        self.line[10] = set([(0,0),(1,2),(2,1)])
        self.line[11] = set([(1,0),(0,1),(2,2)])

        self.cross = [set([]) for i in range(18)]
        self.cross[0] = set([(0,0),(0,1),(0,2),(1,0),(2,0)])
        self.cross[1] = set([(0,0),(0,1),(0,2),(1,2),(2,2)])
        self.cross[2] = set([(0,0),(1,0),(2,0),(2,1),(2,2)])
        self.cross[3] = set([(2,0),(2,1),(2,2),(0,2),(1,2)])
        self.cross[4] = set([(0,0),(0,1),(0,2),(1,1),(2,1)])
        self.cross[5] = set([(0,0),(1,0),(2,0),(1,1),(1,2)])
        self.cross[6] = set([(1,0),(1,1),(1,2),(0,2),(2,2)])
        self.cross[7] = set([(0,1),(1,1),(2,1),(2,0),(2,2)])
        self.cross[8] = set([(0,0),(0,1),(1,0),(1,1),(2,2)])
        self.cross[9] = set([(0,0),(1,1),(1,2),(2,1),(2,2)])
        self.cross[10] = set([(2,0),(2,1),(1,0),(1,1),(0,2)])
        self.cross[11] = set([(0,1),(0,2),(1,1),(1,2),(2,0)])
        self.cross[12] = set([(0,0),(1,0),(0,2),(1,2),(2,1)])
        self.cross[13] = set([(1,0),(0,1),(0,2),(2,1),(2,2)])
        self.cross[14] = set([(0,1),(1,0),(1,2),(2,0),(2,2)])
        self.cross[15] = set([(0,0),(0,1),(1,2),(2,0),(2,1)])
        self.cross[16] = set([(1,0),(1,1),(1,2),(0,1),(2,1)])
        self.cross[17] = set([(0,0),(0,2),(1,1),(2,0),(2,2)])
        self.box = set([(i,j) for i in range(3) for j in range(3)])
        self.square = [set([]) for i in range(18)]
        for i in range(18):
            self.square[i] = self.box - self.cross[i]

        MS34_GF3 = MatrixSpace(GF(3),3,4)
        self.col1 = MS34_GF3([[1,0,0,0],[1,0,0,0],[1,0,0,0]])
        self.col2 = MS34_GF3([[0,1,0,0],[0,1,0,0],[0,1,0,0]])
        self.col3 = MS34_GF3([[0,0,1,0],[0,0,1,0],[0,0,1,0]])
        self.col4 = MS34_GF3([[0,0,0,1],[0,0,0,1],[0,0,0,1]])

        self.tet1 = MS34_GF3([[1,1,1,1],[0,0,0,0],[0,0,0,0]])
        self.tet2 = MS34_GF3([[1,0,0,0],[0,1,1,1],[0,0,0,0]])
        self.tet3 = MS34_GF3([[1,0,0,0],[0,0,0,0],[0,1,1,1]])
        self.tet4 = MS34_GF3([[0,1,0,0],[1,0,1,0],[0,0,0,1]])
        self.tet5 = MS34_GF3([[0,0,0,1],[1,1,0,0],[0,0,1,0]])
        self.tet6 = MS34_GF3([[0,0,1,0],[1,0,0,1],[0,1,0,0]])
        self.tet7 = MS34_GF3([[0,1,0,0],[0,0,0,1],[1,0,1,0]])
        self.tet8 = MS34_GF3([[0,0,1,0],[0,1,0,0],[1,0,0,1]])
        self.tet9 = MS34_GF3([[0,0,0,1],[0,0,1,0],[1,1,0,0]])
        self.col = [ self.col1, self.col2, self.col3, self.col4]
        self.tet = [ self.tet1, self.tet2, self.tet3, self.tet4, self.tet5, self.tet6, self.tet7, self.tet8, self.tet9]
示例#17
0
def maximal_grading(L):
    r"""
    Return a maximal grading of a Lie algebra defined over an
    algebraically closed field.

    A maximal grading of a Lie algebra `\mathfrak{g}` is the finest
    possible grading of `\mathfrak{g}` over torsion free abelian groups.
    If `\mathfrak{g} = \bigoplus_{n\in \mathbb{Z}^k} \mathfrak{g}_n`
    is a maximal grading, then there exists no other grading
    `\mathfrak{g} = \bigoplus_{a\in A} \mathfrak{g}_a` over a torsion
    free abelian group `A` such that every `\mathfrak{g}_a` is contained
    in some `\mathfrak{g}_n`.

    EXAMPLES:

    A maximal grading of an abelian Lie algebra puts each basis element
    into an independent layer::

        sage: import sys, pathlib
        sage: sys.path.append(str(pathlib.Path().absolute()))
        sage: from lie_gradings.gradings.grading import maximal_grading
        sage: L = LieAlgebra(QQbar, 4, abelian=True)
        sage: maximal_grading(L)
        Grading over Additive abelian group isomorphic to Z + Z + Z + Z
        of Abelian Lie algebra on 4 generators (L[0], L[1], L[2], L[3])
        over Algebraic Field with nonzero layers
          (1, 0, 0, 0) : (L[3],)
          (0, 1, 0, 0) : (L[2],)
          (0, 0, 1, 0) : (L[1],)
          (0, 0, 0, 1) : (L[0],)

    A maximal grading of a free nilpotent Lie algebra decomposes the Lie
    algebra based on how many times each generator appears in the
    defining Lie bracket::

        sage: L = LieAlgebra(QQbar, 3, step=3)
        sage: maximal_grading(L)
        Grading over Additive abelian group isomorphic to Z + Z + Z of
        Free Nilpotent Lie algebra on 14 generators (X_1, X_2, X_3,
        X_12, X_13, X_23, X_112, X_113, X_122, X_123, X_132, X_133,
        X_223, X_233) over Algebraic Field with nonzero layers
          (1, 0, 0) : (X_1,)
          (0, 1, 0) : (X_2,)
          (1, 1, 0) : (X_12,)
          (1, 2, 0) : (X_122,)
          (2, 1, 0) : (X_112,)
          (0, 0, 1) : (X_3,)
          (0, 1, 1) : (X_23,)
          (0, 1, 2) : (X_233,)
          (0, 2, 1) : (X_223,)
          (1, 0, 1) : (X_13,)
          (1, 0, 2) : (X_133,)
          (1, 1, 1) : (X_123, X_132)
          (2, 0, 1) : (X_113,)
    """

    # define utilities to convert from matrices to vectors and back
    R = L.base_ring()
    n = L.dimension()
    MS = MatrixSpace(R, n, n)

    def matrix_to_vec(A):
        return vector(R, sum((list(Ar) for Ar in A.rows()), []))

    db = L.derivations_basis()

    def derivation_lincomb(vec):
        return sum((vk * dk for vk, dk in zip(vec, db)), MS.zero())

    # iteratively construct larger and larger tori of derivations
    t = []
    while True:
        # compute the centralizer of the torus in the derivation algebra
        ker = FreeModule(R, len(db))
        for der in t:
            # form the matrix of ad(der) with rows
            # the images of basis derivations
            A = matrix([matrix_to_vec(der * X - X * der) for X in db])
            ker = ker.intersection(A.left_kernel())
        cb = [derivation_lincomb(v) for v in ker.basis()]

        # check the basis of the centralizer for semisimple parts outside of t
        gl = FreeModule(R, n * n)
        t_submodule = gl.submodule([matrix_to_vec(der) for der in t])
        for A in cb:
            As, An = jordan_decomposition(A)
            if matrix_to_vec(As) not in t_submodule:
                # extend the torus by As
                t.append(As)
                break
        else:
            # no new elements found, so the torus is maximal
            break

    # compute the eigenspace intersections to get the concrete grading
    common_eigenspaces = [([], FreeModule(R, n))]
    for A in t:
        new_eigenspaces = []
        eig = A.right_eigenspaces()
        for ev, V in common_eigenspaces:
            for ew, W in eig:
                VW = V.intersection(W)
                if VW.dimension() > 0:
                    new_eigenspaces.append((ev + [ew], VW))
        common_eigenspaces = new_eigenspaces

    if not t:
        # zero dimensional maximal torus
        # the only grading is the trivial grading
        magma = AdditiveAbelianGroup([])
        layers = {magma.zero(): L.basis().list()}
        return grading(L, layers, magma=magma)

    # define a grading with layers indexed by tuples of eigenvalues
    cm = get_coercion_model()
    all_eigenvalues = sum((ev for ev, V in common_eigenspaces), [])
    k = len(common_eigenspaces[0][0])
    evR = cm.common_parent(*all_eigenvalues)
    layers = {
        tuple(ev): [L.from_vector(v) for v in V.basis()]
        for ev, V in common_eigenspaces
    }
    magma = evR.cartesian_product(*[evR] * (k - 1))
    gr = grading(L, layers, magma=magma)

    # convert to a grading over Z^k
    return gr.universal_realization()
def rational_diagonal_form(self, return_matrix=False):
    """
    Returns a diagonal form equivalent to Q over the fraction field of
    its defining ring.  If the return_matrix is True, then we return
    the transformation matrix performing the diagonalization as the
    second argument.

    INPUT:
        none

    OUTPUT:
        Q -- the diagonalized form of this quadratic form
        (optional) T -- matrix which diagonalizes Q (over it's fraction field)

    EXAMPLES::

        sage: Q = QuadraticForm(ZZ, 2, [0,1,-1])
        sage: Q
        Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 0 1 ]
        [ * -1 ]
        sage: Q.rational_diagonal_form()
        Quadratic form in 2 variables over Rational Field with coefficients:
        [ -2 0 ]
        [ * 1/8 ]

    ::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q.rational_diagonal_form(return_matrix=True)
        (
        Quadratic form in 4 variables over Rational Field with coefficients:
        [ 1 0 0 0 ]
        [ * 3 0 0 ]
        [ * * 5 0 ]
        [ * * * 7 ]                                                          ,
        <BLANKLINE>
        [1 0 0 0]
        [0 1 0 0]
        [0 0 1 0]
        [0 0 0 1]
        )

    ::

        sage: Q1 = QuadraticForm(ZZ, 4, [1, 1, 0, 0, 1, 0, 0, 1, 0, 18])
        sage: Q1
        Quadratic form in 4 variables over Integer Ring with coefficients:
        [ 1 1 0 0 ]
        [ * 1 0 0 ]
        [ * * 1 0 ]
        [ * * * 18 ]
        sage: Q1.rational_diagonal_form(return_matrix=True)
        (
        Quadratic form in 4 variables over Rational Field with coefficients:
        [ 1 0 0 0 ]
        [ * 3/4 0 0 ]
        [ * * 1 0 ]
        [ * * * 18 ]                                                         ,
        <BLANKLINE>
        [   1 -1/2    0    0]
        [   0    1    0    0]
        [   0    0    1    0]
        [   0    0    0    1]
        )
    """
    n = self.dim()
    Q = copy.deepcopy(self)
    Q.__init__(FractionField(self.base_ring()), self.dim(), self.coefficients())
    MS = MatrixSpace(Q.base_ring(), n, n)
    T = MS(1)

    ## Clear the entries one row at a time.
    for i in range(n):

        ## Deal with rows where the diagonal entry is zero.
        if Q[i,i] == 0:

            ## Look for a non-zero entry and use it to make the diagonal non-zero (if it exists)
            for j in range(i+1, n):
                if Q[i,j] != 0:
                    temp = MS(1)
                    if Q[i,j] + Q[j,j] == 0:
                        temp[j, i] = -1
                    else:
                        temp[j, i] = 1

                    ## Apply the transformation
                    Q = Q(temp)
                    T = T * temp
                    break

        ## Create a matrix which deals with off-diagonal entries (all at once for each row)
        temp = MS(1)
        for j in range(i+1, n):
            if Q[i,j] != 0:
                temp[i,j] = -Q[i,j] / (Q[i,i] * 2)    ## This should only occur when Q[i,i] != 0, which the above step guarantees.

        Q = Q(temp)
        T = T * temp

    ## Return the appropriate output
    if return_matrix:
        return Q, T
    else:
        return Q
示例#19
0
def level1_UpGj(p, klist, m, extra_data=False):
    r"""
    Return a list `[A_k]` of square matrices over ``IntegerRing(p^m)``
    parameterised by the weights k in ``klist``.

    The matrix `A_k` is the finite square matrix which occurs on input
    p, k and m in Step 6 of Algorithm 1 in [Lau2011]_.

    Notational change from paper: In Step 1 following Wan we defined
    j by `k = k_0 + j(p-1)` with `0 \le k_0 < p-1`. Here we replace j by
    ``kdiv`` so that we may use j as a column index for matrices.

    INPUT:

    - ``p`` -- prime at least 5.
    - ``klist`` -- list of integers congruent modulo `(p-1)` (the weights).
    - ``m`` -- positive integer.
    - ``extra_data`` -- (default: ``False``) boolean

    OUTPUT:

    - list of square matrices. If ``extra_data`` is ``True``, return also
      extra intermediate data, namely the matrix `E` in [Lau2011]_ and
      the integers ``elldash`` and ``mdash``.

    EXAMPLES::

        sage: from sage.modular.overconvergent.hecke_series import level1_UpGj
        sage: level1_UpGj(7,[100],5)
        [
        [    1   980  4802     0     0]
        [    0 13727 14406     0     0]
        [    0 13440  7203     0     0]
        [    0  1995  4802     0     0]
        [    0  9212 14406     0     0]
        ]
        sage: len(level1_UpGj(7,[100],5,extra_data=True))
        4

    """
    # Step 1
    t = cputime()

    k0 = klist[0] % (p - 1)
    n = floor(((p + 1) / (p - 1)) * (m + 1))
    ell = dimension_modular_forms(1, k0 + n * (p - 1))
    ellp = ell * p
    mdash = m + ceil(n / (p + 1))

    verbose("done step 1", t)
    t = cputime()
    # Steps 2 and 3

    e, Ep1 = katz_expansions(k0, p, ellp, mdash, n)

    verbose("done steps 2+3", t)
    t = cputime()
    # Step 4

    G = compute_G(p, Ep1)
    Alist = []

    verbose("done step 4a", t)
    t = cputime()
    for k in klist:
        k = ZZ(k)  # convert to sage integer
        kdiv = k // (p - 1)
        Gkdiv = G**kdiv
        u = []
        for i in range(0, ell):
            ei = e[i]
            ui = Gkdiv * ei
            u.append(ui)

        verbose("done step 4b", t)
        t = cputime()
        # Step 5 and computation of T in Step 6

        S = e[0][0].parent()
        T = matrix(S, ell, ell)

        for i in range(0, ell):
            for j in range(0, ell):
                T[i, j] = u[i][p * j]

        verbose("done step 5", t)
        t = cputime()
        # Step 6: solve T = AE using fact E is upper triangular.
        # Warning: assumes that T = AE (rather than pT = AE) has
        # a solution over Z/(p^mdash). This has always been the case in
        # examples computed by the author, see Note 3.1.

        A = matrix(S, ell, ell)
        verbose("solving a square matrix problem of dimension %s" % ell, t)

        for i in range(0, ell):
            Ti = T[i]
            for j in range(0, ell):
                ej = Ti.parent()([e[j][l] for l in range(0, ell)])
                lj = ZZ(ej[j])
                A[i, j] = S(ZZ(Ti[j]) / lj)
                Ti = Ti - A[i, j] * ej

        Alist.append(MatrixSpace(Zmod(p**m), ell, ell)(A))
        verbose("done step 6", t)

    if extra_data:
        return Alist, e, ell, mdash
    else:
        return Alist
示例#20
0
    def supersingular_points(self):
        r"""
        This function computes the supersingular j-invariants over the
        finite field associated to self.

        INPUT:

        -  ``self`` -- SupersingularModule object

        OUTPUT: list_j, dict_j -- list_j is the list of supersingular
            j-invariants, dict_j is a dictionary with these
            j-invariants as keys and their indexes as values. The
            latter is used to speed up j-invariant look-up. The
            indexes are based on the order of their *discovery*.

        EXAMPLES:

        The following examples calculate supersingular j-invariants
        over finite fields with characteristic 7, 11 and 37::

            sage: S = SupersingularModule(7)
            sage: S.supersingular_points()
            ([6], {6: 0})

            sage: S = SupersingularModule(11)
            sage: S.supersingular_points()
            ([1, 0], {0: 1, 1: 0})

            sage: S = SupersingularModule(37)
            sage: S.supersingular_points()
            ([8, 27*a + 23, 10*a + 20], {8: 0, 10*a + 20: 2, 27*a + 23: 1})

        AUTHORS:

        - David Kohel -- [email protected]

        - Iftikhar Burhanuddin -- [email protected]
        """
        try:
            return (self._ss_points_dic, self._ss_points)
        except AttributeError:
            pass
        Fp2 = self.__finite_field
        level = self.__level
        prime = Fp2.characteristic()
        X = Fp2['x'].gen()
        jinv = supersingular_j(Fp2)

        dim = dimension_supersingular_module(prime, level)

        pos = int(0)
        #using list to keep track of explored nodes using pos
        ss_points = [jinv]

        #using  to keep track of index of the previous node
        ss_points_pre = [-1]

        #using dictionary for fast j-invariant look-up
        ss_points_dic = {jinv:pos}

        T2_matrix = MatrixSpace(rings.Integers(), dim, sparse=True)(0)

        while pos < len(ss_points):
            if pos == 0:
                neighbors = Phi_polys(2,X,ss_points[pos]).roots()
            else:
                j_prev = ss_points_pre[pos]
                # TODO: These are quadratic polynomials -- maybe we should use the
                # quadratic formula and fast square root finding (??)
                neighbors = Phi2_quad(X, ss_points[j_prev], ss_points[pos]).roots()

            for (xj,ej) in neighbors:
                if xj not in ss_points_dic:
                    j = len(ss_points)
                    ss_points += [xj]
                    ss_points_pre += [pos]
                    ss_points_dic[xj] = j
                else:
                    j = ss_points_dic[xj]
                T2_matrix[pos, j] += ej
            # end for
            if pos != 0:
                # also record the root from j_prev
                T2_matrix[pos, j_prev] += 1
            pos += int(1)

        self.__hecke_matrices[2] = T2_matrix
        return (ss_points, ss_points_dic)
示例#21
0
    def __init__(self, n=1, R=0):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: H = groups.matrix.Heisenberg(n=2, R=5)
            sage: TestSuite(H).run()  # long time
            sage: H.category()
            Category of finitely generated finite enumerated groups
            sage: H = groups.matrix.Heisenberg(n=2, R=4)
            sage: TestSuite(H).run()  # long time
            sage: H = groups.matrix.Heisenberg(n=3)
            sage: TestSuite(H).run(max_runs=30, skip="_test_elements")  # long time
            sage: H = groups.matrix.Heisenberg(n=2, R=GF(4))
            sage: TestSuite(H).run()  # long time

        TESTS::

            sage: groups.matrix.Heisenberg(n=2, R=ZZ).category()
            Category of finitely generated infinite enumerated groups
        """
        def elementary_matrix(i, j, val, MS):
            elm = copy(MS.one())
            elm[i, j] = val
            elm.set_immutable()
            return elm

        self._n = n
        self._ring = R
        # We need the generators of the ring as a commutative additive group
        if self._ring is ZZ:
            ring_gens = [self._ring.one()]
        else:
            if self._ring.cardinality() == self._ring.characteristic():
                ring_gens = [self._ring.one()]
            else:
                # This is overkill, but is the only way to ensure
                #   we get all of the elements
                ring_gens = list(self._ring)

        dim = ZZ(n + 2)
        MS = MatrixSpace(self._ring, dim)
        gens_x = [
            elementary_matrix(0, j, gen, MS) for j in range(1, dim - 1)
            for gen in ring_gens
        ]
        gens_y = [
            elementary_matrix(i, dim - 1, gen, MS) for i in range(1, dim - 1)
            for gen in ring_gens
        ]
        gen_z = [elementary_matrix(0, dim - 1, gen, MS) for gen in ring_gens]
        gens = gens_x + gens_y + gen_z

        from sage.libs.gap.libgap import libgap
        gap_gens = [libgap(single_gen) for single_gen in gens]
        gap_group = libgap.Group(gap_gens)

        cat = Groups().FinitelyGenerated()
        if self._ring in Rings().Finite():
            cat = cat.Finite()
        else:
            cat = cat.Infinite()

        FinitelyGeneratedMatrixGroup_gap.__init__(self,
                                                  ZZ(dim),
                                                  self._ring,
                                                  gap_group,
                                                  category=cat)
示例#22
0
    def hecke_matrix(self,L):
        r"""
        This function returns the `L^{\text{th}}` Hecke matrix.

        INPUT:

        - ``self`` -- SupersingularModule object

        - ``L`` -- integer, positive

        OUTPUT:
            matrix -- sparse integer matrix

        EXAMPLES:
        This example computes the action of the Hecke operator `T_2`
        on the module of supersingular points on `X_0(1)/F_{37}`::

            sage: S = SupersingularModule(37)
            sage: M = S.hecke_matrix(2)
            sage: M
            [1 1 1]
            [1 0 2]
            [1 2 0]

        This example computes the action of the Hecke operator `T_3`
        on the module of supersingular points on `X_0(1)/F_{67}`::

            sage: S = SupersingularModule(67)
            sage: M = S.hecke_matrix(3)
            sage: M
            [0 0 0 0 2 2]
            [0 0 1 1 1 1]
            [0 1 0 2 0 1]
            [0 1 2 0 1 0]
            [1 1 0 1 0 1]
            [1 1 1 0 1 0]

        .. note::

            The first list --- list_j --- returned by the supersingular_points
            function are the rows *and* column indexes of the above hecke
            matrices and its ordering should be kept in mind when interpreting
            these matrices.

        AUTHORS:

        - David Kohel -- [email protected]

        - Iftikhar Burhanuddin -- [email protected]
        """
        if L in self.__hecke_matrices:
            return self.__hecke_matrices[L]
        SS, II = self.supersingular_points()
        if L == 2:
            # since T_2 gets computed as a side effect of computing the supersingular points
            return self.__hecke_matrices[2]
        Fp2 = self.__finite_field
        h = len(SS)
        R = self.base_ring()
        T_L = MatrixSpace(R,h)(0)
        S, X = Fp2['x'].objgen()

        if L in [3,5,7,11]:
            for i in range(len(SS)):
                ss_i = SS[i]
                phi_L_in_x = Phi_polys(L, X, ss_i)
                rts = phi_L_in_x.roots()
                for r in rts:
                    T_L[i,int(II[r[0]])] = r[1]
        else:
            DBMP = ClassicalModularPolynomialDatabase()
            phi_L = DBMP[L]
            M, (x,y) =Fp2['x,y'].objgens()
            phi_L = phi_L(x,y)

            # As an optimization, we compute the coefficients of y and evaluate
            # them, since univariate polynomial evaluation is much faster than
            # multivariate evaluation (in Sage :-( ).
            uni_coeff = [phi_L(x,0).univariate_polynomial()] + \
                              [phi_L.coefficient(y**i).univariate_polynomial() for
                                          i in range(1,phi_L.degree(y)+1)]
            for i in range(len(SS)):
                ss_i = SS[i]
                ## We would do the eval below, but it is too slow (right now).
                #phi_L_in_x = phi_L(X, ss_i)

                phi_L_in_x = S([f(ss_i) for f in uni_coeff])
                rts = phi_L_in_x.roots()
                for r in rts:
                    T_L[i,int(II[r[0]])] = r[1]

        self.__hecke_matrices[L] = T_L
        return T_L
def cholesky_decomposition(self, bit_prec=53):
    """
    Give the Cholesky decomposition of this quadratic form `Q` as a real matrix
    of precision ``bit_prec``.

    RESTRICTIONS:
        Q must be given as a QuadraticForm defined over `\ZZ`, `\QQ`, or some
        real field. If it is over some real field, then an error is raised if
        the precision given is not less than the defined precision of the real
        field defining the quadratic form!

    REFERENCE:
        From Cohen's "A Course in Computational Algebraic Number Theory" book,
        p 103.

    INPUT:
        ``bit_prec`` -- a natural number (default 53).

    OUTPUT:
        an upper triangular real matrix of precision ``bit_prec``.


    TO DO:
        If we only care about working over the real double field (RDF), then we
        can use the ``cholesky()`` method present for square matrices over that.

    .. note::

        There is a note in the original code reading

        ::

            ##/////////////////////////////////////////////////////////////////////////////////////////////////
            ##/// Finds the Cholesky decomposition of a quadratic form -- as an upper-triangular matrix!
            ##/// (It's assumed to be global, hence twice the form it refers to.)  <-- Python revision asks:  Is this true?!? =|
            ##/////////////////////////////////////////////////////////////////////////////////////////////////


    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1])
        sage: Q.cholesky_decomposition()
        [ 1.00000000000000 0.000000000000000 0.000000000000000]
        [0.000000000000000  1.00000000000000 0.000000000000000]
        [0.000000000000000 0.000000000000000  1.00000000000000]

    ::

        sage: Q = QuadraticForm(QQ, 3, range(1,7)); Q
        Quadratic form in 3 variables over Rational Field with coefficients:
        [ 1 2 3 ]
        [ * 4 5 ]
        [ * * 6 ]
        sage: Q.cholesky_decomposition()
        [ 1.00000000000000  1.00000000000000  1.50000000000000]
        [0.000000000000000  3.00000000000000 0.333333333333333]
        [0.000000000000000 0.000000000000000  3.41666666666667]

    """

    ## Check that the precision passed is allowed.
    if isinstance(self.base_ring(),
                  RealField_class) and (self.base_ring().prec() < bit_prec):
        raise RuntimeError(
            "Oops! The precision requested is greater than that of the given quadratic form!"
        )

    ## 1. Initialization
    n = self.dim()
    R = RealField(bit_prec)
    MS = MatrixSpace(R, n, n)
    Q = MS(R(0.5)) * MS(
        self.matrix()
    )  ## Initialize the real symmetric matrix A with the matrix for Q(x) = x^t * A * x

    ## DIAGNOSTIC
    #print "After 1:  Q is \n" + str(Q)

    ## 2. Loop on i
    for i in range(n):
        for j in range(i + 1, n):
            Q[j, i] = Q[i, j]  ## Is this line redundant?
            Q[i, j] = Q[i, j] / Q[i, i]

        ## 3. Main Loop
        for k in range(i + 1, n):
            for l in range(k, n):
                Q[k, l] = Q[k, l] - Q[k, i] * Q[i, l]

    ## 4. Zero out the strictly lower-triangular entries
    for i in range(n):
        for j in range(i):
            Q[i, j] = 0

    return Q
示例#24
0
def _rational_diagonal_form_and_transformation(self):
    """
    Return a diagonal form equivalent to the given quadratic from and
    the corresponding transformation matrix. This is over the fraction
    field of the base ring of the given quadratic form.

    OUTPUT: a tuple ``(D,T)`` where

    - ``D`` -- the diagonalized form of this quadratic form.

    - ``T`` -- transformation matrix. This is such that
      ``T.transpose() * self.matrix() * T`` gives ``D.matrix()``.

    Both ``D`` and ``T`` are defined over the fraction field of the
    base ring of the given form.

    EXAMPLES::

        sage: Q = QuadraticForm(ZZ, 4, [1, 1, 0, 0, 1, 0, 0, 1, 0, 18])
        sage: Q
        Quadratic form in 4 variables over Integer Ring with coefficients:
        [ 1 1 0 0 ]
        [ * 1 0 0 ]
        [ * * 1 0 ]
        [ * * * 18 ]
        sage: Q._rational_diagonal_form_and_transformation()
        (
        Quadratic form in 4 variables over Rational Field with coefficients:
        [ 1 0 0 0 ]
        [ * 3/4 0 0 ]
        [ * * 1 0 ]
        [ * * * 18 ]                                                         ,
        <BLANKLINE>
        [   1 -1/2    0    0]
        [   0    1    0    0]
        [   0    0    1    0]
        [   0    0    0    1]
        )
    """
    n = self.dim()
    K = self.base_ring().fraction_field()
    Q = self.base_change_to(K)
    MS = MatrixSpace(K, n, n)

    try:
        # Try PARI if the type is supported
        pariself = self._pari_()
        # Check that conversion back works
        MS(pariself.sage())
    except Exception:
        pass
    else:
        R = pariself.qfgaussred()
        # Diagonal matrix
        D = MS()
        for i in range(n):
            D[i, i] = R[i, i]
        Q = Q.parent()(D)
        # Transformation matrix (inverted)
        T = MS(R.sage())
        for i in range(n):
            T[i, i] = K.one()
        try:
            return Q, ~T
        except ZeroDivisionError:
            # Singular case is not fully supported by PARI
            pass

    # General case if conversion to/from PARI failed
    T = MS(1)

    ## Clear the entries one row at a time.
    for i in range(n):

        ## Deal with rows where the diagonal entry is zero.
        if Q[i, i] == 0:

            ## Look for a non-zero entry and use it to make the diagonal non-zero (if it exists)
            for j in range(i + 1, n):
                if Q[i, j] != 0:
                    temp = MS(1)
                    if Q[i, j] + Q[j, j] == 0:
                        temp[j, i] = -1
                    else:
                        temp[j, i] = 1

                    ## Apply the transformation
                    Q = Q(temp)
                    T = T * temp
                    break

        ## Create a matrix which deals with off-diagonal entries (all at once for each row)
        temp = MS(1)
        for j in range(i + 1, n):
            if Q[i, j] != 0:
                temp[i, j] = -Q[i, j] / (
                    Q[i, i] * 2
                )  ## This should only occur when Q[i,i] != 0, which the above step guarantees.

        Q = Q(temp)
        T = T * temp

    return Q, T
示例#25
0
    def __init__(self, diffop, dz, derivatives, nterms_est):

        deq_Scalars = diffop.base_ring().base_ring()
        E = dz.parent()
        if deq_Scalars.characteristic() != 0:
            raise ValueError("only makes sense for scalar rings of "
                             "characteristic 0")
        assert deq_Scalars is dz.parent() or deq_Scalars != dz.parent()

        #### Recurrence operator

        # Reduce to the case of a number field generated by an algebraic
        # integer. This is mainly intended to avoid computing gcds (due to
        # denominators in the representation of number field elements) in the
        # product tree, but could also be useful to extend the field using Pari
        # in the future.
        NF_rec, AlgInts_rec = _number_field_with_integer_gen(deq_Scalars)
        # ore_algebra currently does not support orders as scalar rings
        Pols = PolynomialRing(NF_rec, 'n')
        Rops, Sn = ore_algebra.OreAlgebra(Pols, 'Sn').objgen()
        recop = diffop.to_S(Rops).primitive_part().numerator()
        recop = lcm([p.denominator() for p in recop.coefficients()]) * recop
        # Ensure that ordrec >= orddeq. When the homomorphic image of diffop in
        # Rops is divisible by Sn, it can happen that the recop (e.g., after
        # normalization to Sn-valuation 0) has order < orddeq, and our strategy
        # of using vectors of coefficients of the form [u(n-s'), ..., u(n+r-1)]
        # with s'=s-r does not work in this case.
        orddelta = recop.order() - diffop.order()
        if orddelta < 0:
            recop = Sn**(-orddelta) * recop

        #### Choose computation domains

        if ((isinstance(E, (RealBallField, ComplexBallField)) or E is QQ
             or utilities.is_QQi(E) or E is RLF or E is CLF)
                and (deq_Scalars is QQ or utilities.is_QQi(deq_Scalars))):
            # Special-case QQ and QQ[i] to use arb matrices
            # (overwrites AlgInts_rec)
            self.StepMatrix_class = StepMatrix_arb
            self.binsplit_threshold = 8
            # Working precision. We typically want operations on exact balls to
            # be exact, so that overshooting shouldn't be a problem.
            # XXX Less clear in the case dz ∈ XBF!
            # XXX The rough estimate below ignores the height of rec and dz.
            # prec = nterms_est*(recop.degree()*nterms_est.nbits()
            #                    + recop.order().nbits() + 1)
            prec = 8 + nterms_est * (1 + ZZ(ZZ(recop.order()).nbits()).nbits())
            if (E is QQ or isinstance(E, RealBallField)) and deq_Scalars is QQ:
                AlgInts_rec = AlgInts_pow = RealBallField(prec)
            else:
                AlgInts_rec = AlgInts_pow = ComplexBallField(prec)
            if is_NumberField(E):
                pow_den = AlgInts_pow(dz.denominator())
            else:
                pow_den = AlgInts_pow.one()
        else:
            self.StepMatrix_class = StepMatrix_generic
            self.binsplit_threshold = 64
            if is_NumberField(E):
                # In fact we should probably do something similar for dz in any
                # finite-dimensional Q-algebra. (But how?)
                NF_pow, AlgInts_pow = _number_field_with_integer_gen(E)
                pow_den = NF_pow(dz).denominator()
            else:
                # This includes the case E = ZZ, but dz could live in pretty
                # much any algebra over deq_Scalars (including matrices,
                # intervals...). Then the computation of sums_row may take time,
                # but we still hope to gain something on the computation of the
                # coefficients and/or limit interval blow-up thanks to the use
                # of binary splitting.
                AlgInts_pow = E
                pow_den = ZZ.one()
            assert pow_den.parent() is ZZ
        assert AlgInts_pow is AlgInts_rec or AlgInts_pow != AlgInts_rec

        #### Recurrence matrix

        self.recop = recop

        self.orddeq = diffop.order()
        self.ordrec = recop.order()
        self.orddelta = self.ordrec - self.orddeq

        Pols_rec, n = PolynomialRing(AlgInts_rec, 'n').objgen()
        self.rec_coeffs = [
            -Pols_rec(recop[i])(n - self.orddelta) for i in xrange(self.ordrec)
        ]
        self.rec_den = Pols_rec(recop.leading_coefficient())(n - self.orddelta)
        # Guard against various problems related to number field embeddings and
        # uniqueness
        assert Pols_rec.base_ring() is AlgInts_rec
        assert self.rec_den.base_ring() is AlgInts_rec
        assert self.rec_den(
            self.rec_den.base_ring().zero()).parent() is AlgInts_rec

        # Also store a version of the recurrence operator of the form
        # b[0](n) + b[1](n) S^(-1) + ··· + b[s](n) S^(-s).
        # This is convenient to share code with other implementations, or at
        # least make the implementations easier to compare.
        # XXX: understand what to do about variable names!
        self.bwrec = [
            recop[self.ordrec - k](Rops.base_ring().gen() - self.ordrec)
            for k in xrange(self.ordrec + 1)
        ]

        #### Power of dz. Note that this part does not depend on n.

        # If we extend the removal of denominators above to algebras other than
        # number fields, it would probably make more sense to move this into
        # the caller. --> support dz in non-com ring (mat)? power series work
        # only over com rings
        Series_pow = PolynomialRing(AlgInts_pow, 'delta')
        self.pow_num = Series_pow([pow_den * dz, pow_den])
        self.pow_den = pow_den
        self.derivatives = derivatives

        #### Partial sums

        # We need a parent containing both the coefficients of the operator and
        # the evaluation point.
        # XXX: Is this the correct way to get one? Should we use
        # canonical_coercion()? Something else?
        # XXX: This is not powerful enough to find a number field containing
        # two given number fields (both given with embeddings into CC)

        # Work around #14982 (fixed) + weaknesses of the coercion framework for orders
        #Series_sums = sage.categories.pushout.pushout(AlgInts_rec, Series_pow)
        try:
            AlgInts_sums = sage.categories.pushout.pushout(
                AlgInts_rec, AlgInts_pow)
        except sage.structure.coerce_exceptions.CoercionException:
            AlgInts_sums = sage.categories.pushout.pushout(NF_rec, AlgInts_pow)
        assert AlgInts_sums is AlgInts_rec or AlgInts_sums != AlgInts_rec
        assert AlgInts_sums is AlgInts_pow or AlgInts_sums != AlgInts_pow

        Series_sums = PolynomialRing(AlgInts_sums, 'delta')
        assert Series_sums.base_ring() is AlgInts_sums
        # for speed
        self.Series_sums = Series_sums
        self.series_class_sums = type(Series_sums.gen())

        self.Mat_rec = MatrixSpace(AlgInts_rec, self.ordrec, self.ordrec)
        self.Mat_sums_row = MatrixSpace(Series_sums, 1, self.ordrec)
        self.Mat_series_sums = self.Mat_rec.change_ring(Series_sums)
示例#26
0
def algebraic_topological_model_delta_complex(K, base_ring=None):
    r"""
    Algebraic topological model for cell complex ``K``
    with coefficients in the field ``base_ring``.

    This has the same basic functionality as
    :func:`algebraic_topological_model`, but it also works for
    `\Delta`-complexes. For simplicial and cubical complexes it is
    somewhat slower, though.

    INPUT:

    - ``K`` -- a simplicial complex, a cubical complex, or a
      `\Delta`-complex
    - ``base_ring`` -- coefficient ring; must be a field

    OUTPUT: a pair ``(phi, M)`` consisting of

    - chain contraction ``phi``
    - chain complex `M`

    See :func:`algebraic_topological_model` for the main
    documentation. The difference in implementation between the two:
    this uses matrix and vector algebra. The other function does more
    of the computations "by hand" and uses cells (given as simplices
    or cubes) to index various dictionaries. Since the cells in
    `\Delta`-complexes are not as nice, the other function does not
    work for them, while this function relies almost entirely on the
    structure of the associated chain complex.

    EXAMPLES::

        sage: from sage.homology.algebraic_topological_model import algebraic_topological_model_delta_complex as AT_model
        sage: RP2 = simplicial_complexes.RealProjectivePlane()
        sage: phi, M = AT_model(RP2, GF(2))
        sage: M.homology()
        {0: Vector space of dimension 1 over Finite Field of size 2,
         1: Vector space of dimension 1 over Finite Field of size 2,
         2: Vector space of dimension 1 over Finite Field of size 2}
        sage: T = delta_complexes.Torus()
        sage: phi, M = AT_model(T, QQ)
        sage: M.homology()
        {0: Vector space of dimension 1 over Rational Field,
         1: Vector space of dimension 2 over Rational Field,
         2: Vector space of dimension 1 over Rational Field}

    If you want to work with cohomology rather than homology, just
    dualize the outputs of this function::

        sage: M.dual().homology()
        {0: Vector space of dimension 1 over Rational Field,
         1: Vector space of dimension 2 over Rational Field,
         2: Vector space of dimension 1 over Rational Field}
        sage: M.dual().degree_of_differential()
        1
        sage: phi.dual()
        Chain homotopy between:
          Chain complex endomorphism of Chain complex with at most 3 nonzero terms over Rational Field
          and Chain complex morphism:
            From: Chain complex with at most 3 nonzero terms over Rational Field
            To:   Chain complex with at most 3 nonzero terms over Rational Field

    In degree 0, the inclusion of the homology `M` into the chain
    complex `C` sends the homology generator to a single vertex::

        sage: K = delta_complexes.Simplex(2)
        sage: phi, M = AT_model(K, QQ)
        sage: phi.iota().in_degree(0)
        [0]
        [0]
        [1]

    In cohomology, though, one needs the dual of every degree 0 cell
    to detect the degree 0 cohomology generator::

        sage: phi.dual().iota().in_degree(0)
        [1]
        [1]
        [1]

    TESTS::

        sage: T = cubical_complexes.Torus()
        sage: C = T.chain_complex()
        sage: H, M = AT_model(T, QQ)
        sage: C.differential(1) * H.iota().in_degree(1).column(0) == 0
        True
        sage: C.differential(1) * H.iota().in_degree(1).column(1) == 0
        True
        sage: coC = T.chain_complex(cochain=True)
        sage: coC.differential(1) * H.dual().iota().in_degree(1).column(0) == 0
        True
        sage: coC.differential(1) * H.dual().iota().in_degree(1).column(1) == 0
        True
    """
    def conditionally_sparse(m):
        """
        Return a sparse matrix if the characteristic is zero.

        Multiplication of matrices with low density seems to be quicker
        if the matrices are sparse, when over the rationals. Over
        finite fields, dense matrices are faster regardless of
        density.
        """
        if base_ring == QQ:
            return m.sparse_matrix()
        else:
            return m

    if not base_ring.is_field():
        raise ValueError('the coefficient ring must be a field')

    # The following are all dictionaries indexed by dimension.
    # For each n, gens[n] is an ordered list of the n-cells generating the complex M.
    gens = {}
    pi_data = {}
    phi_data = {}
    iota_data = {}

    for n in range(-1, K.dimension() + 1):
        gens[n] = []

    C = K.chain_complex(base_ring=base_ring)
    n_cells = []
    pi_cols = []
    iota_cols = {}

    for dim in range(K.dimension() + 1):
        # old_cells: cells one dimension lower.
        old_cells = n_cells
        # n_cells: the standard basis for the vector space C.free_module(dim).
        n_cells = C.free_module(dim).gens()
        diff = C.differential(dim)
        # diff is sparse and low density. Dense matrices are faster
        # over finite fields, but for low density matrices, sparse
        # matrices are faster over the rationals.
        if base_ring != QQ:
            diff = diff.dense_matrix()

        rank = len(n_cells)
        old_rank = len(old_cells)

        # Create some matrix spaces to try to speed up matrix creation.
        MS_pi_t = MatrixSpace(base_ring, old_rank, len(gens[dim - 1]))

        pi_old = MS_pi_t.matrix(pi_cols).transpose()
        iota_cols_old = iota_cols
        iota_cols = {}
        pi_cols_old = pi_cols
        pi_cols = []
        phi_old = MatrixSpace(base_ring,
                              rank,
                              old_rank,
                              sparse=(base_ring == QQ)).zero()
        phi_old_cols = phi_old.columns()
        phi_old = conditionally_sparse(phi_old)
        to_be_deleted = []

        zero_vector = vector(base_ring, rank)
        pi_nrows = pi_old.nrows()

        for c_idx, c in enumerate(n_cells):
            # c_bar = c - phi(bdry(c)):
            # Avoid a bug in matrix-vector multiplication (trac 19378):
            if not diff:
                c_bar = c
                pi_bdry_c_bar = False
            else:
                if base_ring == QQ:
                    c_bar = c - phi_old * (diff * c)
                    pi_bdry_c_bar = conditionally_sparse(pi_old) * (diff *
                                                                    c_bar)
                else:
                    c_bar = c - phi_old * diff * c
                    pi_bdry_c_bar = conditionally_sparse(pi_old) * diff * c_bar

            # One small typo in the published algorithm: it says
            # "if bdry(c_bar) == 0", but should say
            # "if pi(bdry(c_bar)) == 0".
            if not pi_bdry_c_bar:
                # Append c to list of gens.
                gens[dim].append(c_idx)
                # iota(c) = c_bar
                iota_cols[c_idx] = c_bar
                # pi(c) = c
                pi_cols.append(c)
            else:
                # Take any u in gens so that lambda_i = <u, pi(bdry(c_bar))> != 0.
                # u_idx will be the index of the corresponding cell.
                (u_idx, lambda_i) = pi_bdry_c_bar.leading_item()
                for (u_idx, lambda_i) in iteritems(pi_bdry_c_bar):
                    if u_idx not in to_be_deleted:
                        break
                # This element/column needs to be deleted from gens and
                # iota_old. Do that later.
                to_be_deleted.append(u_idx)
                # pi(c) = 0.
                pi_cols.append(zero_vector)
                for c_j_idx, c_j in enumerate(old_cells):
                    # eta_ij = <u, pi(c_j)>.
                    # That is, eta_ij is the u_idx entry in the vector pi_old * c_j:
                    eta_ij = c_j.dot_product(pi_old.row(u_idx))
                    if eta_ij:
                        # Adjust phi(c_j).
                        phi_old_cols[c_j_idx] += eta_ij * lambda_i**(
                            -1) * c_bar
                        # Adjust pi(c_j).
                        pi_cols_old[c_j_idx] -= eta_ij * lambda_i**(
                            -1) * pi_bdry_c_bar

                # The matrices involved have many zero entries. For
                # such matrices, using sparse matrices is faster over
                # the rationals, slower over finite fields.
                phi_old = matrix(base_ring,
                                 phi_old_cols,
                                 sparse=(base_ring == QQ)).transpose()
                keep = vector(
                    base_ring, pi_nrows,
                    {i: 1
                     for i in range(pi_nrows) if i not in to_be_deleted})
                cols = [v.pairwise_product(keep) for v in pi_cols_old]
                pi_old = MS_pi_t.matrix(cols).transpose()

        # Here cols is a temporary storage for the columns of iota.
        cols = [iota_cols_old[i] for i in sorted(iota_cols_old.keys())]
        for r in sorted(to_be_deleted, reverse=True):
            del cols[r]
            del gens[dim - 1][r]
        iota_data[dim - 1] = matrix(base_ring, len(gens[dim - 1]), old_rank,
                                    cols).transpose()
        # keep: rows to keep in pi_cols_old. Start with all
        # columns, then delete those in to_be_deleted.
        keep = sorted(set(range(pi_nrows)).difference(to_be_deleted))
        # Now cols is a temporary storage for columns of pi.
        cols = [v.list_from_positions(keep) for v in pi_cols_old]
        pi_data[dim - 1] = matrix(base_ring, old_rank, len(gens[dim - 1]),
                                  cols).transpose()
        phi_data[dim - 1] = phi_old

        V_gens = VectorSpace(base_ring, len(gens[dim]))
        if pi_cols:
            cols = []
            for v in pi_cols:
                cols.append(V_gens(v.list_from_positions(gens[dim])))
            pi_cols = cols

    pi_data[dim] = matrix(base_ring, rank, len(gens[dim]), pi_cols).transpose()
    cols = [iota_cols[i] for i in sorted(iota_cols.keys())]
    iota_data[dim] = matrix(base_ring, len(gens[dim]), rank, cols).transpose()

    # M_data will contain (trivial) matrices defining the differential
    # on M. Keep track of the sizes using "M_rows" and "M_cols", which are
    # just the ranks of consecutive graded pieces of M.
    M_data = {}
    M_rows = 0
    for n in range(K.dimension() + 1):
        M_cols = len(gens[n])
        M_data[n] = zero_matrix(base_ring, M_rows, M_cols)
        M_rows = M_cols

    M = ChainComplex(M_data, base_ring=base_ring, degree=-1)

    pi = ChainComplexMorphism(pi_data, C, M)
    iota = ChainComplexMorphism(iota_data, M, C)
    phi = ChainContraction(phi_data, pi, iota)
    return phi, M
def ReedSolomonCode(n, k, F, pts=None):
    r"""
    Given a finite field `F` of order `q`, let
    `n` and `k` be chosen such that
    `1 \leq k \leq n \leq q`. Pick `n` distinct
    elements of `F`, denoted
    `\{ x_1, x_2, ... , x_n \}`. Then, the codewords are
    obtained by evaluating every polynomial in `F[x]` of degree
    less than `k` at each `x_i`:
    
    .. math::
    
       C = \left\{ \left( f(x_1), f(x_2), ..., f(x_n) \right), f \in F[x],
       {\rm deg}(f)<k \right\}.     
    
    
    `C` is a `[n, k, n-k+1]` code. (In particular, `C` is MDS.)
    
    INPUT: n : the length k : the dimension F : the base ring pts :
    (optional) list of n points in F (if None then Sage picks n of them
    in the order given to the elements of F)
    
    EXAMPLES::
    
        sage: C = ReedSolomonCode(6,4,GF(7)); C
        Linear code of length 6, dimension 4 over Finite Field of size 7
        sage: C.minimum_distance()
        3
        sage: C = ReedSolomonCode(6,4,GF(8,"a")); C
        Linear code of length 6, dimension 4 over Finite Field in a of size 2^3
        sage: C.minimum_distance()
        3
        sage: C.minimum_distance(algorithm='gap') # long time, check d=n-k+1
        3
        sage: F.<a> = GF(3^2,"a")
        sage: pts = [0,1,a,a^2,2*a,2*a+1]
        sage: len(Set(pts)) == 6 # to make sure there are no duplicates
        True
        sage: C = ReedSolomonCode(6,4,F,pts); C
        Linear code of length 6, dimension 4 over Finite Field in a of size 3^2
        sage: C.minimum_distance()
        3

    REFERENCES:

    - [W] http://en.wikipedia.org/wiki/Reed-Solomon
    """
    q = F.order()
    power = lambda x, n, F: (x == 0 and n == 0) and F(1) or F(
        x**n)  # since 0^0 is undefined
    if n > q or k > n or k > q:
        raise ValueError, "RS codes does not exist with the given input."
    if not (pts == None) and not (len(pts) == n):
        raise ValueError, "You must provide exactly %s distinct points of %s" % (
            n, F)
    if (pts == None):
        pts = []
        i = 0
        for x in F:
            if i < n:
                pts.append(x)
                i = i + 1
    MS = MatrixSpace(F, k, n)
    rowsG = []
    rowsG = [[power(x, j, F) for x in pts] for j in range(k)]
    G = MS(rowsG)
    return LinearCode(G, d=n - k + 1)
    def __init__(self,
                 R,
                 ngens=None,
                 gram_matrix=None,
                 names=None,
                 index_set=None):
        """
        Initialize self.

        TESTS::

            sage: V = lie_conformal_algebras.Weyl(QQ)
            sage: TestSuite(V).run()
        """
        from sage.matrix.matrix_space import MatrixSpace
        if ngens:
            try:
                from sage.rings.all import ZZ
                assert ngens in ZZ and ngens % 2 == 0
            except AssertionError:
                raise ValueError("ngens needs to be an even positive " +
                                 "Integer, got {}".format(ngens))
        if (gram_matrix is not None):
            if ngens is None:
                ngens = gram_matrix.dimensions()[0]
            try:
                assert (gram_matrix in MatrixSpace(R, ngens, ngens))
            except AssertionError:
                raise ValueError(
                    "The gram_matrix should be a skew-symmetric " +
                    "{0} x {0} matrix, got {1}".format(ngens, gram_matrix))
            if (not gram_matrix.is_skew_symmetric()) or \
                                                (gram_matrix.is_singular()):
                raise ValueError("The gram_matrix should be a non degenerate " +
                                 "skew-symmetric {0} x {0} matrix, got {1}"\
                                 .format(ngens,gram_matrix))
        elif (gram_matrix is None):
            if ngens is None:
                ngens = 2
            A = identity_matrix(R, ngens / 2)
            from sage.matrix.special import block_matrix
            gram_matrix = block_matrix([[R.zero(), A], [-A, R.zero()]])

        latex_names = None
        if (names is None) and (index_set is None):
            names = 'alpha'
            latex_names = tuple(r'\alpha_{%d}' % i \
                                      for i in range (ngens)) + ('K',)
        names, index_set = standardize_names_index_set(names=names,
                                                       index_set=index_set,
                                                       ngens=ngens)
        weyldict = {(i, j): {
            0: {
                ('K', 0): gram_matrix[index_set.rank(i),
                                      index_set.rank(j)]
            }
        }
                    for i in index_set for j in index_set}

        super(WeylLieConformalAlgebra, self).__init__(R,
                                                      weyldict,
                                                      names=names,
                                                      latex_names=latex_names,
                                                      index_set=index_set,
                                                      central_elements=('K', ))
        self._gram_matrix = gram_matrix
def TrivialCode(F, n):
    MS = MatrixSpace(F, 1, n)
    return LinearCode(MS(0))
示例#30
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()
    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