Exemplo n.º 1
0
 def integral_cuspidal_subspace(self):
     """
     In certatain cases this might return the integral structure of the cuspidal subspace.
     This code is mainly a way to compute the integral structe faster than sage does now. 
     It returns None if it cannot find the integral subspace. 
     """
     if self.verbose: tm = cputime(); mem = get_memory_usage(); print "Int struct start"
     #This code is the same as the firs part of self.M.integral_structure
     G = set([i for i, _ in self.M._mod2term])
     G = list(G)
     G.sort()
     #if there is a two term relation between two manin symbols we only need one of the two
     #so that's why we only use elements from G instead of all manin symbols.
     if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "G"
     B = self.M._manin_gens_to_basis.matrix_from_rows(list(G)).sparse_matrix()
     if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "B"
     #The collums of B now span self.M.integral_structure as ZZ-module
     B, d = B._clear_denom()
     if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "Clear denom"
     if d == 1:
         #for explanation see d == 2
         assert len(set([B.nonzero_positions_in_row(i)[0] for i in xrange(B.nrows()) if len(B.nonzero_positions_in_row(i)) == 1 and B[i, B.nonzero_positions_in_row(i)[0]] == 1])) == B.ncols(), "B doesn't contain the Identity"
         if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "Check Id"
         ZZbasis = MatrixSpace(QQ, B.ncols(), sparse=True)(1)
         if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "ZZbasis"
     elif d == 2:
         #in this case the matrix B will contain 2*Id as a minor this allows us to compute the hermite normal form of B in a very efficient way. This will give us the integral basis ZZbasis.
         #if it turns out to be nessecarry this can be generalized to the case d%4==2 if we don't mind to only get the right structure localized at 2
         assert len(set([B.nonzero_positions_in_row(i)[0] for i in xrange(B.nrows()) if len(B.nonzero_positions_in_row(i)) == 1 and B[i, B.nonzero_positions_in_row(i)[0]] == 2])) == B.ncols(), "B doesn't contain 2*Identity"    
         if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "Check 2*Id"
         E = matrix_modp(B,sparse=True)
         if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "matmodp"
         E = E.echelon_form()
         if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "echelon"
         ZZbasis = MatrixSpace(QQ, B.ncols(), sparse=True)(1)
         for (pivot_row, pivot_col) in zip(E.pivot_rows(), E.pivots()):
             for j in E.nonzero_positions_in_row(pivot_row):
                 ZZbasis[pivot_col, j] = QQ(1) / 2 
         if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "ZZbasis"
     else:
         return None
     #now we compute the integral kernel of the boundary map with respect to the integral basis. This will give us the integral cuspidal submodule.                 
     boundary_matrix = self.M.boundary_map().matrix()
     if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "Boundary matrix"
     ZZboundary_matrix=(ZZbasis*boundary_matrix).change_ring(ZZ)
     if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "ZZBoundary matrix"
     left_kernel_matrix=ZZboundary_matrix.transpose().dense_matrix()._right_kernel_matrix(algorithm='pari')
     if type(left_kernel_matrix)==tuple:
         left_kernel_matrix=left_kernel_matrix[1]
     if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "kernel matrix"
     ZZcuspidal_basis=left_kernel_matrix*ZZbasis
     if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "ZZkernel matrix"
     assert ZZcuspidal_basis.change_ring(QQ).echelon_form()==self.S.basis_matrix() , "the calculated integral basis does not span the right QQ vector space" # a little sanity check. This shows that the colums of ZZcuspidal_basis really span the right QQ vectorspace
     if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "check"
     #finally create the sub-module, we delibarately do this as a QQ vector space with custom basis, because this is faster then dooing the calculations over ZZ since sage will then use a slow hermite normal form algorithm.
     ambient_module=VectorSpace(QQ,ZZcuspidal_basis.ncols())
     int_struct = ambient_module.submodule_with_basis(ZZcuspidal_basis.rows())
     if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "finnished"
     return int_struct
Exemplo n.º 2
0
 def integral_cuspidal_subspace(self):
     """
     In certatain cases this might return the integral structure of the cuspidal subspace.
     This code is mainly a way to compute the integral structe faster than sage does now. 
     It returns None if it cannot find the integral subspace. 
     """
     if self.verbose: tm = cputime(); mem = get_memory_usage(); print("Int struct start")
     #This code is the same as the firs part of self.M.integral_structure
     G = set([i for i, _ in self.M._mod2term])
     G = list(G)
     G.sort()
     #if there is a two term relation between two manin symbols we only need one of the two
     #so that's why we only use elements from G instead of all manin symbols.
     if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "G")
     B = self.M._manin_gens_to_basis.matrix_from_rows(list(G)).sparse_matrix()
     if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "B")
     #The collums of B now span self.M.integral_structure as ZZ-module
     B, d = B._clear_denom()
     if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "Clear denom")
     if d == 1:
         #for explanation see d == 2
         assert len(set([B.nonzero_positions_in_row(i)[0] for i in range(B.nrows()) if len(B.nonzero_positions_in_row(i)) == 1 and B[i, B.nonzero_positions_in_row(i)[0]] == 1])) == B.ncols(), "B doesn't contain the Identity"
         if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "Check Id")
         ZZbasis = MatrixSpace(QQ, B.ncols(), sparse=True)(1)
         if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "ZZbasis")
     elif d == 2:
         #in this case the matrix B will contain 2*Id as a minor this allows us to compute the hermite normal form of B in a very efficient way. This will give us the integral basis ZZbasis.
         #if it turns out to be nessecarry this can be generalized to the case d%4==2 if we don't mind to only get the right structure localized at 2
         assert len(set([B.nonzero_positions_in_row(i)[0] for i in range(B.nrows()) if len(B.nonzero_positions_in_row(i)) == 1 and B[i, B.nonzero_positions_in_row(i)[0]] == 2])) == B.ncols(), "B doesn't contain 2*Identity"    
         if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "Check 2*Id")
         E = matrix_modp(B,sparse=True)
         if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "matmodp")
         E = E.echelon_form()
         if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "echelon")
         ZZbasis = MatrixSpace(QQ, B.ncols(), sparse=True)(1)
         for (pivot_row, pivot_col) in zip(E.pivot_rows(), E.pivots()):
             for j in E.nonzero_positions_in_row(pivot_row):
                 ZZbasis[pivot_col, j] = QQ(1) / 2 
         if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "ZZbasis")
     else:
         return None
     #now we compute the integral kernel of the boundary map with respect to the integral basis. This will give us the integral cuspidal submodule.                 
     boundary_matrix = self.M.boundary_map().matrix()
     if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "Boundary matrix")
     ZZboundary_matrix=(ZZbasis*boundary_matrix).change_ring(ZZ)
     if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "ZZBoundary matrix")
     left_kernel_matrix=ZZboundary_matrix.transpose().dense_matrix()._right_kernel_matrix(algorithm='pari')
     if type(left_kernel_matrix)==tuple:
         left_kernel_matrix=left_kernel_matrix[1]
     if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "kernel matrix")
     ZZcuspidal_basis=left_kernel_matrix*ZZbasis
     if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "ZZkernel matrix")
     assert ZZcuspidal_basis.change_ring(QQ).echelon_form()==self.S.basis_matrix() , "the calculated integral basis does not span the right QQ vector space" # a little sanity check. This shows that the colums of ZZcuspidal_basis really span the right QQ vectorspace
     if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "check")
     #finally create the sub-module, we delibarately do this as a QQ vector space with custom basis, because this is faster then dooing the calculations over ZZ since sage will then use a slow hermite normal form algorithm.
     ambient_module=VectorSpace(QQ,ZZcuspidal_basis.ncols())
     int_struct = ambient_module.submodule_with_basis(ZZcuspidal_basis.rows())
     if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "finnished")
     return int_struct
Exemplo n.º 3
0
def _get_labels(M, x, rows, L):
    from sage.all import VectorSpace, Set, Matrix

    # If non-central, then this is true iff not intersecting.
    not_e1 = lambda v: list(v)[1:] != [0] * (len(v) - 1)

    # Determine new hyperplanes and group like rows together.
    V = VectorSpace(M.base_ring(), M.ncols())
    lines = []
    labels = []
    for r in range(M.nrows()):
        v = M[r]
        is_new = not_e1(v)
        i = 0
        while i < len(lines) and is_new:
            if v in V.subspace([lines[i]]):
                is_new = False
                labels[i] = labels[i].union(Set([r]))
            else:
                i += 1
        if is_new:
            lines.append(v)
            labels.append(Set([r]))

    # Adjust the labels because we are missing rows.
    fix_sets = lambda F: lambda S: Set(list(map(lambda s: F(s), S)))
    for k in rows:
        adjust = lambda i: i + (k <= i) * 1
        labels = list(map(fix_sets(adjust), labels))
    labels = [Set(rows)] + labels

    # Adjust the row labels to hyperplane labels
    HL = L.hyperplane_labels
    A = L.hyperplane_arrangement
    HL_lab = lambda i: list(filter(lambda j: HL[j] == A[i], HL.keys()))[0]
    labels = list(map(fix_sets(HL_lab), labels))

    # Get the new hyperplanes
    FL = L.flat_labels
    new_hyp = [labels[k].union(labels[0]) for k in range(1, len(labels))]
    P = L.poset
    flat = lambda S: list(filter(lambda j: FL[j] == S, P.upper_covers(x)))[0]
    new_hyp = list(map(flat, new_hyp))

    def last_adj(S):
        l_hyp = labels[1:]
        T = S.difference(labels[0])
        new_T = Set([])
        for k in range(len(l_hyp)):
            if l_hyp[k].issubset(T):
                new_T = new_T.union(Set([new_hyp[k]]))
        return new_T

    return Matrix(lines), last_adj, {
        new_hyp[i]: i
        for i in range(len(new_hyp))
    }
Exemplo n.º 4
0
def monics(F, d, u=1):
    """Iterate through all degree d polynomials over F with leading coefficient u.

    NB Use u=1 to get monics, and u=0 to give all polys of degree <d.
    """
    Fx = PolynomialRing(F, 'x')
    for v in VectorSpace(F, d):
        yield Fx(v.list() + [u])
Exemplo n.º 5
0
def _random_ini(dop):
    import random
    from sage.all import VectorSpace, QQ
    ind = dop.indicial_polynomial(dop.base_ring().gen())
    sl_decomp = my_shiftless_decomposition(ind)
    pol, shifts = random.choice(sl_decomp)
    expo = random.choice(pol.roots(QQbar))[0]
    values = {
        shift: tuple(VectorSpace(QQ, mult).random_element(10))
        for shift, mult in shifts
    }
    return LogSeriesInitialValues(expo, values, dop)
Exemplo n.º 6
0
 def randomize(self, prime):
     assert not self.randomized
     MSZp = MatrixSpace(ZZ.residue_field(ZZ.ideal(prime)), self.size)
     def random_matrix():
         while True:
             m = MSZp.random_element()
             if not m.is_singular() and m.rank() == self.size:
                 return m, m.inverse()
     m0, m0i = random_matrix()
     self.bp[0] = self.bp[0].group(MSZp, prime).mult_left(m0)
     for i in xrange(1, len(self.bp)):
         mi, mii = random_matrix()
         self.bp[i-1] = self.bp[i-1].group(MSZp, prime).mult_right(mii)
         self.bp[i] = self.bp[i].group(MSZp, prime).mult_left(mi)
     self.bp[-1] = self.bp[-1].group(MSZp, prime).mult_right(m0i)
     VSZp = VectorSpace(ZZ.residue_field(ZZ.ideal(prime)), self.size)
     self.s = copy(VSZp.zero())
     self.s[0] = 1
     self.t = copy(VSZp.zero())
     self.t[len(self.t) - 1] = 1
     self.m0, self.m0i = m0, m0i
     self.randomized = True
Exemplo n.º 7
0
def random_ini(dop):
    import random
    from sage.all import VectorSpace
    ind = dop.indicial_polynomial(dop.base_ring().gen())
    sl_decomp = my_shiftless_decomposition(ind)
    pol, shifts = random.choice(sl_decomp)
    expo = random.choice(pol.roots(QQbar))[0]
    expo = utilities.as_embedded_number_field_element(expo)
    values = {}
    while all(a.is_zero() for v in values.values() for a in v):
        values = {
            shift: tuple(VectorSpace(QQ, mult).random_element(10))
            for shift, mult in shifts
        }
    return LogSeriesInitialValues(expo, values, dop)
Exemplo n.º 8
0
    def randomize(self, prime):
        assert not self.randomized
        MSZp = MatrixSpace(ZZ.residue_field(ZZ.ideal(prime)), self.size)

        def random_matrix():
            while True:
                m = MSZp.random_element()
                if not m.is_singular() and m.rank() == self.size:
                    return m, m.inverse()

        m0, m0i = random_matrix()
        self.bp[0] = self.bp[0].group(MSZp, prime).mult_left(m0)
        for i in xrange(1, len(self.bp)):
            mi, mii = random_matrix()
            self.bp[i - 1] = self.bp[i - 1].group(MSZp, prime).mult_right(mii)
            self.bp[i] = self.bp[i].group(MSZp, prime).mult_left(mi)
        self.bp[-1] = self.bp[-1].group(MSZp, prime).mult_right(m0i)
        VSZp = VectorSpace(ZZ.residue_field(ZZ.ideal(prime)), self.size)
        self.s = copy(VSZp.zero())
        self.s[0] = 1
        self.t = copy(VSZp.zero())
        self.t[len(self.t) - 1] = 1
        self.m0, self.m0i = m0, m0i
        self.randomized = True
    def __pow__(self, n, _=None):
        r"""
        Return the vector space of dimension ``n`` over this field.

        EXAMPLES::

            sage: from pyeantic import RealEmbeddedNumberField
            sage: K = NumberField(x**2 - 2, 'a', embedding=sqrt(AA(2)))
            sage: K = RealEmbeddedNumberField(K)
            sage: K^3
            Vector space of dimension 3 over Real Embedded Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?

        """
        if isinstance(n, tuple):
            m, n = n
            from sage.all import MatrixSpace
            return MatrixSpace(self, m, n)
        else:
            from sage.all import VectorSpace
            return VectorSpace(self, n)
Exemplo n.º 10
0
def _para_intersection_poset(A):
    from sage.geometry.hyperplane_arrangement.affine_subspace import AffineSubspace
    from sage.all import exists, flatten, Set, QQ, VectorSpace, Poset
    from .Globals import __SANITY

    N = _N
    K = A.base_ring()
    whole_space = AffineSubspace(0, VectorSpace(K, A.dimension()))
    # L is the ranked list of affine subspaces in L(A).
    L = [[whole_space], list(map(lambda H: H._affine_subspace(), A))]
    # hyp_cont is the ranked list describing which hyperplanes contain the
    # corresponding intersection.
    hyp_cont = [[Set([])], [Set([k]) for k in range(len(A))]]

    c = A.is_central() * (-1)
    for r in range(2, A.rank() + c + 1):
        print("{1}Working on elements of rank {0}".format(r, _time()))
        m = len(L[r - 1])
        pmax = lambda k: (k + 1) * (m // N) + (k == N - 1) * (m % N)
        pmin = lambda k: k * (m // N)
        all_input = lambda k: tuple([
            A,
            range(pmin(k), pmax(k)), hyp_cont[r - 1][pmin(k):pmax(k)], L[r - 1]
            [pmin(k):pmax(k)]
        ])
        data = list(
            build_next([all_input(k) for k in range(N) if pmin(k) != pmax(k)]))
        data = _reduce(lambda x, y: x + y[1], data, [])
        new_lev, new_hyp = list(zip(*data))
        new_lev = list(new_lev)
        new_hyp = list(new_hyp)
        i = 0
        # Merge the lists down
        print("{0}Merging the lists from the {1} workers".format(_time(), N))
        # First we check the affine spaces
        while i < len(new_lev):
            U = new_lev[i]
            B1 = U.linear_part().basis_matrix()
            p1 = U.point()
            j = i + 1
            while j < len(new_lev):
                V = new_lev[j]
                B2 = V.linear_part().basis_matrix()
                p2 = V.point()
                if B1 == B2 and p1 == p2:
                    new_lev = new_lev[:j] + new_lev[j + 1:]
                    new_hyp[i] = new_hyp[i].union(new_hyp[j])
                    new_hyp = new_hyp[:j] + new_hyp[j + 1:]
                else:
                    j += 1
            i += 1
        # Second we check the labels of intersection (don't want duplicates)
        i = 0
        while i < len(new_lev):
            j = i + 1
            while j < len(new_lev):
                if new_hyp[i] == new_hyp[j]:
                    new_lev = new_lev[:j] + new_lev[j + 1:]
                    new_hyp = new_hyp[:j] + new_hyp[j + 1:]
                else:
                    j += 1
            i += 1
        L.append(new_lev)
        hyp_cont.append(new_hyp)

    # A silly optimization for centrals.
    if A.is_central() and len(A) > 1:
        inter = lambda X, Y: X.intersection(Y._affine_subspace())
        L.append([_reduce(inter, A[1:], A[0]._affine_subspace())])
        hyp_cont.append([Set(list(range(len(A))))])

    L_flat = list(_reduce(lambda x, y: x + y, L, []))
    hc_flat = list(_reduce(lambda x, y: x + y, hyp_cont, []))

    # Sanity checks
    if __SANITY:
        print("{0}Running sanity check".format(_time()))
        assert len(L_flat) == len(hc_flat)
        for i in range(len(hc_flat)):
            for j in range(i + 1, len(hc_flat)):
                assert hc_flat[i] != hc_flat[j], "{0} vs {1}".format(i, j)
        for i in range(len(L_flat)):
            I = list(map(lambda x: A[x], hc_flat[i]))
            U = _reduce(lambda x, y: x.intersection(y._affine_subspace()), I,
                        whole_space)
            assert U == L_flat[i], "{0} vs {1}".format(U, L_flat[i])

    print("{0}Constructing lattice of flats".format(_time()))
    t = {}
    for i in range(len(hc_flat)):
        t[i] = Set(list(map(lambda x: x + 1, hc_flat[i])))
    cmp_fn = lambda p, q: t[p].issubset(t[q])
    label_dict = {i: t[i] for i in range(len(hc_flat))}
    get_hyp = lambda i: A[label_dict[i].an_element() - 1]
    hyp_dict = {i + 1: get_hyp(i + 1) for i in range(len(A))}

    return [Poset((t, cmp_fn)), label_dict, hyp_dict]
Exemplo n.º 11
0

def vector_to_double_char(v):
    assert len(v) == 2
    return CHARSET[v[0]] + CHARSET[v[1]]


def encrypt(msg, K):
    assert all(c in CHARSET for c in msg)
    assert len(msg) % 2 == 0

    A, v = K
    ciphertext = ""
    for i in range(0, len(msg), 2):
        tmp = A * double_char_to_vector(msg[i:i + 2]) + v
        ciphertext += vector_to_double_char(tmp)

    return ciphertext


if __name__ == '__main__':
    from secret import flag
    assert flag.startswith('kmactf')
    A = MatrixSpace(Fp, 2, 2).random_element()
    v = VectorSpace(Fp, 2).random_element()
    assert A.determinant() != 0
    print('ciphertext =', repr(encrypt(flag, (A, v))))

    # Output:
    # ciphertext = 'u_rm3eefa}_7det1znb{sce{qo0h7yf0b}sktse8xtr6'
def solve(vectors, goal):
  M = MatrixSpace(GF(2), len(vectors), len(vectors[0]))
  V = VectorSpace(GF(2), len(goal))
  A = M(vectors)
  b = V(goal)
  return A.solve_left(b)
Exemplo n.º 13
0
    def __init__(self, p, congruence_type=1, sign=1, algorithm="custom", verbose=False, dump_dir=None):
        """
        Create a Kamienny criterion object.

        INPUT:

            - `p` -- prime -- verify that there is no order p torsion
              over a degree `d` field
            - `sign` -- 1 (default),-1 or 0 -- the sign of the modular symbols space to use 
            - ``algorithm`` -- "default" or "custom" whether to use a custom (faster)
              integral structure algorithm or to use the sage builtin algortihm
            - ``verbose`` -- bool; whether to print extra stuff while
              running.

        EXAMPLES::

            sage: from mdsage import *
            sage: C = KamiennyCriterion(29, algorithm="custom", verbose=False); C
            Kamienny's Criterion for p=29
            sage: C.use_custom_algorithm
            True
            sage: C.p
            29
            sage: C.verbose
            False        
        """
        self.verbose = verbose
        self.dump_dir = dump_dir
        if self.verbose: tm = cputime(); mem = get_memory_usage(); print "init"
        assert congruence_type == 0 or congruence_type == 1
        self.congruence_type=congruence_type
        try:
            p = ZZ(p)
            if congruence_type==0:
                self.congruence_group = Gamma0(p)
            if congruence_type==1:
                self.congruence_group = GammaH(p,[-1])
        except TypeError:
            self.congruence_group = GammaH(p.level(),[-1]+p._generators_for_H())
            self.congruence_type = ("H",self.congruence_group._list_of_elements_in_H())
            
        self.p = self.congruence_group.level()
  
        self.algorithm=algorithm
        self.sign=sign
        
        self.M = ModularSymbols(self.congruence_group, sign=sign)
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "modsym"
        self.S = self.M.cuspidal_submodule()
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "cuspsub"
        self.use_custom_algorithm = False
        if algorithm=="custom":
            self.use_custom_algorithm = True
        if self.use_custom_algorithm:
            int_struct = self.integral_cuspidal_subspace()
            if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "custom int_struct"
        else:    
            int_struct = self.S.integral_structure()
            if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "sage int_struct"
        self.S_integral = int_struct
        v = VectorSpace(GF(2), self.S.dimension()).random_element()
        self.v=v
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "rand_vect"
        if dump_dir:
            v.dump(dump_dir+"/vector%s_%s" % (p,congruence_type))
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "dump"
Exemplo n.º 14
0
    def __init__(self, p, congruence_type=1, sign=1, algorithm="custom", verbose=False, dump_dir=None):
        """
        Create a Kamienny criterion object.

        INPUT:

            - `p` -- prime -- verify that there is no order p torsion
              over a degree `d` field
            - `sign` -- 1 (default),-1 or 0 -- the sign of the modular symbols space to use 
            - ``algorithm`` -- "default" or "custom" whether to use a custom (faster)
              integral structure algorithm or to use the sage builtin algortihm
            - ``verbose`` -- bool; whether to print extra stuff while
              running.

        EXAMPLES::

            sage: from mdsage import *
            sage: C = KamiennyCriterion(29, algorithm="custom", verbose=False); C
            Kamienny's Criterion for p=29
            sage: C.use_custom_algorithm
            True
            sage: C.p
            29
            sage: C.verbose
            False        
        """
        self.verbose = verbose
        self.dump_dir = dump_dir
        if self.verbose: tm = cputime(); mem = get_memory_usage(); print("init")
        assert congruence_type == 0 or congruence_type == 1
        self.congruence_type=congruence_type
        try:
            p = ZZ(p)
            if congruence_type==0:
                self.congruence_group = Gamma0(p)
            if congruence_type==1:
                self.congruence_group = GammaH(p,[-1])
        except TypeError:
            self.congruence_group = GammaH(p.level(),[-1]+p._generators_for_H())
            self.congruence_type = ("H",self.congruence_group._list_of_elements_in_H())
            
        self.p = self.congruence_group.level()
  
        self.algorithm=algorithm
        self.sign=sign
        
        self.M = ModularSymbols(self.congruence_group, sign=sign)
        if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "modsym")
        self.S = self.M.cuspidal_submodule()
        if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "cuspsub")
        self.use_custom_algorithm = False
        if algorithm=="custom":
            self.use_custom_algorithm = True
        if self.use_custom_algorithm:
            int_struct = self.integral_cuspidal_subspace()
            if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "custom int_struct")
        else:    
            int_struct = self.S.integral_structure()
            if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "sage int_struct")
        self.S_integral = int_struct
        v = VectorSpace(GF(2), self.S.dimension()).random_element()
        self.v=v
        if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "rand_vect")
        if dump_dir:
            v.dump(dump_dir+"/vector%s_%s" % (p,congruence_type))
        if self.verbose: print("time and mem", cputime(tm), get_memory_usage(mem), "dump")