Esempio n. 1
0
 def __init__(self, G, coloring, name=None, check=True):
     from flexible_rigid_graph import FlexRiGraph
     if type(G) == FlexRiGraph or 'FlexRiGraph' in str(
             type(G)) or isinstance(G, FlexRiGraph):
         self._graph = G
     else:
         raise exceptions.TypeError('The graph G must be FlexRiGraph.')
     if type(coloring) in [list, Set] and len(coloring) == 2:
         self._red_edges = Set([Set(e) for e in coloring[0]])
         self._blue_edges = Set([Set(e) for e in coloring[1]])
     elif type(coloring) == dict:
         self._red_edges = Set(
             [Set(e) for e in coloring if coloring[e] == 'red'])
         self._blue_edges = Set(
             [Set(e) for e in coloring if coloring[e] == 'blue'])
     elif type(coloring) == NACcoloring or isinstance(
             coloring, NACcoloring) or 'NACcoloring' in str(type(coloring)):
         self._red_edges = copy(coloring._red_edges)
         self._blue_edges = copy(coloring._blue_edges)
     else:
         raise exceptions.TypeError(
             'The coloring must be a dict, list consisting of two lists or an instance of NACcoloring.'
         )
     self._check_edges()
     self._name = name
     if check and not self.is_NAC_coloring():
         raise exceptions.ValueError('The coloring is not a NAC-coloring.')
Esempio n. 2
0
    def _to_relaxed_matrix_bp(self, graph):
        # convert graph to a topological sorting of the vertices
        nodes = nx.topological_sort(graph.graph)
        # the accept vertex must be last
        a = nodes.index(('acc', graph.num))
        b = nodes.index(('rej', graph.num))
        if a < b:
            nodes[b], nodes[a] = nodes[a], nodes[b]
        # the source vertex must be first
        src = nodes.index(('src', graph.num))
        nodes[0], nodes[src] = nodes[src], nodes[0]

        mapping = dict(zip(nodes, range(self.size)))
        g = nx.relabel_nodes(graph.graph, mapping)
        # convert graph to relaxed matrix BP
        self.bp = []
        G = MatrixSpace(GF(2), self.size)
        for layer in xrange(self.nlayers):
            zero = copy(G.one())
            one = copy(G.one())
            for edge in g.edges_iter():
                e = g[edge[0]][edge[1]]
                assert e['label'] in (0, 1)
                if g.node[edge[0]]['layer'] == layer:
                    if e['label'] == 0:
                        zero[edge[0], edge[1]] = 1
                    else:
                        one[edge[0], edge[1]] = 1
            self.bp.append(Layer(graph.inp(layer), zero, one))
        self.zero = G.one()
Esempio n. 3
0
    def _to_relaxed_matrix_bp(self, graph):
        # convert graph to a topological sorting of the vertices
        nodes = nx.topological_sort(graph.graph)
        # the accept vertex must be last
        a = nodes.index(('acc', graph.num))
        b = nodes.index(('rej', graph.num))
        if a < b:
            nodes[b], nodes[a] = nodes[a], nodes[b]
        # the source vertex must be first
        src = nodes.index(('src', graph.num))
        nodes[0], nodes[src] = nodes[src], nodes[0]

        mapping = dict(zip(nodes, range(self.size)))
        g = nx.relabel_nodes(graph.graph, mapping)
        # convert graph to relaxed matrix BP
        self.bp = []
        G = MatrixSpace(GF(2), self.size)
        for layer in xrange(self.nlayers):
            zero = copy(G.one())
            one = copy(G.one())
            for edge in g.edges_iter():
                e = g[edge[0]][edge[1]]
                assert e['label'] in (0, 1)
                if g.node[edge[0]]['layer'] == layer:
                    if e['label'] == 0:
                        zero[edge[0], edge[1]] = 1
                    else:
                        one[edge[0], edge[1]] = 1
            self.bp.append(Layer(graph.inp(layer), zero, one))
        self.zero = G.one()
Esempio n. 4
0
    def __init__(self, L, **MetaData):
        r"""
        NOTE:

        An instance of ``BarCode`` should not be directly constructed.
        Usually, it is obtained as output of
        :meth:`~pGroupCohomology.cohomology.COHO.bar_code`

        INPUT:

        ``L`` - a list of persistence data
        ``M`` - Metadata in the form of optional parameters

        ASSUMPTIONS:

        ``dict(L)`` should yield a dictionary whose keys give the
        positions and whose values give the marks of a persistence
        matrix. A persistence matrix is an upper triangular
        matrix whose marks are univariate power series with non-negative
        integer coefficients (Poincaré series). For each degree,
        the corresponding coefficients of the Poincaré series yield
        an upper triangular integer matrix with the additional
        property that the matrix columns are increasing from top to
        bottom and the maatrix rows are decreasing from left to right.
        However, this is not a sufficient condition.

        We are sorry for the fact that the numbering of rows and colums
        does not start with zero; instead, the numbering ranges from
        ``-d`` to ``d``, where ``d`` is given by the length of the
        normal series (non-trivial terms only) by which the bar code
        is defined.

        TESTS::

            sage: from pGroupCohomology.barcode import BarCode
            sage: from pGroupCohomology import CohomologyRing
            sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
            sage: R.<t> = ZZ[]
            sage: L = [((-1, -1), -1/(t - 1)), ((-1, 0), -1/(t^2 - 1)), ((-1, 1), 1), ((0, 0), 1/(t^2 - 2*t + 1)), ((0, 1), (-t - 1)/(t - 1)), ((1, 1), 1/(t^2 - 2*t + 1))]
            sage: B = BarCode(L,ring='some ring')    # indirect doctest
            sage: B
            Persistence data for some ring
            sage: ascii_art(B[3])
                *
                *
              *-*
              *-*
              *
              *
            *

        """
        from sage.all import copy
        self._Meta = copy(MetaData)
        self._L = dict(copy(L))
        self._length = max([X[1] for X in self._L.keys()])
Esempio n. 5
0
def compare_data(d1,
                 d2,
                 keylist=['dims', 'traces', 'polys', 'ALs', 'eigdata'],
                 verbose=False):
    assert d1.keys() == d1.keys()
    QX = PolynomialRing(QQ, 'x')
    nforms = len(d1.keys())
    nstep = ZZ(max(1, int(nforms / 20.0)))
    nf = 0
    print("Comparing data for {} newforms".format(nforms))
    for k in d1.keys():
        nf += 1
        if nf % nstep == 0:
            print("compared {}/{} ({:0.3f}%)".format(nf, nforms,
                                                     100.0 * nf / nforms))
        if d1[k] != d2[k]:
            for key in keylist:
                # take copies! we want to be able to change these without affecting the input dicts
                t1 = copy(d1[k][key])
                t2 = copy(d2[k][key])
                if key == 'polys':
                    n = len(t1)
                    for i in range(n):
                        if t1[i] != t2[i]:
                            pol1 = QX(t1[i])
                            pol2 = QX(t2[i])
                            F1 = NumberField(pol1, 'a')
                            F2 = NumberField(pol2, 'a')
                            if F1.is_isomorphic(F2):
                                pol1 = pol2 = F1.optimized_representation(
                                )[0].defining_polynomial()
                                t1[i] = t2[i] = list(pol1)

                if t1 != t2:
                    if key == 'traces':
                        print(
                            "traces differ for {}: \nfirst #= {}, \nsecond #={}"
                            .format(k, [len(t) for t in t1],
                                    [len(t) for t in t2]))
                        print("first starts\t {}".format(t1[0][:10]))
                        print("second starts\t {}".format(t2[0][:10]))
                    elif key == 'eigdata':
                        for f1, f2 in zip(t1, t2):
                            ok, reason = compare_eigdata(k, f1, f2, verbose)
                            if not ok:
                                print("an do not match for (N,k,o)={}: {}".
                                      format(k, reason))
                    else:
                        print("{} differ for {}: \nfirst  {}, \nsecond {}".
                              format(key, k, t1, t2))
Esempio n. 6
0
    def mul(self, a):
        assert a in ZZ
        if a == 1:
            return copy(self)

        if a == 0:
            return Divisor(self.Pic)

        if a < 0:
            self.neg().mul(-a)
            a = -a
            sign = 1
        else:
            sign = 0
        result = copy(self)
        negself = None
        #negselflower = None;

        n = floor(log(a, 2)) + 1
        for i in range(n - 2, -1, -1):
            result = result.mDouble()
            sign = (sign + 1) % 2
            if a & (1 << i):

                if sign == 1:
                    if negself == None:
                        negself = self.neg()

                    # result = -correct
                    tmp, lower = self.Pic.AddFlip(result.basis_RR,
                                                  negself.basis_RR)
                    lower = max(result.lower, lower, negself.lower)
                    result = Divisor(self.Pic, basis_RR=tmp, lower=lower)
                    #result = - (-correct - self) = self + correct
                    sign = 0
                else:
                    #result = correct
                    tmp, lower = self.Pic.AddFlip(result.basis_RR,
                                                  self.basis_RR)
                    lower = max(result.lower, lower, self.lower)
                    result = Divisor(self.Pic, basis_RR=tmp, lower=lower)

                    #result = -correct - self
                    sign = 1

        if sign == 1:
            result = result.neg()

        return result
Esempio n. 7
0
    def rrkc_precomputations(self):
        self.Li = [m.inverse() for m in self.Lt]
        self.LiK = [self.Kt[i + 1] * self.Li[i] for i in range(self.r)]
        self.LiC = [self.C[i] * self.Li[i] for i in range(self.r)]

        mod_Li = [copy(self.Li[i]) for i in range(self.r)]
        for j in range(self.r):
            mod_Li[j][self.n - 3 * self.s:, :self.n] = matrix(
                F, 3 * self.s, self.n)

        self.precomputed_key_matrix = None
        self.precomputed_key_matrix_nl = matrix(F, self.n,
                                                (self.s * 3) * self.r)
        self.precomputed_constant = None
        self.precomputed_constant_nl = vector(F, (self.s * 3) * self.r)

        for round in range(self.r):
            tmp = copy(self.LiK[round])
            tmpC = copy(self.LiC[round])

            for i in range(round + 1, self.r):
                x = self.LiK[i]
                c = self.LiC[i]
                for j in range(i - 1, round - 1, -1):
                    x = x * mod_Li[j]
                    c = c * mod_Li[j]
                tmp += x
                tmpC += c

            # non-linear part
            idx = round * (3 * self.s)
            self.precomputed_key_matrix_nl[:self.n, idx:idx +
                                           3 * self.s] = tmp[:self.n, self.n -
                                                             3 * self.s:]
            self.precomputed_constant_nl[idx:idx +
                                         3 * self.s] = tmpC[self.n -
                                                            3 * self.s:]

            # linear part
            if round == 0:
                tmp[:, self.n - 3 * self.s:] = matrix(F, self.n, 3 * self.s)
                tmpC[self.n - 3 * self.s:] = vector(F, 3 * self.s)
                self.precomputed_key_matrix = tmp
                self.precomputed_constant = tmpC

        self.rrkc_precomputations_done = True
Esempio n. 8
0
 def __init__(self,M=None,genus_list=None):
   #print genus_list
   if M:
     self.M = copy(M)
   elif genus_list:
     self.M = Matrix(StrataGraph.R,len(genus_list)+1,1,[-1]+genus_list)
   else:
     self.M = Matrix(StrataGraph.R,1,1,-1)
Esempio n. 9
0
    def show(self, *args, **kwds):
        r"""
        Show a 3D picture of self.

        INPUT:

        - ``dmin`` (default = 1): optional non-negative integer,
          the lowest shown degree
        - ``dmax`` (default = 10): optional non-negative integer,
          the highest shown degree

        The resulting picture combines the planar bar codes for
        each degree between ``dmin`` and ``dmax`` to a 3-dimensional
        arrangement of bars.

        TESTS::

            sage: from pGroupCohomology import CohomologyRing
            sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
            sage: H = CohomologyRing(16,3)
            sage: H.make()
            sage: B = H.bar_code('LowerCentralSeries')
            sage: show(B,dmin=3,dmax=15)
            <html><script type="math/tex">\newcommand{\Bold}[1]{\mathbf{#1}}\verb|Persistence|\phantom{\verb!x!}\verb|data|\phantom{\verb!x!}\verb|for|\phantom{\verb!x!}\verb|H^*(SmallGroup(16,3);|\phantom{\verb!x!}\verb|GF(2))|\phantom{\verb!x!}\verb|associated|\phantom{\verb!x!}\verb|with|\phantom{\verb!x!}\verb|LowerCentralSeries|</script></html>

        For seeing a nice picture, you should instead do
        ``B.show(dmin=3, dmax=15)``.

        """
        dmin = kwds.get('dmin', 1)
        dmax = kwds.get('dmax', 10)
        from sage.all import sphere, line
        if dmin >= dmax:
            raise ValueError(
                "Optional parameters dmin, dmax must satisfy dmin < dmax")
        bars = [self[i]._bars for i in range(dmin, dmax + 1)]
        G = None
        for d in range(0, dmax - dmin + 1):
            l = len(bars[d])
            for B in range(l):
                if bars[d][B][0] != bars[d][B][1]:
                    G += line(
                        [(X, dmin + d, l + 1 - B)
                         for X in range(bars[d][B][0], bars[d][B][1] + 1)],
                        thickness=2)
                G = sum([
                    sphere(center=(X, dmin + d, l + 1 - B),
                           size=0.1,
                           color=(0, 0, 1))
                    for X in range(bars[d][B][0], bars[d][B][1] + 1)
                ], G)
        from sage.all import copy
        KWDS = copy(kwds)
        if 'dmin' in KWDS:
            del KWDS['dmin']
        if 'dmax' in KWDS:
            del KWDS['dmax']
        G.show(*args, **KWDS)
Esempio n. 10
0
 def __init__(self, M=None, genus_list=None):
     #print genus_list
     if M:
         self.M = copy(M)
     elif genus_list:
         self.M = Matrix(StrataGraph.R,
                         len(genus_list) + 1, 1, [-1] + genus_list)
     else:
         self.M = Matrix(StrataGraph.R, 1, 1, -1)
Esempio n. 11
0
 def dual_multiplier(self):
     r"""
     Returns the dual multiplier of self.
     """
     m = copy(self)
     m._is_dual = int(not self._is_dual)
     o = self._character.order()
     m._character = self._character**(o-1)
     m._weight = QQ(2) - QQ(self._weight)
     return m
Esempio n. 12
0
 def dual_multiplier(self):
     r"""
     Returns the dual multiplier of self.
     """
     m = copy(self)
     m._is_dual = int(not self._is_dual)
     o = self._character.order()
     m._character = self._character**(o - 1)
     m._weight = QQ(2) - QQ(self.weight())
     return m
Esempio n. 13
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
Esempio n. 14
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
Esempio n. 15
0
 def _action(self, A):
     #if A not in self._group:
     #    raise ValueError,"Action is only defined for {0}!".format(self._group)
     a, b, c, d = A
     [z, n, l] = factor_matrix_in_sl2z(int(a), int(b), int(c), int(d))
     #l,ep = factor_matrix_in_sl2z_in_S_and_T(A_in)
     res = copy(self.T.parent().one())
     if z == -1 and self.v != None:
         tmp = self.v(SL2Z([-1, 0, 0, -1]))
         for j in range(self._dim):
             res[j, j] = tmp
     if n != 0:
         res = self.T**n
     for i in range(len(l)):
         res = res * self.S * self.T**l[i]
     return res
Esempio n. 16
0
    def graph(self):
        r""" Return the weighted graph underlying this resolution graph.

        Output: An undirected, weighted Sage Graph.

        The vertices are labeled by the integers `0,\ldots,n-1`. The weight
        of an edge is the intersection number of the components corresponding
        to the vertices connected by the edge.

        """
        if not hasattr(self, "_graph"):
            M = copy(self._intersection_matrix)
            for i in self.components():
                M[i, i] = 0
            self._graph = Graph(M, format='weighted_adjacency_matrix')
        return self._graph
Esempio n. 17
0
 def _action(self,A):
     #if A not in self._group:
     #    raise ValueError,"Action is only defined for {0}!".format(self._group) 
     a,b,c,d=A
     [z,n,l]=factor_matrix_in_sl2z(int(a),int(b),int(c),int(d))
     #l,ep = factor_matrix_in_sl2z_in_S_and_T(A_in)
     res = copy(self.T.parent().one())
     if z==-1 and self.v<>None:
         tmp = self.v(SL2Z([-1,0,0,-1]))
         for j in range(self._dim):
             res[j,j]=tmp
     if n<>0:
         res = self.T**n
     for i in range(len(l)):
         res = res*self.S*self.T**l[i]
     return res
Esempio n. 18
0
                print "\t\t!! WARNING !!"
                print "\t\t\tsomething went wrong?"
                print "\t\t\tsign = %s R1 = %s" % (sign, R1)
                print "\t\t\tP = %s" % vector(CC, P)
                print "\t\t\tR0 = %s" % vector(CC, R0)

    print "\tTesting P, Q -> Divisor(P,Q) -> Divisor(P,Q).compute_coordinates() = P + Q - D0?"
    for i, pair in enumerate(pairs):
        p0, p1 = pair
        Dp0p1 = Divisor(Pic, [p0, p1])
        R0, R1 = Dp0p1.coordinates()
        R0 = vector(R0)
        R1 = vector(R1)

        if norm(R0 - p0) > norm(R0 - p1):
            tmp = copy(R1)
            R1 = R0
            R0 = tmp
        N = [norm(R0 - p0), norm(R1 - p1)]
        N = RealField(15)(max(N))

        print "\t\tP + Q = R0 + R1? :%s" % N
        if N > threshold:
            print "\t\t!! WARNING !!"
            print "\t\t\tsomething went wrong?"
            print "\t\t\tP = %s" % vector(CC, p0)
            print "\t\t\tQ = %s" % vector(CC, p1)
            print "\t\t\tR0 = %s" % vector(CC, R0)
            print "\t\t\tR1 = %s" % vector(CC, R1)

    print "\tTesting P, Q -> (Divisor(P,0)  + Divisor(Q,1)) -> (Divisor(P,0)  + Divisor(Q,1)).compute_coordinates() = P + Q - D0?"
Esempio n. 19
0
def smith_normal_form(A, v):
    r""" Return the Smith normal form of the matrix ``A``.

    INPUT:

    - ``A`` -- a matrix over a field `K`
    - ``v`` -- a discrete valuation on `K`

    OUTPUT:

    a tuple`(D, S, T, rank)` `D, S, T` matrices, such that

    .. MATH::

        S\cdot A\codt T = D,

    where `S` and `T` are square invertible matrices over the valuation ring `R`
    of `v`, `D` is the Smith normal form of `A` over `R`, and `rank` is the rank of `D`.

    """
    K = A.base_ring()
    m = A.nrows()
    n = A.ncols()
    # assert all([v(a) >= 0 for a in A.coefficients()]), "A must have integral coefficients"
    D = copy(A)
    S = matrix.identity(K, m)
    T = matrix.identity(K, n)
    k = -1
    while not D.submatrix(k + 1, k + 1).is_zero():
        # the parameter k indicates that the rows i=0,..,k and columns j=0,..,k
        # are already in the required form
        i, j, e = find_pivot(v, D, k)
        # the entry D[i, j] is the next entry with the smallest valuation e
        switch_rows(D, k + 1, i)
        switch_columns(S, k + 1, i)
        switch_columns(D, k + 1, j)
        switch_rows(T, k + 1, j)
        assert A == S * D * T, "something is wrong!"
        # now D[k + 1, k + 1] is a nonzero entry, with minimal valuation e
        a0 = v.element_with_valuation(e)
        a = a0 / D[k + 1, k + 1]
        D.rescale_col(k + 1, a)
        T.rescale_row(k + 1, 1 / a)
        assert A == S * D * T, "something is wrong!"
        for j in range(k + 2, n):
            if not D[k + 1, j].is_zero():
                x = -D[k + 1, j] / a0
                D.add_multiple_of_column(j, k + 1, x)
                T.add_multiple_of_row(k + 1, j, -x)
                assert A == S * D * T, "something is wrong!"
        # now we kill the rest of the (k+1)th column
        for i in range(k + 2, m):
            if not D[i, k + 1].is_zero():
                x = -D[i, k + 1] / a0
                D.add_multiple_of_row(i, k + 1, x)
                S.add_multiple_of_column(k + 1, i, -x)
                assert A == S * D * T, "something is wrong!"
        if k < n - 1 and k < m - 1:
            k += 1
    assert v(S.determinant()) == 0, "S is not invertible!"
    assert v(T.determinant()) == 0, "T is not invertible!"
    return D, S, T, k + 1
Esempio n. 20
0
def make_luts(field, sub_folder, seed, sparse=False):
    global FIELD, RING
    print(f"Making LUTs for {field}")

    ###############################################################################
    # Finite field arithmetic
    ###############################################################################
    folder = os.path.join(PATH, "fields", "data", sub_folder)
    if os.path.exists(folder):
        shutil.rmtree(folder)
    os.mkdir(folder)

    FIELD = field
    RING = PolynomialRing(field, names="x")
    characteristic = int(field.characteristic())
    order = int(field.order())
    dtype = np.int64 if order <= np.iinfo(np.int64).max else object
    alpha = field.primitive_element()
    # assert field.gen() == field.multiplicative_generator()

    d = {
        "characteristic": int(field.characteristic()),
        "degree": int(field.degree()),
        "order": int(field.order()),
        "primitive_element": I(field.primitive_element()),
        "irreducible_poly": [int(c) for c in field.modulus().list()[::-1]]
    }
    save_json(d, folder, "properties.json", indent=True)

    set_seed(seed + 1)
    X, Y, XX, YY, ZZ = io_2d(0, order, 0, order, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j]) + F(YY[i, j]))
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "add.pkl")

    set_seed(seed + 2)
    X, Y, XX, YY, ZZ = io_2d(0, order, 0, order, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j]) - F(YY[i, j]))
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "subtract.pkl")

    set_seed(seed + 3)
    X, Y, XX, YY, ZZ = io_2d(0, order, 0, order, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j]) * F(YY[i, j]))
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "multiply.pkl")

    set_seed(seed + 4)
    X, Y, XX, YY, ZZ = io_2d(0, order, -order - 2, order + 3, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j]) * YY[i, j])
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "scalar_multiply.pkl")

    set_seed(seed + 5)
    X, Y, XX, YY, ZZ = io_2d(0, order, 1, order, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j]) / F(YY[i, j]))
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "divide.pkl")

    set_seed(seed + 6)
    X, Z = io_1d(0, order, sparse=sparse)
    for i in range(X.shape[0]):
        Z[i] = I(-F(X[i]))
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "additive_inverse.pkl")

    set_seed(seed + 7)
    X, Z = io_1d(1, order, sparse=sparse)
    for i in range(X.shape[0]):
        Z[i] = I(1 / F(X[i]))
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "multiplicative_inverse.pkl")

    set_seed(seed + 8)
    X, Y, XX, YY, ZZ = io_2d(1, order, -order - 2, order + 3, sparse=sparse)
    for i in range(ZZ.shape[0]):
        for j in range(ZZ.shape[1]):
            ZZ[i, j] = I(F(XX[i, j])**YY[i, j])
    d = {"X": X, "Y": Y, "Z": ZZ}
    save_pickle(d, folder, "power.pkl")

    set_seed(seed + 9)
    X, Z = io_1d(1, order, sparse=sparse)
    for i in range(Z.shape[0]):
        try:
            Z[i] = I(field.fetch_int(X[i]).log(alpha))
        except:
            Z[i] = I(log(F(X[i]), alpha))
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "log.pkl")

    set_seed(seed + 10)
    X, Z = io_1d(0, order, sparse=sparse)
    for i in range(X.shape[0]):
        Z[i] = int(F(X[i]).additive_order())
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "additive_order.pkl")

    set_seed(seed + 11)
    X, Z = io_1d(1, order, sparse=sparse)
    for i in range(X.shape[0]):
        Z[i] = int(F(X[i]).multiplicative_order())
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "multiplicative_order.pkl")

    set_seed(seed + 12)
    X, _ = io_1d(0, order, sparse=sparse)
    Z = []
    for i in range(len(X)):
        x = F(X[i])
        p = x.charpoly()
        z = poly_to_list(p)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "characteristic_poly_element.pkl")

    set_seed(seed + 13)
    shapes = [(2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]
    X = []
    Z = []
    for i in range(len(shapes)):
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        p = x.charpoly()
        z = poly_to_list(p)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "characteristic_poly_matrix.pkl")

    set_seed(seed + 14)
    X, _ = io_1d(0, order, sparse=sparse)
    Z = []
    for i in range(len(X)):
        x = F(X[i])
        p = x.minpoly()
        z = poly_to_list(p)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "minimal_poly_element.pkl")

    # set_seed(seed + 15)
    # shapes = [(2,2), (3,3), (4,4), (5,5), (6,6)]
    # X = []
    # Z = []
    # for i in range(len(shapes)):
    #     x = randint_matrix(0, order, shapes[i])
    #     X.append(x)
    #     x = matrix(FIELD, [[F(e) for e in row] for row in x])
    #     p = x.minpoly()
    #     z = np.array([I(e) for e in p.list()[::-1]], dtype=dtype).tolist()
    #     z = z if z != [] else [0]
    #     Z.append(z)
    # d = {"X": X, "Z": Z}
    # save_pickle(d, folder, "minimal_poly_matrix.pkl")

    set_seed(seed + 16)
    X, Z = io_1d(0, order, sparse=sparse)
    for i in range(X.shape[0]):
        z = F(X[i]).trace()
        Z[i] = int(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "field_trace.pkl")

    set_seed(seed + 17)
    X, Z = io_1d(0, order, sparse=sparse)
    for i in range(X.shape[0]):
        z = F(X[i]).norm()
        Z[i] = int(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "field_norm.pkl")

    ###############################################################################
    # Linear algebra
    ###############################################################################

    set_seed(seed + 201)
    X_shapes = [(2, 2), (2, 3), (3, 2), (3, 3), (3, 4)]
    Y_shapes = [(2, 2), (3, 3), (2, 4), (3, 3), (4, 5)]
    X = []
    Y = []
    Z = []
    for i in range(len(shapes)):
        x = randint_matrix(0, order, X_shapes[i])
        y = randint_matrix(0, order, Y_shapes[i])
        X.append(x)
        Y.append(y)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        y = matrix(FIELD, [[F(e) for e in row] for row in y])
        z = x * y
        z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "matrix_multiply.pkl")

    set_seed(seed + 202)
    shapes = [(2, 2), (2, 3), (3, 2), (3, 3), (3, 4)]
    X = []
    Z = []
    for i in range(len(shapes)):
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = x.rref()
        z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "row_reduce.pkl")

    set_seed(seed + 203)
    shapes = [(2, 2), (2, 3), (3, 2), (3, 3), (3, 4), (4, 3), (4, 4), (4, 5),
              (5, 4), (5, 5), (5, 6), (6, 5), (6, 6)]
    X = []
    L = []
    U = []
    for i in range(len(shapes)):
        while True:
            # Ensure X has a PLU decomposition with P = I, which means it has an LU decomposition
            x = randint_matrix(0, order, shapes[i])
            x_orig = x.copy()
            x = matrix(FIELD, [[F(e) for e in row] for row in x])
            p, l, u = x.LU()
            if p == matrix.identity(FIELD, shapes[i][0]):
                break
        X.append(x_orig)
        l = np.array([[I(e) for e in row] for row in l], dtype)
        u = np.array([[I(e) for e in row] for row in u], dtype)
        L.append(l)
        U.append(u)
    d = {"X": X, "L": L, "U": U}
    save_pickle(d, folder, "lu_decompose.pkl")

    set_seed(seed + 204)
    shapes = [(2, 2), (2, 3), (3, 2), (3, 3), (3, 4), (4, 3), (4, 4), (4, 5),
              (5, 4), (5, 5), (5, 6), (6, 5), (6, 6)]
    X = []
    L = []
    U = []
    P = []
    for i in range(len(shapes)):
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        p, l, u = x.LU()
        p = np.array([[I(e) for e in row] for row in p], dtype)
        l = np.array([[I(e) for e in row] for row in l], dtype)
        u = np.array([[I(e) for e in row] for row in u], dtype)
        P.append(p)
        L.append(l)
        U.append(u)
    d = {"X": X, "P": P, "L": L, "U": U}
    save_pickle(d, folder, "plu_decompose.pkl")

    set_seed(seed + 205)
    shapes = [(2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]
    X = []
    Z = []
    for i in range(len(shapes)):
        while True:
            x = randint_matrix(0, order, shapes[i])
            x_orig = x.copy()
            x = matrix(FIELD, [[F(e) for e in row] for row in x])
            if x.rank() == shapes[i][0]:
                break
        X.append(x_orig)
        z = x.inverse()
        z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "matrix_inverse.pkl")

    set_seed(seed + 206)
    shapes = [(2, 2), (2, 2), (2, 2), (3, 3), (3, 3), (3, 3), (4, 4), (4, 4),
              (4, 4), (5, 5), (5, 5), (5, 5), (6, 6), (6, 6), (6, 6)]
    X = []
    Z = []
    for i in range(len(shapes)):
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = I(x.determinant())
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "matrix_determinant.pkl")

    set_seed(seed + 207)
    shapes = [(2, 2), (2, 2), (2, 2), (3, 3), (3, 3), (3, 3), (4, 4), (4, 4),
              (4, 4), (5, 5), (5, 5), (5, 5), (6, 6), (6, 6), (6, 6)]
    X = []
    Y = []
    Z = []
    for i in range(len(shapes)):
        while True:
            x = randint_matrix(0, order, shapes[i])
            x_orig = x.copy()
            x = matrix(FIELD, [[F(e) for e in row] for row in x])
            if x.rank() == shapes[i][0]:
                break
        X.append(x_orig)
        y = randint_matrix(0, order, shapes[i][1])  # 1-D vector
        Y.append(y)
        y = vector(FIELD, [F(e) for e in y])
        z = x.solve_right(y)
        z = np.array([I(e) for e in z], dtype)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "matrix_solve.pkl")

    set_seed(seed + 208)
    shapes = [(2, 2), (2, 3), (2, 4), (3, 2), (4, 2), (3, 3)]
    X = []
    Z = []
    for i in range(len(shapes)):
        deg = shapes[i][1]  # The degree of the vector space

        # Random matrix
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = x.row_space()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)

        # Reduce the row space by 1 by copying the 0th row to the jth row
        for j in range(1, shapes[i][0]):
            x = copy(x)
            x[j, :] = F(random.randint(0, order - 1)) * x[0, :]

            z = x.row_space()
            if z.dimension() == 0:
                z = randint_matrix(0, 1, (0, deg))
            else:
                z = z.basis_matrix()
                z = np.array([[I(e) for e in row] for row in z], dtype)
            X.append(np.array([[I(e) for e in row] for row in x], dtype))
            Z.append(z)

        # Zero matrix
        x = copy(x)
        x[:] = F(0)
        z = x.row_space()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        X.append(np.array([[I(e) for e in row] for row in x], dtype))
        Z.append(z)

    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "row_space.pkl")

    set_seed(seed + 209)
    shapes = [(2, 2), (2, 3), (2, 4), (3, 2), (4, 2), (3, 3)]
    X = []
    Z = []
    for i in range(len(shapes)):
        deg = shapes[i][0]  # The degree of the vector space

        # Random matrix
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = x.column_space()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)

        # Reduce the column space by 1 by copying the 0th column to the jth column
        for j in range(1, shapes[i][1]):
            x = copy(x)
            x[:, j] = F(random.randint(0, order - 1)) * x[:, 0]

            z = x.column_space()
            if z.dimension() == 0:
                z = randint_matrix(0, 1, (0, deg))
            else:
                z = z.basis_matrix()
                z = np.array([[I(e) for e in row] for row in z], dtype)
            X.append(np.array([[I(e) for e in row] for row in x], dtype))
            Z.append(z)

        # Zero matrix
        x = copy(x)
        x[:] = F(0)
        z = x.column_space()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        X.append(np.array([[I(e) for e in row] for row in x], dtype))
        Z.append(z)

    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "column_space.pkl")

    set_seed(seed + 210)
    shapes = [(2, 2), (2, 3), (2, 4), (3, 2), (4, 2), (3, 3)]
    X = []
    Z = []
    for i in range(len(shapes)):
        deg = shapes[i][0]  # The degree of the vector space

        # Random matrix
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = x.left_kernel()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)

        # Reduce the left null space by 1 by copying the 0th row to the jth row
        for j in range(1, shapes[i][0]):
            x = copy(x)
            x[j, :] = F(random.randint(0, order - 1)) * x[0, :]

            z = x.left_kernel()
            if z.dimension() == 0:
                z = randint_matrix(0, 1, (0, deg))
            else:
                z = z.basis_matrix()
                z = np.array([[I(e) for e in row] for row in z], dtype)
            X.append(np.array([[I(e) for e in row] for row in x], dtype))
            Z.append(z)

        # Zero matrix
        x = copy(x)
        x[:] = F(0)
        z = x.left_kernel()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        X.append(np.array([[I(e) for e in row] for row in x], dtype))
        Z.append(z)

    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "left_null_space.pkl")

    set_seed(seed + 211)
    shapes = [(2, 2), (2, 3), (2, 4), (3, 2), (4, 2), (3, 3)]
    X = []
    Z = []
    for i in range(len(shapes)):
        deg = shapes[i][1]  # The degree of the vector space

        # Random matrix
        x = randint_matrix(0, order, shapes[i])
        X.append(x)
        x = matrix(FIELD, [[F(e) for e in row] for row in x])
        z = x.right_kernel()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)

        # Reduce the null space by 1 by copying the 0th column to the jth column
        for j in range(1, shapes[i][1]):
            x = copy(x)
            x[:, j] = F(random.randint(0, order - 1)) * x[:, 0]

            z = x.right_kernel()
            if z.dimension() == 0:
                z = randint_matrix(0, 1, (0, deg))
            else:
                z = z.basis_matrix()
                z = np.array([[I(e) for e in row] for row in z], dtype)
            X.append(np.array([[I(e) for e in row] for row in x], dtype))
            Z.append(z)

        # Zero matrix
        x = copy(x)
        x[:] = F(0)
        z = x.right_kernel()
        if z.dimension() == 0:
            z = randint_matrix(0, 1, (0, deg))
        else:
            z = z.basis_matrix()
            z = np.array([[I(e) for e in row] for row in z], dtype)
        X.append(np.array([[I(e) for e in row] for row in x], dtype))
        Z.append(z)

    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "null_space.pkl")

    ###############################################################################
    # Polynomial arithmetic
    ###############################################################################
    folder = os.path.join(PATH, "polys", "data", sub_folder)
    if os.path.exists(folder):
        shutil.rmtree(folder)
    os.mkdir(folder)

    MIN_COEFFS = 1
    MAX_COEFFS = 12

    set_seed(seed + 101)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = list_to_poly(Y[i])
        z = x + y
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "add.pkl")

    set_seed(seed + 102)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = list_to_poly(Y[i])
        z = x - y
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "subtract.pkl")

    set_seed(seed + 103)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = list_to_poly(Y[i])
        z = x * y
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "multiply.pkl")

    set_seed(seed + 104)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random.randint(1, 2 * characteristic) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = Y[i]
        z = x * y
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "scalar_multiply.pkl")

    set_seed(seed + 105)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    # Add some specific polynomial types
    X.append([0]), Y.append(random_coeffs(0, order, MIN_COEFFS,
                                          MAX_COEFFS))  # 0 / y
    X.append(random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS // 2)), Y.append(
        random_coeffs(0, order, MAX_COEFFS // 2,
                      MAX_COEFFS))  # x / y with x.degree < y.degree
    X.append(random_coeffs(0, order, 2, MAX_COEFFS)), Y.append(
        random_coeffs(0, order, 1, 2))  # x / y with y.degree = 0
    Q = []
    R = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = list_to_poly(Y[i])
        q = x // y
        r = x % y
        q = poly_to_list(q)
        Q.append(q)
        r = poly_to_list(r)
        R.append(r)
    d = {"X": X, "Y": Y, "Q": Q, "R": R}
    save_pickle(d, folder, "divmod.pkl")

    set_seed(seed + 106)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(4)]
    X.append(random_coeffs(0, order, 1, 2))
    Y = [0, 1, 2, 3]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        ZZ = []
        for j in range(len(Y)):
            y = Y[j]
            z = x**y
            z = poly_to_list(z)
            ZZ.append(z)
        Z.append(ZZ)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "power.pkl")

    set_seed(seed + 107)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = arange(0, order, sparse=sparse)
    Z = np.array(np.zeros((len(X), len(Y))), dtype=dtype)
    for i in range(len(X)):
        for j in range(len(Y)):
            x = list_to_poly(X[i])
            y = F(Y[j])
            z = x(y)
            Z[i, j] = I(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "evaluate.pkl")

    set_seed(seed + 108)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [randint_matrix(0, order, (2, 2)) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = matrix(FIELD, [[F(e) for e in row] for row in Y[i]])
        z = x(y)
        z = np.array([[I(e) for e in row] for row in z], dtype)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "evaluate_matrix.pkl")

    ###############################################################################
    # Polynomial arithmetic methods
    ###############################################################################

    set_seed(seed + 301)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        z = x.reverse()
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "reverse.pkl")

    set_seed(seed + 302)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    R = []
    M = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        roots = x.roots()
        RR, MM = [], []
        for root in roots:
            r = root[0]
            m = root[1]
            RR.append(I(r))
            MM.append(int(m))
        idxs = np.argsort(RR)  # Sort by ascending roots
        RR = (np.array(RR, dtype=dtype)[idxs]).tolist()
        MM = (np.array(MM, dtype=dtype)[idxs]).tolist()
        R.append(RR)
        M.append(MM)
    d = {"X": X, "R": R, "M": M}
    save_pickle(d, folder, "roots.pkl")

    set_seed(seed + 303)
    X = [
        random_coeffs(0, order, 2 * FIELD.degree(), 6 * FIELD.degree())
        for i in range(20)
    ]
    Y = [
        1,
    ] * 10 + [random.randint(2,
                             FIELD.degree() + 1) for i in range(10)]
    Z = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        z = x.derivative(Y[i])
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "derivative.pkl")

    ###############################################################################
    # Polynomial arithmetic functions
    ###############################################################################

    set_seed(seed + 401)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    D = []
    S = []
    T = []
    for i in range(len(X)):
        x = list_to_poly(X[i])
        y = list_to_poly(Y[i])
        d, s, t = xgcd(x, y)
        d = poly_to_list(d)
        s = poly_to_list(s)
        t = poly_to_list(t)
        D.append(d)
        S.append(s)
        T.append(t)
    d = {"X": X, "Y": Y, "D": D, "S": S, "T": T}
    save_pickle(d, folder, "egcd.pkl")

    set_seed(seed + 402)
    X = []
    Z = []
    for i in range(20):
        XX = [
            random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS)
            for i in range(random.randint(2, 5))
        ]
        X.append(XX)
        xx = [list_to_poly(XXi) for XXi in XX]
        z = lcm(xx)
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "lcm.pkl")

    set_seed(seed + 403)
    X = []
    Z = []
    for i in range(20):
        XX = [
            random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS)
            for i in range(random.randint(2, 5))
        ]
        X.append(XX)
        xx = [list_to_poly(XXi) for XXi in XX]
        z = prod(xx)
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "prod.pkl")

    set_seed(seed + 404)
    X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    E = [random.randint(2, 10) for i in range(20)]
    M = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)]
    Z = []
    for i in range(20):
        x = list_to_poly(X[i])
        e = E[i]
        m = list_to_poly(M[i])
        z = (x**e) % m
        z = poly_to_list(z)
        Z.append(z)
    d = {"X": X, "E": E, "M": M, "Z": Z}
    save_pickle(d, folder, "modular_power.pkl")

    set_seed(seed + 405)
    X = [
        0,
    ] * 20  # The remainder
    Y = [
        0,
    ] * 20  # The modulus
    Z = [
        0,
    ] * 20  # The solution
    for i in range(20):
        n = random.randint(2, 4)  # The number of polynomials
        x, y = [], []
        for j in range(n):
            d = random.randint(3, 5)
            x.append(random_coeffs(0, order, d, d + 1))
            y.append(random_coeffs(
                0, order, d + 1, d +
                2))  # Ensure modulus degree is greater than remainder degree
        X[i] = x
        Y[i] = y
        try:
            x = [list_to_poly(xx) for xx in x]
            y = [list_to_poly(yy) for yy in y]
            z = crt(x, y)
            Z[i] = poly_to_list(z)
        except:
            Z[i] = None
    d = {"X": X, "Y": Y, "Z": Z}
    save_pickle(d, folder, "crt.pkl")

    ###############################################################################
    # Special polynomials
    ###############################################################################

    set_seed(seed + 501)
    X = [random_coeffs(0, order, 1, 6) for _ in range(20)]
    Z = [
        False,
    ] * len(X)
    for i in range(len(X)):
        if random.choice(["one", "other"]) == "one":
            X[i][0] = 1
        x = list_to_poly(X[i])
        z = x.is_monic()
        Z[i] = bool(z)
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "is_monic.pkl")

    set_seed(seed + 502)
    IS = []
    IS_NOT = []
    if order <= 2**16:
        while len(IS) < 10:
            x = random_coeffs(0, order, 1, 6)
            f = list_to_poly(x)
            if f.is_irreducible():
                IS.append(x)
        while len(IS_NOT) < 10:
            x = random_coeffs(0, order, 1, 6)
            f = list_to_poly(x)
            if not f.is_irreducible():
                IS_NOT.append(x)
    d = {"IS": IS, "IS_NOT": IS_NOT}
    save_pickle(d, folder, "is_irreducible.pkl")

    set_seed(seed + 503)
    IS = []
    IS_NOT = []
    if order <= 2**16:
        while len(IS) < 10:
            x = random_coeffs(0, order, 1, 6)
            f = list_to_poly(x)
            # f = f / f.coefficients()[-1]  # Make monic
            # assert f.is_monic()
            if f.degree() == 1 and f.coefficients(sparse=False)[0] == 0:
                continue  # For some reason `is_primitive()` crashes on f(x) = a*x
            if not f.is_irreducible():
                continue  # Want to find an irreducible polynomial that is also primitive
            if f.is_primitive():
                IS.append(x)
        while len(IS_NOT) < 10:
            x = random_coeffs(0, order, 1, 6)
            f = list_to_poly(x)
            # f = f / f.coefficients()[-1]  # Make monic
            # assert f.is_monic()
            if f.degree() == 1 and f.coefficients(sparse=False)[0] == 0:
                continue  # For some reason `is_primitive()` crashes on f(x) = a*x
            if not f.is_irreducible():
                continue  # Want to find an irreducible polynomial that is not primitive
            if not f.is_primitive():
                IS_NOT.append(x)
    d = {"IS": IS, "IS_NOT": IS_NOT}
    save_pickle(d, folder, "is_primitive.pkl")

    set_seed(seed + 504)
    if order <= 2**16:
        X = [random_coeffs(0, order, 1, 6) for _ in range(20)]
        Z = [
            False,
        ] * len(X)
        for i in range(len(X)):
            x = list_to_poly(X[i])
            z = x.is_squarefree()
            Z[i] = bool(z)
    else:
        X = []
        Z = []
    d = {"X": X, "Z": Z}
    save_pickle(d, folder, "is_square_free.pkl")
Esempio n. 21
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
Esempio n. 22
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;
Esempio n. 23
0
 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)
Esempio n. 24
0
    def __init__(self, L, **MetaData):
        r"""
        NOTE:

        An instance of ``BarCode2d`` should not be directly constructed.
        Usually, it is obtained as output of
        :meth:`~pGroupCohomology.cohomology.COHO.bar_code`, or as a slice
        of an instance of :class:`~pGroupCohomology.barcode.BarCode`.

        INPUT:

        ``L`` - a list of persistence data
        ``M`` - Metadata in the form of optional parameters

        ASSUMPTIONS:

        ``dict(L)`` should yield a dictionary whose keys give the
        positions and whose values give the marks of a persistence
        matrix. A persistence matrix is an upper triangular
        non-negative integer matrix, with the additional
        property that the matrix columns are increasing from top to
        bottom and the maatrix rows are decreasing from left to right.
        However, this is not a sufficient condition.

        We are sorry for the fact that the numbering of rows and colums
        does not start with zero; instead, the numbering ranges from
        ``-d`` to ``d``, where ``d`` is given by the length of the
        normal series (non-trivial terms only) by which the bar code
        is defined.

        The metadata can be anything. Currently used is:

        - ``degree``, an integer, the degree to which this bar code belongs
        - ``ring``, the name (string) of the cohomology ring of a group ``G``
        - ``command``, the GAP command producing the normal series of ``G``
          by which the bar code is defined.

        EXAMPLES::

            sage: from pGroupCohomology.barcode import BarCode2d
            sage: L = [((-2,-2),2),((-2,-1),2),((-2,0),1),((-2,1),1),((-2,2),0),((-1,-1),3),((-1,0),1),((-1,1),1),((-1,2),0),((0,0),3),((0,1),2),((0,2),1),((1,1),2),((1,2),1),((2,2),2)]
            sage: B = BarCode2d(L, ring='some ring', degree=3, command='my favourite GAP command') # indirect doctest
            sage: B
            Barcode of degree 3 for some ring associated with my favourite GAP command
            sage: ascii_art(B)
                    *
                *-*-*
                *
              *
            *-*-*-*
            *-*
            sage: B.matrix()
            [2 2 1 1 0]
            [0 3 1 1 0]
            [0 0 3 2 1]
            [0 0 0 2 1]
            [0 0 0 0 2]

        """
        from sage.all import copy
        self._Meta = copy(MetaData)
        D = self._D = dict(L)
        l = self._length = max([X[1] for X in D.keys()])
        # our codes will always range from -self._length to +self._length
        bars = []
        lowerbars = dict([(k, 0) for k in range(-l, l + 1)])
        for i in range(-l, l + 1):
            for j in range(l - i + 1):
                n = D[i, l - j] - lowerbars[l - j]  # - drawn
                for k in range(i, l + 1 - j):
                    lowerbars[k] = lowerbars[k] + n
                for k in range(n):
                    bars.append([i, l - j])
        bars.sort()
        bars.reverse()
        self._bars = bars
Esempio n. 25
0
 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)
Esempio n. 26
0
def add_trace_and_norm_ladic(g, D, alpha_geo, verbose=True):
    if verbose:
        print "add_trace_and_norm_ladic()"
    #load Fields
    L = D['L']
    if L is QQ:
        QQx = PolynomialRing(QQ, "x")
        L = NumberField(QQx.gen(), "b")

    prec = D['prec']
    CCap = ComplexField(prec)

    # load endo
    alpha = D['alpha']
    rosati = bound_rosati(alpha_geo)

    if alpha.base_ring() is not L:
        alpha_K = copy(alpha)
        alpha = Matrix(L, 2, 2)
        #shift alpha field from K to L
        for i, row in enumerate(alpha_K.rows()):
            for j, elt in enumerate(row):
                if elt not in L:
                    assert elt.base_ring().absolute_polynomial(
                    ) == L.absolute_polynomial()
                    alpha[i, j] = L(elt.list())
                else:
                    alpha[i, j] = L(elt)

    # load algx_poly
    algx_poly_coeff = D['algx_poly']

    #sometimes, by mistake the algx_poly is defined over K where K == L, but with a different name
    for i, elt in enumerate(algx_poly_coeff):
        if elt not in L:
            assert elt.base_ring().absolute_polynomial(
            ) == L.absolute_polynomial()
            algx_poly_coeff[i] = L(elt.list())
        else:
            algx_poly_coeff[i] = L(elt)

    x_poly = vector(CCap, D['x_poly'])
    for i in [0, 1]:
        assert almost_equal(
            x_poly[i],
            algx_poly_coeff[i]), "%s != %s" % (algx_poly_coeff[i], x_poly[i])

    # load P
    P0 = vector(L, [D['P'][0], D['P'][1]])
    for i, elt in enumerate(P0):
        if elt not in L:
            assert elt.base_ring().absolute_polynomial(
            ) == L.absolute_polynomial()
            P0[i] = L(elt.list())
        else:
            P0[i] = L(elt)
    if verbose:
        print "P0 = %s" % (P0, )

    # load image points, P1 and P2

    L_poly = PolynomialRing(L, "xL")
    xL = L_poly.gen()

    Xpoly = L_poly(algx_poly_coeff)
    if Xpoly.is_irreducible():
        M = Xpoly.root_field("c")
    else:
        # this avoids bifurcation later on in the code, we don't want to be always checking if M is L
        M = NumberField(xL, "c")

    # trying to be sure that we keep the same complex_embedding...
    M_complex_embedding = 0
    if L.gen() not in QQ:
        M_complex_embedding = None
        Lgen_CC = toCCap(L.gen(), prec=prec)
        for i, _ in enumerate(M.complex_embeddings()):
            if norm(Lgen_CC - M(L.gen()).complex_embedding(prec=prec, i=i)
                    ) < CCap(2)**(-0.7 * Lgen_CC.prec()) * Lgen_CC.abs():
                M_complex_embedding = i

        assert M_complex_embedding is not None, "\nL = %s\n%s = %s\n%s" % (
            L, L.gen(), Lgen_CC, M.complex_embeddings())

    M_poly = PolynomialRing(M, "xM")
    xM = M_poly.gen()

    # convert everything to M
    P0_M = vector(M, [elt for elt in P0])
    alpha_M = Matrix(M, [[elt for elt in row] for row in alpha.rows()])
    Xpoly_M = M_poly(Xpoly)

    for i in [0, 1]:
        assert almost_equal(x_poly[i],
                            Xpoly_M.list()[i],
                            ithcomplex_embedding=M_complex_embedding
                            ), "%s != %s" % (Xpoly_M.list()[i], x_poly[i])

    P1 = vector(M, 2)
    P1_ap = vector(CCap, D['R'][0])
    P2 = vector(M, 2)
    P2_ap = vector(CCap, D['R'][1])

    M_Xpoly_roots = Xpoly_M.roots()
    assert len(M_Xpoly_roots) > 0

    Ypoly_M = prod([xM**2 - g(root)
                    for root, _ in M_Xpoly_roots])  # also \in L_poly

    assert sum(m for _, m in Ypoly_M.roots(M)) == Ypoly_M.degree(
    ), "%s != %s\n%s\n%s" % (sum(m for _, m in Ypoly_M.roots(M)),
                             Ypoly_M.degree(), Ypoly_M, Ypoly_M.roots(M))

    if len(M_Xpoly_roots) == 1:
        # we have a double root
        P1[0] = M_Xpoly_roots[0][0]
        P2[0] = M_Xpoly_roots[0][0]
        ae_prec = prec * 0.4
    else:
        assert len(M_Xpoly_roots) == 2
        ae_prec = prec
        # we have two distinct roots
        P1[0] = M_Xpoly_roots[0][0]
        P2[0] = M_Xpoly_roots[1][0]
        if not_equal(P1_ap[0], P1[0],
                     ithcomplex_embedding=M_complex_embedding):
            P1[0] = M_Xpoly_roots[1][0]
            P2[0] = M_Xpoly_roots[0][0]

    assert almost_equal(
        P1_ap[0],
        P1[0],
        ithcomplex_embedding=M_complex_embedding,
        prec=ae_prec), "\n%s = %s \n != %s" % (
            P1[0], toCCap(
                P1[0], ithcomplex_embedding=M_complex_embedding), CC(P1_ap[0]))
    assert almost_equal(
        P2_ap[0],
        P2[0],
        ithcomplex_embedding=M_complex_embedding,
        prec=ae_prec), "\n%s = %s \n != %s" % (
            P2[0], toCCap(
                P2[0], ithcomplex_embedding=M_complex_embedding), CC(P2_ap[0]))

    # figure out the right square root

    # pick the default branch
    P1[1] = sqrt(g(P1[0]))
    P2[1] = sqrt(g(P2[0]))

    if 0 in [P1[1], P2[1]]:
        print "one of image points is a Weirstrass point"
        print P1
        print P2
        raise ZeroDivisionError

    #switch if necessary
    if not_equal(P1_ap[1],
                 P1[1],
                 ithcomplex_embedding=M_complex_embedding,
                 prec=ae_prec):
        P1[1] *= -1

    if not_equal(P2_ap[1],
                 P2[1],
                 ithcomplex_embedding=M_complex_embedding,
                 prec=ae_prec):
        P2[1] *= -1

    # double check
    for i in [0, 1]:
        assert almost_equal(P1_ap[i],
                            P1[i],
                            ithcomplex_embedding=M_complex_embedding,
                            prec=ae_prec), "%s != %s" % (P1_ap[i], P1[i])
        assert almost_equal(P2_ap[i],
                            P2[i],
                            ithcomplex_embedding=M_complex_embedding,
                            prec=ae_prec), "%s != %s" % (P2_ap[i], P2[i])

    # now alpha, P0 \in L
    # P1, P2 \in L

    if verbose:
        print "P1 = %s\nP2 = %s" % (P1, P2)
        print "Computing the trace and the norm ladically\n"
        trace_and_norm = trace_and_norm_ladic(L,
                                              M,
                                              P0_M,
                                              P1,
                                              P2,
                                              g,
                                              2 * alpha_M,
                                              16 * rosati,
                                              primes=ceil(prec * L.degree() /
                                                          61))
    else:
        trace_and_norm = trace_and_norm_ladic(L,
                                              M,
                                              P0_M,
                                              P1,
                                              P2,
                                              g,
                                              2 * alpha_M,
                                              16 * rosati,
                                              primes=ceil(prec * L.degree() /
                                                          61))

    # Convert the coefficients to polynomials
    trace_numerator, trace_denominator, norm_numerator, norm_denominator = [
        L_poly(coeff) for coeff in trace_and_norm
    ]

    assert trace_numerator(P0[0]) == trace_denominator(
        P0[0]) * -algx_poly_coeff[1], "%s/%s (%s) != %s" % (
            trace_numerator, trace_denominator, P0[0], -algx_poly_coeff[1])
    assert norm_numerator(P0[0]) == norm_denominator(
        P0[0]) * algx_poly_coeff[0], "%s/%s (%s) != %s" % (
            norm_numerator, norm_denominator, P0[0], algx_poly_coeff[0])
    buffer = "# x1 + x2 = degree %d/ degree %d\n" % (
        trace_numerator.degree(), trace_denominator.degree())
    buffer += "# = (%s) / (%s) \n" % (trace_numerator, trace_denominator)
    buffer += "# max(%d, %d) <= %d\n\n" % (
        trace_numerator.degree(), trace_denominator.degree(), 16 * rosati)

    buffer += "# x1 * x2 = degree %d/ degree %d\n" % (
        norm_numerator.degree(), norm_denominator.degree())
    buffer += "# = (%s) / (%s) \n" % (norm_numerator, norm_denominator)
    buffer += "# max(%d, %d) <= %d\n" % (
        norm_numerator.degree(), norm_denominator.degree(), 16 * rosati)

    if verbose:
        print buffer
        print "\n"
    assert max(trace_numerator.degree(),
               trace_denominator.degree()) <= 16 * rosati
    assert max(norm_numerator.degree(),
               norm_denominator.degree()) <= 16 * rosati

    if verbose:
        print "Veritfying if x1*x2 and x1 + x2 are correct..."

    verified = verify_algebraically(g,
                                    P0,
                                    alpha,
                                    trace_and_norm,
                                    verbose=verbose)
    if verbose:
        print "\nDoes it act on the tangent space as expected? %s\n" % verified
        print "Done add_trace_and_norm_ladic()"

    return verified, [
        trace_numerator.list(),
        trace_denominator.list(),
        norm_numerator.list(),
        norm_denominator.list()
    ]
Esempio n. 27
0
def main(filein,
         vhdl_fileout,
         blocksize=256,
         keysize=256,
         rounds=19,
         sboxes=10):
    with io.open(filein, 'rb') as matfile:
        inst = pickle.load(matfile)

    if inst.n != blocksize or inst.k != keysize or inst.r != rounds:
        raise ValueError("Unexpected LowMC instance.")
    if blocksize != keysize:
        raise ValueError("Only blocksize == keysize is currently supported!")

    P = matrix(F, blocksize, blocksize)
    for i in range(blocksize):
        P[blocksize - i - 1, i] = 1

    Ls = [P * matrix(F, L) * P for L in inst.L]
    Ks = [P * matrix(F, K) * P for K in inst.K]
    Cs = [P * vector(F, C) for C in inst.R]

    Kt = [m.transpose() for m in Ks]
    Lt = [m.transpose() for m in Ls]

    Li = [m.inverse() for m in Lt]
    LiK = [Kt[i + 1] * Li[i] for i in range(inst.r)]
    LiC = [Cs[i] * Li[i] for i in range(inst.r)]

    mod_Li = [copy(Li[i]) for i in range(inst.r)]
    for j in range(inst.r):
        mod_Li[j][inst.n - 3 * sboxes:, :inst.n] = matrix(
            F, 3 * sboxes, inst.n)

    precomputed_key_matrix = None
    precomputed_key_matrix_nl = matrix(F, inst.n, (sboxes * 3) * inst.r)
    precomputed_constant = None
    precomputed_constant_nl = vector(F, (sboxes * 3) * inst.r)

    for round in range(inst.r):
        tmp = copy(LiK[round])
        tmpC = copy(LiC[round])

        for i in range(round + 1, inst.r):
            x = LiK[i]
            c = LiC[i]
            for j in range(i - 1, round - 1, -1):
                x = x * mod_Li[j]
                c = c * mod_Li[j]
            tmp += x
            tmpC += c

        # non-linear part
        idx = round * (3 * sboxes)
        precomputed_key_matrix_nl[:inst.n,
                                  idx:idx + 3 * sboxes] = tmp[:inst.n, inst.n -
                                                              3 * sboxes:]
        precomputed_constant_nl[idx:idx + 3 * sboxes] = tmpC[inst.n -
                                                             3 * sboxes:]

        # linear part
        if round == 0:
            tmp[:, inst.n - 3 * sboxes:] = matrix(F, inst.n, 3 * sboxes)
            tmpC[inst.n - 3 * sboxes:] = vector(F, 3 * sboxes)
            precomputed_key_matrix = tmp
            precomputed_constant = tmpC

    #RRKC precomputation done
    R_full = []
    R_dot = []
    R_dot_inv = []
    R_wedge = []
    T_vee = []
    R_wedge_snipped = []
    R_cols = []
    Z_i = []

    # i = 1
    R_full.append(Lt[0][:, 0:inst.n - 3 * sboxes])
    Rdot, colR = calc_dot_from_full_rank(R_full[0])
    R_dot.append(Rdot)
    R_dot_inv.append(R_dot[0].inverse())
    R_cols.append(colR)

    R_wedge.append(R_full[0] * R_dot_inv[0])
    Z_i.append(Lt[0][:, inst.n - 3 * sboxes:inst.n])
    R_wedge_snipped.append(snip_r_wedge(R_wedge[0], colR))

    # i = 2...r-1
    for i in range(1, rounds - 1):
        T_vee.append(R_dot[i - 1] * Lt[i][0:inst.n - sboxes * 3, :])
        R = matrix(F, inst.n, inst.n - sboxes * 3)
        R[0:inst.n - 3 * sboxes, :] = T_vee[-1][0:inst.n - 3 * sboxes,
                                                0:inst.n - 3 * sboxes]
        R[inst.n - 3 * sboxes:inst.n, :] = Lt[i][inst.n - 3 * sboxes:inst.n,
                                                 0:inst.n - 3 * sboxes]
        R_full.append(R)
        Rdot, colR = calc_dot_from_full_rank(R_full[i])
        R_dot.append(Rdot)
        R_dot_inv.append(R_dot[i].inverse())
        R_cols.append(colR)
        R_wedge.append(R_full[i] * R_dot_inv[i])
        Z_i.append(
            T_vee[i - 1][0:inst.n - 3 * sboxes,
                         inst.n - 3 * sboxes:inst.n].transpose().augment(
                             Lt[i][inst.n - sboxes * 3:inst.n, inst.n -
                                   sboxes * 3:inst.n].transpose()).transpose())
        R_wedge_snipped.append(snip_r_wedge(R_wedge[-1], colR))

    # i = r
    T_vee.append(R_dot[rounds - 2] * Lt[rounds - 1][0:inst.n - sboxes * 3, :])

    # vhdl fileout
    with io.open(vhdl_fileout, 'w') as matfile:
        matfile.write("library ieee;\n")
        matfile.write("use ieee.std_logic_1164.all;\n\n")
        matfile.write("library work;\n\n")
        matfile.write("package lowmc_pkg is\n")
        matfile.write("  constant N : integer := {};\n".format(blocksize))
        matfile.write("  constant K : integer := {};\n".format(keysize))
        matfile.write("  constant M : integer := {};\n".format(sboxes))
        matfile.write("  constant R : integer := {};\n".format(rounds))
        matfile.write("  constant S : integer := {};\n\n".format(3 * sboxes))

        matfile.write(
            "  type T_NK_MATRIX is array(0 to N - 1) of std_logic_vector(K - 1 downto 0);\n"
        )
        matfile.write(
            "  type T_NN_MATRIX is array(0 to N - 1) of std_logic_vector(N - 1 downto 0);\n"
        )
        matfile.write(
            "  type T_SK_MATRIX is array(0 to S - 1) of std_logic_vector(K - 1 downto 0);\n"
        )
        matfile.write(
            "  type T_SN_MATRIX is array(0 to S - 1) of std_logic_vector(N - 1 downto 0);\n"
        )
        matfile.write(
            "  type T_NSS_MATRIX is array(0 to (N - S) - 1) of std_logic_vector(S - 1 downto 0);\n"
        )
        matfile.write(
            "  type T_RS_MATRIX is array(0 to R - 1) of std_logic_vector(S - 1 downto 0);\n\n"
        )

        matfile.write(
            "  type T_KMATRIX is array (0 to R - 1) of T_SK_MATRIX;\n")
        matfile.write(
            "  type T_ZMATRIX is array (0 to R - 2) of T_SN_MATRIX;\n")
        matfile.write(
            "  type T_RMATRIX is array (0 to R - 2) of T_NSS_MATRIX;\n\n")

        # linaer part of key matrices (n x k)
        K0 = (precomputed_key_matrix + Kt[0]).transpose()
        matfile.write("  constant K0 : T_NK_MATRIX := (\n")
        for i, k in enumerate(K0):
            print_vector_vhdl(matfile, k, keysize)
            if i != K0.nrows() - 1:
                matfile.write(",")
            matfile.write("\n")
        matfile.write("  );\n\n")

        # nonlinear part of key matrices (s x k)
        precomputed_key_matrix_nlt = precomputed_key_matrix_nl.transpose()
        matfile.write("  constant KMATRIX : T_KMATRIX := (\n")
        for i in range(rounds):
            index_a = i * sboxes * 3
            index_b = (i + 1) * sboxes * 3
            print_matrix_vhdl(matfile,
                              precomputed_key_matrix_nlt[index_a:index_b],
                              keysize)
            if i != rounds - 1:
                matfile.write(",")
            matfile.write("\n")
        matfile.write("  );\n\n")

        # linear part of Constants (n x 1)
        matfile.write(
            "  constant C0 : std_logic_vector(N - 1 downto 0) := (\n")
        print_vector_vhdl(matfile, precomputed_constant, blocksize)
        matfile.write("\n")
        matfile.write("  );\n\n")

        # nonlinear part of Constants (s x 1)
        matfile.write("  constant CONSTANTS : T_RS_MATRIX := (\n")
        for i in range(rounds):
            index_a = i * sboxes * 3
            index_b = (i + 1) * sboxes * 3
            print_vector_vhdl(matfile,
                              precomputed_constant_nl[index_a:index_b],
                              sboxes * 3)
            if i != rounds - 1:
                matfile.write(",")
            matfile.write("\n")
        matfile.write("  );\n\n")

        # L1_0* (s x n)
        L1 = Lt[0][:, blocksize - 3 * sboxes:blocksize].transpose()
        # Z_i (s x n)
        matfile.write("  constant ZMATRIX : T_ZMATRIX := (\n")
        for i in range(0, rounds - 1):
            if i == 0:
                print_matrix_vhdl(matfile, L1, blocksize)
            else:
                print_matrix_vhdl(matfile, Z_i[i].transpose(), blocksize)
            if i != rounds - 2:
                matfile.write(",")
            matfile.write("\n")
        matfile.write("  );\n\n")

        # Z_r (s x s)
        Z_r = T_vee[-1].transpose().augment(
            Lt[-1][inst.n - sboxes * 3:inst.n, :].transpose())
        matfile.write("  constant ZR : T_NN_MATRIX := (\n")
        for i, z in enumerate(Z_r):
            print_vector_vhdl(matfile, z, blocksize)
            if i != Z_r.nrows() - 1:
                matfile.write(",")
            matfile.write("\n")
        matfile.write("  );\n\n")

        # Ri_wedge_snipped ((n - s) x s)
        matfile.write("  constant RMATRIX : T_RMATRIX := (\n")
        for i in range(0, rounds - 1):
            Ri = R_wedge_snipped[i].transpose()
            print_matrix_vhdl(matfile, Ri, sboxes * 3)
            if i != rounds - 2:
                matfile.write(",")
            matfile.write("\n")
        matfile.write("  );\n\n")

        matfile.write(
            "-------------------------------------------------------------------------------\n\n"
        )

        matfile.write("  -- constants for State permutation for RMATRIX\n")
        max = 0
        for i, R in enumerate(R_cols):
            if len(R) > max:
                max = len(R)

        matfile.write(
            "  type INT_ARRAY is array(integer range <>) of integer;\n")
        if (max > 0):
            matfile.write(
                "  type R_C_ARRAY is array(0 to {}) of integer;\n".format(max -
                                                                          1))
            matfile.write(
                "  type R_ARRAY is array(0 to R - 2) of R_C_ARRAY;\n\n")

        matfile.write("  -- number of columns to swap per matrix\n")
        matfile.write("  constant R_CC : INT_ARRAY(0 to R - 2) := (\n")
        for i, R in enumerate(R_cols):
            matfile.write("    {}".format(len(R)))
            if (i != len(R_cols) - 1):
                matfile.write(",")
            matfile.write("\n")
        matfile.write("  );\n\n")

        matfile.write("  -- columns to swap per matrix\n")
        matfile.write("  constant R_C : R_ARRAY := (\n")
        for i, R in enumerate(R_cols):
            matfile.write("    (\n")
            matfile.write("      ")
            for j in range(max):
                idx = 0
                if j < len(R):
                    idx = R[j]
                matfile.write("{}".format(idx))
                if (j != max - 1):
                    matfile.write(", ")
            matfile.write("\n")
            matfile.write("    )")
            if (i != len(R_cols) - 1):
                matfile.write(",")
            matfile.write("\n")
        matfile.write("  );\n\n")

        matfile.write("end lowmc_pkg;\n")