Ejemplo n.º 1
0
    def __init__(self, projection_direction, height = 1.1):
        """
        Initializes the projection.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.plot import ProjectionFuncSchlegel
            sage: proj = ProjectionFuncSchlegel([2,2,2])
            sage: proj.__init__([2,2,2])
            sage: proj(vector([1.1,1.1,1.11]))[0]
            0.0302...
            sage: TestSuite(proj).run(skip='_test_pickling')
        """
        self.projection_dir = vector(RDF, projection_direction)
        if norm(self.projection_dir).is_zero():
            raise ValueError, "projection direction must be a non-zero vector."
        self.dim = self.projection_dir.degree()
        spcenter = height * self.projection_dir/norm(self.projection_dir)
        self.height = height
        v = vector(RDF, [0.0]*(self.dim-1) + [self.height]) - spcenter
        polediff = matrix(RDF,v).transpose()
        denom = (polediff.transpose()*polediff)[0][0]
        if denom.is_zero():
            self.house = identity_matrix(RDF,self.dim)
        else:
            self.house = identity_matrix(RDF,self.dim) \
            - 2*polediff*polediff.transpose()/denom #Householder reflector
Ejemplo n.º 2
0
    def mutate(self, k, mutating_F=True):
        r"""
        mutate seed
        bla bla ba
        """
        n = self.parent().rk

        if k not in xrange(n):
            raise ValueError('Cannot mutate in direction ' + str(k) + '.')

        # store mutation path
        if self._path != [] and self._path[-1] == k:
            self._path.pop()
        else:
            self._path.append(k)

        # find sign of k-th c-vector
        # Will this be used enough that it should be a built-in function?
        if any(x > 0 for x in self._C.column(k)):
            eps = +1
        else:
            eps = -1

        # store the g-vector to be mutated in case we are mutating F-polynomials also
        old_g_vector = self.g_vector(k)

        # G-matrix
        J = identity_matrix(n)
        for j in xrange(n):
            J[j,k] += max(0, -eps*self._B[j,k])
        J[k,k] = -1
        self._G = self._G*J

        # g-vector path list
        g_vector = self.g_vector(k)
        if g_vector not in self.parent().g_vectors_so_far():
            self.parent()._path_dict[g_vector] = copy(self._path)
            # F-polynomials
            if mutating_F:
                self.parent()._F_poly_dict[g_vector] = self._mutated_F(k, old_g_vector)

        # C-matrix
        J = identity_matrix(n)
        for j in xrange(n):
            J[k,j] += max(0, eps*self._B[k,j])
        J[k,k] = -1
        self._C = self._C*J

        # B-matrix
        self._B.mutate(k)

        # exchange relation
        if self.parent()._store_exchange_relations:
            ex_pair = frozenset([g_vector,old_g_vector])
            if ex_pair not in self.parent()._exchange_relations:
                coefficient = self.coefficient(k).lift()
                variables = zip(self.g_vectors(), self.b_matrix().column(k))
                Mp = [ (g,p) for (g,p) in variables if p > 0 ]
                Mm = [ (g,-p) for (g,p) in variables if p < 0 ]
                self.parent()._exchange_relations[ex_pair] = ( (Mp,coefficient.numerator()), (Mm,coefficient.denominator()) )
Ejemplo n.º 3
0
    def __init__(self, projection_point):
        """
        Create a stereographic projection function.

        INPUT:

        - ``projection_point`` -- a list of coordinates in the
          appropriate dimension, which is the point projected from.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.plot import ProjectionFuncStereographic
            sage: proj = ProjectionFuncStereographic([1.0,1.0])
            sage: proj.__init__([1.0,1.0])
            sage: proj.house
            [-0.7071067811...  0.7071067811...]
            [ 0.7071067811...  0.7071067811...]
            sage: TestSuite(proj).run(skip='_test_pickling')
        """
        self.projection_point = vector(projection_point)
        self.dim = self.projection_point.degree()

        pproj = vector(RDF,self.projection_point)
        self.psize = norm(pproj)
        if (self.psize).is_zero():
            raise ValueError, "projection direction must be a non-zero vector."
        v = vector(RDF, [0.0]*(self.dim-1) + [self.psize]) - pproj
        polediff = matrix(RDF,v).transpose()
        denom = RDF((polediff.transpose()*polediff)[0][0])
        if denom.is_zero():
            self.house = identity_matrix(RDF,self.dim)
        else:
            self.house = identity_matrix(RDF,self.dim) \
            - 2*polediff*polediff.transpose()/denom   # Householder reflector
Ejemplo n.º 4
0
    def mutate(self, sequence, inplace=True, mutate_F=True):
        if not isinstance(mutate_F, bool):
            raise ValueError('mutate_F must be boolean.')

        if not isinstance(inplace, bool):
            raise ValueError('inplace must be boolean.')
        if inplace:
            seed = self.current_seed
        else:
            seed = copy(self.current_seed)
            
        if sequence in xrange(seed._n):
            seq = iter([sequence])
        else:
            seq = iter(sequence)
            
        for k in seq:
            if k not in xrange(seed._n):
                raise ValueError('Cannot mutate in direction' + str(k) + '.')

            # G-matrix
            J = identity_matrix(seed._n)
            if any(x > 0 for x in seed._C.column(k)):
                eps = +1
            else:
                eps = -1
            for j in xrange(seed._n):
                J[j,k] += max(0, -eps*seed._B[j,k])
            J[k,k] = -1
            seed._G = seed._G*J

            # F-polynomials
            if mutating_F:
                gvect = tuple(seed._G.column(k))
                if not self._F_dict.has_key(gvect):
                    self._F_dict.setdefault(gvect,self._mutated_F(k))
                seed._F[k] = self._F_dict[gvect]
            
            # C-matrix
            J = identity_matrix(seed._n)
            if any(x > 0 for x in seed._C.column(k)):
                eps = +1
            else:
                eps = -1
            for j in xrange(seed._n):
                J[k,j] += max(0, eps*seed._B[k,j])
            J[k,k] = -1
            seed._C = seed._C*J
            
            # B-matrix
            seed._B.mutate(k)
            
        if not inplace:
            return seed
Ejemplo n.º 5
0
    def _extend1(self):
        "Increases the matrix size by 1"

        #save current self
        self.iv0 = copy(self)
        self.iv0.abel_raw0 = lambda z: self.iv0.abel0poly(z-self.iv0.x0)

        N = self.N

        A = self.A
        #Carleman matrix without 0-th row:
        Ct = A + identity_matrix(self.R,N).submatrix(1,0,N-1,N-1)
        AI = self.AI
        #assert AI*self.A == identity_matrix(N-1)

        if isinstance(self.f,FormalPowerSeries):
            coeffs = [ self.f[n] for n in xrange(0,N) ]
        else:
            x = self.f.args()[0]
            coeffs = taylor(self.f.substitute({x:x+self.x0sym})-self.x0sym,x,0,N).polynomial(self.R)

        self.Ct = matrix(self.R,N,N)
        self.Ct.set_block(0,0,Ct)
        self.Ct[0,N-1] = coeffs[N-1]
        for m in range(1,N-1):
            self.Ct[m,N-1] = psmul_at(self.Ct[0],self.Ct[m-1],N-1)
        self.Ct[N-1] = psmul(self.Ct[0],self.Ct[N-2])

        print "C extended"
        self.A = self.Ct - identity_matrix(self.R,N+1).submatrix(1,0,N,N)

        av=self.A.column(N-1)[:N-1]
        ah=self.A.row(N-1)[:N-1]
        a_n=self.A[N-1,N-1]

        # print 'A:';print A
        # print 'A\''; print self.A
        # print 'ah:',ah
        # print 'av:',av
        # print 'a_n:',a_n

        AI0 = matrix(self.R,N,N)
        AI0.set_block(0,0,self.AI)

        horiz = matrix(self.R,1,N)
        horiz.set_block(0,0,(ah*AI).transpose().transpose())
        horiz[0,N-1] = -1

        vert = matrix(self.R,N,1)
        vert.set_block(0,0,(AI*av).transpose())
        vert[N-1,0] = -1

        self.N += 1
        self.AI = AI0 +  vert*horiz/(a_n-ah*AI*av)
Ejemplo n.º 6
0
Archivo: braid.py Proyecto: CETHop/sage
    def burau_matrix(self, var='t'):
        """
        Return the Burau matrix of the braid.

        INPUT:

        - ``var`` -- string (default: ``'t'``). The name of the
          variable in the entries of the matrix.

        OUTPUT:

        The Burau matrix of the braid. It is a matrix whose entries
        are Laurent polynomials in the variable ``var``.

        EXAMPLES::

            sage: B = BraidGroup(4)
            sage: B.inject_variables()
            Defining s0, s1, s2
            sage: b=s0*s1/s2/s1
            sage: b.burau_matrix()
            [     -t + 1           0    -t^2 + t         t^2]
            [          1           0           0           0]
            [          0           0           1           0]
            [          0        t^-2 t^-1 - t^-2    1 - t^-1]
            sage: s2.burau_matrix('x')
            [     1      0      0      0]
            [     0      1      0      0]
            [     0      0 -x + 1      x]
            [     0      0      1      0]

        REFERENCES:

            http://en.wikipedia.org/wiki/Burau_representation
        """
        R = LaurentPolynomialRing(IntegerRing(), var)
        t = R.gen()
        M = identity_matrix(R, self.strands())
        for i in self.Tietze():
            A = identity_matrix(R, self.strands())
            if i>0:
                A[i-1, i-1] = 1-t
                A[i, i] = 0
                A[i, i-1] = 1
                A[i-1, i] = t
            if i<0:
                A[-1-i, -1-i] = 0
                A[-i, -i] = 1-t**(-1)
                A[-1-i, -i] = 1
                A[-i, -1-i] = t**(-1)
            M=M*A
        return M
Ejemplo n.º 7
0
    def mutate_initial(self, k):
        r"""
        Mutate ``self`` in direction `k` at the initial cluster.

        INPUT:
        - ``k`` -- integer in between 0 and ``self.rk``
        """
        n = self.rk

        if k not in xrange(n):
            raise ValueError('Cannot mutate in direction %s, please try a value between 0 and %s.'%(str(k),str(n-1)))

        #modify self._path_dict using Nakanishi-Zelevinsky (4.1) and self._F_poly_dict using CA-IV (6.21)
        new_path_dict = dict()
        new_F_dict = dict()
        new_path_dict[tuple(identity_matrix(n).column(k))] = []
        new_F_dict[tuple(identity_matrix(n).column(k))] = self._U(1)

        poly_ring = PolynomialRing(ZZ,'u')
        h_subs_tuple = tuple([poly_ring.gen(0)**(-1) if j==k else poly_ring.gen(0)**max(-self._B0[k][j],0) for j in xrange(n)])
        F_subs_tuple = tuple([self._U.gen(k)**(-1) if j==k else self._U.gen(j)*self._U.gen(k)**max(-self._B0[k][j],0)*(1+self._U.gen(k))**(self._B0[k][j]) for j in xrange(n)])

        for g_vect in self._path_dict:
            #compute new path
            path = self._path_dict[g_vect]
            if g_vect == tuple(identity_matrix(n).column(k)):
                new_path = [k]
            elif path != []:
                if path[0] != k:
                    new_path = [k] + path
                else:
                    new_path = path[1:]
            else:
                new_path = []

            #compute new g-vector
            new_g_vect = vector(g_vect) - 2*g_vect[k]*identity_matrix(n).column(k)
            for i in xrange(n):
                new_g_vect += max(sign(g_vect[k])*self._B0[i,k],0)*g_vect[k]*identity_matrix(n).column(i)
            new_path_dict[tuple(new_g_vect)] = new_path

            #compute new F-polynomial
            h = 0
            trop = tropical_evaluation(self._F_poly_dict[g_vect](h_subs_tuple))
            if trop != 1:
                h = trop.denominator().exponents()[0]-trop.numerator().exponents()[0]
            new_F_dict[tuple(new_g_vect)] = self._F_poly_dict[g_vect](F_subs_tuple)*self._U.gen(k)**h*(self._U.gen(k)+1)**g_vect[k]

        self._path_dict = new_path_dict
        self._F_poly_dict = new_F_dict

        self._B0.mutate(k)
Ejemplo n.º 8
0
 def initial_seed(self):
     r"""
     Return the initial seed
     """
     n = self.rk
     I = identity_matrix(n)
     return ClusterAlgebraSeed(self._B0, I, I, self)
Ejemplo n.º 9
0
    def invariant_form(self):
        """
        Return the hermitian form preserved by the unitary
        group.

        OUTPUT:

        A square matrix describing the bilinear form

        EXAMPLES::

            sage: SU4 = SU(4,QQ)
            sage: SU4.invariant_form()
            [1 0 0 0]
            [0 1 0 0]
            [0 0 1 0]
            [0 0 0 1]
        """
        if self._invariant_form is not None:
            return self._invariant_form

        from sage.matrix.constructor import identity_matrix
        m = identity_matrix(self.base_ring(), self.degree())
        m.set_immutable()
        return m
Ejemplo n.º 10
0
    def initial_pair(self):
        """
        Return an initial double description pair.

        Picks an initial set of rays by selecting a basis. This is
        probably the most efficient way to select the initial set.

        INPUT:

        - ``pair_class`` -- subclass of
          :class:`DoubleDescriptionPair`.

        OUTPUT:

        A pair consisting of a :class:`DoubleDescriptionPair` instance
        and the tuple of remaining unused inequalities.

        EXAMPLES::

            sage: A = matrix([(-1, 1), (-1, 2), (1/2, -1/2), (1/2, 2)])
            sage: from sage.geometry.polyhedron.double_description import Problem
            sage: DD, remaining = Problem(A).initial_pair()
            sage: DD.verify()
            sage: remaining
            [(1/2, -1/2), (1/2, 2)]
        """
        pivot_rows = self.A_matrix().pivot_rows()
        A0 = [self.A()[pivot] for pivot in pivot_rows]
        Ac = [self.A()[i] for i in range(len(self.A())) if i not in pivot_rows]
        from sage.matrix.constructor import identity_matrix, matrix
        I = identity_matrix(self.base_ring(), self.dim())
        R = matrix(self.base_ring(), A0).solve_right(I)
        return self.pair_class(self, A0, R.columns()), list(Ac)
Ejemplo n.º 11
0
 def initial_seed(self):
     r"""
     Return the initial seed
     """
     n = self.rk
     I = identity_matrix(n)
     return ClusterAlgebraSeed(self._B0, I, I, self)
Ejemplo n.º 12
0
    def ARP(self):
        from sage.matrix.constructor import identity_matrix
        A1 = matrix(3, [1,1,1, 0,1,0, 0,0,1])
        A2 = matrix(3, [1,0,0, 1,1,1, 0,0,1])
        A3 = matrix(3, [1,0,0, 0,1,0, 1,1,1])
        P12 = matrix(3, [1,0,1, 1,1,1, 0,0,1])
        P13 = matrix(3, [1,1,0, 0,1,0, 1,1,1])
        P23 = matrix(3, [1,0,0, 1,1,0, 1,1,1])
        P21 = matrix(3, [1,1,1, 0,1,1, 0,0,1])
        P31 = matrix(3, [1,1,1, 0,1,0, 0,1,1])
        P32 = matrix(3, [1,0,0, 1,1,1, 1,0,1])
        gens = (A1, A2, A3, P23, P32, P13, P31, P12, P21)
        alphabet = [1, 2, 3, 123, 132, 213, 231, 312, 321]
        gens = dict(zip(alphabet, gens))

        cone = {}
        cone[123] = H23 = matrix(3, [1,0,1, 0,1,0, 0,0,1])
        cone[132] = H32 = matrix(3, [1,1,0, 0,1,0, 0,0,1])
        cone[213] = H13 = matrix(3, [1,0,0, 0,1,1, 0,0,1])
        cone[231] = H31 = matrix(3, [1,0,0, 1,1,0, 0,0,1])
        cone[312] = H12 = matrix(3, [1,0,0, 0,1,0, 0,1,1])
        cone[321] = H21 = matrix(3, [1,0,0, 0,1,0, 1,0,1])
        cone[1] = cone[2] = cone[3] = identity_matrix(3) 

        from .language import languages
        return MatrixCocycle(gens, cone, language=languages.ARP())
Ejemplo n.º 13
0
    def calculate_generators(self):
        """
        If generators haven't already been computed, calculate generators
        for this homspace. If they have been computed, do nothing.

        EXAMPLES::

            sage: E = End(J0(11))
            sage: E.calculate_generators()
        """

        if self._gens is not None:
            return

        if (self.domain() == self.codomain()) and (self.domain().dimension() == 1):
            self._gens = tuple([ identity_matrix(ZZ,2) ])
            return

        phi = self.domain()._isogeny_to_product_of_powers()
        psi = self.codomain()._isogeny_to_product_of_powers()

        H_simple = phi.codomain().Hom(psi.codomain())
        im_gens = H_simple._calculate_product_gens()

        M = phi.matrix()
        Mt = psi.complementary_isogeny().matrix()

        R = ZZ**(4*self.domain().dimension()*self.codomain().dimension())
        gens = R.submodule([ (M*self._get_matrix(g)*Mt).list()
                             for g in im_gens ]).saturation().basis()
        self._gens = tuple([ self._get_matrix(g) for g in gens ])
Ejemplo n.º 14
0
    def calculate_generators(self):
        """
        If generators haven't already been computed, calculate generators
        for this homspace. If they have been computed, do nothing.

        EXAMPLES::

            sage: E = End(J0(11))
            sage: E.calculate_generators()
        """

        if self._gens is not None:
            return

        if (self.domain() == self.codomain()) and (self.domain().dimension()
                                                   == 1):
            self._gens = tuple([identity_matrix(ZZ, 2)])
            return

        phi = self.domain()._isogeny_to_product_of_powers()
        psi = self.codomain()._isogeny_to_product_of_powers()

        H_simple = phi.codomain().Hom(psi.codomain())
        im_gens = H_simple._calculate_product_gens()

        M = phi.matrix()
        Mt = psi.complementary_isogeny().matrix()

        R = ZZ**(4 * self.domain().dimension() * self.codomain().dimension())
        gens = R.submodule([(M * self._get_matrix(g) * Mt).list()
                            for g in im_gens]).saturation().basis()
        self._gens = tuple([self._get_matrix(g) for g in gens])
Ejemplo n.º 15
0
    def initial_pair(self):
        """
        Return an initial double description pair.

        Picks an initial set of rays by selecting a basis. This is
        probably the most efficient way to select the initial set.

        INPUT:

        - ``pair_class`` -- subclass of
          :class:`DoubleDescriptionPair`.

        OUTPUT:

        A pair consisting of a :class:`DoubleDescriptionPair` instance
        and the tuple of remaining unused inequalities.

        EXAMPLES::

            sage: A = matrix([(-1, 1), (-1, 2), (1/2, -1/2), (1/2, 2)])
            sage: from sage.geometry.polyhedron.double_description import Problem
            sage: DD, remaining = Problem(A).initial_pair()
            sage: DD.verify()
            sage: remaining
            [(1/2, -1/2), (1/2, 2)]
        """
        pivot_rows = self.A_matrix().pivot_rows()
        A0 = [self.A()[pivot] for pivot in pivot_rows]
        Ac = [self.A()[i] for i in range(len(self.A())) if i not in pivot_rows]
        from sage.matrix.constructor import identity_matrix, matrix
        I = identity_matrix(self.base_ring(), self.dim())
        R = matrix(self.base_ring(), A0).solve_right(I)
        return self.pair_class(self, A0, R.columns()), list(Ac)
Ejemplo n.º 16
0
    def __init__(self, similarity_surface):
        if similarity_surface.underlying_surface().is_mutable():
            if similarity_surface.is_finite():
                self._ss=similarity_surface.copy()
            else:
                raise ValueError("Can not construct MinimalTranslationCover of a surface that is mutable and infinite.")
        else:
            self._ss = similarity_surface

        # We are finite if and only if self._ss is a finite RationalConeSurface.
        if not self._ss.is_finite():
            finite = False
        else:
            try:
                from flatsurf.geometry.rational_cone_surface import RationalConeSurface
                ss_copy = self._ss.reposition_polygons(relabel=True)
                rcs = RationalConeSurface(ss_copy)
                rcs._test_edge_matrix()
                finite=True
            except AssertionError:
                # print("Warning: Could be indicating infinite surface falsely.")
                finite=False
        
        I = identity_matrix(self._ss.base_ring(),2)
        I.set_immutable()
        base_label=(self._ss.base_label(), I)
        
        Surface.__init__(self, self._ss.base_ring(), base_label, finite=finite, mutable=False)
Ejemplo n.º 17
0
def calculate_voronoi_cell(basis, radius=None, verbose=False):
    """
    Calculate the Voronoi cell of the lattice defined by basis

    INPUT:

    - ``basis`` -- embedded basis matrix of the lattice

    - ``radius`` -- radius of basis vectors to consider

    - ``verbose`` -- whether to print debug information

    OUTPUT:

    A :class:`Polyhedron` instance.

    EXAMPLES::

        sage: from sage.modules.diamond_cutting import calculate_voronoi_cell
        sage: V = calculate_voronoi_cell(matrix([[1, 0], [0, 1]]))
        sage: V.volume()
        1
    """

    dim = basis.dimensions()
    artificial_length = None
    if dim[0] < dim[1]:
        # introduce "artificial" basis points (representing infinity)
        artificial_length = max(abs(v) for v in basis).ceil() * 2
        additional_vectors = identity_matrix(dim[1]) * artificial_length
        basis = basis.stack(additional_vectors)
        # LLL-reduce to get quadratic matrix
        basis = basis.LLL()
        basis = matrix([v for v in basis if v])
        dim = basis.dimensions()
    if dim[0] != dim[1]:
        raise ValueError("invalid matrix")
    basis = basis / 2

    ieqs = []
    for v in basis:
        ieqs.append(plane_inequality(v))
        ieqs.append(plane_inequality(-v))
    Q = Polyhedron(ieqs=ieqs)

    # twice the length of longest vertex in Q is a safe choice
    if radius is None:
        radius = 2 * max(abs(v) ** 2 for v in basis)

    V = diamond_cut(Q, basis, radius, verbose=verbose)

    if artificial_length is not None:
        # remove inequalities introduced by artificial basis points
        H = V.Hrepresentation()
        H = [v for v in H if all(not V._is_zero(v.A() * w / 2 - v.b() and
             not V._is_zero(v.A() * (-w) / 2 - v.b())) for w in additional_vectors)]
        V = Polyhedron(ieqs=H)

    return V
def step_transition_matrix(step,
                           eps,
                           rows=None,
                           ctx=None,
                           split=0,
                           max_split=3):
    dop = step.start.dop
    order = dop.order()
    if rows is None:
        rows = order
    z0, z1 = step
    if order == 0:
        logger.info("%s: trivial case", step)
        return matrix(ZZ)  # 0 by 0
    elif z0.value == z1.value:
        logger.info("%s: trivial case", step)
        return identity_matrix(ZZ, order)[:rows]
    elif z0.is_ordinary() and z1.is_ordinary():
        logger.info("%s: ordinary case", step)
        logger.debug("fraction of cvrad: %s/%s", step.length(),
                     z0.dist_to_sing())
        fun = ordinary_step_transition_matrix
    elif z0.is_regular() and z1.is_ordinary():
        logger.info("%s: regular singular case (going out)", step)
        logger.debug("fraction of cvrad: %s/%s", step.length(),
                     z0.dist_to_sing())
        fun = singular_step_transition_matrix
    elif z0.is_ordinary() and z1.is_regular():
        logger.info("%s: regular singular case (going in)", step)
        logger.debug("fraction of cvrad: %s/%s", step.length(),
                     z1.dist_to_sing())
        fun = inverse_singular_step_transition_matrix
    else:
        raise TypeError(type(z0), type(z1))
    try:
        return fun(dop,
                   step,
                   eps,
                   rows,
                   ctx=ctx,
                   fail_fast=(split < max_split))
    except (accuracy.PrecisionError, bounds.BoundPrecisionError):
        # XXX it would be nicer to return something in this case...
        if split >= max_split:
            raise
        logger.info("splitting step...")
        s0, s1 = step.split()
        m0 = step_transition_matrix(s0,
                                    eps / 2,
                                    rows=None,
                                    ctx=ctx,
                                    split=split + 1)
        m1 = step_transition_matrix(s1,
                                    eps / 2,
                                    rows=rows,
                                    ctx=ctx,
                                    split=split + 1)
        return m1 * m0
Ejemplo n.º 19
0
    def matrix_power(self,t):
        eigenvalues = self.eigenvalues
        iprec = self.iprec
        CM = self.CM
        
        ev = [ e.n(iprec) for e in eigenvalues]
        n = len(ev)
    
        Char = [CM - ev[k] * identity_matrix(n) for k in range(n)]
    
        #product till k-1
        prodwo = n * [0]
        prod = identity_matrix(n)

	#if we were to start here with prod = IdentityMatrix
	#prodwo[k]/sprodwo[k] would be the component projector of ev[k]
        #component projector of ev[k] is a matrix Z such that
        #CM * Z = ev[k] * Z and Z*Z=Z
        #then f(CM)=sum_k f(ev[k])*Z[k]
        #as we are only interested in the first line we can start 
        #left with (0,1,...) instead of the identity matrix
        
        for k in range(n):
            prodwo[k] = prod
            for i in range(k+1,n):
                prodwo[k] = prodwo[k] * Char[i]
    
            if k == n:
                break
            prod = prod * Char[k]
    
        sprodwo = n * [0]
        for k in range(n):
            if k == 0:
                sprodwo[k] = ev[k] - ev[1]
                start = 2
            else:
                sprodwo[k] = ev[k] - ev[0]
                start = 1
            
            for i in range(start,n):
                if not i == k:
                    sprodwo[k] = sprodwo[k] * (ev[k]-ev[i])
    
        return sum([ev[k]**t/sprodwo[k]*prodwo[k] for k in range(n)])
Ejemplo n.º 20
0
 def reduce(self, t) :
     ## We compute the rational diagonal form of t. Whenever a zero entry occures we
     ## find a primitive isotropic vector and apply a base change, such that t finally
     ## has the form diag(0,0,...,P) where P is positive definite. P will then be a
     ## LLL reduced.
     
     ot = t
     t = matrix(QQ, t)
     n = t.nrows()
     u = identity_matrix(QQ, n)
     
     for i in xrange(n) :
         if t[i,i] < 0 :
             return None
         elif t[i,i] == 0 :
             ## get the isotropic vector
             v = u.column(i)
             v = v.denominator() * v
             v = v / gcd(list(v))
             u = self._gln_lift(v, 0)
             
             t = u.transpose() * ot * u
             ts = self.reduce(t.submatrix(1,1,n-1,n-1))
             if ts is None :
                 return None
             t.set_block(1, 1, ts[0])
             
             t.set_immutable()
             
             return (t,1)
         else :
             for j in xrange(i + 1, n) :
                 us = identity_matrix(QQ, n, n)
                 us[i,j] = -t[i,j]/t[i,i]
                 u = u * us
                  
                 t.add_multiple_of_row(j, i, -t[j,i]/t[i,i])
                 t.add_multiple_of_column(j, i, -t[i,j]/t[i,i])
     
     u = ot.LLL_gram()
     t = u.transpose() * ot * u
     t.set_immutable()
     
     return (t, 1)
Ejemplo n.º 21
0
    def _rank(self, K) :
        
        if K is QQ or K in NumberFields() :
            return len(_jacobi_forms_by_taylor_expansion_coords(self.__index, self.__weight, 0))

            ## This is the formula used by Poor and Yuen in Paramodular cusp forms
            if self.__weight == 2 :
                delta = len(self.__index.divisors()) // 2 - 1
            else :
                delta = 0
                
            return sum( ModularForms(1, self.__weight + 2 * j).dimension() + j**2 // (4 * self.__index)
                        for j in xrange(self.__index + 1) ) \
                   + delta
            

            ## This is the formula given by Skoruppa in 
            ## Jacobi forms of critical weight and Weil representations
            ##FIXME: There is some mistake here
            if self.__weight % 2 != 0 :
                ## Otherwise the space X(i**(n - 2 k)) is different
                ## See: Skoruppa, Jacobi forms of critical weight and Weil representations
                raise NotImplementedError
            
            m = self.__index
            K = CyclotomicField(24 * m, 'zeta')
            zeta = K.gen(0)
            
            quadform = lambda x : 6 * x**2
            bilinform = lambda x,y : quadform(x + y) - quadform(x) - quadform(y)
            
            T = diagonal_matrix([zeta**quadform(i) for i in xrange(2*m)])
            S =   sum(zeta**(-quadform(x)) for x in xrange(2 * m)) / (2 * m) \
                * matrix([[zeta**(-bilinform(j,i)) for j in xrange(2*m)] for i in xrange(2*m)])
            subspace_matrix_1 = matrix( [ [1 if j == i or j == 2*m - i else 0 for j in xrange(m + 1) ]
                                        for i in xrange(2*m)] )
            subspace_matrix_2 = zero_matrix(ZZ, m + 1, 2*m)
            subspace_matrix_2.set_block(0,0,identity_matrix(m+1))
            
            T = subspace_matrix_2 * T * subspace_matrix_1
            S = subspace_matrix_2 * S * subspace_matrix_1
            
            sqrt3 = (zeta**(4*m) - zeta**(-4*m)) * zeta**(-6*m) 
            rank =   (self.__weight - 1/2 - 1) / 2 * (m + 1) \
                   + 1/8 * (   zeta**(3*m * (2*self.__weight - 1)) * S.trace()
                             + zeta**(3*m * (1 - 2*self.__weight)) * S.trace().conjugate() ) \
                   + 2/(3*sqrt3) * (   zeta**(4 * m * self.__weight) * (S*T).trace()
                                     + zeta**(-4 * m * self.__weight) * (S*T).trace().conjugate() ) \
                   - sum((j**2 % (m+1))/(m+1) -1/2 for j in range(0,m+1))
            
            if self.__weight > 5 / 2 :
                return rank
            else :
                raise NotImplementedError
            
        raise NotImplementedError
Ejemplo n.º 22
0
def step_transition_matrix(dop, step, eps, rows=None, split=0, ctx=dctx):
    r"""
    TESTS::

        sage: from ore_algebra.examples import fcc
        sage: fcc.dop4.numerical_solution([0, 0, 0, 1], [0, 1], 1e-3)
        [1...] + [+/- ...]*I
    """

    order = dop.order()
    if rows is None:
        rows = order
    z0, z1 = step
    if order == 0:
        logger.debug("%s: trivial case", step)
        return matrix(ZZ)  # 0 by 0
    elif z0.value == z1.value:
        logger.debug("%s: trivial case", step)
        return identity_matrix(ZZ, order)[:rows]
    elif z0.is_ordinary() and z1.is_ordinary():
        logger.info("%s: ordinary case", step)
        if z0.is_exact():
            inverse = False
        # XXX maybe also invert the step when z1 is much simpler than z0
        else:  # can happen with the very first step
            step = Step(z1, z0, max_split=0)
            inverse = True
    elif z0.is_regular() and z1.is_ordinary():
        logger.info("%s: regular singular case (going out)", step)
        inverse = False
    elif z0.is_ordinary() and z1.is_regular():
        logger.info("%s: regular singular case (going in)", step)
        step = Step(z1, z0)
        inverse = True
        eps /= 2
    else:
        raise ValueError(z0, z1)
    try:
        mat = regular_step_transition_matrix(dop,
                                             step,
                                             eps,
                                             rows,
                                             fail_fast=(step.max_split > 0),
                                             effort=split,
                                             ctx=ctx)
    except (accuracy.PrecisionError, bounds.BoundPrecisionError):
        if step.max_split == 0:
            raise  # XXX: can we return something?
        logger.info("splitting step...")
        s0, s1 = step.split()
        m0 = step_transition_matrix(dop, s0, eps / 4, None, split + 1, ctx)
        m1 = step_transition_matrix(dop, s1, eps / 4, rows, split + 1, ctx)
        mat = m1 * m0
    if inverse:
        mat = ~mat
    return mat
Ejemplo n.º 23
0
def fundamental_matrix_ordinary(dop, pt, eps, rows, maj, max_prec=100000):
    eps_col = bounds.IR(eps)/bounds.IR(dop.order()).sqrt()
    evpt = EvaluationPoint(pt, jet_order=rows)
    inis = [
        LogSeriesInitialValues(ZZ.zero(), ini, dop, check=False)
        for ini in identity_matrix(dop.order())]
    cols = [
        series_sum(dop, ini, evpt, eps_col, maj=maj, max_prec=max_prec)
        for ini in inis]
    return matrix(cols).transpose()
    def _normalisation_factor_zz(self, tau=3):
        r"""
        This function returns an approximation of `∑_{x ∈ \ZZ^n}
        \exp(-|x|_2^2/(2σ²))`, i.e. the normalisation factor such that the sum
        over all probabilities is 1 for `\ZZⁿ`.

        If this ``self.B`` is not an identity matrix over `\ZZ` a
        ``NotImplementedError`` is raised.

        INPUT:

        - ``tau`` -- all vectors `v` with `|v|_∞ ≤ τ·σ` are enumerated
                     (default: ``3``).

        EXAMPLES::

            sage: from sage.stats.distributions.discrete_gaussian_lattice import DiscreteGaussianDistributionLatticeSampler
            sage: n = 3; sigma = 1.0
            sage: D = DiscreteGaussianDistributionLatticeSampler(ZZ^n, sigma)
            sage: f = D.f
            sage: c = D._normalisation_factor_zz(); c
            15.528...

            sage: from collections import defaultdict
            sage: counter = defaultdict(Integer)
            sage: m = 0
            sage: def add_samples(i):
            ....:     global counter, m
            ....:     for _ in range(i):
            ....:         counter[D()] += 1
            ....:         m += 1

            sage: v = vector(ZZ, n, (0, 0, 0))
            sage: v.set_immutable()
            sage: while v not in counter: add_samples(1000)

            sage: while abs(m*f(v)*1.0/c/counter[v] - 1.0) >= 0.1: add_samples(1000)

            sage: v = vector(ZZ, n, (-1, 2, 3))
            sage: v.set_immutable()
            sage: while v not in counter: add_samples(1000)

            sage: while abs(m*f(v)*1.0/c/counter[v] - 1.0) >= 0.2: add_samples(1000)  # long time
        """
        if self.B != identity_matrix(ZZ, self.B.nrows()):
            raise NotImplementedError(
                "This function is only implemented when B is an identity matrix."
            )

        f = self.f
        n = self.B.ncols()
        sigma = self._sigma
        return sum(
            f(x)
            for x in _iter_vectors(n, -ceil(tau * sigma), ceil(tau * sigma)))
Ejemplo n.º 25
0
def homogeneous_components(self):
    deg_matrix = block_matrix([[identity_matrix(self.parent().rk),-self.parent()._B0]])
    components = dict()
    x = self.lift()
    monomials = x.monomials()
    for m in monomials:
        g_vect = tuple(deg_matrix*vector(m.exponents()[0]))
        if g_vect in components:
            components[g_vect] += self.parent().retract(x.monomial_coefficient(m)*m)
        else:
            components[g_vect] = self.parent().retract(x.monomial_coefficient(m)*m)
    return components
Ejemplo n.º 26
0
    def cone_points_iter(self):
        """
        Iterate over the open torus orbits and yield distinct points.
        
        OUTPUT:

        For each open torus orbit (cone): A triple consisting of the
        cone, the nonzero homogeneous coordinates in that orbit (list
        of integers), and the nonzero log coordinates of distinct
        points as a cokernel.

        EXAMPLES::

            sage: fan = NormalFan(ReflexivePolytope(2, 0))
            sage: X = ToricVariety(fan, base_ring=GF(7))
            sage: point_set = X.point_set()
            sage: ffe = point_set._finite_field_enumerator()
            sage: cpi = ffe.cone_points_iter()
            sage: cone, nonzero_points, cokernel = list(cpi)[5]
            sage: cone
            1-d cone of Rational polyhedral fan in 2-d lattice N
            sage: cone.ambient_ray_indices()
            (2,)
            sage: nonzero_points
            [0, 1]
            sage: cokernel
            Finitely generated module V/W over Integer Ring with invariants (2)
            sage: list(cokernel)
            [(0), (1)]
            sage: [p.lift() for p in cokernel]
            [(0, 0), (0, 1)]
        """
        from sage.matrix.constructor import matrix, block_matrix, identity_matrix
        from sage.rings.all import ZZ
        nrays = len(self.rays())
        N = self.multiplicative_group_order()
        # Want cokernel of the log rescalings in (ZZ/N)^(#rays). But
        # ZZ/N is not a integral domain. Instead: work over ZZ
        log_generators = self.rescaling_log_generators()
        log_relations = block_matrix(2, 1, [
            matrix(ZZ, len(log_generators), nrays, log_generators),
            N * identity_matrix(ZZ, nrays)
        ])
        for cone in self.cone_iter():
            nrays = self.fan().nrays() + len(self.fan().virtual_rays())
            nonzero_coordinates = [
                i for i in range(nrays) if i not in cone.ambient_ray_indices()
            ]
            log_relations_nonzero = log_relations.matrix_from_columns(
                nonzero_coordinates)
            image = log_relations_nonzero.image()
            cokernel = image.ambient_module().quotient(image)
            yield cone, nonzero_coordinates, cokernel
Ejemplo n.º 27
0
def lift(A, N):
    r"""
    Lift a matrix A from SL_m(Z/NZ) to SL_m(Z).

    Follows Shimura, Lemma 1.38, p21.

    """
    assert A.is_square()
    assert A.determinant() != 0
    m = A.nrows()
    if m == 1:
        return identity_matrix(1)

    D, U, V = A.smith_form()
    if U.determinant() == -1:
        U = matrix(2, 2, [-1, 0, 0, 1]) * U
    if V.determinant() == -1:
        V = V * matrix(2, 2, [-1, 0, 0, 1])
    D = U * A * V
    assert U.determinant() == 1
    assert V.determinant() == 1
    a = [D[i, i] for i in range(m)]
    b = prod(a[1:])
    W = identity_matrix(m)
    W[0, 0] = b
    W[1, 0] = b - 1
    W[0, 1] = 1
    X = identity_matrix(m)
    X[0, 1] = -a[1]
    Ap = D.parent()(D)
    Ap[0, 0] = 1
    Ap[1, 0] = 1 - a[0]
    Ap[1, 1] *= a[0]
    assert (W * U * A * V * X).change_ring(Zmod(N)) == Ap.change_ring(Zmod(N))
    Cp = diagonal_matrix(a[1:])
    Cp[0, 0] *= a[0]
    C = lift(Cp, N)
    Cpp = block_diagonal_matrix(identity_matrix(1), C)
    Cpp[1, 0] = 1 - a[0]
    return (~U * ~W * Cpp * ~X * ~V).change_ring(ZZ)
Ejemplo n.º 28
0
def lift(A, N):
    r"""
    Lift a matrix A from SL_m(Z/NZ) to SL_m(Z).

    Follows Shimura, Lemma 1.38, p21.

    """
    assert A.is_square()
    assert A.determinant() != 0
    m = A.nrows()
    if m == 1:
        return identity_matrix(1)

    D, U, V = A.smith_form()
    if U.determinant() == -1 :
        U = matrix(2,2,[-1,0,0,1])* U
    if V.determinant() == -1 :
        V = V *matrix(2,2,[-1,0,0,1])
    D = U*A*V
    assert U.determinant() == 1
    assert V.determinant() == 1
    a = [ D[i, i] for i in range(m) ]
    b = prod(a[1:])
    W = identity_matrix(m)
    W[0, 0] = b
    W[1, 0] = b-1
    W[0, 1] = 1
    X = identity_matrix(m)
    X[0, 1] = -a[1]
    Ap = D.parent()(D)
    Ap[0, 0] = 1
    Ap[1, 0] = 1-a[0]
    Ap[1, 1] *= a[0]
    assert (W*U*A*V*X).change_ring(Zmod(N)) == Ap.change_ring(Zmod(N))
    Cp = diagonal_matrix(a[1:])
    Cp[0, 0] *= a[0]
    C = lift(Cp, N)
    Cpp = block_diagonal_matrix(identity_matrix(1), C)
    Cpp[1, 0] = 1-a[0]
    return (~U * ~W * Cpp * ~X * ~V).change_ring(ZZ)
Ejemplo n.º 29
0
    def cone_points_iter(self):
        """
        Iterate over the open torus orbits and yield distinct points.
        
        OUTPUT:

        For each open torus orbit (cone): A triple consisting of the
        cone, the nonzero homogeneous coordinates in that orbit (list
        of integers), and the nonzero log coordinates of distinct
        points as a cokernel.

        EXAMPLES::

            sage: fan = NormalFan(ReflexivePolytope(2, 0))
            sage: X = ToricVariety(fan, base_ring=GF(7))
            sage: point_set = X.point_set()
            sage: ffe = point_set._finite_field_enumerator()
            sage: cpi = ffe.cone_points_iter()
            sage: cone, nonzero_points, cokernel = list(cpi)[5]
            sage: cone
            1-d cone of Rational polyhedral fan in 2-d lattice N
            sage: cone.ambient_ray_indices()
            (2,)
            sage: nonzero_points
            [0, 1]
            sage: cokernel
            Finitely generated module V/W over Integer Ring with invariants (2)
            sage: list(cokernel)
            [(0), (1)]
            sage: [p.lift() for p in cokernel]
            [(0, 0), (0, 1)]
        """
        from sage.matrix.constructor import matrix, block_matrix, identity_matrix
        from sage.rings.all import ZZ
        nrays = len(self.rays())
        N = self.multiplicative_group_order()
        # Want cokernel of the log rescalings in (ZZ/N)^(#rays). But
        # ZZ/N is not a integral domain. Instead: work over ZZ
        log_generators = self.rescaling_log_generators()
        log_relations = block_matrix(2, 1, [
            matrix(ZZ, len(log_generators), nrays, log_generators), 
            N * identity_matrix(ZZ, nrays)])
        for cone in self.cone_iter():
            nrays = self.fan().nrays() + len(self.fan().virtual_rays())
            nonzero_coordinates = [i for i in range(nrays)
                                   if i not in cone.ambient_ray_indices()]
            log_relations_nonzero = log_relations.matrix_from_columns(nonzero_coordinates)
            image = log_relations_nonzero.image()
            cokernel = image.ambient_module().quotient(image)
            yield cone, nonzero_coordinates, cokernel
def analytic_continuation(ctx, ini=None, post=None):
    """
    INPUT:

    - ``ini`` (constant matrix, optional) - initial values, one column per
      solution
    - ``post`` (matrix of polynomial/rational functions, optional) - linear
      combinations of the first Taylor coefficients to take, as a function of
      the evaluation point

    TESTS::

        sage: from ore_algebra import DifferentialOperators
        sage: _, x, Dx = DifferentialOperators()
        sage: (Dx^2 + 2*x*Dx).numerical_solution([0, 2/sqrt(pi)], [0,i])
        [+/- ...] + [1.65042575879754...]*I
    """
    logger.info("path: %s", ctx.path)
    eps1 = (ctx.eps / (1 + len(ctx.path))) >> 2  # TBI, +: move to ctx?
    prec = utilities.prec_from_eps(eps1)
    if ini is not None:
        if not isinstance(ini, Matrix):  # should this be here?
            try:
                ini = matrix(ctx.dop.order(), 1, list(ini))
            except (TypeError, ValueError):
                raise ValueError("incorrect initial values: {}".format(ini))
        try:
            ini = ini.change_ring(RealBallField(prec))
        except (TypeError, ValueError):
            ini = ini.change_ring(ComplexBallField(prec))
    res = []
    path_mat = identity_matrix(ZZ, ctx.dop.order())

    def store_value_if_wanted(point):
        if point.options.get('keep_value'):
            value = path_mat
            if ini is not None: value = value * ini
            if post is not None: value = post(point.value) * value
            res.append((point.value, value))

    store_value_if_wanted(ctx.path.vert[0])
    for step in ctx.path:
        step_mat = step_transition_matrix(step, eps1, ctx=ctx)
        path_mat = step_mat * path_mat
        store_value_if_wanted(step.end)
    cm = sage.structure.element.get_coercion_model()
    OutputIntervals = cm.common_parent(
        utilities.ball_field(ctx.eps, ctx.real()),
        *[mat.base_ring() for pt, mat in res])
    return [(pt, mat.change_ring(OutputIntervals)) for pt, mat in res]
Ejemplo n.º 31
0
def permutation_simplicial_action(r, u, n, w):
    r"""
    From a word in 'l','r' return the simplicial action on homology as
    well as the obtained origami.

    INPUT:

    - ``r`` and ``u`` - permutations

    - ``n`` - the degree of the permutations

    - ``w`` - a string in 'l' and 'r' or a list of 2-tuples which are made of
      the letter 'l' or 'r' and a positive integer

    """
    if w is None:
        w = []
    elif isinstance(w, list):
        w = flatten_word(w)

    res = identity_matrix(2 * n)

    for letter in reversed(w):
        if letter == 'l':
            u = u * ~r
            m = identity_matrix(2 * n)
            m[:n, n:] = u.matrix()
            res = m * res
        elif letter == 'r':
            r = r * ~u
            m = identity_matrix(2 * n)
            m[n:, :n] = r.matrix()
            res = m * res
        else:
            raise ValueError, "does not understand the letter %s" % str(letter)

    return r, u, res
Ejemplo n.º 32
0
def permutation_simplicial_action(r,u,n,w):
    r"""
    From a word in 'l','r' return the simplicial action on homology as
    well as the obtained origami.

    INPUT:

    - ``r`` and ``u`` - permutations

    - ``n`` - the degree of the permutations

    - ``w`` - a string in 'l' and 'r' or a list of 2-tuples which are made of
      the letter 'l' or 'r' and a positive integer

    """
    if w is None:
        w = []
    elif isinstance(w,list):
        w = flatten_word(w)

    res = identity_matrix(2*n)

    for letter in reversed(w):
        if letter == 'l':
            u = u*~r
            m = identity_matrix(2*n)
            m[:n,n:] = u.matrix()
            res = m * res
        elif letter == 'r':
            r = r*~u
            m = identity_matrix(2*n)
            m[n:,:n] = r.matrix()
            res = m * res
        else:
            raise ValueError, "does not understand the letter %s" %str(letter)

    return r,u,res
Ejemplo n.º 33
0
def homogeneous_components(self):
    deg_matrix = block_matrix(
        [[identity_matrix(self.parent().rk), -self.parent()._B0]])
    components = dict()
    x = self.lift()
    monomials = x.monomials()
    for m in monomials:
        g_vect = tuple(deg_matrix * vector(m.exponents()[0]))
        if g_vect in components:
            components[g_vect] += self.parent().retract(
                x.monomial_coefficient(m) * m)
        else:
            components[g_vect] = self.parent().retract(
                x.monomial_coefficient(m) * m)
    return components
Ejemplo n.º 34
0
def construct_from_dim_degree(dim, max_degree, base_ring, check):
    """
    Construct a filtered vector space.

    INPUT:

    - ``dim`` -- integer. The dimension.

    - ``max_degree`` -- integer or infinity. The maximal degree where
      the vector subspace of the filtration is still the entire space.

    EXAMPLES::

        sage: V = FilteredVectorSpace(2, 5);  V
        QQ^2 >= 0
        sage: V.get_degree(5)
        Vector space of degree 2 and dimension 2 over Rational Field
        Basis matrix:
        [1 0]
        [0 1]
        sage: V.get_degree(6)
        Vector space of degree 2 and dimension 0 over Rational Field
        Basis matrix:
        []

        sage: FilteredVectorSpace(2, oo)
        QQ^2
        sage: FilteredVectorSpace(2, -oo)
        0 in QQ^2

    TESTS::

        sage: from sage.modules.filtered_vector_space import construct_from_dim_degree
        sage: V = construct_from_dim_degree(2, 5, QQ, True);  V
        QQ^2 >= 0
    """
    if dim not in ZZ:
        raise ValueError('dimension must be an integer')
    dim = ZZ(dim)
    from sage.matrix.constructor import identity_matrix
    generators = identity_matrix(base_ring, dim).columns()
    filtration = dict()
    if max_degree is None:
        max_degree = infinity
    filtration[normalize_degree(max_degree)] = range(dim)
    return construct_from_generators_indices(generators, filtration, base_ring,
                                             check)
Ejemplo n.º 35
0
def construct_from_dim_degree(dim, max_degree, base_ring, check):
    """
    Construct a filtered vector space.

    INPUT:

    - ``dim`` -- integer. The dimension.

    - ``max_degree`` -- integer or infinity. The maximal degree where
      the vector subspace of the filtration is still the entire space.

    EXAMPLES::

        sage: V = FilteredVectorSpace(2, 5);  V
        QQ^2 >= 0
        sage: V.get_degree(5)
        Vector space of degree 2 and dimension 2 over Rational Field
        Basis matrix:
        [1 0]
        [0 1]
        sage: V.get_degree(6)
        Vector space of degree 2 and dimension 0 over Rational Field
        Basis matrix:
        []

        sage: FilteredVectorSpace(2, oo)
        QQ^2
        sage: FilteredVectorSpace(2, -oo)
        0 in QQ^2

    TESTS::

        sage: from sage.modules.filtered_vector_space import construct_from_dim_degree
        sage: V = construct_from_dim_degree(2, 5, QQ, True);  V
        QQ^2 >= 0
    """
    if dim not in ZZ:
        raise ValueError('dimension must be an integer')
    dim = ZZ(dim)
    from sage.matrix.constructor import identity_matrix
    generators = identity_matrix(base_ring, dim).columns()
    filtration = dict()
    if max_degree is None:
        max_degree = infinity
    filtration[normalize_degree(max_degree)] = range(dim)
    return construct_from_generators_indices(generators, filtration, base_ring, check)
Ejemplo n.º 36
0
    def gens(self):
        """
        Return the generators.
        
        OUTPUT:

        A tuple of linear expressions, one for each linear variable.

        EXAMPLES::

            sage: from sage.geometry.linear_expression import LinearExpressionModule
            sage: L = LinearExpressionModule(QQ, ('x', 'y', 'z'))
            sage: L.gens()
            (x + 0*y + 0*z + 0, 0*x + y + 0*z + 0, 0*x + 0*y + z + 0)
        """
        from sage.matrix.constructor import identity_matrix
        identity = identity_matrix(self.base_ring(), self.ngens())
        return tuple(self(e, 0) for e in identity.rows())
Ejemplo n.º 37
0
    def gens(self):
        """
        Return the generators of ``self``.

        OUTPUT:

        A tuple of linear expressions, one for each linear variable.

        EXAMPLES::

            sage: from sage.geometry.linear_expression import LinearExpressionModule
            sage: L = LinearExpressionModule(QQ, ('x', 'y', 'z'))
            sage: L.gens()
            (x + 0*y + 0*z + 0, 0*x + y + 0*z + 0, 0*x + 0*y + z + 0)
        """
        from sage.matrix.constructor import identity_matrix
        identity = identity_matrix(self.base_ring(), self.ngens())
        return tuple(self(e, 0) for e in identity.rows())
Ejemplo n.º 38
0
 def __init__(self, Prg, Rng, H = [], Settings = {'Iterations':150,'detail':True,'tryKKT':0, 'AutoMatrix':True, 'precision':7}):
     
     f = Prg[0]
     self.Prog = []
     self.PolyRng = Rng
     self.VARS = self.PolyRng.gens()
     self.polynomial = f
     self.Field = self.polynomial.base_ring()
     self.number_of_variables = len(self.VARS)
     self.total_degree = f.total_degree()
     self.constant_term = f.constant_coefficient()
     self.prg_size = 1
     if len(Prg) > 1:
         self.prg_size = len(Prg[1]) + 1
     if H == []:
         self.H = identity_matrix(self.Field, self.prg_size)
     else:
         self.H = H
     self.Prog.append(f)
     self.constant_terms.append(f.constant_coefficient())
     for i in range(self.prg_size - 1):
         self.Prog.append(Prg[1][i])
         self.constant_terms.append(Prg[1][i].constant_coefficient())
         tmp_deg = Prg[1][i].total_degree()
         if self.total_degree < tmp_deg:
            self.total_degree = tmp_deg
     self.Settings = Settings
     if 'AutoMatrix' in Settings:
         self.AutoMatrix = Settings['AutoMatrix']
     else:
         self.AutoMatrix = False
     if 'Order' in Settings:
         self.Ord = max(Settings['Order'], self.total_degree)
     else:
         self.Ord = self.total_degree
     if (self.Ord % 2) == 1:
         self.Ord = self.Ord + 1
         self.MarginalCoeffs = []
     if 'precision' in Settings:
         self.error_bound = 10**(-Settings['precision'])
     else:
         self.error_bound = 10**(-7)
     self.Info = {'gp':0,'CPU':0,'Wall':0,'status':'Unknown','Message':''}
Ejemplo n.º 39
0
    def invariant_bilinear_form(self):
        """
        Return the symmetric bilinear form preserved by ``self``.

        OUTPUT:

        A matrix.

        EXAMPLES::

            sage: GO(2,3,+1).invariant_bilinear_form()
            [0 1]
            [1 0]
            sage: GO(2,3,-1).invariant_bilinear_form()
            [2 1]
            [1 1]
            sage: G = GO(4, QQ)
            sage: G.invariant_bilinear_form()
            [1 0 0 0]
            [0 1 0 0]
            [0 0 1 0]
            [0 0 0 1]
            sage: GO3m = GO(3,QQ, invariant_form=(1,0,0,0,2,0,0,0,3))
            sage: GO3m.invariant_bilinear_form()
            [1 0 0]
            [0 2 0]
            [0 0 3]

        TESTS::

            sage: GO3m.invariant_form()
            [1 0 0]
            [0 2 0]
            [0 0 3]
        """
        if self._invariant_form is not None:
            return self._invariant_form

        from sage.matrix.constructor import identity_matrix
        m = identity_matrix(self.base_ring(), self.degree())
        m.set_immutable()
        return m
Ejemplo n.º 40
0
    def invariant_bilinear_form(self):
        """
        Return the symmetric bilinear form preserved by ``self``.

        OUTPUT:

        A matrix.

        EXAMPLES::

            sage: GO(2,3,+1).invariant_bilinear_form()
            [0 1]
            [1 0]
            sage: GO(2,3,-1).invariant_bilinear_form()
            [2 1]
            [1 1]
            sage: G = GO(4, QQ)
            sage: G.invariant_bilinear_form()
            [1 0 0 0]
            [0 1 0 0]
            [0 0 1 0]
            [0 0 0 1]
            sage: GO3m = GO(3,QQ, invariant_form=(1,0,0,0,2,0,0,0,3))
            sage: GO3m.invariant_bilinear_form()
            [1 0 0]
            [0 2 0]
            [0 0 3]

        TESTS::

            sage: GO3m.invariant_form()
            [1 0 0]
            [0 2 0]
            [0 0 3]
        """
        if self._invariant_form is not None:
            return self._invariant_form

        from sage.matrix.constructor import identity_matrix
        m = identity_matrix(self.base_ring(), self.degree())
        m.set_immutable()
        return m
Ejemplo n.º 41
0
    def cartan_matrix(self):
        r"""
        Returns the Cartan matrix for this Dynkin diagram

        EXAMPLES::

            sage: DynkinDiagram(['C',3]).cartan_matrix()
            [ 2 -1  0]
            [-1  2 -2]
            [ 0 -1  2]
        """
        from sage.matrix.constructor import identity_matrix
        from sage.rings.all import ZZ
        index_set = self.index_set()
        reverse = dict((index_set[i], i) for i in range(len(index_set)))
        m = 2*identity_matrix(ZZ, len(self.index_set()), sparse=True)
        for (i,j,l) in self.edge_iterator():
            m[reverse[j], reverse[i]] = -l
        m.set_immutable()
        return m
Ejemplo n.º 42
0
    def cartan_matrix(self):
        r"""
        Returns the Cartan matrix for this Dynkin diagram

        EXAMPLES::

            sage: DynkinDiagram(['C',3]).cartan_matrix()
            [ 2 -1  0]
            [-1  2 -2]
            [ 0 -1  2]
        """
        from sage.matrix.constructor import identity_matrix
        from sage.rings.all import ZZ
        index_set = self.index_set()
        reverse = dict((index_set[i], i) for i in range(len(index_set)))
        m = 2*identity_matrix(ZZ, len(self.index_set()), sparse=True)
        for (i,j,l) in self.edge_iterator():
            m[reverse[j], reverse[i]] = -l
        m.set_immutable()
        return m
Ejemplo n.º 43
0
    def invariant_quadratic_form(self):
        """
        Return the quadratic form preserved by the orthogonal group.

        OUTPUT:

        A matrix.

        EXAMPLES::

            sage: GO(2,3,+1).invariant_quadratic_form()
            [0 1]
            [0 0]
            sage: GO(2,3,-1).invariant_quadratic_form()
            [1 1]
            [0 2]
        """
        from sage.matrix.constructor import identity_matrix
        m = identity_matrix(self.base_ring(), self.degree())
        m.set_immutable()
        return m
Ejemplo n.º 44
0
    def invariant_quadratic_form(self):
        """
        Return the quadratic form preserved by the orthogonal group.

        OUTPUT:

        A matrix.

        EXAMPLES::

            sage: GO(2,3,+1).invariant_quadratic_form()
            [0 1]
            [0 0]
            sage: GO(2,3,-1).invariant_quadratic_form()
            [1 1]
            [0 2]
        """
        from sage.matrix.constructor import identity_matrix
        m = identity_matrix(self.base_ring(), self.degree())
        m.set_immutable()
        return m
Ejemplo n.º 45
0
    def _normalisation_factor_zz(self, tau=3):
        r"""
        This function returns an approximation of `∑_{x ∈ \ZZ^n}
        \exp(-|x|_2^2/(2σ²))`, i.e. the normalisation factor such that the sum
        over all probabilities is 1 for `\ZZⁿ`.

        If this ``self.B`` is not an identity matrix over `\ZZ` a
        ``NotImplementedError`` is raised.

        INPUT:

        - ``tau`` -- all vectors `v` with `|v|_∞ ≤ τ·σ` are enumerated
                     (default: ``3``).

        EXAMPLE::

            sage: from sage.stats.distributions.discrete_gaussian_lattice import DiscreteGaussianDistributionLatticeSampler
            sage: n = 3; sigma = 1.0; m = 1000
            sage: D = DiscreteGaussianDistributionLatticeSampler(ZZ^n, sigma)
            sage: f = D.f
            sage: c = D._normalisation_factor_zz(); c
            15.528...

            sage: l = [D() for _ in xrange(m)]
            sage: v = vector(ZZ, n, (0, 0, 0))
            sage: l.count(v), ZZ(round(m*f(v)/c))
            (57, 64)

        """
        if self.B != identity_matrix(ZZ, self.B.nrows()):
            raise NotImplementedError(
                "This function is only implemented when B is an identity matrix."
            )

        f = self.f
        n = self.B.ncols()
        sigma = self._sigma
        return sum(
            f(x)
            for x in _iter_vectors(n, -ceil(tau * sigma), ceil(tau * sigma)))
def hnf_with_transformation(A, proof=True):
    """
    Compute the HNF H of A along with a transformation matrix U
    such that U*A = H.  Also return the pivots of H.

    INPUT:

    - A -- an n x m matrix A over the integers.
    - proof -- whether or not to prove the result correct.

    OUTPUT:

    - matrix -- the Hermite normal form H of A
    - U -- a unimodular matrix such that U * A = H
    - pivots -- the pivot column positions of A

    EXAMPLES::

        sage: import sage.matrix.matrix_integer_dense_hnf as matrix_integer_dense_hnf
        sage: A = matrix(ZZ, 2, [1, -5, -10, 1, 3, 197]); A
        [  1  -5 -10]
        [  1   3 197]
        sage: H, U, pivots = matrix_integer_dense_hnf.hnf_with_transformation(A)
        sage: H
        [  1   3 197]
        [  0   8 207]
        sage: U
        [ 0  1]
        [-1  1]
        sage: U*A
        [  1   3 197]
        [  0   8 207]
    """
    # All we do is augment the input matrix with the identity matrix of the appropriate rank on the right.
    C = A.augment(identity_matrix(ZZ, A.nrows()))
    H, pivots = hnf(C, include_zero_rows=True, proof=proof)
    U = H.matrix_from_columns(range(A.ncols(), H.ncols()))
    H2 = H.matrix_from_columns(range(A.ncols()))
    return H2, U, pivots
Ejemplo n.º 47
0
def fundamental_matrix_ordinary(dop, pt, eps, rows, maj, fail_fast):
    eps_col = bounds.IR(eps) / bounds.IR(dop.order()).sqrt()
    eps_col = accuracy.AbsoluteError(eps_col)
    evpt = EvaluationPoint(pt, jet_order=rows)
    bwrec = bw_shift_rec(dop)
    inis = [
        LogSeriesInitialValues(ZZ.zero(), ini, dop, check=False)
        for ini in identity_matrix(dop.order())
    ]
    stop = accuracy.StoppingCriterion(maj, eps_col.eps)
    cols = [
        interval_series_sum_wrapper(series_sum_ordinary,
                                    dop,
                                    ini,
                                    evpt,
                                    eps_col,
                                    bwrec,
                                    stop,
                                    fail_fast,
                                    max_prec=None) for ini in inis
    ]
    return matrix(cols).transpose()
Ejemplo n.º 48
0
def hnf_with_transformation(A, proof=True):
    """
    Compute the HNF H of A along with a transformation matrix U
    such that U*A = H.  Also return the pivots of H.

    INPUT:

    - A -- an n x m matrix A over the integers.
    - proof -- whether or not to prove the result correct.

    OUTPUT:

    - matrix -- the Hermite normal form H of A
    - U -- a unimodular matrix such that U * A = H
    - pivots -- the pivot column positions of A

    EXAMPLES::

        sage: import sage.matrix.matrix_integer_dense_hnf as matrix_integer_dense_hnf
        sage: A = matrix(ZZ, 2, [1, -5, -10, 1, 3, 197]); A
        [  1  -5 -10]
        [  1   3 197]
        sage: H, U, pivots = matrix_integer_dense_hnf.hnf_with_transformation(A)
        sage: H
        [  1   3 197]
        [  0   8 207]
        sage: U
        [ 0  1]
        [-1  1]
        sage: U*A
        [  1   3 197]
        [  0   8 207]
    """
    # All we do is augment the input matrix with the identity matrix of the appropriate rank on the right.
    C = A.augment(identity_matrix(ZZ, A.nrows()))
    H, pivots = hnf(C, include_zero_rows=True, proof=proof)
    U = H.matrix_from_columns(range(A.ncols(), H.ncols()))
    H2 = H.matrix_from_columns(range(A.ncols()))
    return H2, U, pivots
Ejemplo n.º 49
0
    def identity(self):
        r"""
        Return identity morphism in an endomorphism ring.

        EXAMPLES::

            sage: V=FreeModule(ZZ,5)
            sage: H=V.Hom(V)
            sage: H.identity()
            Free module morphism defined by the matrix
            [1 0 0 0 0]
            [0 1 0 0 0]
            [0 0 1 0 0]
            [0 0 0 1 0]
            [0 0 0 0 1]
            Domain: Ambient free module of rank 5 over the principal ideal domain ...
            Codomain: Ambient free module of rank 5 over the principal ideal domain ...
        """
        if self.is_endomorphism_set():
            return self(identity_matrix(self.base_ring(),self.domain().rank()))
        else:
            raise TypeError("Identity map only defined for endomorphisms. Try natural_map() instead.")
Ejemplo n.º 50
0
    def generator_matrix(self):
        r"""
        Return a generator matrix of ``self``.

        EXAMPLES::

            sage: C = codes.ParityCheckCode(GF(5),7)
            sage: E = codes.encoders.ParityCheckCodeGeneratorMatrixEncoder(C)
            sage: E.generator_matrix()
            [1 0 0 0 0 0 0 4]
            [0 1 0 0 0 0 0 4]
            [0 0 1 0 0 0 0 4]
            [0 0 0 1 0 0 0 4]
            [0 0 0 0 1 0 0 4]
            [0 0 0 0 0 1 0 4]
            [0 0 0 0 0 0 1 4]
        """
        k = self.code().dimension()
        field = self.code().base_field()
        G = identity_matrix(field, k)
        G = G.augment(vector(field, [-field.one()] * k))
        G.set_immutable()
        return G
Ejemplo n.º 51
0
    def _Hasse_Witt_cached(self):
        r"""
        INPUT:

        - ``E`` : Hyperelliptic Curve of the form `y^2 = f(x)` over a finite field, `\mathbb{F}_q`

        OUTPUT:

        - ``N`` : The matrix `N = M M^p \dots M^{p^{g-1}}` where `M = c_{pi-j}, f(x)^{(p-1)/2} = \sum c_i x^i`
        - ``E`` : The initial curve to check some caching conditions.

        EXAMPLES::

            sage: K.<x>=GF(9,'x')[]
            sage: C=HyperellipticCurve(x^7-1,0)
            sage: C._Hasse_Witt_cached()
            (
            [0 0 0]
            [0 0 0]
            [0 0 0], Hyperelliptic Curve over Finite Field in x of size 3^2 defined by y^2 = x^7 + 2
            )

            sage: K.<x>=GF(49,'x')[]
            sage: C=HyperellipticCurve(x^5+1,0)
            sage: C._Hasse_Witt_cached()
            (
            [0 0]
            [0 0], Hyperelliptic Curve over Finite Field in x of size 7^2 defined by y^2 = x^5 + 1
            )

            sage: P.<x>=GF(9,'a')[]
            sage: C=HyperellipticCurve(x^29+1,0)
            sage: C._Hasse_Witt_cached()
            (
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0]
            [0 0 0 0 0 0 0 0 0 0 0 0 0 0], Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 = x^29 + 1
            )

        """

        # If Cartier Matrix is already cached for this curve, use that or evaluate it to get M,
        #Coeffs, genus, Fq=base field of self, p=char(Fq). This is so we have one less matrix to
        #compute.

        #We use caching here since Cartier matrix is needed to compute Hasse Witt. So if the Cartier
        #is already computed it is stored in list A. If it was not cached (i.e. A is empty), we simply
        #compute it. If it is cached then we need to make sure that we have the correct one. So check
        #which curve does the matrix correspond to. Since caching stores a lot of stuff, we only check
        #the last entry in A. If it does not match, clear A and compute Cartier.
        #
        #Since Trac Ticket #11115, there is a different cache for methods
        #that don't  accept arguments. Anyway, the easiest is to call
        #the cached method and simply see whether the data belong to self.
        M, Coeffs, g, Fq, p, E = self._Cartier_matrix_cached()
        if E != self:
            self._Cartier_matrix_cached.clear_cache()
            M, Coeffs, g, Fq, p, E = self._Cartier_matrix_cached()

        #This compute the action of p^kth Frobenius  on list of coefficients
        def frob_mat(Coeffs, k):
            a = p**k
            mat = []
            Coeffs_pow = [c**a for c in Coeffs]
            for i in range(1, g + 1):
                H = [(Coeffs[j])
                     for j in range((p * i - 1), (p * i - g - 1), -1)]
                mat.append(H)
            return matrix(Fq, mat)

        #Computes all the different possible action of frobenius on matrix M and stores in list Mall
        Mall = [M] + [frob_mat(Coeffs, k) for k in range(1, g)]

        #initial N=I, so we can go through Mall and multiply all matrices with I and
        #get the Hasse-Witt matrix.
        N = identity_matrix(Fq, g)
        for l in Mall:
            N = N * l
        return N, E
Ejemplo n.º 52
0
def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, \
                quotient=None, dual=False, ntl=False):
    """
    This function generates different types of integral lattice bases
    of row vectors relevant in cryptography.

    Randomness can be set either with ``seed``, or by using
    :func:`sage.misc.randstate.set_random_seed`.

    INPUT:

    * ``type`` - one of the following strings
        * ``'modular'`` (default). A class of lattices for which
          asymptotic worst-case to average-case connections hold. For
          more refer to [A96]_.
        * ``'random'`` - Special case of modular (n=1). A dense class
          of lattice used for testing basis reduction algorithms
          proposed by Goldstein and Mayer [GM02]_.
        * ``'ideal'`` - Special case of modular. Allows for a more
          compact representation proposed by [LM06]_.
        * ``'cyclotomic'`` - Special case of ideal. Allows for
          efficient processing proposed by [LM06]_.
    * ``n`` - Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`.
      For ideal lattices this is also the degree of the quotient polynomial.
    * ``m`` - Lattice dimension, `L \subseteq Z^m`.
    * ``q`` - Coefficent size, `q*Z^m \subseteq L`.
    * ``seed`` - Randomness seed.
    * ``quotient`` - For the type ideal, this determines the quotient
      polynomial. Ignored for all other types.
    * ``dual`` - Set this flag if you want a basis for `q*dual(L)`, for example
      for Regev's LWE bases [R05]_.
    * ``ntl`` - Set this flag if you want the lattice basis in NTL readable
      format.

    OUTPUT: ``B`` a unique size-reduced triangular (primal: lower_left, 
      dual: lower_right) basis of row vectors for the lattice in question.

    EXAMPLES:

    * Modular basis ::

        sage: sage.crypto.gen_lattice(m=10, seed=42)
        [11  0  0  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0  0  0]
        [ 2  4  3  5  1  0  0  0  0  0]
        [ 1 -5 -4  2  0  1  0  0  0  0]
        [-4  3 -1  1  0  0  1  0  0  0]
        [-2 -3 -4 -1  0  0  0  1  0  0]
        [-5 -5  3  3  0  0  0  0  1  0]
        [-4 -3  2 -5  0  0  0  0  0  1]

    * Random basis ::

        sage: sage.crypto.gen_lattice(type='random', n=1, m=10, q=11^4, seed=42)
        [14641     0     0     0     0     0     0     0     0     0]
        [  431     1     0     0     0     0     0     0     0     0]
        [-4792     0     1     0     0     0     0     0     0     0]
        [ 1015     0     0     1     0     0     0     0     0     0]
        [-3086     0     0     0     1     0     0     0     0     0]
        [-5378     0     0     0     0     1     0     0     0     0]
        [ 4769     0     0     0     0     0     1     0     0     0]
        [-1159     0     0     0     0     0     0     1     0     0]
        [ 3082     0     0     0     0     0     0     0     1     0]
        [-4580     0     0     0     0     0     0     0     0     1]

    * Ideal bases with quotient x^n-1, m=2*n are NTRU bases ::

        sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4-1)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [ 4 -2 -3 -3  1  0  0  0]
        [-3  4 -2 -3  0  1  0  0]
        [-3 -3  4 -2  0  0  1  0]
        [-2 -3 -3  4  0  0  0  1]

    * Cyclotomic bases with n=2^k are SWIFFT bases ::

        sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [ 4 -2 -3 -3  1  0  0  0]
        [ 3  4 -2 -3  0  1  0  0]
        [ 3  3  4 -2  0  0  1  0]
        [ 2  3  3  4  0  0  0  1]

    * Dual modular bases are related to Regev's famous public-key
      encryption [R05]_ ::

        sage: sage.crypto.gen_lattice(type='modular', m=10, seed=42, dual=True)
        [ 0  0  0  0  0  0  0  0  0 11]
        [ 0  0  0  0  0  0  0  0 11  0]
        [ 0  0  0  0  0  0  0 11  0  0]
        [ 0  0  0  0  0  0 11  0  0  0]
        [ 0  0  0  0  0 11  0  0  0  0]
        [ 0  0  0  0 11  0  0  0  0  0]
        [ 0  0  0  1 -5 -2 -1  1 -3  5]
        [ 0  0  1  0 -3  4  1  4 -3 -2]
        [ 0  1  0  0 -4  5 -3  3  5  3]
        [ 1  0  0  0 -2 -1  4  2  5  4]

    * Relation of primal and dual bases ::

        sage: B_primal=sage.crypto.gen_lattice(m=10, q=11, seed=42)
        sage: B_dual=sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True)
        sage: B_dual_alt=transpose(11*B_primal.inverse()).change_ring(ZZ)
        sage: B_dual_alt.hermite_form() == B_dual.hermite_form()
        True

    REFERENCES:

.. [A96] Miklos Ajtai.
   Generating hard instances of lattice problems (extended abstract).
   STOC, pp. 99--108, ACM, 1996.

.. [GM02] Daniel Goldstein and Andrew Mayer.
   On the equidistribution of Hecke points.
   Forum Mathematicum, 15:2, pp. 165--189, De Gruyter, 2003.

.. [LM06] Vadim Lyubashevsky and Daniele Micciancio.
   Generalized compact knapsacks are collision resistant.
   ICALP, pp. 144--155, Springer, 2006.

.. [R05] Oded Regev.
   On lattices, learning with errors, random linear codes, and cryptography.
   STOC, pp. 84--93, ACM, 2005.
    """
    from sage.rings.finite_rings.integer_mod_ring \
        import IntegerModRing
    from sage.matrix.constructor import matrix, \
        identity_matrix, block_matrix
    from sage.matrix.matrix_space import MatrixSpace
    from sage.rings.integer_ring import IntegerRing
    if seed != None:
        from sage.misc.randstate import set_random_seed
        set_random_seed(seed)

    if type == 'random':
        if n != 1: raise ValueError('random bases require n = 1')

    ZZ = IntegerRing()
    ZZ_q = IntegerModRing(q)
    A = identity_matrix(ZZ_q, n)

    if type == 'random' or type == 'modular':
        R = MatrixSpace(ZZ_q, m-n, n)
        A = A.stack(R.random_element())

    elif type == 'ideal':
        if quotient == None: raise \
            ValueError('ideal bases require a quotient polynomial')
        x = quotient.default_variable()
        if n != quotient.degree(x): raise \
            ValueError('ideal bases require n  = quotient.degree()')
        R = ZZ_q[x].quotient(quotient, x)
        for i in range(m//n):
            A = A.stack(R.random_element().matrix())

    elif type == 'cyclotomic':
        from sage.rings.arith import euler_phi
        from sage.misc.functional import cyclotomic_polynomial

        # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n
        found = False
        for k in range(2*n,n,-1):
            if euler_phi(k) == n:
                found = True
                break
        if not found: raise \
            ValueError('cyclotomic bases require that n is an image of' + \
                       'Euler\'s totient function')

        R = ZZ_q['x'].quotient(cyclotomic_polynomial(k, 'x'), 'x')
        for i in range(m//n):
            A = A.stack(R.random_element().matrix())

    # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2
    def minrep(a):
        if abs(a-q) < abs(a): return a-q
        else: return a
    A_prime = A[n:m].lift().apply_map(minrep)

    if not dual:
        B = block_matrix([[ZZ(q), ZZ.zero()], [A_prime, ZZ.one()] ], \
                         subdivide=False)
    else:
        B = block_matrix([[ZZ.one(), -A_prime.transpose()], [ZZ.zero(), \
                         ZZ(q)]], subdivide=False)
        for i in range(m//2): B.swap_rows(i,m-i-1)

    if not ntl:
        return B
    else:
        return B._ntl_()
Ejemplo n.º 53
0
def saturation(A, proof=True, p=0, max_dets=5):
    """
    Compute a saturation matrix of A.

    INPUT:

    - A     -- a matrix over ZZ
    - proof -- bool (default: True)
    - p     -- int (default: 0); if not 0 only guarantees that output is
      p-saturated
    - max_dets -- int (default: 4) max number of dets of submatrices to
      compute.

    OUTPUT:

    matrix -- saturation of the matrix A.

    EXAMPLES::

        sage: from sage.matrix.matrix_integer_dense_saturation import saturation
        sage: A = matrix(ZZ, 2, 2, [3,2,3,4]); B = matrix(ZZ, 2,3,[1,2,3,4,5,6]); C = A*B
        sage: C
        [11 16 21]
        [19 26 33]
        sage: C.index_in_saturation()
        18
        sage: S = saturation(C); S
        [11 16 21]
        [-2 -3 -4]
        sage: S.index_in_saturation()
        1
        sage: saturation(C, proof=False)
        [11 16 21]
        [-2 -3 -4]
        sage: saturation(C, p=2)
        [11 16 21]
        [-2 -3 -4]
        sage: saturation(C, p=2, max_dets=1)
        [11 16 21]
        [-2 -3 -4]
    """
    # Find a submatrix of full rank and instead saturate that matrix.
    r = A.rank()
    if A.is_square() and r == A.nrows():
        return identity_matrix(ZZ, r)
    if A.nrows() > r:
        P = []
        while len(P) < r:
            P = matrix_integer_dense_hnf.probable_pivot_rows(A)
        A = A.matrix_from_rows(P)

    # Factor out all common factors from all rows, just in case.
    A = copy(A)
    A._factor_out_common_factors_from_each_row()

    if A.nrows() <= 1:
        return A

    A, zero_cols = A._delete_zero_columns()

    if max_dets > 0:
        # Take the GCD of at most num_dets randomly chosen determinants.
        nr = A.nrows()
        nc = A.ncols()
        d = 0
        trials = min(binomial(nc, nr), max_dets)
        already_tried = []
        while len(already_tried) < trials:
            v = random_sublist_of_size(nc, nr)
            tm = verbose('saturation -- checking det condition on submatrix')
            d = gcd(d, A.matrix_from_columns(v).determinant(proof=proof))
            verbose('saturation -- got det down to %s' % d, tm)
            if gcd(d, p) == 1:
                return A._insert_zero_columns(zero_cols)
            already_tried.append(v)

        if gcd(d, p) == 1:
            # already p-saturated
            return A._insert_zero_columns(zero_cols)

        # Factor and p-saturate at each p.
        # This is not a good algorithm, because all the HNF's in it are really slow!
        #
        #tm = verbose('factoring gcd %s of determinants'%d)
        #limit = 2**31-1
        #F = d.factor(limit = limit)
        #D = [p for p, e in F if p <= limit]
        #B = [n for n, e in F if n > limit]  # all big factors -- there will only be at most one
        #assert len(B) <= 1
        #C = B[0]
        #for p in D:
        #    A = p_saturation(A, p=p, proof=proof)

    # This is a really simple but powerful algorithm.
    # FACT: If A is a matrix of full rank, then hnf(transpose(A))^(-1)*A is a saturation of A.
    # To make this practical we use solve_system_with_difficult_last_row, since the
    # last column of HNF's are typically the only really big ones.
    B = A.transpose().hermite_form(include_zero_rows=False, proof=proof)
    B = B.transpose()

    # Now compute B^(-1) * A
    C = solve_system_with_difficult_last_row(B, A)
    return C.change_ring(ZZ)._insert_zero_columns(zero_cols)
Ejemplo n.º 54
0
    def simplicial_action_generators(self):
        r"""
        Return action of generators of the Veech group on homology
        """
        from sage.matrix.constructor import matrix, identity_matrix

        tree, reps, word_reps, gens = self._veech_group._spanning_tree_verrill(
            on_right=False)
        n = self[0].nb_squares()

        l_mat = identity_matrix(2 * n)
        s_mat = matrix(2 * n)
        s_mat[:n, n:] = -identity_matrix(n)

        reps = [None] * len(tree)
        reps_o = [None] * len(tree)

        reps[0] = identity_matrix(2 * n)
        reps_o[0] = self.origami()

        waiting = [0]

        while waiting:
            x = waiting.pop()
            for (e0, e1, label) in tree.outgoing_edges(x):
                waiting.append(e1)
                o = reps_o[e0]
                if label == 's':
                    m = copy(s_mat)
                    m[n:, :n] = o.u().matrix().transpose()
                    reps[e1] = m * reps[e0]
                    reps_o[e1] = o.S_action()
                elif label == 'l':
                    o = o.L_action()
                    m = copy(l_mat)
                    m[:n, n:] = (~o.u()).matrix().transpose()
                    reps[e1] = m * reps[e0]
                    reps_o[e1] = o
                elif label == 'r':
                    o = o.R_action()
                    m = copy(l_mat)
                    m[n:, :n] = (~o.r()).matrix().transpose()
                    reps[e1] = m * reps[e0]
                    reps_o[e1] = o
                else:
                    raise ValueError("does know how to do only with slr")

        m_gens = []

        for (e0, e1, label) in gens:
            o = reps_o[e0]
            if label == 's':
                oo = o.S_action()
                m = copy(s_mat)
                m[n:, :n] = o.u().matrix().transpose()
            elif label == 'l':
                oo = o.L_action()
                m = copy(l_mat)
                m[:n, n:] = (~oo.u()).matrix().transpose()
            elif label == 'r':
                oo = o.R_action()
                m = copy(l_mat)
                m[:n, n:] = (~oo.r()).matrix().transpose()
            else:
                raise ValueError("does know how to do only with slr")

            ooo = reps_o[e1]
            ot, oo_renum = oo.standard_form(True)
            os, ooo_renum = ooo.standard_form(True)

            assert (ot == os)

            m_ren = (oo_renum * ~ooo_renum).matrix().transpose()
            m_s = matrix(2 * n)
            m_s[:n, :n] = m_ren
            m_s[n:, n:] = m_ren

            m_gens.append(~reps[e1] * m_s * m * reps[e0])

        return tree, reps, reps_o, gens, m_gens, word_reps
Ejemplo n.º 55
0
    def multiplier(self, P, n, check=True):
        r"""
        Returns the multiplier of the point ``P`` of period ``n`` by the map.

        The map must be an endomorphism.

        INPUT:

        - ``P`` - a point on domain of the map.

        - ``n`` - a positive integer, the period of ``P``.

        - ``check`` -- verify that ``P`` has period ``n``, Default:True.

        OUTPUT:

        - a square matrix of size ``self.codomain().dimension_relative()`` in
          the ``base_ring`` of the map.

        EXAMPLES::

            sage: P.<x,y> = AffineSpace(QQ, 2)
            sage: H = End(P)
            sage: f = H([x^2, y^2])
            sage: f.multiplier(P([1, 1]), 1)
            [2 0]
            [0 2]

        ::

            sage: P.<x,y,z> = AffineSpace(QQ, 3)
            sage: H = End(P)
            sage: f = H([x, y^2, z^2 - y])
            sage: f.multiplier(P([1/2, 1, 0]), 2)
            [1 0 0]
            [0 4 0]
            [0 0 0]

        ::

            sage: P.<x> = AffineSpace(CC, 1)
            sage: H = End(P)
            sage: f = H([x^2 + 1/2])
            sage: f.multiplier(P([0.5 + 0.5*I]), 1)
            [1.00000000000000 + 1.00000000000000*I]

        ::

            sage: R.<t> = PolynomialRing(CC, 1)
            sage: P.<x> = AffineSpace(R, 1)
            sage: H = End(P)
            sage: f = H([x^2 - t^2 + t])
            sage: f.multiplier(P([-t + 1]), 1)
            [(-2.00000000000000)*t + 2.00000000000000]

        ::

            sage: P.<x,y> = AffineSpace(QQ, 2)
            sage: X = P.subscheme([x^2-y^2])
            sage: H = End(X)
            sage: f = H([x^2, y^2])
            sage: f.multiplier(X([1, 1]), 1)
            [2 0]
            [0 2]
        """
        if not self.is_endomorphism():
            raise TypeError("must be an endomorphism")
        if check:
            if self.nth_iterate(P, n) != P:
                raise ValueError("%s is not periodic of period %s" % (P, n))
            if n < 1:
                raise ValueError("period must be a positive integer")
        N = self.domain().ambient_space().dimension_relative()
        l = identity_matrix(FractionField(self.codomain().base_ring()), N, N)
        Q = P
        J = self.jacobian()
        for i in range(0, n):
            R = self(Q)
            l = J(tuple(Q)) * l  #chain rule matrix multiplication
            Q = R
        return l
Ejemplo n.º 56
0
def calculate_voronoi_cell(basis, radius=None, verbose=False):
    """
    Calculate the Voronoi cell of the lattice defined by basis

    INPUT:

    - ``basis`` -- embedded basis matrix of the lattice

    - ``radius`` -- radius of basis vectors to consider

    - ``verbose`` -- whether to print debug information

    OUTPUT:

    A :class:`Polyhedron` instance.

    EXAMPLES::

        sage: from sage.modules.diamond_cutting import calculate_voronoi_cell
        sage: V = calculate_voronoi_cell(matrix([[1, 0], [0, 1]]))
        sage: V.volume()
        1
    """
    dim = basis.dimensions()
    artificial_length = None
    if dim[0] < dim[1]:
        # introduce "artificial" basis points (representing infinity)
        artificial_length = max(abs(v) for v in basis).ceil() * 2
        additional_vectors = identity_matrix(dim[1]) * artificial_length
        basis = basis.stack(additional_vectors)
        # LLL-reduce to get quadratic matrix
        basis = basis.LLL()
        basis = matrix([v for v in basis if v])
        dim = basis.dimensions()
    if dim[0] != dim[1]:
        raise ValueError("invalid matrix")
    basis = basis / 2

    ieqs = []
    for v in basis:
        ieqs.append(plane_inequality(v))
        ieqs.append(plane_inequality(-v))
    Q = Polyhedron(ieqs=ieqs)

    # twice the length of longest vertex in Q is a safe choice
    if radius is None:
        radius = 2 * max(abs(v)**2 for v in basis)

    V = diamond_cut(Q, basis, radius, verbose=verbose)

    if artificial_length is not None:
        # remove inequalities introduced by artificial basis points
        H = V.Hrepresentation()
        H = [
            v for v in H if all(not V._is_zero(v.A() * w / 2 - v.b())
                                and not V._is_zero(v.A() * (-w) / 2 - v.b())
                                for w in additional_vectors)
        ]
        V = Polyhedron(ieqs=H)

    return V
Ejemplo n.º 57
0
def gen_lattice(type='modular', n=4, m=8, q=11, seed=None,
                quotient=None, dual=False, ntl=False, lattice=False):
    r"""
    This function generates different types of integral lattice bases
    of row vectors relevant in cryptography.

    Randomness can be set either with ``seed``, or by using
    :func:`sage.misc.randstate.set_random_seed`.

    INPUT:

    - ``type`` -- one of the following strings
        - ``'modular'`` (default) -- A class of lattices for which
          asymptotic worst-case to average-case connections hold. For
          more refer to [Aj1996]_.
        - ``'random'`` -- Special case of modular (n=1). A dense class
          of lattice used for testing basis reduction algorithms
          proposed by Goldstein and Mayer [GM2002]_.
        - ``'ideal'`` -- Special case of modular. Allows for a more
          compact representation proposed by [LM2006]_.
        - ``'cyclotomic'`` -- Special case of ideal. Allows for
          efficient processing proposed by [LM2006]_.
    - ``n`` -- Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`.
      For ideal lattices this is also the degree of the quotient polynomial.
    - ``m`` -- Lattice dimension, `L \subseteq Z^m`.
    - ``q`` -- Coefficient size, `q-Z^m \subseteq L`.
    - ``seed`` -- Randomness seed.
    - ``quotient`` -- For the type ideal, this determines the quotient
      polynomial. Ignored for all other types.
    - ``dual`` -- Set this flag if you want a basis for `q-dual(L)`, for example
      for Regev's LWE bases [Reg2005]_.
    - ``ntl`` -- Set this flag if you want the lattice basis in NTL readable
      format.
    - ``lattice`` -- Set this flag if you want a
      :class:`FreeModule_submodule_with_basis_integer` object instead
      of an integer matrix representing the basis.

    OUTPUT: ``B`` a unique size-reduced triangular (primal: lower_left,
      dual: lower_right) basis of row vectors for the lattice in question.

    EXAMPLES:

    Modular basis::

        sage: sage.crypto.gen_lattice(m=10, seed=42)
        [11  0  0  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0  0  0]
        [ 2  4  3  5  1  0  0  0  0  0]
        [ 1 -5 -4  2  0  1  0  0  0  0]
        [-4  3 -1  1  0  0  1  0  0  0]
        [-2 -3 -4 -1  0  0  0  1  0  0]
        [-5 -5  3  3  0  0  0  0  1  0]
        [-4 -3  2 -5  0  0  0  0  0  1]

    Random basis::

        sage: sage.crypto.gen_lattice(type='random', n=1, m=10, q=11^4, seed=42)
        [14641     0     0     0     0     0     0     0     0     0]
        [  431     1     0     0     0     0     0     0     0     0]
        [-4792     0     1     0     0     0     0     0     0     0]
        [ 1015     0     0     1     0     0     0     0     0     0]
        [-3086     0     0     0     1     0     0     0     0     0]
        [-5378     0     0     0     0     1     0     0     0     0]
        [ 4769     0     0     0     0     0     1     0     0     0]
        [-1159     0     0     0     0     0     0     1     0     0]
        [ 3082     0     0     0     0     0     0     0     1     0]
        [-4580     0     0     0     0     0     0     0     0     1]

    Ideal bases with quotient x^n-1, m=2*n are NTRU bases::

        sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4-1)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [-2 -3 -3  4  1  0  0  0]
        [ 4 -2 -3 -3  0  1  0  0]
        [-3  4 -2 -3  0  0  1  0]
        [-3 -3  4 -2  0  0  0  1]

    Ideal bases also work with polynomials::

        sage: R.<t> = PolynomialRing(ZZ)
        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=t^4-1)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [ 1  4 -3  3  1  0  0  0]
        [ 3  1  4 -3  0  1  0  0]
        [-3  3  1  4  0  0  1  0]
        [ 4 -3  3  1  0  0  0  1]

    Cyclotomic bases with n=2^k are SWIFFT bases::

        sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42)
        [11  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0]
        [-2 -3 -3  4  1  0  0  0]
        [-4 -2 -3 -3  0  1  0  0]
        [ 3 -4 -2 -3  0  0  1  0]
        [ 3  3 -4 -2  0  0  0  1]

    Dual modular bases are related to Regev's famous public-key
    encryption [Reg2005]_::

        sage: sage.crypto.gen_lattice(type='modular', m=10, seed=42, dual=True)
        [ 0  0  0  0  0  0  0  0  0 11]
        [ 0  0  0  0  0  0  0  0 11  0]
        [ 0  0  0  0  0  0  0 11  0  0]
        [ 0  0  0  0  0  0 11  0  0  0]
        [ 0  0  0  0  0 11  0  0  0  0]
        [ 0  0  0  0 11  0  0  0  0  0]
        [ 0  0  0  1 -5 -2 -1  1 -3  5]
        [ 0  0  1  0 -3  4  1  4 -3 -2]
        [ 0  1  0  0 -4  5 -3  3  5  3]
        [ 1  0  0  0 -2 -1  4  2  5  4]

    Relation of primal and dual bases::

        sage: B_primal=sage.crypto.gen_lattice(m=10, q=11, seed=42)
        sage: B_dual=sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True)
        sage: B_dual_alt=transpose(11*B_primal.inverse()).change_ring(ZZ)
        sage: B_dual_alt.hermite_form() == B_dual.hermite_form()
        True

    TESTS:

    Test some bad quotient polynomials::

        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x))
        Traceback (most recent call last):
        ...
        TypeError: unable to convert cos(x) to an integer
        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1)
        Traceback (most recent call last):
        ...
        ValueError: ideal basis requires n = quotient.degree()
        sage: R.<u,v> = ZZ[]
        sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=u+v)
        Traceback (most recent call last):
        ...
        TypeError: quotient should be a univariate polynomial

    We are testing output format choices::

        sage: sage.crypto.gen_lattice(m=10, q=11, seed=42)
        [11  0  0  0  0  0  0  0  0  0]
        [ 0 11  0  0  0  0  0  0  0  0]
        [ 0  0 11  0  0  0  0  0  0  0]
        [ 0  0  0 11  0  0  0  0  0  0]
        [ 2  4  3  5  1  0  0  0  0  0]
        [ 1 -5 -4  2  0  1  0  0  0  0]
        [-4  3 -1  1  0  0  1  0  0  0]
        [-2 -3 -4 -1  0  0  0  1  0  0]
        [-5 -5  3  3  0  0  0  0  1  0]
        [-4 -3  2 -5  0  0  0  0  0  1]

        sage: sage.crypto.gen_lattice(m=10, q=11, seed=42, ntl=True)
        [
        [11 0 0 0 0 0 0 0 0 0]
        [0 11 0 0 0 0 0 0 0 0]
        [0 0 11 0 0 0 0 0 0 0]
        [0 0 0 11 0 0 0 0 0 0]
        [2 4 3 5 1 0 0 0 0 0]
        [1 -5 -4 2 0 1 0 0 0 0]
        [-4 3 -1 1 0 0 1 0 0 0]
        [-2 -3 -4 -1 0 0 0 1 0 0]
        [-5 -5 3 3 0 0 0 0 1 0]
        [-4 -3 2 -5 0 0 0 0 0 1]
        ]

        sage: sage.crypto.gen_lattice(m=10, q=11, seed=42, lattice=True)
        Free module of degree 10 and rank 10 over Integer Ring
        User basis matrix:
        [ 0  0  1  1  0 -1 -1 -1  1  0]
        [-1  1  0  1  0  1  1  0  1  1]
        [-1  0  0  0 -1  1  1 -2  0  0]
        [-1 -1  0  1  1  0  0  1  1 -1]
        [ 1  0 -1  0  0  0 -2 -2  0  0]
        [ 2 -1  0  0  1  0  1  0  0 -1]
        [-1  1 -1  0  1 -1  1  0 -1 -2]
        [ 0  0 -1  3  0  0  0 -1 -1 -1]
        [ 0 -1  0 -1  2  0 -1  0  0  2]
        [ 0  1  1  0  1  1 -2  1 -1 -2]
    """
    from sage.rings.finite_rings.integer_mod_ring import IntegerModRing
    from sage.matrix.constructor import identity_matrix, block_matrix
    from sage.matrix.matrix_space import MatrixSpace
    from sage.rings.integer_ring import IntegerRing
    if seed is not None:
        from sage.misc.randstate import set_random_seed
        set_random_seed(seed)

    if type == 'random':
        if n != 1: raise ValueError('random bases require n = 1')

    ZZ = IntegerRing()
    ZZ_q = IntegerModRing(q)
    A = identity_matrix(ZZ_q, n)

    if type == 'random' or type == 'modular':
        R = MatrixSpace(ZZ_q, m-n, n)
        A = A.stack(R.random_element())

    elif type == 'ideal':
        if quotient is None:
            raise ValueError('ideal bases require a quotient polynomial')
        try:
            quotient = quotient.change_ring(ZZ_q)
        except (AttributeError, TypeError):
            quotient = quotient.polynomial(base_ring=ZZ_q)

        P = quotient.parent()
        # P should be a univariate polynomial ring over ZZ_q
        if not is_PolynomialRing(P):
            raise TypeError("quotient should be a univariate polynomial")
        assert P.base_ring() is ZZ_q

        if quotient.degree() != n:
            raise ValueError('ideal basis requires n = quotient.degree()')
        R = P.quotient(quotient)
        for i in range(m//n):
            A = A.stack(R.random_element().matrix())

    elif type == 'cyclotomic':
        from sage.arith.all import euler_phi
        from sage.misc.functional import cyclotomic_polynomial

        # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n
        found = False
        for k in range(2*n,n,-1):
            if euler_phi(k) == n:
                found = True
                break
        if not found:
            raise ValueError("cyclotomic bases require that n "
                       "is an image of Euler's totient function")

        R = ZZ_q['x'].quotient(cyclotomic_polynomial(k, 'x'), 'x')
        for i in range(m//n):
            A = A.stack(R.random_element().matrix())

    # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2
    def minrep(a):
        if abs(a-q) < abs(a): return a-q
        else: return a
    A_prime = A[n:m].lift().apply_map(minrep)

    if not dual:
        B = block_matrix([[ZZ(q), ZZ.zero()], [A_prime, ZZ.one()] ],
                         subdivide=False)
    else:
        B = block_matrix([[ZZ.one(), -A_prime.transpose()],
            [ZZ.zero(), ZZ(q)]], subdivide=False)
        for i in range(m//2):
            B.swap_rows(i,m-i-1)

    if ntl and lattice:
        raise ValueError("Cannot specify ntl=True and lattice=True "
                         "at the same time")

    if ntl:
        return B._ntl_()
    elif lattice:
        from sage.modules.free_module_integer import IntegerLattice
        return IntegerLattice(B)
    else:
        return B