Example #1
0
    def test_diagonal_locations(self):
        # tests the helper function `diagonal_locations` which identifies where
        # the diagonal elements or blocks occur in the H matrix
        H = Matrix(GF(2), [[0, 0, 0], [0, 0, 0], [0, 0, 0]])
        index_one, index_B = diagonal_locations(H)
        self.assertEqual(index_one, 3)
        self.assertEqual(index_B, -1)

        H = Matrix(GF(2), [[1, 0, 0], [0, 0, 0], [0, 0, 0]])
        index_one, index_B = diagonal_locations(H)
        self.assertEqual(index_one, 0)
        self.assertEqual(index_B, -1)

        H = Matrix(GF(2), [[0, 1, 0], [1, 0, 0], [0, 0, 0]])
        index_one, index_B = diagonal_locations(H)
        self.assertEqual(index_one, 3)
        self.assertEqual(index_B, 0)

        H = Matrix(GF(2), [[0, 1, 0], [1, 0, 0], [0, 0, 1]])
        index_one, index_B = diagonal_locations(H)
        self.assertEqual(index_one, 2)
        self.assertEqual(index_B, 0)

        H = Matrix(GF(2), [[1, 0, 0], [0, 0, 1], [0, 1, 0]])
        index_one, index_B = diagonal_locations(H)
        self.assertEqual(index_one, 0)
        self.assertEqual(index_B, 1)
Example #2
0
def attack(p, t, a, B):
    """
    Solves the hidden number problem using an attack based on the shortest vector problem.
    The hidden number problem is defined as finding y such that {x_i - t_i * y + a_i = 0 mod p}.
    More information: Breitner J., Heninger N., "Biased Nonce Sense: Lattice Attacks against Weak ECDSA Signatures in Cryptocurrencies"
    :param p: the modulus
    :param t: the t_i values
    :param a: the a_i values
    :param B: a bound on the x values
    :return: a tuple containing y, and a list of x values
    """
    assert len(t) == len(a), "t and a lists should be of equal length."

    m = len(t)
    M = Matrix(QQ, m + 2, m + 2)
    for i in range(m):
        M[i, i] = p

    M[m] = t + [B / QQ(p), 0]
    M[m + 1] = list(map(lambda x: x - B // 2, a)) + [0, B]

    L = M.LLL()

    for row in L.rows():
        y = (int(row[m] * p) // B) % p
        if y != 0 and row[m + 1] == B:
            return int(y), list(map(lambda x: int(x + B // 2), row[:m]))
    def TwoPointsMinusInfinity(self, P, Q): # Creates a divisor class of P + Q - g*\infty
        maxlower = self.lower
        xP, yP = self.Rextraprec(P[0]), self.Rextraprec(P[1])
        xQ, yQ = self.Rextraprec(Q[0]), self.Rextraprec(Q[1])

        assert (self.f(xP) - yP**2).abs() <= (yP**2).abs() * self.almostzero
        assert (self.f(xQ) - yQ**2).abs() <= (yQ**2).abs() * self.almostzero

        WPQ = Matrix(self.Rextraprec, self.nZ, 3 * self.g + 7) # H0(3D0  - g*\infty)
        Ev = Matrix(self.Rextraprec, 2, 3 * self.g + 7) # basis of  H0(3D0  - g*\infty) evaluated at P and Q
        Exps=[]
        for n in range( 2 * self.g + 4):
            Exps.append((n,0))
            if n > self.g:
                Exps.append(( n - self.g - 1, 1))

        for j in range( 3 * self.g + 7):
            u, v = Exps[j]
            for i in range( self.nZ ):
                x, y = self.Z[i]
                WPQ[ i, j ] = x**u * y**v

            Ev[0,j] = xP**u * yP**v
            Ev[1,j] = xQ**u * yQ**v
        
        K, upper, lower = Kernel(Ev, 2)
        assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower))
        maxlower = max(maxlower, lower);
        #Returns H0(3*D0 - P - Q - g infty)
        # note that  [P + Q + g infty - D0] ~ P + Q - infty
        return (WPQ * K).change_ring(self.R), maxlower
Example #4
0
def delta_rank(f):
    """Returns the Gamma-rank of the function with LUT f.

    The Gamma-rank is the rank of the 2^{2n} \times 2^{2n} binary
    matrix M defined by

    M[x][y] = 1 if and only if x + y \in \Delta,

    where \Delta is defined as

    \Delta = \{ (a, b), DDT_f[a][b] == 2  \} ~.

    """
    n = int(log(len(f), 2))
    dim = 2**(2 * n)
    d = ddt(f)
    gamma = [(a << n) | b
             for a, b in itertools.product(xrange(1, 2**n), xrange(0, 2**n))
             if d[a][b] == 2]
    mat_content = []
    for x in xrange(0, dim):
        row = [0 for j in xrange(0, dim)]
        for y in gamma:
            row[oplus(x, y)] = 1
        mat_content.append(row)
    mat_gf2 = Matrix(GF(2), dim, dim, mat_content)
    return mat_gf2.rank()
Example #5
0
def extract_basis(v, N):
    """Returns a subset of v such that the span of these elements is at
    least as big as v. In particular, if v is a vector space, it returns a
    base.

    """
    dim = rank_of_vector_set(v, N)
    i = 0
    basis = []
    while i < len(v) and v[i] == 0:
        i += 1
    if i == len(v):
        return []
    basis.append(v[i])
    if dim == 1:
        return basis
    i += 1
    r = Matrix(GF(2), 1, N, [tobin(x, N) for x in basis]).rank()
    while r < dim and i < len(v):
        new_basis = basis + [v[i]]
        new_r = Matrix(GF(2), len(new_basis), N,
                       [tobin(x, N) for x in new_basis]).rank()
        if new_r == dim:
            return new_basis
        elif new_r > r:
            basis = new_basis
            r = new_r
        i += 1
    return []
 def test_lll(self):
     # do a quick verification of the basis from cryptopals
     B = Matrix(
         QQ,
         [[-_sage_const_2, _sage_const_0, _sage_const_2, _sage_const_0],
          [
              _sage_const_1 / _sage_const_2, -_sage_const_1, _sage_const_0,
              _sage_const_0
          ],
          [
              -_sage_const_1, _sage_const_0, -_sage_const_2,
              _sage_const_1 / _sage_const_2
          ], [-_sage_const_1, _sage_const_1, _sage_const_1, _sage_const_2]])
     ex = Matrix(QQ, [[
         _sage_const_1 / _sage_const_2, -_sage_const_1, _sage_const_0,
         _sage_const_0
     ],
                      [
                          -_sage_const_1, _sage_const_0, -_sage_const_2,
                          _sage_const_1 / _sage_const_2
                      ],
                      [
                          -_sage_const_1 / _sage_const_2, _sage_const_0,
                          _sage_const_1, _sage_const_2
                      ],
                      [
                          -_sage_const_3 / _sage_const_2, -_sage_const_1,
                          _sage_const_2, _sage_const_0
                      ]])
     re = matrix_utils.LLL(B)
     assert re == ex
Example #7
0
    def get_shift_and_width_for_coset(self, n):
        r"""
        Compute the shift and width of coset nr. n.
        """
        if self._shift.has_key(n) and self._width.has_key(n):
            return self._shift[n], self._width[n]
        if not is_squarefree(self._level):
            raise NotImplementedError, "Only square-free levels implemented"
        G = Gamma0(self._level)
        A = self.coset_rep(n)
        a = A[0, 0]
        c = A[1, 0]
        width = G.cusp_width(Cusp(a, c))
        if self._verbose > 0:
            print "width=", width
        Amat = Matrix(ZZ, 2, 2, A.matrix().list())
        h = -1
        for j in range(width):
            Th = Matrix(ZZ, 2, 2, [width, -j, 0, 1])
            W = Amat * Th
            if self._verbose > 1:
                print "W=", W

            if self.is_involution(W):
                h = j
                break
        if h < 0:
            raise ArithmeticError, "Could not find shift!"
        self._shift[n] = h
        self._width[n] = width
        return h, width
Example #8
0
    def matrix(self):
        r"""
        Return the persistence matrix of self.

        EXAMPLES::

            sage: from pGroupCohomology import CohomologyRing
            sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
            sage: H = CohomologyRing(8,3)
            sage: H.make()
            sage: B = H.bar_code('UpperCentralSeries')
            sage: B.matrix()
            [       1/(-t + 1)      -1/(t^2 - 1)                 1]
            [                0 1/(t^2 - 2*t + 1)  (-t - 1)/(t - 1)]
            [                0                 0 1/(t^2 - 2*t + 1)]

        """
        from sage.all import Matrix
        M = Matrix(2 * self._length + 1, 2 * self._length + 1)
        for X in self._L.items():
            if not (isinstance(X[1], int)
                    or M.base_ring().has_coerce_map_from(X[1].parent())):
                M = M * X[1].parent()(1)
            M[X[0][0] + self._length, X[0][1] + self._length] = X[1]
        return M
    def PointMinusInfinity(self, P, sign = 0):
        # Creates a divisor class of P- \inty_{(-1)**sign}
        maxlower = self.lower 
        assert self.f.degree() == 2*self.g + 2;
        sqrtan = (-1)**sign * self.Rextraprec( sqrt( self.Rdoubleextraprec(self.an)) );

        xP, yP = self.Rextraprec(P[0]),self.Rextraprec(P[1])
        assert (self.f(xP) - yP**2).abs() <= (yP**2).abs() * self.almostzero

        if xP != 0 and self.a0 != 0:
            x0 = self.Rextraprec(0);    
        else:
            x0 = xP
            while x0 == xP:
                x0 = self.Rextraprec(ZZ.random_element())
            
        y0 =  self.Rextraprec( sqrt( self.Rdoubleextraprec( self.f( x0 )))) # P0 = (x0, y0) 

        WP1 = Matrix(self.Rextraprec, self.nZ, 3 * self.g + 6) # H0(3D0 - P0 - g \infty) = H0(3D0 - P0 - g(\infty_{+} + \infty_{-}))
        EvP = Matrix(self.Rextraprec, 1, 3 * self.g + 6) # the functions of  H0(3D0-P0-g \infty) at P
        B =  Matrix(self.Rextraprec, self.nZ, 3 * self.g + 5) # H0(3D0 - \infty_{sign} - P0 - g\infty)

        # adds the functions x - x0, (x - x0)**1,  ..., (x - x0)**(2g+2) to it
        for j in xrange(2 * self.g + 2 ):
            for i, (x, y) in enumerate( self.Z ):
                WP1[ i, j] = B[ i, j] = (x - x0) ** (j + 1)
            EvP[ 0, j] = (xP - x0) ** (j + 1)
        
        # adds y - y0
        for i, (x, y) in enumerate( self.Z ):
            WP1[ i, 2 * self.g + 2 ] = B[ i, 2 * self.g + 2] = y - y0
        EvP[ 0, 2 * self.g + 2] = yP - y0

        # adds (x - x0) * y ... (x-x0)**(g+1)*y
        for j in range(1, self.g + 2):
            for i, (x,y) in enumerate( self.Z ):
                WP1[ i, 2 * self.g + 2 + j ] = B[ i, 2 * self.g + 2 + j] = (x-x0)**j * y 
            EvP[ 0, 2 * self.g + 2 + j] = (xP - x0)**j * yP


        # adds (x - x0)**(2g + 3) and  y *  (x - x0)**(g + 2)
        for i,(x,y) in enumerate(self.Z):
            WP1[ i, 3 * self.g + 4 ] =  (x - x0)**( 2 * self.g + 3)
            WP1[ i, 3 * self.g + 5 ] = y *  (x - x0)**(self.g + 2)
            B[ i, 3 * self.g + 4 ] =  (x - x0)**( self.g + 2) * ( y - sqrtan * x**(self.g + 1) )

        EvP[ 0, 3 * self.g + 4] = (xP - x0) ** ( 2 * self.g + 3)
        EvP[ 0, 3 * self.g + 5] = yP * (xP - x0)**(self.g + 2)
        
        # A = functions in  H0(3D0-P0-g \infty) that vanish at P
        # = H**0(3D0 - P0 - P -g \infty)
        K, upper, lower = Kernel(EvP, EvP.ncols() - (3 * self.g + 5))
        assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower))
        maxlower = max(maxlower, lower);

        A = WP1 * K
        # A - B = P0 + P + g \infty - (\infty_{+} + P0 + g\infty) = P - \inty_{+}
        res, lower = self.Sub(A,B)
        maxlower = max(maxlower, lower);
        return res.change_ring(self.R), maxlower;
Example #10
0
def upper_bound_index_cusps_in_JG_torsion(G, d, bound=60):
    """
    INPUT:
        
    - G - a congruence subgroup
    - d - integer, the size of the rational cuspidal subgroup
    - bound (optional, default = 60) - the bound for the primes p up to which to use
      the hecke matrix `T_p - <p> - p` for bounding the torsion subgroup
    
    OUTPUT:
        
    - an integer `i` such that `(\#J_G(\QQ)_{tors})/d` is a divisor of `i`.
    
    EXAMPLES::

        sage: from mdsage import *
        sage: d = rational_cuspidal_classgroup(Gamma1(23)).cardinality()
        sage: upper_bound_index_cusps_in_JG_torsion(Gamma1(23),d)
        1

    """
    N = G.level()
    M = ModularSymbols(G)
    Sint = cuspidal_integral_structure(M)
    kill_mat = (M.star_involution().matrix().restrict(Sint) - 1)
    kill = kill_mat.transpose().change_ring(ZZ).row_module()
    for p in prime_range(3, bound):
        if not N % p == 0:
            kill += kill_torsion_coprime_to_q(
                p, M).restrict(Sint).change_ring(ZZ).transpose().row_module()
        if kill.matrix().is_square() and kill.matrix().determinant() == d:
            #print p
            break
    kill_mat = kill.matrix().transpose()
    #print N,"index of torsion in stuff killed",kill.matrix().determinant()/d
    if kill.matrix().determinant() == d:
        return 1

    pm = integral_period_mapping(M)
    period_images1 = [
        sum([M.coordinate_vector(M([c, infinity])) for c in cusps]) * pm
        for cusps in galois_orbits(G)
    ]

    m = (Matrix(period_images1) * kill_mat).stack(kill_mat)
    diag = m.change_ring(ZZ).echelon_form().diagonal()
    #print diag,prod(diag)
    assert prod(diag) == kill.matrix().determinant() / d

    period_images2 = [
        M.coordinate_vector(M([c, infinity])) * pm for c in G.cusps()
        if c != Cusp(oo)
    ]
    m = (Matrix(period_images2) * kill_mat).stack(kill_mat)
    m, denom = m._clear_denom()
    diag = (m.change_ring(ZZ).echelon_form() / denom).diagonal()
    #print diag
    #print prod(i.numerator() for i in diag),"if this is 1 then :)"
    return prod(i.numerator() for i in diag)
def fractional_CRT_QQ(residues, ps_roots):
    residues_ZZ = [ r.lift() for r in residues];
    primes = [p for p, _ in ps_roots]
    lift = CRT_list(residues_ZZ, primes);
    N = prod(primes);
    M = Matrix([[1 ,lift, N]]);
    short_vector = Matrix(M.transpose().kernel().basis()).LLL()[0]
    return -short_vector[0]/short_vector[1];
Example #12
0
 def __init__(self,M=None,genus_list=None):
   #print genus_list
   if M:
     self.M = copy(M)
   elif genus_list:
     self.M = Matrix(StrataGraph.R,len(genus_list)+1,1,[-1]+genus_list)
   else:
     self.M = Matrix(StrataGraph.R,1,1,-1)
Example #13
0
    def __init__(self,
                 parent,
                 matrix,
                 inhomogeneous,
                 is_zero=lambda p: False,
                 relations=[]):
        ## Checking the input of matrix and vector
        if (not SAGE_element.is_Matrix(matrix)):
            matrix = Matrix(matrix)

        if (not SAGE_element.is_Vector(inhomogeneous)):
            inhomogeneous = vector(inhomogeneous)

        if (isinstance(parent, Wrap_w_Sequence_Ring)):
            parent = parent.base()

        ## Building the parent of the matrix and the vector
        pmatrix = matrix.parent().base()
        pinhom = inhomogeneous.parent().base()

        ## Setting the variables for the matrix, the parent and the vector
        self.__parent = pushout(pmatrix, pinhom)
        self.__matrix = matrix.change_ring(self.__parent)
        self.__inhomogeneous = inhomogeneous.change_ring(self.__parent)

        ## Setting the parent for the solutions
        if (not pushout(parent, self.__parent) == parent):
            try:
                self.__matrix = self.__matrix.change_ring(parent)
                self.__inhomogeneous = self.__inhomogeneous.change_ring(parent)
                self.__parent = parent
            except:
                raise TypeError(
                    "The parent for the solutions must be an extension of the parent for the input"
                )
        self.__solution_parent = parent

        ## Setting other variables
        if (relations is None):
            relations = []
        self.__relations = [self.__parent(el) for el in relations]
        try:
            self.__gb = ideal(self.parent(), self.__relations).groebner_basis()
        except AttributeError:
            try:
                self.__gb = [ideal(self.parent(), self.__relations).gen()]
            except:
                self.__gb = [0]

        self.__is_zero = is_zero

        ## Creating the variables for the echelon form
        self.__echelon = None
        self.__transformation = None

        ## Creating the variables for the solutions
        self.__solution = None
        self.__syzygy = None
Example #14
0
    def from_nice_matrix(lists):
        Mx = Matrix(StrataGraph.R, len(lists), len(lists[0]))
        Mx[0, 0] = -1
        Mx[0, :] = Matrix([lists[0]])
        for v in range(1, len(lists)):
            if lists[v][0] in ZZ:
                Mx[v, 0] = lists[v][0]
                continue
            if lists[v][0].operator() == sage.symbolic.operators.add_vararg:
                operands = lists[v][0].operands()
                if len(operands) != 2:
                    raise Exception("Input error!")
                genus = operands[1]  #the genus
                kappas = operands[0]
            else:
                kappas = lists[v][0]
                genus = 0

            if kappas.operator() == sage.symbolic.operators.mul_vararg:
                for operand in kappas.operands():
                    Mx[v, 0] += StrataGraph._kappaSR_monom_to_X(operand)
                Mx[v, 0] += genus
            else:
                Mx[v, 0] = StrataGraph._kappaSR_monom_to_X(kappas) + genus

        X = StrataGraph.Xvar
        for v in range(1, len(lists)):
            for edge in range(1, len(lists[0])):
                if lists[v][edge] in ZZ:
                    Mx[v, edge] = lists[v][edge]
                else:
                    for operand in lists[v][edge].operands():
                        if operand in ZZ:
                            Mx[v, edge] += operand
                        elif operand.operator() is None:
                            #it is a ps or ps2
                            Mx[v, edge] += X
                        elif operand.operator() == operator.pow:
                            #it is ps^n or ps2^n
                            Mx[v, edge] += X * operand.operands()[1]
                        elif operand.operator(
                        ) == sage.symbolic.operators.mul_vararg:
                            #it is a ps^n*ps2^m
                            op1, op2 = operand.operands()
                            if op1.operator() is None:
                                exp1 = 1
                            else:
                                exp1 = op1.operand()[1]
                            if op2.operator() == None:
                                exp2 = 1
                            else:
                                exp2 = op2.operand()[1]

                            if exp1 >= exp2:
                                Mx[v, edge] += exp1 * X + exp2 * X**2
                            else:
                                Mx[v, edge] += exp1 * X**2 + exp2 * X
        return StrataGraph(Mx)
Example #15
0
 def __init__(self, M=None, genus_list=None):
     #print genus_list
     if M:
         self.M = copy(M)
     elif genus_list:
         self.M = Matrix(StrataGraph.R,
                         len(genus_list) + 1, 1, [-1] + genus_list)
     else:
         self.M = Matrix(StrataGraph.R, 1, 1, -1)
Example #16
0
def symmetrize_periods(Pa, Pb, tol=1e-4):
    r"""Returns symmetric a- and b-periods `Pa_symm` and `Pb_symm`, as well as the
    corresponding symplectic operator `Gamma` such that `Gamma [Pa \\ Pb] =
    [Pa_symm \\ Pb_symm]`.

    Parameters
    ----------
    Pa : complex matrix
    Pb : complex matrix
        The a- and b-periods, respectively, of a genus `g` Riemann surface.
    tol : double
        (Default: 1e-4) Tolerance used to verify integrality of intermediate
        matrices. Dependent on precision of period matrices.

    Returns
    -------
    Gamma : integer matrix
        The symplectic transformation operator.
    Pa : complex matrix
    Pb : complex matrix
        Symmetric a- and b-periods, respectively, of a genus `g` Riemann surface.

    Notes
    -----
    The algorithm described in Kalla, Klein actually operates on the transposes
    of the a- and b-period matrices.
    """
    # coerce from numpy, if necessary
    if isinstance(Pa, numpy.ndarray):
        Pa = Matrix(CDF, numpy.ascontiguousarray(Pa))
    if isinstance(Pb, numpy.ndarray):
        Pb = Matrix(CDF, numpy.ascontiguousarray(Pb))

    # use the transposes of the period matrices and coerce to Sage matrices
    Pa = Pa.T
    Pb = Pb.T

    # use above functions to obtain topological type matrix
    g,g = Pa.dimensions()
    R = involution_matrix(Pa, Pb, tol=tol)
    S = integer_kernel_basis(R)
    N1 = N1_matrix(Pa, Pb, S, tol=tol)
    H,Q = symmetric_block_diagonalize(N1)
    Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=tol)

    # compute the corresponding symmetric periods
    stacked_periods = zero_matrix(CDF, 2*g, g)
    stacked_periods[:g,:] = Pa
    stacked_periods[g:,:] = Pb
    stacked_symmetric_periods = Gamma*stacked_periods
    Pa_symm = stacked_symmetric_periods[:g,:]
    Pb_symm = stacked_symmetric_periods[g:,:]

    # transpose results back
    Pa_symm = Pa_symm.T
    Pb_symm = Pb_symm.T
    return Pa_symm, Pb_symm
Example #17
0
def symmetrize_periods(Pa, Pb, tol=1e-4):
    r"""Returns symmetric a- and b-periods `Pa_symm` and `Pb_symm`, as well as the
    corresponding symplectic operator `Gamma` such that `Gamma [Pa \\ Pb] =
    [Pa_symm \\ Pb_symm]`.

    Parameters
    ----------
    Pa : complex matrix
    Pb : complex matrix
        The a- and b-periods, respectively, of a genus `g` Riemann surface.
    tol : double
        (Default: 1e-4) Tolerance used to verify integrality of intermediate
        matrices. Dependent on precision of period matrices.

    Returns
    -------
    Gamma : integer matrix
        The symplectic transformation operator.
    Pa : complex matrix
    Pb : complex matrix
        Symmetric a- and b-periods, respectively, of a genus `g` Riemann surface.

    Notes
    -----
    The algorithm described in Kalla, Klein actually operates on the transposes
    of the a- and b-period matrices.
    """
    # coerce from numpy, if necessary
    if isinstance(Pa, numpy.ndarray):
        Pa = Matrix(CDF, numpy.ascontiguousarray(Pa))
    if isinstance(Pb, numpy.ndarray):
        Pb = Matrix(CDF, numpy.ascontiguousarray(Pb))

    # use the transposes of the period matrices and coerce to Sage matrices
    Pa = Pa.T
    Pb = Pb.T

    # use above functions to obtain topological type matrix
    g, g = Pa.dimensions()
    R = involution_matrix(Pa, Pb, tol=tol)
    S = integer_kernel_basis(R)
    N1 = N1_matrix(Pa, Pb, S, tol=tol)
    H, Q = symmetric_block_diagonalize(N1)
    Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=tol)

    # compute the corresponding symmetric periods
    stacked_periods = zero_matrix(CDF, 2 * g, g)
    stacked_periods[:g, :] = Pa
    stacked_periods[g:, :] = Pb
    stacked_symmetric_periods = Gamma * stacked_periods
    Pa_symm = stacked_symmetric_periods[:g, :]
    Pb_symm = stacked_symmetric_periods[g:, :]

    # transpose results back
    Pa_symm = Pa_symm.T
    Pb_symm = Pb_symm.T
    return Pa_symm, Pb_symm
 def as_polynomial_in_E4_and_E6(self,insert_in_db=True):
     r"""
     If self is on the full modular group writes self as a polynomial in E_4 and E_6.
     OUTPUT:
     -''X'' -- vector (x_1,...,x_n)
     with f = Sum_{i=0}^{k/6} x_(n-i) E_6^i * E_4^{k/4-i}
     i.e. x_i is the coefficient of E_6^(k/6-i)*
     """
     if(self.level() != 1):
         raise NotImplementedError("Only implemented for SL(2,Z). Need more generators in general.")
     if(self._as_polynomial_in_E4_and_E6 is not None and self._as_polynomial_in_E4_and_E6 != ''):
         return self._as_polynomial_in_E4_and_E6
     d = self._parent.dimension_modular_forms()  # dimension of space of modular forms
     k = self.weight()
     K = self.base_ring()
     l = list()
     # for n in range(d+1):
     #    l.append(self._f.q_expansion(d+2)[n])
     # v=vector(l) # (self._f.coefficients(d+1))
     v = vector(self.coefficients(range(d),insert_in_db=insert_in_db))
     d = dimension_modular_forms(1, k)
     lv = len(v)
     if(lv < d):
         raise ArithmeticError("not enough Fourier coeffs")
     e4 = EisensteinForms(1, 4).basis()[0].q_expansion(lv + 2)
     e6 = EisensteinForms(1, 6).basis()[0].q_expansion(lv + 2)
     m = Matrix(K, lv, d)
     lima = floor(k / 6)  # lima=k\6;
     if((lima - (k / 2)) % 2 == 1):
         lima = lima - 1
     poldeg = lima
     col = 0
     monomials = dict()
     while(lima >= 0):
         deg6 = ZZ(lima)
         deg4 = (ZZ((ZZ(k / 2) - 3 * lima) / 2))
         e6p = (e6 ** deg6)
         e4p = (e4 ** deg4)
         monomials[col] = [deg4, deg6]
         eis = e6p * e4p
         for i in range(1, lv + 1):
             m[i - 1, col] = eis.coefficients()[i - 1]
         lima = lima - 2
         col = col + 1
     if (col != d):
         raise ArithmeticError("bug dimension")
     # return [m,v]
     if self._verbose > 0:
         wmf_logger.debug("m={0}".format(m, type(m)))
         wmf_logger.debug("v={0}".format(v, type(v)))
     try:
         X = m.solve_right(v)
     except:
         return ""
     self._as_polynomial_in_E4_and_E6 = [poldeg, monomials, X]
     return [poldeg, monomials, X]
Example #19
0
def modular_univariate(f, N, m, t, X, early_return=True):
    """
    Computes small modular roots of a univariate polynomial.
    More information: May A., "New RSA Vulnerabilities Using Lattice Reduction Methods (Section 3.2)"
    :param f: the polynomial
    :param N: the modulus
    :param m: the amount of g shifts to use
    :param t: the amount of h shifts to use
    :param X: an approximate bound on the roots
    :param early_return: try to return as early as possible (default: true)
    :return: a generator generating small roots of the polynomial
    """
    f = f.monic().change_ring(ZZ)
    x = f.parent().gen()
    d = f.degree()

    B = Matrix(ZZ, d * m + t)
    row = 0
    logging.debug("Generating g shifts...")
    for i in range(m):
        for j in range(d):
            g = x**j * N**(m - i) * f**i
            for col in range(row + 1):
                B[row, col] = g(x * X)[col]

            row += 1

    logging.debug("Generating h shifts...")
    for i in range(t):
        h = x**i * f**m
        h = h(x * X)
        for col in range(row + 1):
            B[row, col] = h[col]

        row += 1

    logging.debug("Executing the LLL algorithm...")
    B = B.LLL()

    logging.debug("Reconstructing polynomials...")
    for row in range(B.nrows()):
        new_polynomial = 0
        for col in range(B.ncols()):
            new_polynomial += B[row, col] * x**col

        if new_polynomial.is_constant():
            continue

        new_polynomial = new_polynomial(x / X).change_ring(ZZ)
        for x0, _ in new_polynomial.roots():
            yield int(x0)

        if early_return:
            # Assuming that the first "good" polynomial in the lattice doesn't provide roots, we return.
            return
Example #20
0
def tu_decomposition(s, v, verbose=False):
    """Using the knowledge that v is a subspace of Z_s of dimension n, a
    TU-decomposition (as defined in [Perrin17]) of s is performed and T
    and U are returned.

    """
    N = int(log(len(s), 2))
    # building B
    basis = extract_basis(v[0], N)
    t = len(basis)
    basis = complete_basis(basis, N)
    B = Matrix(GF(2), N, N, [tobin(x, N) for x in reversed(basis)])
    if verbose:
        print "B=  (rank={})\n{}".format(B.rank(), B.str())
    # building A
    basis = complete_basis(extract_basis(v[1], N), N)
    A = Matrix(GF(2), N, N, [tobin(x, N) for x in reversed(basis)])
    if verbose:
        print "A=  (rank={})\n{}".format(A.rank(), A.str())
    # building linear equivalent s_prime
    s_prime = [
        apply_bin_mat(s[apply_bin_mat(x, A.inverse())], B)
        for x in xrange(0, 2**N)
    ]
    # TU decomposition of s'
    T, U = get_tu_open(s_prime, t)
    if verbose:
        print "T=["
        for i in xrange(0, 2**(N - t)):
            print "  {} {}".format(T[i], is_permutation(T[i]))
        print "]\nU=["
        for i in xrange(0, 2**t):
            print "  {} {}".format(U[i], is_permutation(U[i]))
        print "]"
    return T, U
Example #21
0
def convert_magma_matrix_to_sage(m, K):
    try:
        return Matrix(K, m.sage());
    except:
        pass
    from re import sub
    text = str(m)
    text = sub('\[\s+', '[', text)
    text = sub('\s+', ' ', text)
    text = '['+text.replace(' ',', ').replace('\n',', ')+']'
    return Matrix(K, sage_eval(text, locals={'r': K.gens()}))
Example #22
0
def involution_matrix(Pa, Pb, tol=1e-4):
    r"""Returns the transformation matrix `R` corresponding to the anti-holomorphic
    involution on the periods of the Riemann surface.

    Given an aritrary `2g x g` period matrix `[Pa, Pb]^T` of a genus `g`
    Riemann surface `X` the action of the anti-holomorphic involution on `X` of
    these periods is given by left-multiplication by a `2g x 2g` matrix `R`.
    That is, .. math::

        [\tau P_a^T, \tau P_b^T]^T = R [P_a^T, P_b^T]^T

    Parameters
    ----------
    Pa : complex matrix
    Pb : complex matrix
        The a- and b-periods, respectively, of a genus `g` Riemann surface.
    tol : double
        (Default: 1e-4) Tolerance used to veryify integrality of transformation
        matrix. Dependent on precision of period matrices.

    Returns
    -------
    R : complex matrix
        The anti-holomorphic involution matrix.

    Todo
    ----
    For numerical stability, replace matrix inversion with linear system
    solves.
    """
    g, g = Pa.dimensions()
    R_RDF = Matrix(RDF, 2 * g, 2 * g)

    Ig = identity_matrix(RDF, g)
    M = Im(Pb.T) * Re(Pa) - Im(Pa.T) * Re(Pb)
    Minv = M.inverse()

    R_RDF[:g, :g] = (2 * Re(Pb) * Minv * Im(Pa.T) + Ig).T
    R_RDF[:g, g:] = -2 * Re(Pa) * Minv * Im(Pa.T)
    R_RDF[g:, :g] = 2 * Re(Pb) * Minv * Im(Pb.T)
    R_RDF[g:, g:] = -(2 * Re(Pb) * Minv * Im(Pa.T) + Ig)
    R = R_RDF.round().change_ring(ZZ)

    # sanity check: make sure that R_RDF is close to integral. we perform this
    # test here since the matrix returned should be over ZZ
    error = (R_RDF.round() - R_RDF).norm()
    if error > tol:
        raise ValueError(
            "The anti-holomorphic involution matrix is not "
            "integral. Try increasing the precision of the input "
            "period matrices."
        )
    return R
Example #23
0
def get_ccz_equivalent_permutation(l, v0, v1, verbose=False):
    N = int(log(len(l), 2))
    mask = sum(int(1 << i) for i in xrange(0, N))
    L = v0 + v1
    L = Matrix(GF(2), 2 * N, 2 * N, [tobin(x, 2 * N) for x in L]).transpose()
    if verbose:
        print "\n\nrank={}\n{}".format(L.rank(), L.str())
    new_l = [[0 for b in xrange(0, 2**N)] for a in xrange(0, 2**N)]
    for a, b in itertools.product(xrange(0, 2**N), xrange(0, 2**N)):
        v = apply_bin_mat((a << N) | b, L)
        a_prime, b_prime = v >> N, v & mask
        new_l[a][b] = l[a_prime][b_prime]
    return invert_lat(new_l)
Example #24
0
def involution_matrix(Pa, Pb, tol=1e-4):
    r"""Returns the transformation matrix `R` corresponding to the anti-holomorphic
    involution on the periods of the Riemann surface.

    Given an aritrary `2g x g` period matrix `[Pa, Pb]^T` of a genus `g`
    Riemann surface `X` the action of the anti-holomorphic involution on `X` of
    these periods is given by left-multiplication by a `2g x 2g` matrix `R`.
    That is, .. math::

        [\tau P_a^T, \tau P_b^T]^T = R [P_a^T, P_b^T]^T

    Parameters
    ----------
    Pa : complex matrix
    Pb : complex matrix
        The a- and b-periods, respectively, of a genus `g` Riemann surface.
    tol : double
        (Default: 1e-4) Tolerance used to veryify integrality of transformation
        matrix. Dependent on precision of period matrices.

    Returns
    -------
    R : complex matrix
        The anti-holomorphic involution matrix.

    Todo
    ----
    For numerical stability, replace matrix inversion with linear system
    solves.
    """
    g,g = Pa.dimensions()
    R_RDF = Matrix(RDF, 2*g, 2*g)

    Ig = identity_matrix(RDF, g)
    M = Im(Pb.T)*Re(Pa) - Im(Pa.T)*Re(Pb)
    Minv = M.inverse()

    R_RDF[:g,:g] = (2*Re(Pb)*Minv*Im(Pa.T) + Ig).T
    R_RDF[:g,g:] = -2*Re(Pa)*Minv*Im(Pa.T)
    R_RDF[g:,:g] = 2*Re(Pb)*Minv*Im(Pb.T)
    R_RDF[g:,g:] = -(2*Re(Pb)*Minv*Im(Pa.T) + Ig)
    R = R_RDF.round().change_ring(ZZ)

    # sanity check: make sure that R_RDF is close to integral. we perform this
    # test here since the matrix returned should be over ZZ
    error = (R_RDF.round() - R_RDF).norm()
    if error > tol:
        raise ValueError("The anti-holomorphic involution matrix is not "
                         "integral. Try increasing the precision of the input "
                         "period matrices.")
    return R
Example #25
0
def attack(p, x1, y1, x2, y2):
    """
    Recovers the a and b parameters from an elliptic curve when two points are known.
    :param p: the prime of the curve base ring
    :param x1: the x coordinate of the first point
    :param y1: the y coordinate of the first point
    :param x2: the x coordinate of the second point
    :param y2: the y coordinate of the second point
    :return: a tuple containing the a and b parameters of the elliptic curve
    """
    m = Matrix(GF(p), [[x1, 1], [x2, 1]])
    v = vector(GF(p), [y1**2 - x1**3, y2**2 - x2**3])
    a, b = m.solve_right(v)
    return int(a), int(b)
Example #26
0
    def __init__(self, parent, matrix, is_zero=lambda p: False, relations=[]):
        ## Checking the parent parameter
        if (parent.is_field()):
            parent = parent.base()
        if (not (isUniPolynomial(parent) or isMPolynomial(parent))):
            raise TypeError(
                "The parent for this algorithm must be a polynomial ring.\n\t Got: %s"
                % parent)

        ## Checking the matrix input
        matrix = Matrix(parent, matrix)
        super().__init__(parent, matrix, vector(parent,
                                                matrix.ncols() * [0]), is_zero,
                         relations)
    def _get_system_product(self, other, ncols, inhom=False):
        r'''
            Method to compute an ansatz system for the addition of a fixed size.

            This method computes an ansatz system for the addition of two solutions to
            ``self`` and ``other`` respectively. Namely, if `f(x)` is a solution to 
            ``self`` and `g(x)` is a solution to ``other``, then we can consider the module:

            .. MATH::

                M = \langle \partial^i(f)\partial^j(g)\ :\ i,j\in \mathbb{n}\rangle.

            which (since `f(x)` and `g(x)` are annihilated by ``self`` and ``other``) is a finitely
            generated module. Hence, the module generated by `f(x)+g(x)` is also finitely generated.
            This method creates an ansatz system in the module `M` for computing the linear
            relation between `h(x) = f(x)g(x)` and its derivatives.

            INPUT:
                * ``other``: the operator for the second operand.
                * ``ncols``: size of the desired system (in number of columns)
                * ``inhom``: if ``True``, the method return the ansazt matrix system together
                  with a vector representing the inhomogeneous term of the system.

            OUTPUT:

            The ansazt system for compute a linear relation with `\partial^{ncols}(f(x)g(x))` 
            and its previous derivatives within the module `M`.
        '''
        from ajpastor.misc.matrix import vector_derivative as der

        ## Controlling the input ncols
        if (ncols < 0):
            raise ValueError("The number of columns must be a natural number")

        d_matrix = self._get_derivation_matrix_product(other)

        ## Base case: 0 column, only inhomogeneous term
        if (ncols == 0):
            v = self._get_vector_product(other)
            system = Matrix(d_matrix.parent().base(), [[]])
        else:  # General case, we build the next column
            aux_s, new_v = self._get_system_product(other, ncols - 1, True)
            system = Matrix(aux_s.columns() + [new_v]).transpose()
            v = der(d_matrix, new_v, self.derivate())

        if (inhom):
            return self._post_proc(system), v
        else:
            return self._post_proc(system)
Example #28
0
def incidence_matrix_from_multiplicities(n, mu):
    m = sum(mu.values())
    A = Matrix(n, m)
    j = 0
    for support, multiplicity in mu.items():
        if multiplicity < 0:
            raise ValueError('invalid multiplicity')
        if any(x not in range(n) for x in support):
            raise ValueError('invalid support')

        col = [1 if i in support else 0 for i in range(n)]
        for _ in range(multiplicity):
            A.set_column(j, col)
            j += 1
    return A
Example #29
0
 def _save(self, file, var_name='L'):
     from sage.all import Matrix
     HH = self.hyperplane_arrangement.parent()
     A = Matrix(
         map(lambda H: H.coefficients(),
             self.hyperplane_arrangement.hyperplanes())).rows()
     CR = tuple(map(lambda T: tuple(T), self.poset.cover_relations()))
     FL = self.flat_labels
     FL_tup = tuple([tuple([x, list(FL[x])]) for x in FL.keys()])
     del FL
     dict_builder = "FL = {x[0] : Set(x[1]) for x in FL_tup}\n"
     with open(file, "w") as F:
         F.write(
             "from sage.all import HyperplaneArrangements, QQ, Poset, Set\n"
         )
         F.write("import hypigu as hi\n")
         F.write("H = HyperplaneArrangements(QQ, {0})\n".format(
             HH.variable_names()))
         del HH
         F.write("A = H({0})\n".format(A).replace("), ", "),\n"))
         del A
         F.write("CR = {0}\n".format(CR).replace("), ", "),\n"))
         del CR
         F.write(
             "P = Poset([range({0}), CR], cover_relations=True)\n".format(
                 len(self.poset._elements)))
         F.write("FL_tup = {0}\n".format(FL_tup).replace("), ", "),\n"))
         F.write(dict_builder)
         F.write("del FL_tup\n")
         F.write(
             "{0} = hi.LatticeOfFlats(A, poset=P, flat_labels=FL)\n".format(
                 var_name))
         F.write("del H, A, CR, P, FL\n")
         F.write("print('Loaded a lattice of flats. Variable name: {0}')".
                 format(var_name))
Example #30
0
    def FZ_matrix_pushforward_basis(self,r):
        """
        Return the matrix of Faber-Zagier relations, using the "pushforward" basis, NOT the kappa monomial basis that the rest of the code uses.

        :param r: The codimension.
        :rtype: :class:`Matrix`

        The columns correspond to the basis elements of the Strata algebra, and each row is a relation.
        This matrix should be the same as Pixton's original ``tautrel.sage`` program after permuting columns. ::
        
            sage: from strataalgebra import *
            sage: s = StrataAlgebra(QQ,0,(1,2,3,4))
            sage: s.FZ_matrix_pushforward_basis(1)
            [  -9/4   -9/4   -9/4 -153/4   45/4   45/4   45/4   45/4]
            [   3/2    3/2    3/2  -33/2  -21/2   15/2   15/2   15/2]
            [   3/2    3/2    3/2  -33/2   15/2  -21/2   15/2   15/2]
            [   3/2    3/2    3/2  -33/2   15/2   15/2  -21/2   15/2]
            [   3/2    3/2    3/2  -33/2   15/2   15/2   15/2  -21/2]
            [ -15/4   21/4   21/4  -15/4  -21/4  -21/4   15/4   15/4]
            [  21/4  -15/4   21/4  -15/4  -21/4   15/4  -21/4   15/4]
            [  21/4   21/4  -15/4  -15/4  -21/4   15/4   15/4  -21/4]
            [  21/4   21/4  -15/4  -15/4   15/4  -21/4  -21/4   15/4]
            [  21/4  -15/4   21/4  -15/4   15/4  -21/4   15/4  -21/4]
            [ -15/4   21/4   21/4  -15/4   15/4   15/4  -21/4  -21/4]
            [ -15/4  -15/4  -15/4  -15/4   15/4   15/4   15/4   15/4]
        
        .. SEEALSO ::

            :meth:`~strataalgebra.StrataAlgebra.FZ_matrix`
        """
        return Matrix(self.list_all_FZ(r))
Example #31
0
def _lof_from_matroid(A=None, matroid=None):
    from sage.all import Set, Matrix, Matroid, Poset
    from functools import reduce
    if A != None:
        rows = list(map(lambda H: H.coefficients()[1:], A.hyperplanes()))
        mat = Matrix(A.base_ring(), rows).transpose()
        M = Matroid(mat)
        n = len(A)
        lbl_map = lambda S: S
    else:
        M = matroid.simplify()
        n = len(M.groundset())
        grd_list = list(M.groundset())
        l_map = {x: grd_list.index(x) for x in grd_list}
        lbl_map = lambda S: frozenset([l_map[x] for x in S])

    L = M.lattice_of_flats()
    rank_r = lambda L, r: list(
        map(lbl_map, filter(lambda x: L.rank(x) == r, L._elements)))
    rank_1 = [frozenset([k]) for k in range(n)]
    ranks = reduce(lambda x, y: x + y,
                   [rank_r(L, r)
                    for r in range(2,
                                   L.rank() + 1)], [L.bottom()] + rank_1)
    P = Poset(L,
              element_labels={x: ranks.index(lbl_map(x))
                              for x in L._elements})
    adj_set = lambda S: Set([x + 1 for x in S])
    label_dict = {i: adj_set(ranks[i]) for i in range(len(L))}
    if A != None:
        hyp_dict = {i: A[list(ranks[i])[0]] for i in range(1, n + 1)}
    else:
        hyp_dict = None
    return [P, label_dict, hyp_dict]
Example #32
0
def reduced_FZ_param_list(G,v,g,d,n):
  X = StrataGraph.Xvar
  params = FZ_param_list(n,tuple(range(1,d+1)))
  graph_params = []
  M = Matrix(StrataGraph.R,2,d+1)
  M[0,0] = -1
  for i in range(1,d+1):
    M[0,i] = i
  for p in params:
    G_copy = StrataGraph(G.M)
    M[1,0] = -g-1
    for j in p[0]:
      M[1,0] += X**j
    for i in range(1,d+1):
      M[1,i] = 1 + p[1][i-1][1][0]*X
    G_p = StrataGraph(M)
    G_copy.replace_vertex_with_graph(v,G_p)
    graph_params.append([p,G_copy])
  params_reduced = []
  graphs_seen = []
  for x in graph_params:
    x[1].compute_invariant()
    good = True
    for GG in graphs_seen:
      if graph_isomorphic(x[1],GG):
        good = False
        break
    if good:
      graphs_seen.append(x[1])
      params_reduced.append(x[0])
  return params_reduced  
Example #33
0
    def FZ_matrix(self,r):
        """
        Return the matrix of Faber-Zagier relations.

        :param r: The codimension.
        :rtype: :class:`Matrix`

        The columns correspond to the basis elements of the Strata algebra, and each row is a relation.

        Notice that this matrix considers the kappa classes to be in the monomial basis. Thus, is different than the
        output of Pixton's original ``taurel.sage`` program. ::
        
            sage: from strataalgebra import *
            sage: s = StrataAlgebra(QQ,0,(1,2,3,4))
            sage: s.FZ_matrix(1)
            [  -9/4   -9/4   -9/4 -153/4   45/4   45/4   45/4   45/4]
            [   3/2    3/2    3/2  -33/2  -21/2   15/2   15/2   15/2]
            [   3/2    3/2    3/2  -33/2   15/2  -21/2   15/2   15/2]
            [   3/2    3/2    3/2  -33/2   15/2   15/2  -21/2   15/2]
            [   3/2    3/2    3/2  -33/2   15/2   15/2   15/2  -21/2]
            [ -15/4   21/4   21/4  -15/4  -21/4  -21/4   15/4   15/4]
            [  21/4  -15/4   21/4  -15/4  -21/4   15/4  -21/4   15/4]
            [  21/4   21/4  -15/4  -15/4  -21/4   15/4   15/4  -21/4]
            [  21/4   21/4  -15/4  -15/4   15/4  -21/4  -21/4   15/4]
            [  21/4  -15/4   21/4  -15/4   15/4  -21/4   15/4  -21/4]
            [ -15/4   21/4   21/4  -15/4   15/4   15/4  -21/4  -21/4]
            [ -15/4  -15/4  -15/4  -15/4   15/4   15/4   15/4   15/4]

        .. SEEALSO ::

            :meth:`~strataalgebra.StrataAlgebra.FZ_matrix_pushforward_basis`, :meth:`~strataalgebra.StrataAlgebraElement.in_kernel`


        """
        return Matrix(self.list_all_FZ(r))*self._convert_kappa_basis(r)
Example #34
0
def build_matrix(P, M, c=1000):
    factors_M = factor(M)
    rows = []

    # add logarithms
    for p in P:
        row = []
        for q, e in factors_M:
            row.extend(Zmod(q**e)(p).generalised_log()
                       )  # generalised_log() uses unit_gens() generators
        row = [c * x
               for x in row]  # multiply logs by a large constant to help LLL
        rows.append(row)

    height = len(rows)
    width = len(rows[0])

    # add unit matrix
    for i, row in enumerate(rows):
        row.extend([1 if j == i else 0 for j in range(0, height)])

    # add group orders
    generators_M = [g for q, e in factors_M for g in Zmod(q**e).unit_gens()]
    for i, g in enumerate(generators_M):
        rows.append([
            g.multiplicative_order() * c if j == i else 0
            for j in range(0, width + height)
        ])

    return Matrix(rows)
Example #35
0
def random_matrix_eigenvalues(F,n):
    r"""
    Give a random matrix together with its eigenvalues.
    """
    l=list()
    M = MatrixSpace(F,n)
    U = Matrix(F,n)
    D = Matrix(F,n)
    for i in xrange(n):
        x = F.random_element()
        l.append(x)
        D[i,i]=x
    # now we need a unitary matrix:
    # make a random choice of vectors and use Gram-Schmidt to orthogonolize
    U = random_unitary_matrix(F,n)
    UT = U.transpose().conjugate()
    A = U*D*UT
    l.sort(cmp=my_abscmp)
    return   A,U,l
Example #36
0
def modular_unit_lattice(G,return_ambient=True,ambient_degree_zero=True):
    M=G.modular_symbols()
    period_mapping=integral_period_mapping(M)
    H1QQ=QQ**period_mapping.ncols()
    cusps=G.cusps()
    assert cusps[-1]==Cusp(infinity)
    n=len(cusps)
    D=ZZ**n
    D0=D.submodule_with_basis([D.gen(i)-D.gen(n-1) for i in xrange(n-1)])
    period_images=[M.coordinate_vector(M([c,infinity]))*period_mapping for c in cusps if not c.is_infinity()]
    m=Matrix(period_images).transpose().augment(H1QQ.basis_matrix()).transpose()
    mint=(m*m.denominator()).change_ring(ZZ)
    kernel=mint.kernel()
    F0=kernel.basis_matrix().change_ring(ZZ).transpose()[:n-1].transpose()
    F0inD0=D0.submodule([D0.linear_combination_of_basis(i) for i in F0])
    if return_ambient and ambient_degree_zero:
        return F0inD0,D0
    if return_ambient:
        return F0inD0,D
    return F0inD0
Example #37
0
def get_T1(K, S, unit_first=True, verbose=False):
# Sx is a list of generators of K(S,2) with the unit first or last, assuming h(K)=1
   u = -1 if K==QQ else  K(K.unit_group().torsion_generator())
   from KSp import IdealGenerator
   Sx = [IdealGenerator(P) for P in S]
   if unit_first:
      Sx = [u] + Sx
   else:
      Sx = Sx + [u]
   r = len(Sx)
   N = prod(S,1)
# Initialize T1 to be empty and A to be a matric with 0 rows and r=#Sx columns
   T1 = []
   A = Matrix(GF(2),0,len(Sx))
   primes = primes_iter(K,1)
   p = primes.next()
# Repeat the following until A has full rank: take the next prime p
# from the iterator, skip if it divides N (=product over S), form the
# vector v, and keep p and append v to the bottom of A if it increases
# the rank:
   while A.rank() < r:
      p = primes.next()
      while p.divides(N):
         p = primes.next()
      if verbose:
         print("A={} with {} rows and {} cols".format(A,A.nrows(),A.ncols()))
      v = vector(alphalist(p, Sx))
      if verbose:
         print("v={}".format(v))
      A1 = A.stack(v)
      if A1.rank() > A.rank():
         A = A1
         T1 = T1 + [p]
         if verbose:
            print("new A={} with {} rows and {} cols".format(A,A.nrows(),A.ncols()))
            print("T1 increases to {}".format(T1))

   # the last thing returned is a "decoder" which returns the
   # discriminant Delta given the splitting beavious at the primes in
   # T1:
   B = A.inverse()
   def decoder(alphalist):
      e = list(B*vector(alphalist))
      return prod([D**ZZ(ei) for D,ei in zip(Sx,e)], 1)

   return T1, A, decoder
def NonCubicSet(K,S, verbose=False):
    u = -1 if K==QQ else  K(K.unit_group().torsion_generator())
    from KSp import IdealGenerator
    Sx = [u] + [IdealGenerator(P) for P in S]
    r = len(Sx)
    d123 = r + binomial(r,2) + binomial(r,3)
    vecP = vec123(K,Sx)
    A = Matrix(GF(2),0,d123)
    N = prod(S,1)

    primes = primes_iter(K,None)
    T = []
    while A.rank() < d123:
        p = primes.next()
        while p.divides(N):
            p = primes.next()
        v = vecP(p)
        if verbose:
            print("v={}".format(v))
        A1 = A.stack(vector(v))
        if A1.rank() > A.rank():
            A = A1
            T.append(p)
            if verbose:
                print("new A={} with {} rows and {} cols".format(A,A.nrows(),A.ncols()))
                print("T increases to {}".format(T))
    return T
Example #39
0
def solve_vectors(n,d, verbose=False):
   def w(i,j):
      return 0 if i==j else (d[Set([i,j])] + d[Set([i])] + d[Set([j])])
   W = Matrix(GF(2),[[w(i,j) for j in range(n)] for i in range(n)])
   v = vector(GF(2),[d[Set([i])] for i in range(n)])
   if verbose:
      print("W = {}".format(W))
      print("v = {}".format(v))
   if W==0:
      if v==0:
         return 0
      else:
         return v, v

   Wrows = [wr for wr in W.rows() if wr]
   if v==0:
      x = Wrows[0]
      y = next(wr for wr in Wrows[1:] if wr!=x)
      return x, y

   z = W.row(v.support()[0])
   y = next(wr for wr in Wrows if wr!=z)
   return y+z, y
Example #40
0
class StrataGraph(object):
  R = PolynomialRing(ZZ,"X",1,order='lex')
  Xvar = R.gen()
  
  def __init__(self,M=None,genus_list=None):
    #print genus_list
    if M:
      self.M = copy(M)
    elif genus_list:
      self.M = Matrix(StrataGraph.R,len(genus_list)+1,1,[-1]+genus_list)
    else:
      self.M = Matrix(StrataGraph.R,1,1,-1)
      
  def __repr__(self):
    """
    Drew added this.
    """
    name = self.nice_name()
    if name == None:
        return repr(self.nice_matrix())
    else:
        return name

  def num_vertices(self):
    return self.M.nrows() - 1

  def num_edges(self):
    return self.M.ncols() - 1

  def h1(self):
    return self.M.ncols()-self.M.nrows()+1

  def add_vertex(self,g):
    self.M = self.M.stack(Matrix(1,self.M.ncols()))
    self.M[-1,0] = g

  def add_edge(self,i1,i2,marking=0):
    self.M = self.M.augment(Matrix(self.M.nrows(),1))
    self.M[0,-1] = marking
    if i1 > 0:
      self.M[i1,-1] += 1
    if i2 > 0:
      self.M[i2,-1] += 1

  def del_vertex(self,i):
    self.M = self.M[:i].stack(self.M[(i+1):])

  def del_edge(self,i):
    self.M = self.M[0:,:i].augment(self.M[0:,(i+1):])

  def compute_degree_vec(self):
    self.degree_vec = [sum(self.M[i,j][0] for j in range(1,self.M.ncols())) for i in range(1,self.M.nrows())]

  def degree(self,i):
    return self.degree_vec[i-1]

  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)

  def compute_parity_vec_original(self):
    X = StrataGraph.Xvar
    self.parity_vec = [(ZZ(1+self.M[i,0][0]+sum(self.M[i,k][1] for k in range(1,self.M.ncols()))+sum(self.M[i,k][2] for k in range(1,self.M.ncols()))+self.M[i,0].derivative(X).substitute(X=1)) % 2) for i in range(1,self.M.nrows())]
    
  def compute_parity_vec(self):
    X = StrataGraph.Xvar
    self.parity_vec = [(ZZ(1+self.M[i,0][0]+sum(self.M[i,k][1] for k in range(1,self.M.ncols()))+sum(self.M[i,k][2] for k in range(1,self.M.ncols()))+self.last_parity_summand(i)) % 2) for i in range(1,self.M.nrows())]
    
  def last_parity_summand(self,i):
    return sum(( expon[0] * coef for expon, coef in self.M[i,0].dict().items() ))

  def parity(self,i):
    return self.parity_vec[i-1]

  def replace_vertex_with_graph(self,i,G):
    X = StrataGraph.Xvar
    nv = self.num_vertices()
    ne = self.num_edges()
    #i should have degree d, there should be no classes near i, and G should have markings 1,...,d and genus equal to the genus of i
    hedge_list = []
    for k in range(1,self.M.ncols()):
      for j in range(self.M[i,k]):
        hedge_list.append(k)
    self.del_vertex(i)
    for j in range(G.num_edges() - len(hedge_list)):
      self.add_edge(0,0)
    for j in range(G.num_vertices()):
      self.add_vertex(G.M[j+1,0])
    col = ne+1
    for k in range(1,G.M.ncols()):
      if G.M[0,k] > 0:
        mark = ZZ(G.M[0,k])
        for j in range(G.num_vertices()):
          if self.M[nv+j,hedge_list[mark-1]] == 0:
            self.M[nv+j,hedge_list[mark-1]] = G.M[j+1,k]
          elif G.M[j+1,k] != 0:
            a = self.M[nv+j,hedge_list[mark-1]][1]
            b = G.M[j+1,k][1]
            self.M[nv+j,hedge_list[mark-1]] = 2 + max(a,b)*X + min(a,b)*X**2
      else:
        for j in range(G.num_vertices()):
          self.M[nv+j,col] = G.M[j+1,k]
        col += 1

  def compute_invariant(self):
    self.compute_parity_vec()
    self.compute_degree_vec()
    nr,nc = self.M.nrows(),self.M.ncols()
    self.invariant = [[self.M[i,0], [], [], [[] for j in range(1,nr)]] for i in range(1,nr)]
    for k in range(1,nc):
      L = [i for i in range(1,nr) if self.M[i,k] != 0]
      if len(L) == 1:
        if self.M[0,k] != 0:
          self.invariant[L[0]-1][2].append([self.M[0,k],self.M[L[0],k]])
        else:
          self.invariant[L[0]-1][1].append(self.M[L[0],k])
      else:
        self.invariant[L[0]-1][3][L[1]-1].append([self.M[L[0],k],self.M[L[1],k]])
        self.invariant[L[1]-1][3][L[0]-1].append([self.M[L[1],k],self.M[L[0],k]])
    for i in range(1,nr):
      self.invariant[i-1][3] = [term for term in self.invariant[i-1][3] if len(term) > 0]
      for term in self.invariant[i-1][3]:
        term.sort()
      self.invariant[i-1][3].sort()
      self.invariant[i-1][2].sort()
      self.invariant[i-1][1].sort()
    vertex_invariants = [[i,self.invariant[i-1]] for i in range(1,nr)]
    self.invariant.sort()
    vertex_invariants.sort(key=lambda x: x[1])
    self.vertex_groupings = []
    for i in range(nr-1):
      if i == 0 or vertex_invariants[i][1] != vertex_invariants[i-1][1]:
        self.vertex_groupings.append([])
      self.vertex_groupings[-1].append(vertex_invariants[i][0])
    
    #Drew added this
    self.invariant = tupleit(self.invariant)
    self.hash = hash(self.invariant)
    
  def __eq__(self,other):
        """
        Drew added this.
        """
        return graph_isomorphic(self, other)
        
  def __hash__(self):
        """
        Drew added this.
        Note that it returns a value stored when "compute_invariant" is called.
        """
        try:
            return self.hash
        except:
            self.compute_invariant()
            return self.hash
            
        
  def codim(self):
    codim = 0
    for v in range(1, self.num_vertices()+1):
        for expon, coef in self.M[v,0].dict().items():
            codim += expon[0]*coef
        for e in range(1, self.num_edges()+1):
            for expon, coef in self.M[v,e].dict().items():
                if expon[0] > 0:
                    codim += coef
    for e in range(1, self.num_edges()+1):
        if self.M[0,e] == 0:
            codim +=1   
    return codim
    
  def codim_undecorated(self):
    codim = 0
    for e in range(1, self.num_edges()+1):
        if self.M[0,e] == 0:
            codim +=1   
    return codim
    
                    
            
    print "not implemented!!!!!!"
    return 1

        
  def kappa_on_v(self,v):
    """
    Drew added this.
    
    """
    #print "kappa",self.M[v,0].dict()
    
    for ex, coef in self.M[v,0].dict().items():
        if ex[0] != 0:
            yield ex[0], coef
            
                
  def psi_no_loop_on_v(self,v):
    for edge in range(1,self.num_edges()+1):
        if self.M[v,edge][0] == 1:
            psi_expon = self.M[v,edge][1]
            if psi_expon > 0:
                yield edge, psi_expon
                
  def psi_loop_on_v(self,v):
    for edge in range(1,self.num_edges()+1):
        if self.M[v,edge][0] == 2:
            psi_expon1 = self.M[v,edge][1]
            psi_expon2 = self.M[v,edge][2]
            if psi_expon1 > 0:
                yield edge, psi_expon1, psi_expon2
                    
  def moduli_dim_v(self,v):
    """
    Drew added this.
    """
    return 3*self.M[v,0][0]-3 + sum(( self.M[v,j][0] for j in range(1, self.num_edges()+1 ) ))
   
  def num_loops(self):
    count = 0
    for edge in range(1, self.num_edges()+1):
        for v in range(1, self.num_vertices()+1):
            if self.M[v,edge][0] == 2:
                count+=1
                break
                
    return count
    
  def num_undecorated_loops(self):
    count = 0
    for edge in range(1, self.num_edges()+1):
        for v in range(1, self.num_vertices()+1):
            if self.M[v,edge] == 2:
                count+=1
                break
                
    return count

  def num_full_edges(self):
      count = 0
      for edge in range(1, self.num_edges()+1):
          if sum(( self.M[v,edge][0] for v in range(1, self.num_vertices()+1 ))) == 2:
              count += 1
      return count
    
  def forget_kappas(self):
    M = copy(self.M)
    for v in range(1, self.num_vertices()+1):
        M[v,0] = M[v,0][0]
    return StrataGraph(M)
    
  def forget_decorations(self):
    M = Matrix(StrataGraph.R,[[self.M[r,c][0] for c in range(self.M.ncols())] for r in range(self.M.nrows())] )
    Gnew = StrataGraph(M)
    #Gnew.compute_invariant()
    return Gnew
    
  def is_loop(self,edge):
    for v in range(1, self.num_vertices()+1):
      if self.M[v,edge][0] == 2:
        return True
      if self.M[v,edge][0] == 1:
        return False
        
    raise Exception("Unexpected!")

  ps_name = "ps"
  ps2_name = "ps_"

  def nice_matrix(self):
      Mnice = Matrix(SR, self.M.nrows(), self.M.ncols())
      for edge in range(1, self.num_edges()+1):
          Mnice[0,edge] = self.M[0,edge]
      for v in range(1, self.num_vertices()+1):
          kappas = 1
          for expon, coef in self.M[v,0].dict().items():
              if expon[0]==0:
                  Mnice[v,0] += coef
              else:
                  kappas *= var("ka{0}".format(expon[0]))**coef
          if kappas != 1:
              Mnice[v,0] += kappas

          for edge in range(1, self.num_edges()+1):
              psis = 1
              for expon, coef in self.M[v,edge].dict().items():
                  if expon[0]==0:
                      Mnice[v,edge] += coef
                  elif expon[0]==1:
                      psis *= var(StrataGraph.ps_name)**coef
                  elif expon[0]==2:
                      psis *= var(StrataGraph.ps2_name)**coef
              if psis != 1:
                  Mnice[v,edge] += psis
      return Mnice

  @staticmethod
  def from_nice_matrix(lists):
      Mx = Matrix(StrataGraph.R, len(lists), len(lists[0]))
      Mx[0,0]=-1
      Mx[0,:] = Matrix([lists[0]])
      for v in range(1, len(lists)):
          if lists[v][0] in ZZ:
              Mx[v,0]=lists[v][0]
              continue
          if lists[v][0].operator() == sage.symbolic.operators.add_vararg:
              operands = lists[v][0].operands()
              if len(operands) != 2:
                  raise Exception("Input error!")
              genus = operands[1] #the genus
              kappas = operands[0]
          else:
              kappas = lists[v][0]
              genus = 0


          if kappas.operator() == sage.symbolic.operators.mul_vararg:
              for operand in kappas.operands():
                  Mx[v,0] += StrataGraph._kappaSR_monom_to_X(operand)
              Mx[v,0] += genus
          else:
              Mx[v,0] = StrataGraph._kappaSR_monom_to_X(kappas) + genus

      X = StrataGraph.Xvar
      for v in range(1, len(lists)):
          for edge in range(1, len(lists[0])):
              if lists[v][edge] in ZZ:
                  Mx[v,edge] = lists[v][edge]
              else:
                  for operand in lists[v][edge].operands():
                      if operand in ZZ:
                          Mx[v,edge] += operand
                      elif operand.operator() is None:
                          #it is a ps or ps2
                          Mx[v,edge] += X
                      elif operand.operator() == operator.pow:
                          #it is ps^n or ps2^n
                          Mx[v,edge] += X * operand.operands()[1]
                      elif operand.operator() == sage.symbolic.operators.mul_vararg:
                          #it is a ps^n*ps2^m
                          op1,op2 = operand.operands()
                          if op1.operator() is None:
                              exp1 = 1
                          else:
                              exp1 = op1.operand()[1]
                          if op2.operator() == None:
                              exp2 = 1
                          else:
                              exp2 = op2.operand()[1]

                          if exp1 >= exp2:
                              Mx[v,edge] += exp1*X + exp2*X**2
                          else:
                              Mx[v,edge] += exp1*X**2 + exp2*X
      return StrataGraph(Mx)





  @staticmethod
  def _kappaSR_monom_to_X(expr):
      X = StrataGraph.Xvar
      if expr in ZZ:
          return expr
      elif expr.operator() == None:
          ka_subscript = Integer(str(expr)[2:])
          return  X ** ka_subscript
      elif expr.operator() == operator.pow:
          ops = expr.operands()
          expon = ops[1]
          ka = ops[0]
          ka_subscript = Integer(str(ka)[2:])
          return  expon * X ** ka_subscript

  def nice_name(self):
      """
      :return:
      """
      if self.num_vertices() == 1:
          num_loops = self.num_loops()
          if num_loops >1:
              return None
          elif num_loops == 1:
              if self.codim() == 1:
                  return "D_irr"
              else:
                  return None
          #else, there are no loops
          var_strs = []
          for expon, coef in self.M[1,0].dict().items():
              if expon[0] == 0 or coef == 0:
                  continue
              if coef == 1:
                  var_strs.append("ka{0}".format(expon[0]))
              else:
                  var_strs.append("ka{0}^{1}".format(expon[0],coef))
          for he in range(1,self.num_edges()+1): #should only be half edges now
              if self.M[1,he][1] > 1:
                  var_strs.append("ps{0}^{1}".format(self.M[0,he],self.M[1,he][1]))
              elif self.M[1,he][1] ==  1:
                  var_strs.append("ps{0}".format(self.M[0,he]))
          if len(var_strs) > 0:
              return "*".join(var_strs)
          else:
              return "one"
      if self.num_vertices() == 2 and self.num_full_edges() == 1 and self.codim() == 1:
          #it is a boundary divisor
          v1_marks = [self.M[0,j] for j in range(1, self.num_edges()+1) if self.M[1,j] == 1 and self.M[0,j] != 0]
          v1_marks.sort()
          v2_marks = [self.M[0,j] for j in range(1, self.num_edges()+1) if self.M[2,j] == 1 and self.M[0,j] != 0]
          v2_marks.sort()
          if v1_marks < v2_marks:
              g = self.M[1,0]
          elif v1_marks == v2_marks:
              if self.M[1,0] <= self.M[2,0]:
                  g = self.M[1,0]
              else:
                  g = self.M[2,0]
          else:
              g = self.M[2,0]
              #temp = v1_marks
              v1_marks = v2_marks
              #v2_marks = temp
          if len(v1_marks) == 0:
              return "Dg{0}".format(g)
          else:
              return "Dg{0}m".format(g) + "_".join([str(m) for m in v1_marks])
Example #41
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 (64s on sage.math, 2011)
            [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]
    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+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:
                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))
                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]
Example #43
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 occured for {0}, {1}".format(FQM.jordan_decomposition().genus_symbol(), e), M, V)
        else:
            d = [V.dimension(), 0]
    if debug > 1: print d
    return d
Example #44
0
def algo64(K, S, BB, T2=None, unit_first = True, verbose=False):
   r = 1+len(S)
   if T2 is None:
      T2 = get_T2(QQ,S, unit_first)
      if verbose:
         print("T2 = {}".format(T2))
   assert len(T2)==r*(r+1)//2

   from KSp import IdealGenerator
   Sx = [IdealGenerator(P) for P in S]
   u = -1 if K==QQ else  K(K.unit_group().torsion_generator())
   Sx = [u] + Sx if unit_first else Sx+[u]
   if verbose:
      print("Basis for K(S,2): {}".format(Sx))

   #BBdict = dict((k,BB(T2[k])) for k in T2)
   ap = BB_trace(BB)
   apdict = dict((k,ap(T2[k])) for k in T2)
   t4 = BB_t4(BB)
   t4dict = dict((k,t4(T2[k])) for k in T2)
   if verbose:
      print("apdict = {}".format(apdict))
      print("t4dict = {}".format(t4dict))

   v = vector(GF(2),[t4dict[Set([i])] for i in range(r)])
   if verbose:
      print("v = {}".format(v))

   def w(i,j):
      if i==j:
         return 0
      else:
         return (t4dict[Set([i,j])] + t4dict[Set([i])] + t4dict[Set([j])])

   # Note that W ignores the first coordinate
   Wd = Matrix(GF(2),[[w(i,j) for j in range(1,r)] for i in range(1,r)])
   vd = vector(v.list()[1:])
   rkWd = Wd.rank()
   if verbose:
      print("W' = \n{} with rank {}".format(Wd,rkWd))
   # Case 1: rank(W)=2
   if rkWd==2:
      # x' and y' are any two distinct nonzero rows of W
      Wrows = [wr for wr in Wd.rows() if wr]
      xd = Wrows[0]
      yd = next(wr for wr in Wrows if wr!=xd)
      zd = xd+yd
      ud = vd - vector(xi*yi for xi,yi in zip(list(xd),list(yd)))
      if verbose:
         print("x' = {}".format(xd))
         print("y' = {}".format(yd))
         print("z' = {}".format(zd))
         print("u' = {}".format(ud))
         print("v' = {}".format(vd))

      u = vector([1]+ud.list())
      v = vector([0]+vd.list())

      if t4dict[Set([0])]==1:
         x = vector([1]+xd.list())
         y = vector([1]+yd.list())
         z = vector([1]+zd.list())
         if verbose:
            print("x = {}".format(x))
            print("y = {}".format(y))
            print("z = {}".format(z))
            print("u = {}".format(u))
            print("v = {}".format(v))
      else:
         raise NotImplementedError("t_4(p_1) case not yet implemented in algo64")

      return [vec_to_disc(Sx,vec) for vec in [u,x,y,z]]

   # W==0
   raise NotImplementedError("rank(W)=0 case not yet implemented in algo64")
Example #45
0
def algo63(K, S, BB, T2=None, unit_first = True, verbose=False):
   r = 1+len(S)
   if T2 is None:
      T2 = get_T2(QQ,S, unit_first)
      if verbose:
         print("T2 = {}".format(T2))
   assert len(T2)==r*(r+1)//2

   from KSp import IdealGenerator
   Sx = [IdealGenerator(P) for P in S]
   u = -1 if K==QQ else  K(K.unit_group().torsion_generator())
   Sx = [u] + Sx if unit_first else Sx+[u]
   if verbose:
      print("Basis for K(S,2): {}".format(Sx))

   BBdict = dict((k,BB(T2[k])) for k in T2)
   ap = BB_trace(BB)
   apdict = dict((k,ap(T2[k])) for k in T2)
   t2 = BB_t2(BB)
   t2dict = dict((k,t2(T2[k])) for k in T2)
   if verbose:
      print("apdict = {}".format(apdict))
      print("t2dict = {}".format(t2dict))

   v = vector(GF(2),[t2dict[Set([i])] for i in range(r)])
   if verbose:
      print("v = {}".format(v))

   def w(i,j):
      if i==j:
         return 0
      else:
         return (t2dict[Set([i,j])] + t2dict[Set([i])] + t2dict[Set([j])])

   W = Matrix(GF(2),[[w(i,j) for j in range(r)] for i in range(r)])
   rkW = W.rank()
   if verbose:
      print("W = \n{} with rank {}".format(W,rkW))
   # Case 1: rank(W)=2
   if rkW==2:
      # x and y are any two distinct nonzero rows of W
      Wrows = [wr for wr in W.rows() if wr]
      x = Wrows[0]
      y = next(wr for wr in Wrows if wr!=x)
      z = x+y
      u = v - vector(xi*yi for xi,yi in zip(list(x),list(y)))
      if verbose:
         print("x = {}".format(x))
         print("y = {}".format(y))
         print("z = {}".format(z))
         print("u = {}".format(u))
   else: # W==0
      # y=0, x=z
      u = v
      y = u-u # zero vector
      if verbose:
         print("u = {}".format(u))
         print("y = {}".format(y))
      t3dict = {}
      for k in T2:
         t = 1 if t2dict[k]==0 else -1
         t3dict[k] = (BBdict[k](t)//8)%2
      s = solve_vectors(r,t3dict)
      if not s:
         z = x = y # = 0
         if verbose:
            print("x and  y are both zero, so class has >4 vertices")
      else:
         x, _ = s
         z = x
         if verbose:
            print("x = {}".format(x))
            print("y = {}".format(y))
            print("z = {}".format(z))

   return [vec_to_disc(Sx,vec) for vec in [u,x,y,z]]
Example #46
0
 def wrapper(*args):
     mat = Matrix(f(*args))
     mat.set_immutable()
     return mat
Example #47
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
    if debug > 1: print "FQM = {0}, TM = {1}, TMM = {2}".format(FQM, TM, TMM)
    if debug > 2:
        debug2=debug
    else:
        debug2=0
    inv = invariants(TMM, use_reduction, proof, 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]:
                vv = v.c_list()
                vv[0] = -vv[0]
                vv = TMM(vv,can_coords=True)
                if inv[0].count(vv) > 0:
                    el.append((inv[0].index(vv),1))
                else:
                    el.append((inv[0].index(-vv),f))
            for i in range(len(el)):
                M[el[i][0],i] = el[i][1]
            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:
                raise RuntimeError("Error occured for {0}".format(FQM.jordan_decomposition().genus_symbol()), M, V)
        else:
            d = [V.dimension(), 0]
    if debug > 1: print d
    return d