예제 #1
0
def __cast_input(X, parent):
    if (__check_input(X, parent)):
        return Matrix(parent, X)

    raise TypeError("The input %s can not be seen as a matrix of %s" %
                    (X, parent))
예제 #2
0
def verify_algebraically_PS(g, P0, alpha, trace_and_norm, verbose=True):
    # input:
    # * P0 (only necessary to shift the series)
    # * [trace_numerator, trace_denominator, norm_numerator, norm_denominator]
    # output:
    # a boolean
    if verbose:
        print "verify_algebraically()"
    L = P0.base_ring()
    assert alpha.base_ring() is L
    L_poly = PolynomialRing(L, "xL")
    xL = L_poly.gen()
    # shifting the series makes our life easier
    trace_numerator, trace_denominator, norm_numerator, norm_denominator = [
        L_poly(coeff)(L_poly.gen() + P0[0]) for coeff in trace_and_norm
    ]
    L_fpoly = L_poly.fraction_field()
    trace = L_fpoly(trace_numerator) / L_fpoly(trace_denominator)
    norm = L_fpoly(norm_numerator) / L_fpoly(norm_denominator)

    Xpoly = L_poly([norm(0), -trace(0), 1])
    if verbose:
        print "xpoly = %s" % Xpoly

    if Xpoly.is_irreducible():
        M = Xpoly.root_field("c")
    else:
        # this avoids bifurcation later on in the code
        M = NumberField(xL, "c")
    if verbose:
        print M

    xi_degree = max(
        [elt.degree() for elt in [trace_denominator, norm_denominator]])
    D = 2 * xi_degree
    hard_bound = D + (4 + 2)
    soft_bound = hard_bound + 5
    M_ps = PowerSeriesRing(M, "T", default_prec=soft_bound)
    T = M_ps.gen()
    Tsub = T + P0[0]

    trace_M = M_ps(trace)
    norm_M = M_ps(norm)
    sqrtdisc = sqrt(trace_M**2 - 4 * norm_M)
    x1 = (trace_M - sqrtdisc) / 2
    x2 = (trace_M + sqrtdisc) / 2

    y1 = sqrt(g(x1))

    y2 = sqrt(g(x2))

    iy = 1 / sqrt(g(Tsub))

    dx1 = x1.derivative(T)
    dx2 = x2.derivative(T)

    dx1_y1 = dx1 / y1
    dx2_y2 = dx2 / y2

    eq1 = Matrix([[-2 * M_ps(alpha.row(0).list())(Tsub) * iy, dx1_y1, dx2_y2]])
    eq2 = Matrix(
        [[-2 * M_ps(alpha.row(1).list())(Tsub) * iy, x1 * dx1_y1,
          x2 * dx2_y2]])
    branches = Matrix([[1, 1, 1], [1, 1, -1], [1, -1, 1], [1, -1,
                                                           -1]]).transpose()
    meq1 = eq1 * branches
    meq2 = eq2 * branches
    algzero = False
    for j in range(4):
        if meq1[0, j] == 0 and meq2[0, j] == 0:
            algzero = True
            break
    if verbose:
        print "Done, verify_algebraically()  = %s" % algzero
    return algzero
예제 #3
0
    def invariant_generators(self):
        r"""
        Return invariant ring generators.

        Computes generators for the polynomial ring
        `F[x_1,\ldots,x_n]^G`, where `G` in `GL(n,F)` is a finite matrix
        group.

        In the "good characteristic" case the polynomials returned
        form a minimal generating set for the algebra of `G`-invariant
        polynomials.  In the "bad" case, the polynomials returned
        are primary and secondary invariants, forming a not
        necessarily minimal generating set for the algebra of
        `G`-invariant polynomials.

        ALGORITHM:

        Wraps Singular's ``invariant_algebra_reynolds`` and ``invariant_ring``
        in ``finvar.lib``.

        EXAMPLES::

            sage: F = GF(7); MS = MatrixSpace(F,2,2)
            sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])]
            sage: G = MatrixGroup(gens)
            sage: G.invariant_generators()
            [x1^7*x2 - x1*x2^7,
             x1^12 - 2*x1^9*x2^3 - x1^6*x2^6 + 2*x1^3*x2^9 + x2^12,
             x1^18 + 2*x1^15*x2^3 + 3*x1^12*x2^6 + 3*x1^6*x2^12 - 2*x1^3*x2^15 + x2^18]

            sage: q = 4; a = 2
            sage: MS = MatrixSpace(QQ, 2, 2)
            sage: gen1 = [[1/a,(q-1)/a],[1/a, -1/a]]; gen2 = [[1,0],[0,-1]]; gen3 = [[-1,0],[0,1]]
            sage: G = MatrixGroup([MS(gen1),MS(gen2),MS(gen3)])
            sage: G.cardinality()
            12
            sage: G.invariant_generators()
            [x1^2 + 3*x2^2, x1^6 + 15*x1^4*x2^2 + 15*x1^2*x2^4 + 33*x2^6]

            sage: F = CyclotomicField(8)
            sage: z = F.gen()
            sage: a = z+1/z
            sage: b = z^2
            sage: MS = MatrixSpace(F,2,2)
            sage: g1 = MS([[1/a, 1/a], [1/a, -1/a]])
            sage: g2 = MS([[-b, 0], [0, b]])
            sage: G=MatrixGroup([g1,g2])
            sage: G.invariant_generators()
            [x1^4 + 2*x1^2*x2^2 + x2^4,
             x1^5*x2 - x1*x2^5,
             x1^8 + 28/9*x1^6*x2^2 + 70/9*x1^4*x2^4 + 28/9*x1^2*x2^6 + x2^8]

        AUTHORS:

        - David Joyner, Simon King and Martin Albrecht.

        REFERENCES:

        - Singular reference manual

        - [Stu1993]_

        - S. King, "Minimal Generating Sets of non-modular invariant
          rings of finite groups", :arxiv:`math/0703035`.
        """
        from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
        from sage.interfaces.singular import singular
        gens = self.gens()
        singular.LIB("finvar.lib")
        n = self.degree()  # len((gens[0].matrix()).rows())
        F = self.base_ring()
        q = F.characteristic()
        # test if the field is admissible
        if F.gen() == 1:  # we got the rationals or GF(prime)
            FieldStr = str(F.characteristic())
        elif hasattr(F, 'polynomial'):  # we got an algebraic extension
            if len(F.gens()) > 1:
                raise NotImplementedError(
                    "can only deal with finite fields and (simple algebraic extensions of) the rationals"
                )
            FieldStr = '(%d,%s)' % (F.characteristic(), str(F.gen()))
        else:  # we have a transcendental extension
            FieldStr = '(%d,%s)' % (F.characteristic(), ','.join(
                str(p) for p in F.gens()))

        # Setting Singular's variable names
        # We need to make sure that field generator and variables get different names.
        if str(F.gen())[0] == 'x':
            VarStr = 'y'
        else:
            VarStr = 'x'
        VarNames = '(' + ','.join(
            (VarStr + str(i) for i in range(1, n + 1))) + ')'
        # The function call and affectation below have side-effects. Do not remove!
        # (even if pyflakes say so)
        R = singular.ring(FieldStr, VarNames, 'dp')
        if hasattr(F, 'polynomial') and F.gen() != 1:
            # we have to define minpoly
            singular.eval('minpoly = ' +
                          str(F.polynomial()).replace('x', str(F.gen())))
        A = [singular.matrix(n, n, str((x.matrix()).list())) for x in gens]
        Lgens = ','.join((x.name() for x in A))
        PR = PolynomialRing(F, n, [VarStr + str(i) for i in range(1, n + 1)])

        if q == 0 or (q > 0 and self.cardinality() % q):
            from sage.all import Matrix
            try:
                elements = [g.matrix() for g in self.list()]
            except (TypeError, ValueError):
                elements
            if elements is not None:
                ReyName = 't' + singular._next_var_name()
                singular.eval('matrix %s[%d][%d]' %
                              (ReyName, self.cardinality(), n))
                for i in range(1, self.cardinality() + 1):
                    M = Matrix(F, elements[i - 1])
                    D = [{} for foobar in range(self.degree())]
                    for x, y in M.dict().items():
                        D[x[0]][x[1]] = y
                    for row in range(self.degree()):
                        for t in D[row].items():
                            singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)' %
                                          (ReyName, i, row + 1, ReyName, i,
                                           row + 1, repr(t[1]), t[0] + 1))
                IRName = 't' + singular._next_var_name()
                singular.eval('matrix %s = invariant_algebra_reynolds(%s)' %
                              (IRName, ReyName))
            else:
                ReyName = 't' + singular._next_var_name()
                singular.eval('list %s=group_reynolds((%s))' %
                              (ReyName, Lgens))
                IRName = 't' + singular._next_var_name()
                singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])' %
                              (IRName, ReyName))

            OUT = [
                singular.eval(IRName + '[1,%d]' % (j))
                for j in range(1, 1 + int(singular('ncols(' + IRName + ')')))
            ]
            return [PR(gen) for gen in OUT]
        if self.cardinality() % q == 0:
            PName = 't' + singular._next_var_name()
            SName = 't' + singular._next_var_name()
            singular.eval('matrix %s,%s=invariant_ring(%s)' %
                          (PName, SName, Lgens))
            OUT = [
                singular.eval(PName + '[1,%d]' % (j))
                for j in range(1, 1 + singular('ncols(' + PName + ')'))
            ]
            OUT += [
                singular.eval(SName + '[1,%d]' % (j))
                for j in range(2, 1 + singular('ncols(' + SName + ')'))
            ]
            return [PR(gen) for gen in OUT]
예제 #4
0
def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a = 1):
    """
    INPUT:
        - ``frob_matrix`` -- a matrix representing the p-power Frobenius lift to Z_q up to some precision
        - ``charpoly_prec`` -- a vector ai, such that, frob_matrix.change_ring(ZZ).charpoly()[i] will be correct mod p^ai, this can be easily deduced from the hodge numbers and knowing the q-adic precision of frob_matrix
        - ``p`` -- prime p
        - ``weight`` -- weight of the motive
        - ``a`` -- q = q^a

    OUTPUT:
        a list of integers corresponding to the characteristic polynomial of the Frobenius action

    Examples:
    sage: M = Matrix([[O(17), 8 + O(17)], [O(17), 15 + O(17)]])
    sage: charpoly_frobenius(M, [2, 1, 1], 17, 1, 1)
        [17, 2, 1]

    sage: R = Zq(17 ** 2 , names=('a',));
    sage: M = Matrix(R, [[8*17 + 16*17**2 + O(17**3), 8 + 11*17 + O(17**2)], [7*17**2 + O(17**3), 15 + 8*17 + O(17**2)]])
    sage: charpoly_frobenius(M, [3, 2, 2], 17, 1, 2)
        [289, 30, 1]

    sage: M = Matrix([[8*31 + 8*31**2 + O(31**3), O(31**3), O(31**3), O(31**3)], [O(31**3), 23*31 + 22*31**2 + O(31**3), O(31**3), O(31**3)], [O(31**3), O(31**3), 27 + 7*31 + O(31**3), O(31**3)], [O(31**3), O(31**3), O(31**3), 4 + 23*31 + O(31**3)]])
    sage: charpoly_frobenius(M, [4, 3, 2, 2, 2], 31, 1, 1)
        [961, 0, 46, 0, 1]

    sage: M = Matrix([[4*43**2 + O(43**3), 17*43 + 11*43**2 + O(43**3), O(43**3), O(43**3), 17 + 37*43 + O(43**3), O(43**3)], [30*43 + 23*43**2 + O(43**3), 5*43 + O(43**3), O(43**3), O(43**3), 3 + 38*43 + O(43**3), O(43**3)], [O(43**3), O(43**3), 9*43 + 32*43**2 + O(43**3), 13 + 25*43 + O(43**3), O(43**3), 17 + 18*43 + O(43**3)], [O(43**3), O(43**3), 22*43 + 25*43**2 + O(43**3), 11 + 24*43 + O(43**3), O(43**3), 36 + 5*43 + O(43**3)], [42*43 + 15*43**2 + O(43**3), 22*43 + 8*43**2 + O(43**3), O(43**3), O(43**3), 29 + 4*43 + O(43**3), O(43**3)], [O(43**3), O(43**3), 6*43 + 19*43**2 + O(43**3), 8 + 24*43 + O(43**3), O(43**3), 31 + 42*43 + O(43**3)]])
    sage: charpoly_frobenius(M, [5, 4, 3, 2, 2, 2, 2], 43, 1, 1)
        [79507, 27735, 6579, 1258, 153, 15, 1]

    """
    if a > 1:
        F = frob_matrix
        sigmaF = F;
        for _ in range(a - 1):
            sigmaF = Matrix(F.base_ring(), [[elt.frobenius() for elt in row] for row in sigmaF.rows()])
            F = F * sigmaF
        F = F.change_ring(ZZ)
    else:
        F = frob_matrix.change_ring(ZZ)
    cp = F.charpoly().list();
    
    assert len(charpoly_prec) == len(cp)
    assert cp[-1] == 1;
    
    # reduce cp mod prec
    degree = F.nrows()
    mod = [0] * (degree + 1)
    for i in range(degree):
        mod[i] = p**charpoly_prec[i]
        cp[i] = cp[i] % mod[i]
    
    
    # figure out the sign
    
    if weight % 2 == 1:
        # for odd weight the sign is always 1
        # it's the charpoly of a USp matrix
        # and charpoly of a symplectic matrix is reciprocal
        sign = 1
    else:
        for i in range(degree/2):
            p_power = p ** min( charpoly_prec[i], charpoly_prec[degree - i] + (a*(degree - 2*i)*weight/2)); 
            # Note: degree*weight = 0 mod 2
            if cp[i] % p_power != 0 and cp[degree-i] % p_power != 0:
                if 0 == (cp[i] + cp[degree - i] * p**(a*(degree-2*i)*weight/2)) %  p_power:
                    sign = -1;
                else:
                    sign = 1;
                assert 0 == (-sign*cp[i] + cp[degree - i] * p**(a*(degree-2*i)*weight/2)) %  p_power;
                break;
    cp[0] = sign * p**(a*degree*weight/2)
    
    #calculate the i-th power sum of the roots and correct cp allong the way
    halfdegree = ceil(degree/2) + 1;
    e = [None]*(halfdegree)
    for k in range(halfdegree):
        e[k] = cp[degree - k] if (k%2 ==0) else -cp[degree - k]
        if k > 0:
            # verify if p^charpoly_prec[degree - k] > 2*degree/k * q^(w*k/2)
            assert log(k)/log(p) + charpoly_prec[degree - k] > log(2*degree)/log(p) + a*0.5*weight*k, "log(k)/log(p) + charpoly_prec[degree - k] <= log(2*degree)/log(p) + a*0.5*weight*k, k = %d" % k
    #e[k] = \sum x_{i_1} x_{i_2} ... x_{i_k} # where x_* are eigenvalues
    # and i_1 < i_2 ... < i_k
    
    #s[k] = \sum x_i ^k for i>0
    s = [None]*(halfdegree)
    for k in range(1, halfdegree):
        # assume that s[i] and e[i] are correct for i < k
        # e[k] correct modulo mod[degree - k]
        # S = sum (-1)^i e[k-i] * s[i]
        # s[k] = (-1)^(k-1) (k*e[k] + S) ==> (-1)^(k-1) s[k] - S = k*e[k] 
        S = sum( (-1)**i * e[k-i] * s[i] for i in range(1,k))
        s[k] = (-1)**(k - 1) * (S + k*e[k])
        #hence s[k] is correct modulo k*mod[degree - k] 
        localmod = k*mod[degree - k]
        s[k] = s[k] % localmod
        
        # |x_i| = p^(w*0.5)
        # => s[k] <= degree*p^(a*w*k*0.5)
        # recall, 2*degree*p^(a*w*k*0.5) /k < mod[degree - k] 
        if s[k] > degree*p**(a*weight*k*0.5) :
            s[k] = -(-s[k] % localmod);
        
        #now correct e[k] with:
        # (-1)^(k-1) s[k] - S = k*e[k] 
        e[k] = (-S + (-1)**(k - 1) * s[k])//k;
        assert (-S + (-1)**(k - 1) * s[k])%k == 0
        cp[degree - k] = e[k] if k % 2 == 0 else -e[k]
        cp[k] = sign*cp[degree - k]*p**(a*(degree-2*k)*weight/2)
    return cp    
예제 #5
0
def bound_rosati(alpha_geo):
    H = Matrix(4, 4)
    H[0, 2] = H[1, 3] = -1
    H[2, 0] = H[3, 1] = 1
    return (alpha_geo * H * alpha_geo.transpose() * H.inverse()).trace() / 2
예제 #6
0
def integer_bivariate(p, k, X, Y, early_return=True):
    """
    Computes small integer roots of a bivariate polynomial.
    More information: Coron J., "Finding Small Roots of Bivariate Integer Polynomial Equations: a Direct Approach"
    :param p: the polynomial
    :param k: the amount of shifts to use
    :param X: an approximate bound on the x roots
    :param Y: an approximate bound on the y roots
    :param early_return: try to return as early as possible (default: true)
    :return: a generator generating small roots (tuples of x and y roots) of the polynomial
    """
    x, y = p.parent().gens()
    delta = max(p.degrees())

    (i0, j0), W = max(map(lambda kv: (kv[0], abs(kv[1])),
                          p(x * X, y * Y).dict().items()),
                      key=lambda kv: kv[1])

    logging.debug("Calculating n...")
    S = Matrix(k**2)
    for a in range(k):
        for b in range(k):
            s = x**a * y**b * p
            for i in range(k):
                for j in range(k):
                    S[a * k + b, i * k + j] = s.coefficient([i0 + i, j0 + j])

    n = abs(S.det())
    logging.debug(f"Found n = {n}")

    # Monomials are collected in "left" and "right" lists, which determine where the columns are in relation to eachother
    # This partition ensures the Hermite form will set desired monomial coefficients to zero
    logging.debug("Generating monomials...")
    left_monomials = []
    right_monomials = []
    for i in range(k + delta):
        for j in range(k + delta):
            if 0 <= i - i0 < k and 0 <= j - j0 < k:
                left_monomials.append(x**i * y**j)
            else:
                right_monomials.append(x**i * y**j)

    assert len(left_monomials) == k**2
    monomials = left_monomials + right_monomials

    L = Matrix(k**2 + (k + delta)**2, (k + delta)**2)
    row = 0
    logging.debug("Generating s shifts...")
    for a in range(k):
        for b in range(k):
            s = x**a * y**b * p
            s = s(x * X, y * Y)
            for col, monomial in enumerate(monomials):
                L[row, col] = s.monomial_coefficient(monomial)

            row += 1

    logging.debug("Generating additional shifts...")
    for col, monomial in enumerate(monomials):
        r = monomial * n
        r = r(x * X, y * Y)
        L[row, col] = r.monomial_coefficient(monomial)
        row += 1

    logging.debug(f"Lattice size: {L.nrows()} x {L.ncols()}")
    logging.debug("Generating Echelon form...")
    L = L.echelon_form(algorithm="pari0")

    logging.debug(
        f"Executing the LLL algorithm on the sublattice ({k ** 2} x {k ** 2})..."
    )
    L2 = L.submatrix(k**2, k**2, (k + delta)**2 - k**2).LLL()

    new_polynomials = []
    logging.debug("Reconstructing polynomials...")
    for row in range(L2.nrows()):
        new_polynomial = 0
        # Only use right monomials now (corresponding the the sublattice)
        for col, monomial in enumerate(right_monomials):
            new_polynomial += L2[row, col] * monomial

        if new_polynomial.is_constant():
            continue

        new_polynomial = new_polynomial(x / X, y / Y).change_ring(ZZ)
        new_polynomials.append(new_polynomial)

    logging.debug("Calculating resultants...")
    for h in new_polynomials:
        res = p.resultant(h, y)
        if res.is_constant():
            continue

        for x0, _ in res.univariate_polynomial().roots():
            h_ = p.subs(x=x0)
            if h_.is_constant():
                continue

            for y0, _ in h_.univariate_polynomial().roots():
                yield int(x0), int(y0)

        if early_return:
            # Assuming that the first "good" polynomial in the lattice doesn't provide roots, we return.
            return
예제 #7
0
def E(n, i, j, ring=QQ):
    A = Matrix(ring, n)
    A[i, j] = 1
    return A
예제 #8
0
def qrp(A, rank = None, extra_prec = 16):
    m = A.nrows()
    n = A.ncols()
    s = min(m,n)
    if rank is not None:
        #s = min(s, rank + 1);
        pass;
    base_prec = A.base_ring().precision();
    base_field = A.base_ring()
    if is_ComplexField(base_field):
        field = ComplexField(base_prec + extra_prec + m);
    else:
        field = RealField(base_prec + extra_prec + m);
#    field = base_field; 
    R = copy(A);
    A = A.change_ring(field);
    P = [ j for j in xrange(n) ];
    Q = identity_matrix(field,m)
#    print A.base_ring()
#    print Q.base_ring()
    
    normbound = field(2)**(-0.5*field.precision());

    colnorms2 = [ float_sum([ R[k,j].norm() for k in range(m)]) for j in range(n) ];
    for j in xrange(s):
        # find column with max norm
        maxnorm2 = colnorms2[j];
        p = j;
        for k in xrange(j, n):
            if colnorms2[k] > maxnorm2:
                p = k;
                maxnorm2 = colnorms2[k];     
        #it is worth it to recompute the maxnorm                
        xnorm2 = float_sum([ R[i,p].norm() for i in range(j, m)])                
        xnorm = sqrt(xnorm2);
        # swap j and p in A, P and colnorms
        if j != p:
            P[j], P[p] = P[p], P[j]
            colnorms2[j], colnorms2[p] = colnorms2[p], colnorms2[j]
            for i in xrange(0, m):
                R[i, j], R[i, p] = R[i, p], R[i, j];
        
        # compute householder vector
        u = [ R[k,j] for k in xrange(j, m) ];
        alpha = R[j,j];
        # alphanorm = alpha.abs();
        if alpha.real() < 0:
            u[0] -= xnorm
            z = -1
        else:
            u[0] += xnorm
            z = 1
            

        
        beta = xnorm*(xnorm + alpha * z); 
        if beta.abs() < normbound:
            beta = float_sum( [u[i].conjugate() * R[i+j,j] for i in range(m - j)]) 
        if beta == field(0):
            break;
        beta = 1/beta;
        
        # H = I - beta * u * u^*
        # Apply householder matrix
        #update R
        R[j,j] = -z * xnorm;
        for i in xrange(j+1,m):
            R[i,j] = 0
        for k in xrange(j+1, n):
            lambdR = beta * float_sum( [u[l - j].conjugate() * R[l, k] for l in xrange(j, m)] );
            for i in xrange(j, m):
                R[i, k] -= lambdR * u[i - j];
        
        #update Q
        for k in xrange(m):
            lambdQ = float_sum( [u[l - j].conjugate() * Q[l, k] for l in xrange(j, m)] );
            lambdQ *= beta
            for i in xrange(j,m):
                Q[i, k] -= lambdQ * u[i - j];
        
        for k in xrange(j + 1, n):
            square = R[j,k].norm();
            colnorms2[k] -= square;
            # sometimes is better to just recompute the norm
            if True: #colnorms2[k] < normbound or colnorms2[k] < square*normbound:
                colnorms2[k] = float_sum([ R[i,k].norm() for i in range(j + 1, m)])                
    # compute P matrix
    Pmatrix = Matrix(ZZ, n);
    for i in xrange(n):
        Pmatrix[ P[i], i] = 1;

    return Q.conjugate_transpose().change_ring(base_field), R.change_ring(base_field), Pmatrix;
예제 #9
0
 def to_sage(field,A):
     return Matrix(field, [[ field(A[i,j].real, A[i,j].imag) for j in range(A.cols)] for i in range(A.rows)])
예제 #10
0
    def _get_element_nullspace(self, M):
        ## We take the Conversion System
        R = self.__conversion

        ## We assume the matrix is in the correct space
        M = Matrix(R.poly_field(),
                   [[R.simplify(el.poly()) for el in row] for row in M])

        ## We clean denominators to lie in the polynomial ring
        lcms = [self.__get_lcm([el.denominator() for el in row]) for row in M]
        M = Matrix(R.poly_ring(),
                   [[el * lcms[i] for el in M[i]] for i in range(M.nrows())])
        f = lambda p: R(p).is_zero()
        try:
            assert (f(1) == False)
        except Exception:
            raise ValueError("The method to check membership is not correct")

        ## Computing the kernell of the matrix
        if (len(R.map_of_vars()) > 0):
            bareiss_algorithm = BareissAlgorithm(
                R.poly_ring(), M, f, R._ConversionSystem__relations)
            ker = bareiss_algorithm.syzygy().transpose()
            ## If some relations are found during this process, we add it to the conversion system
            R.add_relations(bareiss_algorithm.relations())
        else:
            ker = [v for v in M.right_kernel_matrix()]

        ## If the nullspace has high dimension, we try to reduce the final vector computing zeros at the end
        aux = [row for row in ker]
        i = 1

        while (len(aux) > 1):
            new = []
            current = None
            for j in range(len(aux)):
                if (aux[j][-(i)] == 0):
                    new += [aux[j]]
                elif (current is None):
                    current = j
                else:
                    new += [
                        aux[current] * aux[j][-(i)] -
                        aux[j] * aux[current][-(i)]
                    ]
                    current = j
            aux = [el / gcd(el) for el in new]
            i = i + 1

        ## When exiting the loop, aux has just one vector
        sol = aux[0]
        sol = [R.simplify(a) for a in sol]

        ## Just to be sure everything is as simple as possible, we divide again by the gcd of all our
        ## coefficients and simplify them using the relations known.
        fin_gcd = gcd(sol)
        finalSolution = [a / fin_gcd for a in sol]
        finalSolution = [R.simplify(a) for a in finalSolution]

        ## We transform our polynomial into elements of our destiny domain
        realSolution = [R.to_real(a) for a in finalSolution]
        for i in range(len(realSolution)):
            try:
                realSolution[i].built = ("polynomial", (finalSolution[i], {
                    str(key): R.map_of_vars()[str(key)]
                    for key in finalSolution[i].variables()
                }))
            except AttributeError:
                pass

        return vector(R.base(), realSolution)
예제 #11
0
def reduce_matrix_split_relative(M, p_root, relative_root):
    return Matrix([[ reduce_constant_split_relative(x, p_root, relative_root) for x in row ] for row in M.rows()]);
예제 #12
0
def swap_cols(M, c1, c2):
    r'''
        Method for performing the swap of two columns in Gauss-Jordan elimination.

        This method takes a matrix `M`, two column indices and returns a new matrix where
        the elements in the columns have been swapped.

        This is one of the basic steps while performing Gauss-Jordan elimination
        on a matrix to compute its determinant/nullspace/solution space/rank etc.

        INPUT:
            * ``M``: the original matrix with entries `m_{i,j}`.
            * ``c1``: first index of the column to be swapped.
            * ``c2``: second index of the column to be swapped.

        OUTPUT:
            A new matrix where the elements of the columns indexed by ``c1`` and ``c2``
            have been exchanged.

        EXAMPLES::

            sage: from ajpastor.misc.matrix import *
            sage: M = Matrix(QQ, [[1,2],[3,4]])
            sage: swap_cols(M, 0, 1)
            [2 1]
            [4 3]
            sage: N = block_matrix(QQ, [[M, 0],[0, 1]])
            sage: swap_cols(N, 0, 1)
            [2 1 0]
            [4 3 0]
            [0 0 1]
            sage: swap_cols(N, 1, 2)
            [1 0 2]
            [3 0 4]
            [0 1 0]

        This method raises a ValueError when the index is not valid::
            
            sage: swap_cols(N, -1, 1)
            Traceback (most recent call last):
            ...
            ValueError: The first column index is not valid
            sage: swap_cols(N, 1, 10)
            Traceback (most recent call last):
            ...
            ValueError: The second column index is not valid

        Also, if the input for the matrix is not such, the method raises a TypeError::

            sage: swap_cols([[1,2,0],[3,4,0],[0,0,1]], 2, 10)
            Traceback (most recent call last):
            ...
            TypeError: First argument must be a matrix. ...
    '''
    try:
        if (0 > c1 or c1 >= M.ncols()):
            raise ValueError("The first column index is not valid")
        if (0 > c2 or c2 >= M.ncols()):
            raise ValueError("The second column index is not valid")

        ## We make a copy of the matrix
        new_rows = []
        for i in range(M.nrows()):
            new_rows += [[M[i][j] for j in range(M.ncols())]]

        ## We make the current operation
        for i in range(M.nrows()):
            new_rows[i][c1] = M[i][c2]
            new_rows[i][c2] = M[i][c1]

        return Matrix(M.parent().base(), new_rows)
    except AttributeError:
        raise TypeError("First argument must be a matrix. Given %s" % M)
예제 #13
0
def scal_col(M, d_c, el):
    r'''
        Method for performing the rescale of a column in Gauss-Jordan elimination.

        This method takes a matrix `M`, a column index and an element from the 
        parent ring of `M` and returns a new matrix where the elements in the 
        column have been scaled by the element.

        This is one of the basic steps while performing Gauss-Jordan elimination
        on a matrix to compute its determinant/nullspace/solution space/rank etc.

        INPUT:
            * ``M``: the original matrix with entries `m_{i,j}`.
            * ``d_c``: index of the column where the scaling will be performed.
            * ``el``: element in the base ring of ``M`` that will be used in the scaling.

        OUTPUT:
            A new matrix `\tilde{M}` with entries `\tilde{m}_{i,j}` such that:
                * If ``j != d_c``: `\tilde{m}_{i,j} = m_{i,j}`.
                * Else: `\tilde{m}_{i,d_c} = (el)m_{i,d_c}`.

        EXAMPLES::

            sage: from ajpastor.misc.matrix import *
            sage: M = Matrix(QQ, [[1,2],[3,4]])
            sage: scal_col(M, 0, 2)
            [2 2]
            [6 4]
            sage: scal_col(M, 1, -1)
            [ 1 -2]
            [ 3 -4]
            sage: N = block_matrix(QQ, [[M, 0],[0, 1]])
            sage: scal_col(N, 2, 10)
            [ 1  2  0]
            [ 3  4  0]
            [ 0  0 10]
            sage: scal_col(N, 1, 1)
            [1 2 0]
            [3 4 0]
            [0 0 1]

        This method raises a ValueError when the index is not valid::
            
            sage: scal_col(N, -1, 1)
            Traceback (most recent call last):
            ...
            ValueError: The column index is not valid
            sage: scal_col(N, 10, 1)
            Traceback (most recent call last):
            ...
            ValueError: The column index is not valid

        Also, if the input for the matrix is not such, the method raises a TypeError::

            sage: scal_col([[1,2,0],[3,4,0],[0,0,1]], 2, 10)
            Traceback (most recent call last):
            ...
            TypeError: First argument must be a matrix. ...

        It is interesting to remark that this method is equivalent to the application of the 
        method :func:`op_cols` with the same destiny and source indices and the element
        being ``-element+1``::

            sage: scal_col(N, 2, 10) == op_cols(N, 2, 2, -9)
            True
    '''
    try:
        if (0 > d_c or d_c >= M.ncols()):
            raise ValueError("The column index is not valid")
        ## We make a copy of the matrix
        new_rows = []
        for i in range(M.nrows()):
            new_rows += [[M[i][j] for j in range(M.ncols())]]

        ## We make the current operations
        for i in range(M.nrows()):
            new_rows[i][d_c] = el * M[i][d_c]

        return Matrix(M.parent().base(), new_rows)
    except AttributeError:
        raise TypeError("First argument must be a matrix. Given %s" % M)
예제 #14
0
def op_rows(M, s_r, d_r, el):
    r'''
        Method for performing the row substraction in Gauss-Jordan elimination.

        This method takes a matrix `M`, two rows indices and an element from the 
        parent ring of `M` and returns a new matrix where the elements in the 
        second row have been "reduced" by the elements in the first row times
        such element.

        This is one of the basic steps while performing Gauss-Jordan elimination
        on a matrix to compute its determinant/nullspace/solution space/rank etc.

        INPUT:
            * ``M``: the original matrix with entries `m_{i,j}`.
            * ``s_r``: index of the row that will be used in the reduction.
            * ``d_r``: index of the row where the reduction will be performed.
            * ``el``: element in the base ring of ``M`` that will be used in the reduction.

        OUTPUT:
            A new matrix `\tilde{M}` with entries `\tilde{m}_{i,j}` such that:
                * If ``i != d_r``: `\tilde{m}_{i,j} = m_{i,j}`.
                * Else: `\tilde{m}_{d_r,j} = m_{d_r,j} - (el)m_{s_r,j}`.

        EXAMPLES::

            sage: from ajpastor.misc.matrix import *
            sage: M = Matrix(QQ, [[1,2],[3,4]])
            sage: op_rows(M, 0, 1, 2)
            [1 2]
            [1 0]
            sage: op_rows(M, 1, 0, -1)
            [4 6]
            [3 4]
            sage: N = block_matrix(QQ, [[M, 0],[0, 1]])
            sage: op_rows(N, 2, 0, 10)
            [  1   2 -10]
            [  3   4   0]
            [  0   0   1]
            sage: op_rows(N, 1, 2, 1)
            [ 1  2  0]
            [ 3  4  0]
            [-3 -4  1]

        This method raises a ValueError when the indices are not valid::
            
            sage: op_rows(N, -1, 2, 1)
            Traceback (most recent call last):
            ...
            ValueError: The source row index is not valid
            sage: op_rows(N, 1, -2, 1)
            Traceback (most recent call last):
            ...
            ValueError: The destiny row index is not valid

        Also, if the input for the matrix is not such, the method raises a TypeError::

            sage: op_rows([[1,2,0],[3,4,0],[0,0,1]], 1, 2, 1)
            Traceback (most recent call last):
            ...
            TypeError: First argument must be a matrix. ...
    '''
    try:
        if (0 > s_r or s_r >= M.nrows()):
            raise ValueError("The source row index is not valid")
        if (0 > d_r or d_r >= M.nrows()):
            raise ValueError("The destiny row index is not valid")

        ## We make a copy of the matrix
        new_rows = []
        for i in range(M.nrows()):
            new_rows += [[M[i][j] for j in range(M.ncols())]]

        ## We make the current operations
        for i in range(M.ncols()):
            new_rows[d_r][i] = M[d_r][i] - el * M[s_r][i]

        return Matrix(M.parent().base(), new_rows)
    except AttributeError:
        raise TypeError("First argument must be a matrix. Given %s" % M)
예제 #15
0
파일: isog_class.py 프로젝트: sanni85/lmfdb
    def make_class(self):

        # Create a list of the curves in the class from the database
        self.db_curves = list(
            db.ec_nfcurves.search({
                'field_label': self.field_label,
                'conductor_norm': self.conductor_norm,
                'conductor_label': self.conductor_label,
                'iso_nlabel': self.iso_nlabel
            }))

        # Rank or bounds
        try:
            self.rk = web_latex(self.db_curves[0]['rank'])
        except KeyError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.db_curves[0]['rank_bounds'])
        except KeyError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not recorded"

        # Extract the isogeny degree matrix from the database
        if not hasattr(self, 'isogeny_matrix'):
            # this would happen if the class is initiated with a curve
            # which is not #1 in its class:
            self.isogeny_matrix = self.db_curves[0].isogeny_matrix
        self.isogeny_matrix = Matrix(self.isogeny_matrix)
        self.one_deg = ZZ(self.class_deg).is_prime()

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img
        self.isogeny_matrix_str = latex(Matrix(self.isogeny_matrix))

        self.field = FIELD(self.field_label)
        self.field_name = field_pretty(self.field_label)
        self.field_knowl = nf_display_knowl(self.field_label, self.field_name)

        def curve_url(c):
            return url_for(".show_ecnf",
                           nf=c['field_label'],
                           conductor_label=c['conductor_label'],
                           class_label=c['iso_label'],
                           number=c['number'])

        self.curves = [[
            c['short_label'],
            curve_url(c),
            web_ainvs(self.field_label, c['ainvs'])
        ] for c in self.db_curves]

        self.urls = {}
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=self.conductor_label,
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=self.conductor_label)
        self.urls['field'] = url_for('.show_ecnf1', nf=self.field_label)
        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0, 1]
        if totally_real:
            self.hmf_label = "-".join(
                [self.field_label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field_label,
                                       label=self.hmf_label)
            if sig[0] <= 2:
                self.urls['Lfunction'] = url_for(
                    "l_functions.l_function_ecnf_page",
                    field_label=self.field_label,
                    conductor_label=self.conductor_label,
                    isogeny_class_label=self.iso_label)
            elif self.abs_disc**2 * self.conductor_norm < 40000:
                # we shouldn't trust the Lfun computed on the fly for large conductor
                self.urls['Lfunction'] = url_for(
                    "l_functions.l_function_hmf_page",
                    field=self.field_label,
                    label=self.hmf_label,
                    character='0',
                    number='0')

        if imag_quadratic:
            self.bmf_label = "-".join(
                [self.field_label, self.conductor_label, self.iso_label])
            self.bmf_url = url_for('bmf.render_bmf_webpage',
                                   field_label=self.field_label,
                                   level_label=self.conductor_label,
                                   label_suffix=self.iso_label)
            self.urls['Lfunction'] = url_for(
                "l_functions.l_function_ecnf_page",
                field_label=self.field_label,
                conductor_label=self.conductor_label,
                isogeny_class_label=self.iso_label)

        self.friends = []
        if totally_real:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label,
                              self.urls['hmf'])]

        if imag_quadratic:
            #self.friends += [('Bianchi Modular Form %s not available' % self.bmf_label, '')]
            self.friends += [('Bianchi Modular Form %s' % self.bmf_label,
                              self.bmf_url)]

        if 'Lfunction' in self.urls:
            self.friends += [('L-function', self.urls['Lfunction'])]
        else:
            self.friends += [('L-function not available', "")]

        self.properties = [('Base field', self.field_name),
                           ('Label', self.class_label),
                           (None, self.graph_link),
                           ('Conductor', '%s' % self.conductor_label)]
        if self.rk != '?':
            self.properties += [('Rank', '%s' % self.rk)]
        else:
            if self.rk_bnds == 'not recorded':
                self.properties += [('Rank', '%s' % self.rk_bnds)]
            else:
                self.properties += [('Rank bounds', '%s' % self.rk_bnds)]

        self.bread = [('Elliptic Curves ', url_for(".index")),
                      (self.field_label, self.urls['field']),
                      (self.conductor_label, self.urls['conductor']),
                      ('isogeny class %s' % self.short_label,
                       self.urls['class'])]
예제 #16
0
def list_of_basis(N,
                  weight,
                  prec=501,
                  tol=1e-20,
                  sv_min=1E-1,
                  sv_max=1E15,
                  set_dim=None):
    r""" Returns a list of pairs (r,D) forming a basis
    """
    # First we find the smallest Discriminant for each of the components
    if set_dim != None and set_dim > 0:
        dim = set_dim
    else:
        dim = dimension_jac_cusp_forms(int(weight + 0.5), N, -1)
    basislist = dict()
    num_gotten = 0
    co_tmp = dict()
    num_gotten = 0
    C0 = 1
    RF = RealField(prec)
    if (silent > 1):
        print("N={0}".format(N))
        print("dim={0}".format(dim))
        print("sv_min={0}".format(sv_min))
        print("sv_max={0}".format(sv_max))
    Aold = Matrix(RF, 1)
    tol0 = 1E-20  #tol
    # we start with the first discriminant, then the second etc.
    Z2N = IntegerModRing(2 * N)
    ZZ4N = IntegerModRing(4 * N)
    for Dp in [1..max(1000, 100 * dim)]:
        D = -Dp  # we use the dual of the Weil representation
        D4N = ZZ4N(D)
        if (not (is_square(D4N))):
            continue
        for r in my_modsqrt(D4N, N):
            # I want to make sure that P_{(D,r)} is independent from the previously computed functions
            # The only sure way to do this is to compute all submatrices (to a much smaller precision than what we want at the end)
            # The candidate is [D,r] and we need to compute the vector of [D,r,D',r']
            # for all D',r' already in the list
            ltmp1 = dict()
            ltmp2 = dict()
            j = 0
            for [Dp, rp] in basislist.values():
                ltmp1[j] = [D, r, Dp, rp]
                ltmp2[j] = [Dp, rp, D, r]
                j = j + 1
            ltmp1[j] = [D, r, D, r]
            #print "Checking: D,r,D,r=",ltmp1
            ctmp1 = ps_coefficients_holomorphic_vec(N, weight, ltmp1, tol0)
            # print "ctmp1=",ctmp1
            if (j > 0):
                #print "Checking: D,r,Dp,rp=",ltmp2    # Data is ok?: {0: True}
                ctmp2 = ps_coefficients_holomorphic_vec(N, weight, ltmp2, tol0)
                # print "ctmp2=",ctmp2
            #print "num_gotten=",num_gotten
            A = matrix(RF, num_gotten + 1)
            # The old matrixc with the elements that are already added to the basis
            # print "Aold=\n",A,"\n"
            # print "num_gotten=",num_gotten
            # print "Aold=\n",Aold,"\n"
            for k in range(Aold.nrows()):
                for l in range(Aold.ncols()):
                    A[k, l] = Aold[k, l]
                    # endfor
                    # print "A set by old=\n",A,"\n"
                    # Add the (D',r',D,r) for each D',r' in the list
            tmp = RF(1.0)
            for l in range(num_gotten):
                # we do not use  the scaling factor when
                # determining linear independence
                # mm=RF(abs(ltmp2[l][0]))/N4
                # tmp=RF(mm**(weight-one))
                A[num_gotten, l] = ctmp2['data'][l] * tmp
                # Add the (D,r,D',r') for each D',r' in the list
                # print "ctmp1.keys()=",ctmp1.keys()
            for l in range(num_gotten + 1):
                #mm=RF(abs(ltmp1[l][2]))/4N
                #tmp=RF(mm**(weight-one))
                # print "scaled with=",tmp.n(200)
                A[l, num_gotten] = ctmp1['data'][l] * tmp
            #[d,B]=mat_inverse(A) # d=det(A)
            #if(silent>1):
            #d=det(A)
            #print "det A = ",d
            # Now we have to determine whether we have a linearly independent set or not
            dold = mpmath.mp.dps
            mpmath.mp.dps = int(prec / 3.3)
            AInt = mpmath.matrix(int(A.nrows()), int(A.ncols()))
            AMp = mpmath.matrix(int(A.nrows()), int(A.ncols()))
            if (silent > 0):
                print("tol0={0}".format(tol0))
            for ir in range(A.nrows()):
                for ik in range(A.ncols()):
                    AInt[ir, ik] = mpmath.mp.mpi(A[ir, ik] - tol0,
                                                 A[ir, ik] + tol0)
                    AMp[ir, ik] = mpmath.mpf(A[ir, ik])

            d = mpmath.det(AMp)
            di = mpmath.mp.mpi(mpmath.mp.det(AInt))
            #for ir in range(A.nrows()):
            #    for ik in range(A.ncols()):
            #        #print "A.d=",AInt[ir,ik].delta
            if (silent > 0):
                print("mpmath.mp.dps={0}".format(mpmath.mp.dps))
                print("det(A)={0}".format(d))
                print("det(A-as-interval)={0}".format(di))
                print("d.delta={0}".format(di.delta))
            #if(not mpmath.mpi(d) in di):
            #    raise ArithmeticError," Interval determinant not ok?"
            #ANP=A.numpy()
            #try:
            #    u,s,vnp=svd(ANP) # s are the singular values
            #    sl=s.tolist()
            #    mins=min(sl)  # the smallest singular value
            #    maxs=max(sl)
            #    if(silent>1):
            #        print "singular values = ",s
            #except LinAlgError:
            #    if(silent>0):
            #        print "could not compute SVD!"
            #        print "using abs(det) instead"
            #   mins=abs(d)
            #    maxs=abs(d)
            #if((mins>sv_min and maxs< sv_max)):
            zero = mpmath.mpi(0)
            if (zero not in di):
                if (silent > 1):
                    print("Adding D,r={0}, {1}".format(D, r))
                basislist[num_gotten] = [D, r]
                num_gotten = num_gotten + 1
                if (num_gotten >= dim):
                    return basislist
                else:
                    #print "setting Aold to A"
                    Aold = A
            else:
                if (silent > 1):
                    print(" do not use D,r={0}, {1}".format(D, r))
            # endif
            mpmath.mp.dps = dold
    # endfor
    if (num_gotten < dim):
        raise ValueError(
            " did not find enough good elements for a basis list!")
예제 #17
0
    def make_class(self):

        # Create a list of the curves in the class from the database
        self.db_curves = list(
            db.ec_nfcurves.search({
                'field_label': self.field_label,
                'conductor_norm': self.conductor_norm,
                'conductor_label': self.conductor_label,
                'iso_nlabel': self.iso_nlabel
            }))

        # Rank or bounds
        try:
            self.rk = web_latex(self.db_curves[0]['rank'])
        except KeyError:
            self.rk = "?"
        try:
            self.rk_bnds = "%s...%s" % tuple(self.db_curves[0]['rank_bounds'])
        except KeyError:
            self.rank_bounds = [0, Infinity]
            self.rk_bnds = "not recorded"

        # Extract the isogeny degree matrix from the database
        if not hasattr(self, 'isogeny_matrix'):
            # this would happen if the class is initiated with a curve
            # which is not #1 in its class:
            self.isogeny_matrix = self.db_curves[0].isogeny_matrix
        self.isogeny_matrix = Matrix(self.isogeny_matrix)
        self.one_deg = ZZ(self.class_deg).is_prime()

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img
        self.isogeny_matrix_str = latex(Matrix(self.isogeny_matrix))

        self.field = FIELD(self.field_label)
        self.field_name = field_pretty(self.field_label)
        self.field_knowl = nf_display_knowl(self.field_label, self.field_name)

        def curve_url(c):
            return url_for(".show_ecnf",
                           nf=c['field_label'],
                           conductor_label=c['conductor_label'],
                           class_label=c['iso_label'],
                           number=c['number'])

        self.curves = [[
            c['short_label'],
            curve_url(c),
            web_ainvs(self.field_label, c['ainvs'])
        ] for c in self.db_curves]

        self.urls = {}
        self.urls['class'] = url_for(".show_ecnf_isoclass",
                                     nf=self.field_label,
                                     conductor_label=self.conductor_label,
                                     class_label=self.iso_label)
        self.urls['conductor'] = url_for(".show_ecnf_conductor",
                                         nf=self.field_label,
                                         conductor_label=self.conductor_label)
        self.urls['field'] = url_for('.show_ecnf1', nf=self.field_label)
        sig = self.signature
        totally_real = sig[1] == 0
        imag_quadratic = sig == [0, 1]
        if totally_real:
            self.hmf_label = "-".join(
                [self.field_label, self.conductor_label, self.iso_label])
            self.urls['hmf'] = url_for('hmf.render_hmf_webpage',
                                       field_label=self.field_label,
                                       label=self.hmf_label)
            lfun_url = url_for("l_functions.l_function_ecnf_page",
                               field_label=self.field_label,
                               conductor_label=self.conductor_label,
                               isogeny_class_label=self.iso_label)
            origin_url = lfun_url.lstrip('/L/').rstrip('/')
            if sig[0] <= 2 and db.lfunc_instances.exists({'url': origin_url}):
                self.urls['Lfunction'] = lfun_url
            elif self.abs_disc**2 * self.conductor_norm < 40000:
                # we shouldn't trust the Lfun computed on the fly for large conductor
                self.urls['Lfunction'] = url_for(
                    "l_functions.l_function_hmf_page",
                    field=self.field_label,
                    label=self.hmf_label,
                    character='0',
                    number='0')

        if imag_quadratic:
            self.bmf_label = "-".join(
                [self.field_label, self.conductor_label, self.iso_label])
            self.bmf_url = url_for('bmf.render_bmf_webpage',
                                   field_label=self.field_label,
                                   level_label=self.conductor_label,
                                   label_suffix=self.iso_label)
            lfun_url = url_for("l_functions.l_function_ecnf_page",
                               field_label=self.field_label,
                               conductor_label=self.conductor_label,
                               isogeny_class_label=self.iso_label)
            origin_url = lfun_url.lstrip('/L/').rstrip('/')
            if db.lfunc_instances.exists({'url': origin_url}):
                self.urls['Lfunction'] = lfun_url

        # most of this code is repeated in WebEllipticCurve.py
        # and should be refactored
        self.friends = []
        if totally_real and not 'Lfunction' in self.urls:
            self.friends += [('Hilbert Modular Form ' + self.hmf_label,
                              self.urls['hmf'])]

        if imag_quadratic:
            if "CM" in self.label:
                self.friends += [('Bianchi modular Form is not cuspidal', '')]
            elif not 'Lfunction' in self.urls:
                if db.bmf_forms.label_exists(self.bmf_label):
                    self.friends += [
                        ('Bianchi modular Form %s' % self.bmf_label,
                         self.bmf_url)
                    ]
                else:
                    self.friends += [
                        ('(Bianchi modular Form %s)' % self.bmf_label, '')
                    ]

        if 'Lfunction' in self.urls:
            Lfun = get_lfunction_by_url(
                self.urls['Lfunction'].lstrip('/L').rstrip('/'),
                projection=['degree', 'trace_hash', 'Lhash'])
            instances = get_instances_by_Lhash_and_trace_hash(
                Lfun['Lhash'], Lfun['degree'], Lfun.get('trace_hash'))
            exclude = {
                elt[1].rstrip('/').lstrip('/')
                for elt in self.friends if elt[1]
            }
            exclude.add(lfun_url.lstrip('/L/').rstrip('/'))
            self.friends += names_and_urls(instances, exclude=exclude)
            self.friends += [('L-function', self.urls['Lfunction'])]
        else:
            self.friends += [('L-function not available', "")]

        self.properties = [('Base field', self.field_name),
                           ('Label', self.class_label),
                           (None, self.graph_link),
                           ('Conductor', '%s' % self.conductor_label)]
        if self.rk != '?':
            self.properties += [('Rank', '%s' % self.rk)]
        else:
            if self.rk_bnds == 'not recorded':
                self.properties += [('Rank', '%s' % self.rk_bnds)]
            else:
                self.properties += [('Rank bounds', '%s' % self.rk_bnds)]

        self.bread = [('Elliptic Curves ', url_for(".index")),
                      (self.field_label, self.urls['field']),
                      (self.conductor_label, self.urls['conductor']),
                      ('isogeny class %s' % self.short_label,
                       self.urls['class'])]
예제 #18
0
def cuspidal_integral_to_rational_basis(M):
    """
    Returns the base change matrix for the cuspidal subspace of M
    """
    S=M.cuspidal_subspace()
    return Matrix([S.coordinate_vector(i) for i in cuspidal_integral_structure_matrix(M)])
예제 #19
0
    def _get_element_nullspace(self, M):
        ## We take the domain where our elements will lie
        ## conversion->lazy domain->domain
        parent = self.__conversion.base().base()

        ## We assume the matrix is in the correct space
        M = self.__conversion.simplify(M)

        ## We clean denominators to lie in the polynomial ring
        lcms = [lcm([el.denominator() for el in row]) for row in M]
        R = M.parent().base().base()
        M = Matrix(R,
                   [[el * lcms[i] for el in M[i]] for i in range(M.nrows())])
        f = lambda p: self.__smart_is_null(p)
        try:
            assert (f(1) == False)
        except Exception:
            raise ValueError("The method to check membership is not correct")

        from sage.rings.polynomial.polynomial_ring import is_PolynomialRing as isUniPolynomial
        from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing as isMPolynomial
        ## Computing the kernell of the matrix
        if (isUniPolynomial(R) or isMPolynomial(R)):
            bareiss_algorithm = BareissAlgorithm(R, M, f)
            ker = bareiss_algorithm.syzygy().transpose()
            ## If some relations are found during this process, we add it to the conversion system
            self.__conversion.add_relations(bareiss_algorithm.relations())
        else:
            ker = [v for v in M.right_kernel_matrix()]

        ## If the nullspace has high dimension, we try to reduce the final vector computing zeros at the end
        aux = [row for row in ker]
        i = 1

        while (len(aux) > 1):
            new = []
            current = None
            for j in range(len(aux)):
                if (aux[j][-(i)] == 0):
                    new += [aux[j]]
                elif (current is None):
                    current = j
                else:
                    new += [
                        aux[current] * aux[j][-(i)] -
                        aux[j] * aux[current][-(i)]
                    ]
                    current = j
            aux = [el / gcd(el) for el in new]
            i = i + 1

        ## When exiting the loop, aux has just one vector
        sol = aux[0]
        sol = [self.__conversion.simplify(a) for a in sol]

        ## This steps for clearing denominator are no longer needed
        #lazyLcm = lcm([a.denominator() for a in sol])
        #finalLazySolution = [a.numerator()*(lazyLcm/(a.denominator())) for a in sol]

        ## Just to be sure everything is as simple as possible, we divide again by the gcd of all our
        ## coefficients and simplify them using the relations known.
        fin_gcd = gcd(sol)
        finalSolution = [a / fin_gcd for a in sol]
        finalSolution = [self.__conversion.simplify(a) for a in finalSolution]

        ## We transform our polynomial into elements of our destiny domain
        finalSolution = [
            self.__conversion.to_real(a).raw() for a in finalSolution
        ]

        return vector(parent, finalSolution)
예제 #20
0
    def invariant_generators(self):
        """
        Wraps Singular's invariant_algebra_reynolds and invariant_ring
        in finvar.lib, with help from Simon King and Martin Albrecht.
        Computes generators for the polynomial ring
        `F[x_1,\ldots,x_n]^G`, where G in GL(n,F) is a finite
        matrix group.
        
        In the "good characteristic" case the polynomials returned form a
        minimal generating set for the algebra of G-invariant polynomials.
        In the "bad" case, the polynomials returned are primary and
        secondary invariants, forming a not necessarily minimal generating
        set for the algebra of G-invariant polynomials.
        
        EXAMPLES::
        
            sage: F = GF(7); MS = MatrixSpace(F,2,2)
            sage: gens = [MS([[0,1],[-1,0]]),MS([[1,1],[2,3]])]
            sage: G = MatrixGroup(gens)
            sage: G.invariant_generators()
            [x1^7*x2 - x1*x2^7, x1^12 - 2*x1^9*x2^3 - x1^6*x2^6 + 2*x1^3*x2^9 + x2^12, x1^18 + 2*x1^15*x2^3 + 3*x1^12*x2^6 + 3*x1^6*x2^12 - 2*x1^3*x2^15 + x2^18]
            sage: q = 4; a = 2
            sage: MS = MatrixSpace(QQ, 2, 2)
            sage: gen1 = [[1/a,(q-1)/a],[1/a, -1/a]]; gen2 = [[1,0],[0,-1]]; gen3 = [[-1,0],[0,1]]
            sage: G = MatrixGroup([MS(gen1),MS(gen2),MS(gen3)])
            sage: G.cardinality()
            12
            sage: G.invariant_generators()
            [x1^2 + 3*x2^2, x1^6 + 15*x1^4*x2^2 + 15*x1^2*x2^4 + 33*x2^6]
            sage: F = GF(5); MS = MatrixSpace(F,2,2)
            sage: gens = [MS([[1,2],[-1,1]]),MS([[1,1],[-1,1]])]
            sage: G = MatrixGroup(gens)
            sage: G.invariant_generators()  # long time (67s on sage.math, 2012)
            [x1^20 + x1^16*x2^4 + x1^12*x2^8 + x1^8*x2^12 + x1^4*x2^16 + x2^20, x1^20*x2^4 + x1^16*x2^8 + x1^12*x2^12 + x1^8*x2^16 + x1^4*x2^20]
            sage: F=CyclotomicField(8)
            sage: z=F.gen()
            sage: a=z+1/z
            sage: b=z^2
            sage: MS=MatrixSpace(F,2,2)
            sage: g1=MS([[1/a,1/a],[1/a,-1/a]])
            sage: g2=MS([[1,0],[0,b]])
            sage: g3=MS([[b,0],[0,1]])
            sage: G=MatrixGroup([g1,g2,g3])
            sage: G.invariant_generators()  # long time (12s on sage.math, 2011)
            [x1^8 + 14*x1^4*x2^4 + x2^8,
             x1^24 + 10626/1025*x1^20*x2^4 + 735471/1025*x1^16*x2^8 + 2704156/1025*x1^12*x2^12 + 735471/1025*x1^8*x2^16 + 10626/1025*x1^4*x2^20 + x2^24]
        
        AUTHORS:

        - David Joyner, Simon King and Martin Albrecht.
        
        REFERENCES:

        - Singular reference manual

        - B. Sturmfels, "Algorithms in invariant theory", Springer-Verlag, 1993.

        - S. King, "Minimal Generating Sets of non-modular invariant rings of
          finite groups", arXiv:math.AC/0703035
        """
        from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
        from sage.interfaces.singular import singular
        gens = self.gens()
        singular.LIB("finvar.lib")
        n = self.degree()  #len((gens[0].matrix()).rows())
        F = self.base_ring()
        q = F.characteristic()
        ## test if the field is admissible
        if F.gen() == 1:  # we got the rationals or GF(prime)
            FieldStr = str(F.characteristic())
        elif hasattr(F, 'polynomial'):  # we got an algebraic extension
            if len(F.gens()) > 1:
                raise NotImplementedError, "can only deal with finite fields and (simple algebraic extensions of) the rationals"
            FieldStr = '(%d,%s)' % (F.characteristic(), str(F.gen()))
        else:  # we have a transcendental extension
            FieldStr = '(%d,%s)' % (F.characteristic(), ','.join(
                [str(p) for p in F.gens()]))

        ## Setting Singular's variable names
        ## We need to make sure that field generator and variables get different names.
        if str(F.gen())[0] == 'x':
            VarStr = 'y'
        else:
            VarStr = 'x'
        VarNames = '(' + ','.join(
            (VarStr + str(i + 1) for i in range(n))) + ')'
        R = singular.ring(FieldStr, VarNames, 'dp')
        if hasattr(F,
                   'polynomial') and F.gen() != 1:  # we have to define minpoly
            singular.eval('minpoly = ' +
                          str(F.polynomial()).replace('x', str(F.gen())))
        A = [singular.matrix(n, n, str((x.matrix()).list())) for x in gens]
        Lgens = ','.join((x.name() for x in A))
        PR = PolynomialRing(F, n, [VarStr + str(i) for i in range(1, n + 1)])
        if q == 0 or (q > 0 and self.cardinality() % q != 0):
            from sage.all import Integer, Matrix
            try:
                gapself = gap(self)
                # test whether the backwards transformation works as well:
                for i in range(self.ngens()):
                    if Matrix(gapself.gen(i + 1), F) != self.gen(i).matrix():
                        raise ValueError
            except (TypeError, ValueError):
                gapself is None
            if gapself is not None:
                ReyName = 't' + singular._next_var_name()
                singular.eval('matrix %s[%d][%d]' %
                              (ReyName, self.cardinality(), n))
                En = gapself.Enumerator()
                for i in range(1, self.cardinality() + 1):
                    M = Matrix(En[i], F)
                    D = [{} for foobar in range(self.degree())]
                    for x, y in M.dict().items():
                        D[x[0]][x[1]] = y
                    for row in range(self.degree()):
                        for t in D[row].items():
                            singular.eval('%s[%d,%d]=%s[%d,%d]+(%s)*var(%d)' %
                                          (ReyName, i, row + 1, ReyName, i,
                                           row + 1, repr(t[1]), t[0] + 1))
                foobar = singular(ReyName)
                IRName = 't' + singular._next_var_name()
                singular.eval('matrix %s = invariant_algebra_reynolds(%s)' %
                              (IRName, ReyName))
            else:
                ReyName = 't' + singular._next_var_name()
                singular.eval('list %s=group_reynolds((%s))' %
                              (ReyName, Lgens))
                IRName = 't' + singular._next_var_name()
                singular.eval('matrix %s = invariant_algebra_reynolds(%s[1])' %
                              (IRName, ReyName))

            OUT = [
                singular.eval(IRName + '[1,%d]' % (j))
                for j in range(1, 1 + singular('ncols(' + IRName + ')'))
            ]
            return [PR(gen) for gen in OUT]
        if self.cardinality() % q == 0:
            PName = 't' + singular._next_var_name()
            SName = 't' + singular._next_var_name()
            singular.eval('matrix %s,%s=invariant_ring(%s)' %
                          (PName, SName, Lgens))
            OUT = [
                singular.eval(PName + '[1,%d]' % (j))
                for j in range(1, 1 + singular('ncols(' + PName + ')'))
            ] + [
                singular.eval(SName + '[1,%d]' % (j))
                for j in range(2, 1 + singular('ncols(' + SName + ')'))
            ]
            return [PR(gen) for gen in OUT]
예제 #21
0
def invariants_eps(FQM, TM, use_reduction = True, proof = False, debug = 0):
    r"""
    Computes the invariants of a direct summand in the decomposition for weight
    one-half modular forms. Such a summand is of the form
    \[
      \mathbb{C}[(\mathbb{Z}/2N\mathbb{Z}, -x^2/4N)]^\epsilon \otimes \mathbb{C}[M],
    \]
    where $M$ is a given finite quadratic module and $\epsilon$ acts on the first
    factor via $\mathfrak{e}_\mu \mapsto \mathfrak{e}_{-\mu}$.

    INPUT:
        - FQM: A given finite quadratic module, referred to as $M$ above
        - TM: A cyclic module of the form as given abve (the first factor)

    NOTE:
        We do not check that TM is of the stated form. The function is an auxiliary function
        usually only called by ``weight_one_half_dim``.

    EXAMPLES:
        NONE
    """
    eps = True
    if TM != None and FQM != None:
        TMM = TM+FQM
    elif TM != None:
        TMM = TM
    else:
        TMM = FQM
        eps = False
    debug2 = 0
    if debug > 1:
        print("FQM = {0}, TM = {1}, TMM = {2}".format(FQM, TM, TMM))
        debug2 = 1
    if debug > 2:
        debug2=debug
    inv = invariants(TMM, use_reduction, proof=proof, debug=debug2)
    if debug > 1: print(inv)
    if type(inv) in [list,tuple]:
        V = inv[1]
    else:
        V = inv
    d = [0,0]
    if V.dimension() != 0:
        el = list()
        M = Matrix(V.base_ring(), V.ambient_module().dimension())
        if eps:
            f = 1 if TMM.signature() % 4 == 0 else -1
            for v in inv[0]:
                #Get the coordinate of this isotropic element
                vv = v.c_list()
                #change the first coordinate to its negative (the eps-action)
                vv[0] = -vv[0]
                vv = TMM(vv,can_coords=True)
                #since the isotropic elements are taken up to the action of +-1, we need to check
                #if we have this element (vv) or its negative (-vv) in the list
                #we append the index of the match, together with a sign to the list `el`,
                #where the sign is -1 if -vv is in inv[0] and the signature is 2 mod 4
                #(i.e. the std generator of the center acts as -1)
                if inv[0].count(vv) > 0:
                    el.append((inv[0].index(vv),1))
                else:
                    el.append((inv[0].index(-vv),f))
            #We create the entries of the matrix M
            #which acts as eps on the space spanned by the isotropic vectors (mod +-1)
            for i in range(len(el)):
                M[el[i][0],i] = el[i][1]
            #import pdb; pdb.set_trace()
            if debug > 1: print("M={0}, V={1}".format(M, V))
            try:
                KM = (M-M.parent().one()).kernel_on(V)
                if debug > 1: print("KM for ev 1 = {0}".format(KM))
                d[0] = KM.dimension()
                KM = (M+M.parent().one()).kernel_on(V)
                if debug > 1: print("KM for ev -1 = {0}".format(KM))
                d[1] = KM.dimension()
            except Exception as e:
                raise RuntimeError("Error occurred for {0}, {1}".format(FQM.jordan_decomposition().genus_symbol(), e), M, V)
        else:
            d = [V.dimension(), 0]
    if debug > 1: print(d)
    return d
예제 #22
0
 def add_vertex(self, g):
     self.M = self.M.stack(Matrix(1, self.M.ncols()))
     self.M[-1, 0] = g
예제 #23
0
def coeff_reduce(C, B, SB, Detail=0, debug=False):
    """B is a list of lists of rationals holding an invertible dxd matrix
    C is a list of lists of rationals holding an nxd matrix
    C*B remains invariant
    SB = Sturm bound: the first SB rows of C should span the whole row space over Z

    Computes invertible U and returns (C', B') = (C*U, U^(-1)*B), so
    that the entries of C' are integers and 'small'
    """
    t0 = time.time()
    if Detail>1:
        print("Before LLL, coefficients:\n{}".format(C))
    # convert to actual matrices:
    d = len(B)
    nan = len(C)
    B=Matrix(B)
    C=Matrix(C)
    if debug:
        print("B has size {}".format(B.dimensions()))
        #print("B={}".format(B))
        print("C has size {}".format(C.dimensions()))
        #print("C={}".format(C))
        CB=C*B
    # Make integral:
    C1, den = C._clear_denom()
    B1 = B/den
    t1 = time.time()
    if Detail:
        print("Cleared denominator = {} in {:0.3f}".format(den,t1-t0))
    # Make primitive:
    if debug:
        print("C1 is in {}".format(C1.parent()))
        #print("C1 = {}".format(C1))
    C1 = pari(C1)
    # if debug:
    #     print("B1={} in {}".format(B1, B1.parent()))
    B1 = pari(B1)
    V1V2S  = C1.matsnf(1)
    t2 = time.time()
    V2 = V1V2S[1]
    S = pari_row_slice(nan-d+1,nan)(V1V2S[2])
    if Detail:
        print("Computed Smith form in {:0.3f}".format(t2-t1))
    if debug:
        print("V1V2S[2] = {}".format(V1V2S[2]))
        print("S = {}".format(S))
        print("About to invert matrix of size {}".format(V2.matsize()))
    C1 *= V2
    B1 = V2**(-1)*B1
    if debug:
        assert CB==C1*B1
    scales = [S[i,i] for i in range(d)]
    if not all(s==1 for s in scales):
        if Detail:
            print("scale factors {}".format(scales))
        C1 *= S**(-1)
        B1 = S*B1
        if debug:
            assert CB==C1*B1

    # LLL-reduce
    U = C1.qflll()
    t3 = time.time()
    if Detail:
        print("LLL done in {:0.3f}".format(t3-t2))
    if debug:
        assert U.matdet() in [1,-1]
    C1 *= U
    B1 = U**(-1)*B1
    if debug:
        assert CB==C1*B1
        print("found Bred, Cred")
    # Convert back to lists of lists
    Cred = [ci.list() for ci in C1.mattranspose()]
    Bred = [bi.list() for bi in B1.mattranspose()]
    if Detail>1:
        print("After LLL, coefficients:\n{}\nbasis={}".format(Cred,Bred))
    return Cred, Bred
예제 #24
0
 def split_vertex(self, i, row1, row2):
     self.M = self.M.stack(Matrix(2, self.M.ncols(), row1 + row2))
     self.add_edge(self.M.nrows() - 2, self.M.nrows() - 1)
     self.del_vertex(i)
예제 #25
0
def verify_algebraically_GB(g, P0, alpha, trace_and_norm, verbose=True):
    # input:
    # * P0 (only necessary to shift the series)
    # * [trace_numerator, trace_denominator, norm_numerator, norm_denominator]
    # output:
    # a boolean
    if verbose:
        print "verify_algebraically()"
    L = P0.base_ring()
    assert alpha.base_ring() is L
    L_poly = PolynomialRing(L, "xL")
    xL = L_poly.gen()
    # shifting the series avoids makes our life easier
    trace_numerator, trace_denominator, norm_numerator, norm_denominator = [
        L_poly(coeff)(L_poly.gen() + P0[0]) for coeff in trace_and_norm
    ]
    L_fpoly = L_poly.fraction_field()
    trace = L_fpoly(trace_numerator) / L_fpoly(trace_denominator)
    norm = L_fpoly(norm_numerator) / L_fpoly(norm_denominator)
    L_fpoly_Z2 = PolynomialRing(L_fpoly, "z")
    z = L_fpoly_Z2.gen()
    gP0 = g(L_poly.gen() + P0[0])
    disc = (trace**2 - 4 * norm)

    IsqrtD = L_fpoly_Z2.ideal([z**2 - disc.numerator()])

    R0 = L_fpoly_Z2.quotient_ring(IsqrtD)

    iz = z / R0(z**2).lift()

    x1 = R0((trace - z / sqrt(disc.denominator())) / 2).lift()
    x2 = R0((trace + z / sqrt(disc.denominator())) / 2).lift()
    assert x1 + x2 == trace, "x1 + x2"
    assert R0(x1 * x2) == norm, "x1 * x2"

    dx1 = R0(
        (trace.derivative(xL) -
         iz * sqrt(disc.denominator()) * disc.derivative(xL) / 2) / 2).lift()
    dx2 = R0(
        (trace.derivative(xL) +
         iz * sqrt(disc.denominator()) * disc.derivative(xL) / 2) / 2).lift()
    assert R0(dx1 + dx2) == R0(trace.derivative(xL)), "dx1 + dx2"

    gx1 = R0(g(x1)).lift()
    gx2 = R0(g(x2)).lift()
    igx1 = R0(gx2).lift() / R0(gx2 * gx1).lift()
    assert R0(gx1 * igx1) == 1, "gx1 * igx1"
    igx2 = R0(gx1).lift() / R0(gx1 * gx2).lift()
    assert R0(gx2 * igx2) == 1, "gx2 * igx2"

    square = gx1.numerator()
    if verbose:
        print "Simplifying sqrt( g(x1).numerator() )"
    a1, a2, d1, d2 = simplify_sqrt(square.constant_coefficient().numerator(),
                                   square.monomial_coefficient(z).numerator(),
                                   disc.numerator())

    assert (d1.numerator() // gP0) in L or (d2.numerator() //
                                            gP0) in L, "d1 or d2"
    L_fpoly_Z = PolynomialRing(L_fpoly, 3, "z, y, w")
    z, y, w = L_fpoly_Z.gens()
    Isqrt = L_fpoly_Z.ideal([z - y * w, y**2 - d1, w**2 - d2])
    R = L_fpoly_Z.quotient_ring(Isqrt)

    iz = z / (d1 * d2)
    assert R(z * iz) == 1
    iw = w / R(w**2).lift()
    assert R(w * iw) == 1
    iy = y / R(y**2).lift()
    assert R(iy * y) == 1

    sgx1 = R(a1 * y + a2 * w).lift() / R(sqrt(gx1.denominator())).lift()
    sgx2 = R(a1 * y - a2 * w).lift() / R(sqrt(gx1.denominator())).lift()
    assert R(sgx1**2) == gx1, "sgx1**2"
    assert R(sgx2**2) == gx2, "sgx2**2"

    isgx1 = R(sgx2).lift() / R(sgx1 * sgx2).lift()
    isgx2 = R(sgx1).lift() / R(sgx1 * sgx2).lift()

    assert R(sgx1 * isgx1) == 1, "sgx1 * isgx1"
    assert R(sgx2 * isgx2) == 1, "sgx2 * isgx2"

    if verbose:
        print "adjusting to d1//g(x) or d1/g(x) in L"

    if R(w**2 / gP0).lift().degree() == 0:
        ct = iw * sqrt(R(w**2 / gP0).lift().constant_coefficient())
    else:
        assert R(w**2 / gP0).lift().degree() == 0
        ct = iy * sqrt(R(y**2 / gP0).lift().constant_coefficient())

#    else:
#        assert R(y**2/gP0).lift() in L, "\n%s\n%s\n%s\n%s\n" % ( R(y**2/gP0).lift(),  R(y**2/gP0).lift() in L, R(w**2/gP0).lift(), R(w**2/gP0).lift() in L, )
#        ct = iy * sqrt(L(R(y**2/gP0).lift()))
    eq1 = Matrix([[
        -2 * L_poly(alpha.row(0).list())(L_poly.gen() + P0[0]) * ct,
        R(dx1 * isgx1),
        R(dx2 * isgx2)
    ]])
    eq2 = Matrix([[
        -2 * L_poly(alpha.row(1).list())(L_poly.gen() + P0[0]) * ct,
        R(x1 * dx1 * isgx1),
        R(x2 * dx2 * isgx2)
    ]])
    branches = Matrix(
        R, [[1, 1, 1], [1, 1, -1], [1, -1, 1], [1, -1, 1]]).transpose()
    meq1 = eq1 * branches
    meq2 = eq2 * branches
    algzero = False
    for j in range(4):
        if meq1[0, j] == 0 and meq2[0, j] == 0:
            algzero = True
            break
    if verbose:
        print "Done, verify_algebraically()  = %s" % algzero
    return algzero
예제 #26
0
def symmetric_block_diagonalize(N1):
    r"""Returns matrices `H` and `Q` such that `N1 = Q*H*Q.T` and `H` is block
    diagonal.

    The algorithm used here is as follows. Whenever a row operation is
    performed (via multiplication on the left by a transformation matrix `q`)
    the corresponding symmetric column operation is also performed via
    multiplication on the right by `q^T`.

    For each column `j` of `N1`:

    1. If column `j` consists only of zeros then swap with the last column with
       non-zero entries.

    2. If there is a `1` in position `j` of the column (i.e. a `1` lies on the
       diagonal in this column) then eliminate further entries below as in
       standard Gaussian elimination.

    3. Otherwise, if there is a `1` in the column, but not in position `j` then
       rows are swapped in a way that it appears in the position `j+1` of the
       column. Eliminate further entries below as in standard Gaussian
       elimination.

    4. After elimination, if `1` lies on the diagonal in column `j` then
       increment `j` by one. If instead the block matrix `[0 1 \\ 1 0]` lies
       along the diagonal then eliminate under the `(j,j+1)` element (the upper
       right element) of this `2 x 2` block and increment `j` by two.

    5. Repeat until `j` passes the final column or until further columns
       consists of all zeros.

    6. Finally, perform the appropriate transformations such that all `2 x 2`
       blocks in `H` appear first in the diagonalization. (Uses the
       `diagonal_locations` helper function.)

    Parameters
    ----------
    N1 : GF(2) matrix

    Returns
    -------
    H : GF(2) matrix
        Symmetric `g x g` matrix where the diagonal elements consist of either
        a "1" or a `2 x 2` block matrix `[0 1 \\ 1 0]`.
    Q : GF(2) matrix
        The corresponding transformation matrix.
    """
    g = N1.nrows()
    H = zero_matrix(GF(2), g)
    Q = identity_matrix(GF(2), g)

    # if N1 is the zero matrix the H is also the zero matrix (and Q is the
    # identity transformation)
    if (N1 % 2) == 0:
        return H,Q

    # perform the "modified gaussian elimination"
    B = Matrix(GF(2),[[0,1],[1,0]])
    H = N1.change_ring(GF(2))
    j = 0
    while (j < g) and (H[:,j:] != 0):
        # if the current column is zero then swap with the last non-zero column
        if H.column(j) == 0:
            last_non_zero_col = max(k for k in range(j,g) if H.column(k) != 0)
            Q.swap_columns(j,last_non_zero_col)
            H = Q.T*N1*Q

        # if the current diagonal element is 1 then gaussian eliminate as
        # usual. otherwise, swap rows so that a "1" appears in H[j+1,j] and
        # then eliminate from H[j+1,j]
        if H[j,j] == 1:
            rows_to_eliminate = (r for r in range(g) if H[r,j] == 1 and r != j)
            for r in rows_to_eliminate:
                Q.add_multiple_of_column(r,j,1)
            H = Q.T*N1*Q
        else:
            # find the first non-zero element in the column after the diagonal
            # element and swap rows with this element
            first_non_zero = min(k for k in range(j,g) if H[k,j] != 0)
            Q.swap_columns(j+1,first_non_zero)
            H = Q.T*N1*Q

            # eliminate *all* other ones in the column, including those above
            # the element (j,j+1)
            rows_to_eliminate = (r for r in range(g) if H[r,j] == 1 and r != j+1)
            for r in rows_to_eliminate:
                Q.add_multiple_of_column(r,j+1,1)
            H = Q.T*N1*Q

        # increment the column based on the diagonal element
        if H[j,j] == 1:
            j += 1
        elif H[j:(j+2),j:(j+2)] == B:
            # in the block diagonal case, need to eliminate below the j+1 term
            rows_to_eliminate = (r for r in range(g) if H[r,j+1] == 1 and r != j)
            for r in rows_to_eliminate:
                Q.add_multiple_of_column(r,j,1)
            H = Q.T*N1*Q
            j += 2

    # finally, check if there are blocks of "special" form. that is, shift all
    # blocks such that they occur first along the diagonal of H
    index_one, index_B = diagonal_locations(H)
    while index_one < index_B:
        j = index_B

        Qtilde = zero_matrix(GF(2), g)
        Qtilde[0,0] = 1
        Qtilde[j,0] = 1; Qtilde[j+1,0] = 1
        Qtilde[0,j] = 1; Qtilde[0,j+1] = 1
        Qtilde[j:(j+2),j:(j+2)] = B

        Q = Q*Qtilde
        H = Q.T*N1*Q

        # continue until none are left
        index_one, index_B = diagonal_locations(H)

    # above, we used Q to store column operations on N1. switch to rows
    # operations on H so that N1 = Q*H*Q.T
    Q = Q.T.inverse()
    return H,Q
예제 #27
0
def pade_sage(input_series, m, n):
    r"""
    Returns the Pade approximant of ``self`` of index `(m, n)`.

    The Pade approximant of index `(m, n)` of a formal power
    series `f` is the quotient `Q/P` of two polynomials `Q` and `P`
    such that `\deg(Q)\leq m`, `\deg(P)\leq n` and

    .. MATH::

        f(z) - Q(z)/P(z) = O(z**{m+n+1}).

    The formal power series `f` must be known up to order `n + m + 1`.

    See :wikipedia:`Pade\_approximant`

    INPUT:

    - ``m``, ``n`` -- integers, describing the degrees of the polynomials

    OUTPUT:

    a ratio of two polynomials

    .. WARNING::

        The current implementation uses a very slow algorithm and is not
        suitable for high orders.

    ALGORITHM:

    This method uses the formula as a quotient of two determinants.

    .. SEEALSO::

        * :mod:`sage.matrix.berlekamp_massey`,
        * :meth:`sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint.rational_reconstruct`

    EXAMPLES::

        sage: z = PowerSeriesRing(QQ, 'z').gen()
        sage: exp(z).pade(4, 0)
        1/24*z**4 + 1/6*z**3 + 1/2*z**2 + z + 1
        sage: exp(z).pade(1, 1)
        (-z - 2)/(z - 2)
        sage: exp(z).pade(3, 3)
        (-z**3 - 12*z**2 - 60*z - 120)/(z**3 - 12*z**2 + 60*z - 120)
        sage: log(1-z).pade(4, 4)
        (25/6*z**4 - 130/3*z**3 + 105*z**2 - 70*z)/(z**4 - 20*z**3 + 90*z**2
        - 140*z + 70)
        sage: sqrt(1+z).pade(3, 2)
        (1/6*z**3 + 3*z**2 + 8*z + 16/3)/(z**2 + 16/3*z + 16/3)
        sage: exp(2*z).pade(3, 3)
        (-z**3 - 6*z**2 - 15*z - 15)/(z**3 - 6*z**2 + 15*z - 15)

    TESTS:

    With real coefficients::

        sage: R.<z> = RR[[]]
        sage: f = exp(2*z)
        sage: f.pade(3, 3) # abs tol 1e-10
        (-1.0*z**3 - 6.0*z**2 - 15.0*z - 15.0)/(z**3 - 6.0*z**2 + 15.0*z - 15.0)

    When precision is too low::

        sage: f = z + O(z**6)
        sage: f.pade(4, 4)
        Traceback (most recent call last):
        ...
        ValueError: the precision of the series is not large enough
    """
    from sage.matrix.constructor import Matrix
    if input_series.precision_absolute() < n + m + 2:
        raise ValueError("the precision of the series is not large enough")
    polyring = input_series.parent()._poly_ring()
    z = polyring.gen()
    c = input_series.list()
    mat = Matrix(polyring, n + 1, n + 1)
    for i in range(1, n + 1):
        for j in range(n + 1):
            if m + i - j < len(c):
                mat[i, j] = c[m + i - j]
    for j in range(n + 1):
        mat[0, j] = z ** j
    resu_v = mat.determinant().truncate(n + 1)
    lead_v = resu_v.leading_coefficient()
    resu_v = resu_v / lead_v
    for j in range(n + 1):
        mat[0, j] = z ** j * (input_series.truncate(max(m - j + 1, 0)))
    resu_u = mat.determinant().truncate(m + 1)
    lead_u = resu_u.leading_coefficient()
    resu_u = resu_u / lead_u
    return lead_u / lead_v * resu_u / resu_v
def reduction_maps(betas, ell, verbose=False):
    """Input: 

    betas: a list of d ZZ-module generators of an order O in a number
    field K of degree d,

    ell: a rational prime ell,

    Output: a (possibly empty) list of maps ZZ^d = GF(ell) encoding all
    possible ring homomorphisms from O to GF(ell).  Each map is
    encoded as a list of d elements of GF(ell) giving the images of
    the order's basis (the betas).

    Method: convert each beta into a dxd integer matrix giving the
    multiplication-by-beta map from O to itself.  Reduce these mod
    ell, and use them to define a FiniteDimensionalAlgebra A over
    GF(ell).  Find the maximal ideals of A whose quotient field is
    GF(ell) (and not some extension of it).  So the ideal has
    dimension d-1 and the required map is the inner product with a
    basis vector for its complement.
    """
    K = betas[0].parent()
    #print("K = {}".format(K))
    #print("betas = {}".format(betas))
    assert betas[0]==1
    Fl = GF(ell)
    if verbose:
        print("creating Hecke order mod {} from betas".format(ell))
    coords = K.gen().coordinates_in_terms_of_powers()
    U = Matrix([coords(b) for b in betas]).inverse()
    structure = [(Matrix([coords(bi*bj) for bj in betas])*U).change_ring(Fl)
                 for bi in betas]
    assert structure[0]==1
    #print("structure = {}".format(structure))
    A = FiniteDimensionalAlgebra(Fl, structure)
    #print("A = {}".format(A))
    MM = A.maximal_ideals()
    d = len(betas)
    # dd = [M.basis_matrix().transpose().nullity() for M in MM]
    # print("Algebra over GF({}) of dimension {}  has {} maximal ideals of residue degrees {}".format(ell,len(betas),len(MM), dd))
    vv = [list(M.basis_matrix().right_kernel().basis()[0])
          for M in MM  if M.basis_matrix().rank()==d-1]

    # Taking the dot product with each of these basis vectors gives a
    # GF(l)-linear map from the Hecke order to GF(l), but we need it
    # to be a ring homomorphism, so we must scale it so 1 maps to 1.
    # In practice Sage will always scale the basis vector so that the
    # first nonzero entry (which here must be the first entry) is 1,
    # but we should not rely on this.

    for v in vv:
        if v[0]!=1:
            if verbose:
                print("Rescaling reduction vector v={}".format(v))
            if v[0]==0:
                raise ValueError("reduction map defined by {} maps 1 to 0".format(v))
            v0inv = 1/v[0]
            v = [vi*v0inv for vi in v]
            if verbose:
                print("Rescaled reduction vector v={}".format(v))
    if verbose:
        print("{} reductions found from Hecke order".format(len(vv)))
        if vv:
            print("Reduction vector(s):")
            for v in vv: print(v)
    #return [lambda w: Fl(sum([vi*Fl(wi) for vi,wi in zip(v,w)])) for v in vv]
    return vv
예제 #29
0
    def AddFlip(self, A, B):

        maxlower = self.lower;

        field = self.R;
        output_field = self.R
        if A.base_ring() == self.Rextraprec or B.base_ring() == self.Rextraprec:
            field = self.Rextraprec;
        if A.base_ring() == self.Rextraprec and B.base_ring() == self.Rextraprec:
            output_field = self.Rextraprec;
        
        # Takes H0(3D0-A), H0(3D0-B), and returns H0(3D0-C), with C s.t. A+B+C~3D0
        # H0(6D0-A-B) = H0(3D0-A) * H0(3D0-B)

        if self.verbose:
            print "PicardGroup.AddFlip(self, A, B)"
        #### STEP 1 ####
        if self.verbose:
            print "Step 1";
        
        AB = Matrix(field, self.nZ, 4 * self.d0  + 1 - self.g);    
        KAB = Matrix(field, AB.nrows() - AB.ncols(), AB.nrows());
        
        ABncols = AB.ncols();
        ABnrows = AB.nrows();
        rank = AB.ncols();
 
        while True:
            # 5 picked at random
            l = 5;
            ABtmp =  Matrix(field, self.nZ, 4 * self.d0  + 1 - self.g + l);

            for j in range(ABtmp.ncols()):
                a = random_vector_in_span(A);
                b = random_vector_in_span(B);
                for i in range(ABnrows):
                    ABtmp[i, j] = a[i] * b[i];

            Q, R, P = qrp(ABtmp, ABncols );

            upper = R[rank - 1, rank - 1].abs();
            lower = 0;
            if ABtmp.ncols() > rank and ABnrows > rank:
                lower = R[rank, rank ].abs();
            
            if self.threshold_check(upper, lower):
                # the first AB.cols columns are a basis for H0(6D0-A-B) = H0(3D0-A) * H0(3D0-B)
                # v in AB iff KAB * v = 0
                for i in range(ABnrows):
                    for j in range(ABncols):
                        AB[i, j] = Q[i, j]
                    for j in range(ABnrows - rank):
                        KAB[j, i] = Q[i, j + rank].conjugate();
                maxlower = max(maxlower, lower);
                break;
            if self.verbose:
                print "Warning: In AddFlip, not full rank at step 1, retrying."
                print "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower))
                


        #### STEP 2 ####
        # H0(3D0-A-B) = {s in V : s*V c H0(6D0-A-B)}

        if self.verbose:
            print "Step 2"

        #### Prec Test ####
        if self.verbose:
            a = random_vector_in_span(A);
            b = random_vector_in_span(B);
            ab = Matrix(field, self.nZ, 1);
            for i in range(self.nZ):
                ab[i, 0] = a[i] * b[i];
            print field
            print "maxlower = %s ,lower = %s " % (RealField(15)(maxlower), RealField(15)(lower))
            print "Precision of the input of MakAddflip: %s"% (RealField(15)(max(map(lambda x: RR(x[0].abs()), list(KAB * ab)))),)

        KABnrows = KAB.nrows();
        KABncols = KAB.ncols();
        while True:
            # columns =  equations for H0(3D0-A-B) = {s in V : s*V c H0(6D0-A-B)} \subset  H0(6D0-A-B)
            l = 2;
            KABred = copy(KAB);
            KABred = KABred.stack( Matrix(field, l*KABnrows, KABncols ) );

            for m in range(l): # Attempt of IGS of V
                v = random_vector_in_span( self.V )
                for j in xrange(KABncols):
                    for i in range( KABnrows ):
                        KABred[i + m * KABnrows + KABnrows , j] = KAB[i, j] * v[j]

            ABred, upper, lower = Kernel(KABred, KABred.ncols() - (self.d0 + 1 - self.g));
            if self.threshold_check(upper, lower):
                maxlower = max(maxlower, lower);
                break;
            
            if self.verbose:
                print "Warning: In AddFlip, failed IGS at step 2, retrying."
                print "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower))

        
        #### STEP 3 ####
        # H0(6D0-A-B-C) = f*H0(3D0), where f in H0(30-A-B)
        if self.verbose:
            print "Step 3"

        # fv represents f*H0(3D0)
        fV= copy(self.V)
        for j in xrange(3*self.d0 + 1 - self.g):
            for i in xrange(self.nZ):
                fV[i,j] *= ABred[i,0]

        KfV, upper, lower = EqnMatrix( fV, 3 * self.d0 + 1 - self.g ) # Equations for f*V
        assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower))
        maxlower = max(maxlower, lower);
 
        KfVnrows = KfV.nrows();
        KfVncols = KfV.ncols();

        ### STEP 4 ###
        # H0(3D0-C) = {s in V : s*H0(3D0-A-B) c H0(6D0-A-B-C)} = {s in V : s*H0(3D0-A-B) c f*V}
        if self.verbose:
            print "Step 4"
        while True:
            # Equations for H0(3D0-C)
            
            #expand KC
            l = 2;
            KC = self.KV.stack(Matrix(field, l * KfV.nrows(), self.KV.ncols()));
            KC_old_rows = self.KV.nrows();

            for m in range(l): # Attempt of IGS of H0(3D0-A-B)
                v = random_vector_in_span(ABred)
                for i in range(KfVnrows):
                    for j in range(KfVncols):
                        KC[i + m * KfVnrows + KC_old_rows, j] = v[j] * KfV[i, j];
            
            output, upper, lower = Kernel(KC, KC.ncols() - (2 * self.d0 + 1 - self.g) );
            if self.threshold_check(upper, lower):
                maxlower = max(maxlower, lower);
                break;

            if self.verbose:
                print "Warning: In MakAddFlip, failed IGS at step 4, retrying."
                print "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower))
        
        return output.change_ring(output_field), maxlower;
예제 #30
0
def block_matrix(parent, rows, constant_or_identity=True):
    '''
        Method that build a matrix using as blocks the elements of rows. 
        
        This method allows the user to build a matrix defining its blocks. There are two options for the inputs:
            * A matrix (that will be directly used as a block
            * Elements alone: will build a constant matrix or a diagonal matrix depending on the argument ``constant_or_identity``.
            
        This method checks that the size of the input is correct, i.e., all rows have the same amount of columns and that all 
        matrices within a row provide the same amount of rows.

        INPUT:
            * ``parent``: the desired parent for the final matrix. All elements mast be inside this parent.
            * ``rows``: a list of arguments representing the rows of the matrix. Each row is another list
              where the elements may be matrices (indicating the number of rows for this block) or elements
              in ``parent`` that will create constant or diagonal matrices with such element.
            * ``constant_or_identity``: this argument decides whether the elements create a diagonal
              matrix (``True``) or a constant matrix (``False``).

        OUTPUT:
            A matrix with the corresponding struture. If any of the sizes does not match, a :class:`~ajpastor.misc.exceptions.SizeMatrixError`
            will be raised.

        EXAMPLES::

            sage: from ajpastor.misc.matrix import *
            sage: M = Matrix(QQ,[[1,2],[3,4]]); I = identity_matrix(QQ, 3)
            sage: block_matrix(QQ,[[M,0],[0,I]])
            [1 2 0 0 0]
            [3 4 0 0 0]
            [0 0 1 0 0]
            [0 0 0 1 0]
            [0 0 0 0 1]
            sage: block_matrix(QQ, [[I, 1],[2, M]])
            [1 0 0 1 0]
            [0 1 0 0 1]
            [0 0 1 0 0]
            [2 0 0 1 2]
            [0 2 0 3 4]
            sage: block_matrix(QQ, [[I, 1],[2, M]], False)
            [1 0 0 1 1]
            [0 1 0 1 1]
            [0 0 1 1 1]
            [2 2 2 1 2]
            [2 2 2 3 4]

        This method also works with non-square matrices::

            sage: N = Matrix(QQ, [[1,2,3],[4,5,6]])
            sage: block_matrix(QQ, [[N,1],[0,M]])
            [1 2 3 1 0]
            [4 5 6 0 1]
            [0 0 0 1 2]
            [0 0 0 3 4]
            sage: block_matrix(QQ, [[N,M],[1,2]], False)
            [1 2 3 1 2]
            [4 5 6 3 4]
            [1 1 1 2 2]
        
        However, the sizes of the columns and rows has to fit::

            sage: block_matrix(QQ, [[N, 1], [M, 0]])
            Traceback (most recent call last):
            ...
            SizeMatrixError: The col has not the proper format -- different size

        This method also allows matrices in list format::

            sage: block_matrix(QQ, [[N, [[0, 1],[-1,0]]], [1, M]])
            [ 1  2  3  0  1]
            [ 4  5  6 -1  0]
            [ 1  0  0  1  2]
            [ 0  1  0  3  4]
            sage: block_matrix(QQ, [[N, [[0, 1],[1,0],[1,1]]],[1, M]])
            Traceback (most recent call last):
            ...
            SizeMatrixError: The row has not the proper format -- different size

        And also, if all entries are matrices, we do not need to have in the input all the 
        rows with the same length::

            sage: L = Matrix(QQ, [[5, 4, 3, 2, 1]])
            sage: block_matrix(QQ, [[M, N],[L]])
            [1 2 1 2 3]
            [3 4 4 5 6]
            [5 4 3 2 1]
            sage: block_matrix(QQ, [[N, I[:2]], [L,[[9]]]])
            [1 2 3 1 0 0]
            [4 5 6 0 1 0]
            [5 4 3 2 1 9]
            sage: block_matrix(QQ, [[N, I[:2]], [L]])
            Traceback (most recent call last):
            ...
            SizeMatrixError: The given rows have different column size

        Finally, this method also allows the user to create a Matrix in a normal fashion 
        (providing each of its elements)::

            sage: block_matrix(QQ, [[1,2],[3,4]]) == M
            True
    '''
    ## We have two different ways of seeing the input: either all the provided rows are of the same size,
    ## allowing to have input in the parent ring, or the sizes must match perfectly between the rows.

    # Checking the first case: if any element is in parent
    if (any(any((el in parent) for el in row) for row in rows)):
        d = len(rows[0])
        for i in range(1, len(rows)):
            if (d != len(rows[i])):
                raise SizeMatrixError(
                    "The rows provided can not be seen as a matrix")

        ## We check the sizes
        rows_hights = [__check_row(row, parent) for row in rows]
        cols_widths = [
            __check_col([rows[i][j] for i in range(len(rows))], parent)
            for j in range(len(rows[0]))
        ]

        rows_with_matrix = []
        for i in range(len(rows)):
            row_with_matrix = []
            for j in range(len(rows[0])):
                if (rows[i][j] in parent):
                    if (constant_or_identity):
                        row_with_matrix += [
                            Matrix(parent, [[
                                rows[i][j] * kronecker_delta(k, l)
                                for l in range(cols_widths[j])
                            ] for k in range(rows_hights[i])])
                        ]
                    else:
                        row_with_matrix += [
                            Matrix(
                                parent,
                                [[rows[i][j] for l in range(cols_widths[j])]
                                 for k in range(rows_hights[i])])
                        ]
                else:
                    row_with_matrix += [Matrix(parent, rows[i][j])]
            rows_with_matrix += [row_with_matrix]
    else:  # Second case: all elements are matrices, hence they must fit exactly
        ## We check the sizes
        rows_hights = [__check_row(row, parent) for row in rows]
        cols_widths = [sum(__ncols(el) for el in row) for row in rows]

        if (any(el != cols_widths[0] for el in cols_widths)):
            raise SizeMatrixError("The given rows have different column size")

        rows_with_matrix = []
        for i in range(len(rows)):
            row_with_matrix = []
            for j in range(len(rows[i])):
                row_with_matrix += [Matrix(parent, rows[i][j])]
            rows_with_matrix += [row_with_matrix]

    ## At this point the variable "row_with_matrix" has all the entries for the final matrix
    ## No checks are needed
    final_rows = []
    for i in range(len(rows_with_matrix)):
        for j in range(rows_hights[i]):
            final_rows += [
                reduce(lambda p, q: p + q,
                       [list(el[j]) for el in rows_with_matrix[i]])
            ]
    return Matrix(parent, final_rows)