예제 #1
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
예제 #2
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
예제 #3
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
예제 #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 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;
예제 #7
0
    def _compute_solution(self):
        
        A = self.echelon_form()
        b = self.transformation_matrix()*self.inhomogeneous().change_ring(self.solution_parent())

        ## We compute the solution equation by equation
        r = A.nrows()-1
        while(all(self.is_zero(el) for el in A[r])):
            r-=1
        ## A.row(r) is the first real equation
        solution = vector(self.solution_parent(), self.A.ncols()*[0])
        syzygy = identity_matrix(self.solution_parent(), self.A.ncols())
        while(r >= 0):
            M = Matrix(self.solution_parent(),[A.row(r)]).transpose()
            hs = HermiteSolver(self.solution_parent(), M, vector([b[r]]), self.__euclidean, self.__xgcd)
            ## We check the condition for having a solution
            g = hs.echelon_form()[0][0]
            quo,rem = self.__euclidean(b[r],g)
            if(rem != 0):
                raise NoSolutionError("There is no solution to equation %s = %s" %(M.transpose(), b[r]))
            
            U = hs.transformation_matrix()
            ## Solution to the particular equation (alpha + S*beta)
            alpha = quo*U.row(0)
            S = Matrix(self.solution_parent(), U.rows()[1:]).transpose()
            ##Update the general values
            solution += syzygy*alpha
            if(S.nrows() == 0): # the solution is unique
                if(self.A*solution != self.b): # the solution is not valid --> no solution to system
                    raise NoSolutionError("There is no solution to the system")
                # otherwise, we found the solution, we break the loop
                syzygy = Matrix(self.solution_parent(), [])
                break
            else:
                syzygy *= S

            ## Update the system
            b -= A*alpha
            A *= S

            # We update the index of the equation
            while(r >= 0 and all(self.is_zero(el) for el in A[r])):
                r-=1

        return self.__reduce_solution(solution, syzygy)
예제 #8
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;
예제 #9
0
    def _get_element_nullspace(self, M):
        ## We take the domain where our elements will lie
        ## conversion->lazy domain->domain
        parent = self.__conversion.base().base()

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

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

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

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

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

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

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

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

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

        return vector(parent, finalSolution)
예제 #10
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])
예제 #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):
    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])
예제 #12
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!")
예제 #13
0
    def _get_element_nullspace(self, M):
        ## We take the Conversion System
        R = self.__conversion

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

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

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

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

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

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

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

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

        return vector(R.base(), realSolution)