예제 #1
0
    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;
예제 #2
0
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
예제 #3
0
    def _compute_echelon(self):
        A = Matrix(self.solution_parent(), self.A.rows()) # we create a copy
        U = identity_matrix(self.solution_parent(), A.nrows())
        ## Step 1: initialize
        r = 0; c = 0 # we are looking from (r,c)
        while(r < A.nrows() and c < A.ncols()):
            ir = self.__find_pivot(A, r,c)
            if(ir != None): # we found a pivot
                if(ir != r): # swapping rows
                    A.swap_rows(r, ir); U.swap_rows(r,ir)
                
                # We reduce the next rows
                for m in range(r+1, A.nrows()):
                    if(A[m][c] != 0):
                        g, t, s = self.__xgcd(A[r][c], A[m][c])
                        p,_ = self.__euclidean(A[r][c],g); q,_ = self.__euclidean(A[m][c],g)

                        Ar = A.row(r); Am = A.row(m)
                        Ur = U.row(r); Um = U.row(m)

                        A.set_row(r,t*Ar + s*Am); U.set_row(r,t*Ur + s*Um)
                        A.set_row(m,p*Am - q*Ar); U.set_row(m,p*Um - q*Ur)
                # We reduce previous rows with the new gcd
                for m in range(r):
                    if(A[m][c] != 0):
                        q,_ = self.__euclidean(A[m][c], A[r][c])
                        Ar = A.row(r); Am = A.row(m)
                        Ur = U.row(r); Um = U.row(m)

                        A.set_row(m, Am - q*Ar); U.set_row(m, Um-q*Ur)
                r += 1
            c+= 1
        return A, U
예제 #4
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
예제 #5
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
예제 #6
0
    def _compute_echelon(self):
        A = Matrix(self.parent(),
                   self.A.rows())  # we create a copy of the matrix
        U = identity_matrix(self.parent(), A.nrows())

        if (self.have_ideal):  # we do simplifications
            A = self.simplify(A)

        ## Step 1: initialize
        r = 0
        c = 0  # we look from the position (r,c)
        while (r < A.nrows() and c < A.ncols()):
            ir = self.__find_pivot(A, r, c)
            A = self.simplify(A)
            U = self.simplify(U)  # we simplify in case relations pop up

            if (ir != None):  # we found a pivot
                # We do the swapping (if needed)
                if (ir != r):
                    A.swap_rows(r, ir)
                    U.swap_rows(r, ir)

                # We do the bareiss step
                Arc = A[r][c]
                Arows = A.rows()
                Urows = U.rows()
                for i in range(r):  # we create zeros on top of the pivot
                    Aic = A[i][c]
                    A.set_row(i, Arc * Arows[i] - Aic * Arows[r])
                    U.set_row(i, Arc * Urows[i] - Aic * Urows[r])

                # We then leave the row r without change
                for i in range(r + 1,
                               A.nrows()):  # we create zeros below the pivot
                    Aic = A[i][c]
                    A.set_row(i, Aic * Arows[r] - Arc * Arows[i])
                    U.set_row(i, Aic * Urows[r] - Arc * Urows[i])

                r += 1
                c += 1

            else:  # no pivot then only advance in column
                c += 1

        # We finish simplifying the gcds in each row
        gcds = [gcd(row) for row in A]
        T = diagonal_matrix([1 / el if el != 0 else 1 for el in gcds])
        A = (T * A).change_ring(self.parent())
        U = T * U
        return A, U
예제 #7
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)
예제 #8
0
def Kernel(A, rank):
    # used the QR factorization to extra dim elements of the kernel
    m = A.nrows();
    n = A.ncols();
    assert rank <= min(n,m)
    Q, R, P = qrp(A.conjugate_transpose(), rank);
    K = Matrix(A.base_ring(), n, n - rank)
    for i in xrange(K.nrows()):
        for j in xrange(K.ncols()):
            K[i, j] = Q[i, n - 1 - j]

    upper = R[rank - 1, rank - 1].abs();
    lower = 0;
    if n > rank and m > rank:
        lower = R[rank, rank].abs();
    return K, upper, lower;
예제 #9
0
    def linearequations(self, W):
        maxlower = self.lower
        # From W = H0( 3*D0 - D ), return H0((g + 1)*\infty - E), where E is effective of degree g s.t. E - (g/2) * \infty + D-(g+1)\infty ~ 0. /!\ Assumes g even /!\
        # E0 = (3g/2+2)\infty = E + D + \infty
        # H0(3D0 - D - E0) = W( - E0) = {w in W : w*x**(3g/2+2) in W} has dim >= 1
        # phi \in W(-E0)  
        # <=>  div phi + 3D0 - D - E0  >= 0
        # <=>  div phi + 3D0 - D - E0 = E effective
        # <=> div phi = E + D - (3g/2 + 1)\infty
        assert self.g % 2 == 0, "the genus must be even for this implementation to work";

        KW, upper, lower = EqnMatrix(W.change_ring(self.Rextraprec), 2 * self.d0 + 1 - self.g);
        assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower));
        maxlower = max(maxlower, lower);

        KWnrows = KW.nrows();
        KWncols = KW.ncols();


        K = KW.stack(Matrix(self.Rextraprec, KWnrows, KWncols));

        for j, (x, y) in enumerate(self.Z):
            xpower =  x**( 3 * self.g/2 + 2);
            for i in range(KWnrows):
                K[i + KWnrows,j] = KW[i,j] * xpower;

        phi, upper, lower = Kernel(K, KWncols - 1);
        # rank >= 1
        if self.verbose:
            print "phi upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower))    
        assert self.threshold_check(1,lower), "upper = %s lower = %s" % (RealField(35)(1), RealField(35)(lower))
        maxlower = max(maxlower, lower);

        # phi*H0( (5g/2+3) \infty) = H0( (4g + 4) \infty - D - E)
        Exps=[]

        for i in range( 5 * self.g / 2 + 4 ):
            Exps.append((i,0))
            if i > self.g:
                Exps.append(( i - self.g - 1, 1))
        
        # H0((4g+4)\infty-D-E)
        H4 = Matrix(self.Rextraprec, self.nZ, 4 * self.g + 7)

        for j, (u,v) in enumerate(Exps):
            for i, (x, y) in enumerate(self.Z):
                H4[i,j] = phi[i, 0] * x**u * y**v
        


        K4, upper, lower = EqnMatrix(H4, 4 * self.g + 7 )
        assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower))
        maxlower = max(maxlower, lower);


        # H0((g+1)\infty - E) = {s in V : s*W c H0((4g+4)OO-D-E)}
        # \dim >= 3 = self.d0 + 1 - 2 * self.g (equality holds for g <= 3)
        if self.g >= 4:
            print "Warning: Riemann--Roch correction term ignored when computing \dim H**0((g+1)\infty - E)!!!"
        K4nrows = K4.nrows();
        K4ncols = K4.ncols();
        while True:
            l = 2;
            Kres = copy(self.KV);
            Kres_old_rows = Kres.nrows();
            Kres = Kres.stack(Matrix(self.R, l * K4nrows, K4ncols));
            
            for m in range(l): # Attempt of IGS of W
                v=random_vector_in_span(W)
                for i in range(K4nrows):
                    for j in range(K4ncols):
                        Kres[i + m*K4nrows + Kres_old_rows, j] = v[j] * K4[i, j]
            
            res, upper, lower = Kernel(Kres, Kres.ncols() - (self.d0 + 1 - 2 * self.g));
            if self.threshold_check(upper, lower):
                maxlower = max(maxlower, lower);
                break;
            
            if self.verbose:
                print "Warning: In MakOutput, failed IGS at step 3, retrying."
                print "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower))
        

        

        # Expressing H0((g+1)\infty-E) in terms of H0(D0)

        S = Matrix(self.R, self.nZ, (self.g + 3) + (self.d0 + 1 - 2 * self.g) )
        for i in range( self.nZ ):
            for j in range( self.g + 3):
                S[i,j] = self.Vout[i,j]

            for j in range( self.d0 + 1 - 2 * self.g):
                S[i ,j + self.g + 3] = res[i,  j ]

        K, upper, lower = Kernel(S, S.ncols() - ( self.d0 + 1 - 2 * self.g)) # S.cols - 3
        assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower))
        maxlower = max(maxlower, lower);
        
        # dropping the last  (self.d0 + 1 - 2 * self.g)  rows
        # K.rows = self.g + 3 
        out = K.matrix_from_rows([i for i in range(self.g + 3)])
        # a basis in H**0( D_0) for H**0((g+1)\infty - E)
        return out, maxlower
예제 #10
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;
예제 #11
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):
        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(ZZ(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])
예제 #12
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])
예제 #13
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!")