def space(self):
        r'''
        Calculates the space of cocyles modulo coboundaries, as a Z-module.

        TESTS:

        sage: from darmonpoints.sarithgroup import *
        sage: from darmonpoints.cohomology_abstract import *
        sage: from darmonpoints.ocmodule import *
        sage: GS = BigArithGroup(5, 6,1,use_shapiro=False,outfile='/tmp/darmonpoints.tmp') #  optional - magma
        sage: G = GS.large_group() #  optional - magma
        sage: V = OCVn(5,1)     #  optional - magma
        sage: Coh = CohomologyGroup(G,V,trivial_action = False) #  optional - magma
        '''
        verb = get_verbose()
        set_verbose(0)
        V = self.coefficient_module()
        R = V.base_ring()
        Vdim = V.dimension()
        G = self.group()
        gens = G.gens()
        ambient = R**(Vdim * len(gens))
        # Now find the subspace of cocycles
        A = Matrix(R, Vdim * len(gens), 0)
        for r in G.get_relation_words():
            Alist = self.fox_gradient(r)
            newA = block_matrix(Alist, nrows = 1)
            A = A.augment(newA.transpose())
        A = A.transpose()
        cocycles = ambient.submodule([ambient(o) for o in A.right_kernel_matrix().rows()])
        gmat = block_matrix([self._gen_pows[i][1] - 1 for i in range(len(G.gens()))], nrows = len(G.gens()))
        coboundaries = cocycles.submodule([ambient(o) for o in gmat.columns()])
        ans = cocycles.quotient(coboundaries)
        set_verbose(verb)
        return ans
Esempio n. 2
0
def NTRU(h, K, q):
    basis = K.integral_basis()
    H = h.matrix()

    return IntegerLattice(block_matrix([[Integer(1), H],
                                        [Integer(0), Integer(q)]]),
                          lll_reduce=True)
Esempio n. 3
0
def Hadamard3Design(n):
    """
    Return the Hadamard 3-design with parameters `3-(n, \\frac n 2, \\frac n 4 - 1)`.

    This is the unique extension of the Hadamard `2`-design (see
    :meth:`HadamardDesign`).  We implement the description from pp. 12 in
    [CvL]_.

    INPUT:

    - ``n`` (integer) -- a multiple of 4 such that `n>4`.

    EXAMPLES::

        sage: designs.Hadamard3Design(12)
        Incidence structure with 12 points and 22 blocks

    We verify that any two blocks of the Hadamard `3`-design `3-(8, 4, 1)`
    design meet in `0` or `2` points. More generally, it is true that any two
    blocks of a Hadamard `3`-design meet in `0` or `\\frac{n}{4}` points (for `n
    > 4`).

    ::

        sage: D = designs.Hadamard3Design(8)
        sage: N = D.incidence_matrix()
        sage: N.transpose()*N
        [4 2 2 2 2 2 2 2 2 2 2 2 2 0]
        [2 4 2 2 2 2 2 2 2 2 2 2 0 2]
        [2 2 4 2 2 2 2 2 2 2 2 0 2 2]
        [2 2 2 4 2 2 2 2 2 2 0 2 2 2]
        [2 2 2 2 4 2 2 2 2 0 2 2 2 2]
        [2 2 2 2 2 4 2 2 0 2 2 2 2 2]
        [2 2 2 2 2 2 4 0 2 2 2 2 2 2]
        [2 2 2 2 2 2 0 4 2 2 2 2 2 2]
        [2 2 2 2 2 0 2 2 4 2 2 2 2 2]
        [2 2 2 2 0 2 2 2 2 4 2 2 2 2]
        [2 2 2 0 2 2 2 2 2 2 4 2 2 2]
        [2 2 0 2 2 2 2 2 2 2 2 4 2 2]
        [2 0 2 2 2 2 2 2 2 2 2 2 4 2]
        [0 2 2 2 2 2 2 2 2 2 2 2 2 4]


    REFERENCES:

    .. [CvL] P. Cameron, J. H. van Lint, Designs, graphs, codes and
      their links, London Math. Soc., 1991.
    """
    if n == 1 or n == 4:
        raise ValueError("The Hadamard design with n = %s does not extend to a three design." % n)
    from sage.combinat.matrices.hadamard_matrix import hadamard_matrix
    from sage.matrix.constructor import matrix, block_matrix
    H = hadamard_matrix(n) #assumed to be normalised.
    H1 = H.matrix_from_columns(range(1, n))
    J = matrix(ZZ, n, n-1, [1]*(n-1)*n)
    A1 = (H1+J)/2
    A2 = (J-H1)/2
    A = block_matrix(1, 2, [A1, A2]) #the incidence matrix of the design.
    return IncidenceStructure(incidence_matrix=A, name="HadamardThreeDesign")
Esempio n. 4
0
def Hadamard3Design(n):
    r"""
    Return the Hadamard 3-design with parameters `3-(n, \frac n 2, \frac n 4 - 1)`.

    This is the unique extension of the Hadamard `2`-design (see
    :meth:`HadamardDesign`).  We implement the description from pp. 12 in
    [CvL]_.

    INPUT:

    - ``n`` (integer) -- a multiple of 4 such that `n>4`.

    EXAMPLES::

        sage: designs.Hadamard3Design(12)
        Incidence structure with 12 points and 22 blocks

    We verify that any two blocks of the Hadamard `3`-design `3-(8, 4, 1)`
    design meet in `0` or `2` points. More generally, it is true that any two
    blocks of a Hadamard `3`-design meet in `0` or `\frac{n}{4}` points (for `n
    > 4`).

    ::

        sage: D = designs.Hadamard3Design(8)
        sage: N = D.incidence_matrix()
        sage: N.transpose()*N
        [4 2 2 2 2 2 2 2 2 2 2 2 2 0]
        [2 4 2 2 2 2 2 2 2 2 2 2 0 2]
        [2 2 4 2 2 2 2 2 2 2 2 0 2 2]
        [2 2 2 4 2 2 2 2 2 2 0 2 2 2]
        [2 2 2 2 4 2 2 2 2 0 2 2 2 2]
        [2 2 2 2 2 4 2 2 0 2 2 2 2 2]
        [2 2 2 2 2 2 4 0 2 2 2 2 2 2]
        [2 2 2 2 2 2 0 4 2 2 2 2 2 2]
        [2 2 2 2 2 0 2 2 4 2 2 2 2 2]
        [2 2 2 2 0 2 2 2 2 4 2 2 2 2]
        [2 2 2 0 2 2 2 2 2 2 4 2 2 2]
        [2 2 0 2 2 2 2 2 2 2 2 4 2 2]
        [2 0 2 2 2 2 2 2 2 2 2 2 4 2]
        [0 2 2 2 2 2 2 2 2 2 2 2 2 4]


    REFERENCES:

    .. [CvL] \P. Cameron, J. H. van Lint, Designs, graphs, codes and
      their links, London Math. Soc., 1991.
    """
    if n == 1 or n == 4:
        raise ValueError("The Hadamard design with n = %s does not extend to a three design." % n)
    from sage.combinat.matrices.hadamard_matrix import hadamard_matrix
    from sage.matrix.constructor import matrix, block_matrix
    H = hadamard_matrix(n) #assumed to be normalised.
    H1 = H.matrix_from_columns(range(1, n))
    J = matrix(ZZ, n, n-1, [1]*(n-1)*n)
    A1 = (H1+J)/2
    A2 = (J-H1)/2
    A = block_matrix(1, 2, [A1, A2]) #the incidence matrix of the design.
    return IncidenceStructure(incidence_matrix=A, name="HadamardThreeDesign")
Esempio n. 5
0
def RSHCD_324(e):
    r"""
    Return a size 324x324 Regular Symmetric Hadamard Matrix with Constant Diagonal.

    We build the matrix `M` for the case `n=324`, `\epsilon=1` directly from
    :meth:`JankoKharaghaniTonchevGraph
    <sage.graphs.graph_generators.GraphGenerators.JankoKharaghaniTonchevGraph>`
    and for the case `\epsilon=-1` from the "twist" `M'` of `M`, using Lemma 11
    in [HX10]_. Namely, it turns out that the matrix

    .. MATH::

        M'=\begin{pmatrix} M_{12} & M_{11}\\ M_{11}^\top & M_{21} \end{pmatrix},
        \quad\text{where}\quad
        M=\begin{pmatrix} M_{11} & M_{12}\\ M_{21} & M_{22} \end{pmatrix},

    and the `M_{ij}` are 162x162-blocks, also RSHCD, its diagonal blocks having zero row
    sums, as needed by [loc.cit.]. Interestingly, the corresponding
    `(324,152,70,72)`-strongly regular graph
    has a vertex-transitive automorphism group of order 2592, twice the order of the
    (intransitive) automorphism group of the graph corresponding to `M`. Cf. [CP16]_.

    INPUT:

    - ``e`` -- one of `-1` or `+1`, equal to the value of `\epsilon`

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import RSHCD_324, is_hadamard_matrix
        sage: for e in [1,-1]:  # long time
        ....:     M = RSHCD_324(e)
        ....:     print("{} {} {}".format(M==M.T,is_hadamard_matrix(M),all([M[i,i]==1 for i in range(324)])))
        ....:     print(set(map(sum,M)))
        True True True
        set([18])
        True True True
        set([-18])

    REFERENCE:

    .. [CP16] \N. Cohen, D. Pasechnik,
       Implementing Brouwer's database of strongly regular graphs,
       Designs, Codes, and Cryptography, 2016
       :doi:`10.1007/s10623-016-0264-x`
    """

    from sage.graphs.generators.smallgraphs import JankoKharaghaniTonchevGraph as JKTG
    M = JKTG().adjacency_matrix()
    M = J(324) - 2 * M
    if e == -1:
        M1 = M[:162].T
        M2 = M[162:].T
        M11 = M1[:162]
        M12 = M1[162:].T
        M21 = M2[:162].T
        M = block_matrix([[M12, -M11], [-M11.T, M21]])
    return M
Esempio n. 6
0
def RSHCD_324(e):
    r"""
    Return a size 324x324 Regular Symmetric Hadamard Matrix with Constant Diagonal.

    We build the matrix `M` for the case `n=324`, `\epsilon=1` directly from
    :meth:`JankoKharaghaniTonchevGraph
    <sage.graphs.graph_generators.GraphGenerators.JankoKharaghaniTonchevGraph>`
    and for the case `\epsilon=-1` from the "twist" `M'` of `M`, using Lemma 11
    in [HX10]_. Namely, it turns out that the matrix

    .. MATH::

        M'=\begin{pmatrix} M_{12} & M_{11}\\ M_{11}^\top & M_{21} \end{pmatrix},
        \quad\text{where}\quad
        M=\begin{pmatrix} M_{11} & M_{12}\\ M_{21} & M_{22} \end{pmatrix},

    and the `M_{ij}` are 162x162-blocks, also RSHCD, its diagonal blocks having zero row
    sums, as needed by [loc.cit.]. Interestingly, the corresponding
    `(324,152,70,72)`-strongly regular graph
    has a vertex-transitive automorphism group of order 2592, twice the order of the
    (intransitive) automorphism group of the graph corresponding to `M`. Cf. [CP16]_.

    INPUT:

    - ``e`` -- one of `-1` or `+1`, equal to the value of `\epsilon`

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import RSHCD_324, is_hadamard_matrix
        sage: for e in [1,-1]:  # long time
        ....:     M = RSHCD_324(e)
        ....:     print("{} {} {}".format(M==M.T,is_hadamard_matrix(M),all([M[i,i]==1 for i in range(324)])))
        ....:     print(set(map(sum,M)))
        True True True
        set([18])
        True True True
        set([-18])

    REFERENCE:

    .. [CP16] \N. Cohen, D. Pasechnik,
       Implementing Brouwer's database of strongly regular graphs,
       Designs, Codes, and Cryptography, 2016
       :doi:`10.1007/s10623-016-0264-x`
    """

    from sage.graphs.generators.smallgraphs import JankoKharaghaniTonchevGraph as JKTG
    M = JKTG().adjacency_matrix()
    M = J(324) - 2*M
    if e==-1:
        M1=M[:162].T
        M2=M[162:].T
        M11=M1[:162]
        M12=M1[162:].T
        M21=M2[:162].T
        M=block_matrix([[M12,-M11],[-M11.T,M21]])
    return M
    def space(self):
        r'''
        Calculates the space of cocyles modulo coboundaries, as a Z-module.

        TESTS:

        sage: from darmonpoints.sarithgroup import *
        sage: from darmonpoints.cohomology_abstract import *
        sage: from darmonpoints.ocmodule import *
        sage: GS = BigArithGroup(5, 6,1,use_shapiro=False,outfile='/tmp/darmonpoints.tmp') #  optional - magma
        sage: G = GS.large_group() #  optional - magma
        sage: V = OCVn(5,1)     #  optional - magma
        sage: Coh = CohomologyGroup(G,V,trivial_action = False) #  optional - magma
        '''
        verb = get_verbose()
        set_verbose(0)
        V = self.coefficient_module()
        R = V.base_ring()
        Vdim = V.dimension()
        G = self.group()
        gens = G.gens()
        ambient = R**(Vdim * len(gens))
        # Now find the subspace of cocycles
        A = Matrix(R, Vdim * len(gens), 0)
        for nr, r in enumerate(G.get_relation_words()):
            set_verbose(verb)
            verbose('Processing relation word %s' % nr)
            set_verbose(0)
            Alist = [
                MatrixSpace(R, Vdim, Vdim)(self.GA_to_local(o))
                for o in self.fox_gradient(tuple(r))
            ]
            newA = block_matrix(Alist, nrows=1)
            A = A.augment(newA.transpose())
        A = A.transpose()
        cocycles = ambient.submodule(
            [ambient(o) for o in A.right_kernel_matrix().rows()])
        gmat = block_matrix(
            [self._acting_matrix(g, Vdim) - 1 for g in G.gens()],
            nrows=len(G.gens()))
        coboundaries = cocycles.submodule([ambient(o) for o in gmat.columns()])
        ans = cocycles.quotient(coboundaries)
        set_verbose(verb)
        return ans
Esempio n. 8
0
def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True):
    r"""
    Williamson-Goethals-Seidel construction of a skew Hadamard matrix

    Given `n\times n` (anti)circulant matrices `A`, `B`, `C`, `D` with 1,-1 entries, 
    and satisfying `A+A^\top = 2I`, `AA^\top + BB^\top + CC^\top + DD^\top = 4nI`,
    one can construct a skew Hadamard matrix of order `4n`, cf. [GS70s]_.

    INPUT:

    - ``a`` -- 1,-1 list specifying the 1st row of `A`

    - ``b`` -- 1,-1 list specifying the 1st row of `B`

    - ``d`` -- 1,-1 list specifying the 1st row of `C`

    - ``c`` -- 1,-1 list specifying the 1st row of `D`

    EXAMPLES::

        sage: from sage.combinat.matrices.hadamard_matrix import williamson_goethals_seidel_skew_hadamard_matrix as WGS
        sage: a=[ 1,  1, 1, -1,  1, -1,  1, -1, -1]
        sage: b=[ 1, -1, 1,  1, -1, -1,  1,  1, -1]
        sage: c=[-1, -1]+[1]*6+[-1]
        sage: d=[ 1,  1, 1, -1,  1,  1, -1,  1,  1]
        sage: M=WGS(a,b,c,d,check=True)

    REFERENCES:

    .. [GS70s] \J.M. Goethals and J. J. Seidel,
      A skew Hadamard matrix of order 36,
      J. Aust. Math. Soc. 11(1970), 343-344
    .. [Wall71] \J. Wallis,
      A skew-Hadamard matrix of order 92,
      Bull. Aust. Math. Soc. 5(1971), 203-204
    .. [KoSt08] \C. Koukouvinos, S. Stylianou
      On skew-Hadamard matrices,
      Discrete Math. 308(2008) 2723-2731


    """
    n = len(a)
    R = matrix(ZZ, n, n, lambda i,j: 1 if i+j==n-1 else 0)
    A,B,C,D=map(matrix.circulant, [a,b,c,d])
    if check:
        assert A*A.T+B*B.T+C*C.T+D*D.T==4*n*I(n)
        assert A+A.T==2*I(n)

    M = block_matrix([[   A,    B*R,    C*R,    D*R],
                      [-B*R,      A, -D.T*R,  C.T*R],
                      [-C*R,  D.T*R,      A, -B.T*R],
                      [-D*R, -C.T*R,  B.T*R,      A]])
    if check:
        assert is_hadamard_matrix(M, normalized=False, skew=True)
    return M
Esempio n. 9
0
def williamson_goethals_seidel_skew_hadamard_matrix(a, b, c, d, check=True):
    r"""
    Williamson-Goethals-Seidel construction of a skew Hadamard matrix

    Given `n\times n` (anti)circulant matrices `A`, `B`, `C`, `D` with 1,-1 entries,
    and satisfying `A+A^\top = 2I`, `AA^\top + BB^\top + CC^\top + DD^\top = 4nI`,
    one can construct a skew Hadamard matrix of order `4n`, cf. [GS70s]_.

    INPUT:

    - ``a`` -- 1,-1 list specifying the 1st row of `A`

    - ``b`` -- 1,-1 list specifying the 1st row of `B`

    - ``d`` -- 1,-1 list specifying the 1st row of `C`

    - ``c`` -- 1,-1 list specifying the 1st row of `D`

    EXAMPLES::

        sage: from sage.combinat.matrices.hadamard_matrix import williamson_goethals_seidel_skew_hadamard_matrix as WGS
        sage: a=[ 1,  1, 1, -1,  1, -1,  1, -1, -1]
        sage: b=[ 1, -1, 1,  1, -1, -1,  1,  1, -1]
        sage: c=[-1, -1]+[1]*6+[-1]
        sage: d=[ 1,  1, 1, -1,  1,  1, -1,  1,  1]
        sage: M=WGS(a,b,c,d,check=True)

    REFERENCES:

    .. [GS70s] \J.M. Goethals and J. J. Seidel,
      A skew Hadamard matrix of order 36,
      J. Aust. Math. Soc. 11(1970), 343-344
    .. [Wall71] \J. Wallis,
      A skew-Hadamard matrix of order 92,
      Bull. Aust. Math. Soc. 5(1971), 203-204
    .. [KoSt08] \C. Koukouvinos, S. Stylianou
      On skew-Hadamard matrices,
      Discrete Math. 308(2008) 2723-2731


    """
    n = len(a)
    R = matrix(ZZ, n, n, lambda i,j: 1 if i+j==n-1 else 0)
    A,B,C,D=map(matrix.circulant, [a,b,c,d])
    if check:
        assert A*A.T+B*B.T+C*C.T+D*D.T==4*n*I(n)
        assert A+A.T==2*I(n)

    M = block_matrix([[   A,    B*R,    C*R,    D*R],
                      [-B*R,      A, -D.T*R,  C.T*R],
                      [-C*R,  D.T*R,      A, -B.T*R],
                      [-D*R, -C.T*R,  B.T*R,      A]])
    if check:
        assert is_hadamard_matrix(M, normalized=False, skew=True)
    return M
Esempio n. 10
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
Esempio n. 11
0
def NTRU_subfield(hprime, q, nprime, r):
    z = hprime.parent().gen()

    mat = []
    for i in range(nprime):
        coordinate = (hprime * z**(r * i)).vector().list()
        mat.append([coordinate[r * j] for j in range(nprime)])

    Hprime = matrix(mat)

    return IntegerLattice(block_matrix([[Integer(1), Hprime],
                                        [Integer(0), Integer(q)]]),
                          lll_reduce=True)
Esempio n. 12
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
Esempio n. 13
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(12).det()
        2985984
        sage: 12^6
        2985984
    """
    N = Integer(n/2)
    p = N - 1
    if not(is_prime(p) and (p % 4 == 1)):
        raise ValueError("The order %s is not covered by the Paley type II construction." % n)
    S = matrix(ZZ, [[H2(i, j, p) for i in range(N)] for j in range(N)])
    return block_matrix([[S + 1, S - 1], [S - 1, -S - 1]])
Esempio n. 14
0
    def matrix(self):
        """
        Return the standard matrix representation of ``self``.

        .. SEEALSO::

            - :meth:`AffineGroup.linear_space()`

        EXAMPLES::

            sage: G = AffineGroup(3, GF(7))
            sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12])
            sage: g
                  [1 2 3]     [3]
            x |-> [4 5 6] x + [4]
                  [0 1 0]     [5]
            sage: g.matrix()
            [1 2 3|3]
            [4 5 6|4]
            [0 1 0|5]
            [-----+-]
            [0 0 0|1]
            sage: parent(g.matrix())
            Full MatrixSpace of 4 by 4 dense matrices over Finite Field of size 7
            sage: g.matrix() == matrix(g)
            True

        Composition of affine group elements equals multiplication of
        the matrices::

            sage: g1 = G.random_element()
            sage: g2 = G.random_element()
            sage: g1.matrix() * g2.matrix() == (g1*g2).matrix()
            True
        """
        A = self._A
        b = self._b
        parent = self.parent()
        d = parent.degree()
        from sage.matrix.constructor import matrix, zero_matrix, block_matrix

        zero = zero_matrix(parent.base_ring(), 1, d)
        one = matrix(parent.base_ring(), [[1]])
        m = block_matrix(2, 2, [A, b.column(), zero, one])
        m.set_immutable()
        return m
Esempio n. 15
0
    def matrix(self):
        """
        Return the standard matrix representation of ``self``.

        .. SEEALSO::

            - :meth:`AffineGroup.linear_space()`

        EXAMPLES::

            sage: G = AffineGroup(3, GF(7))
            sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12])
            sage: g
                  [1 2 3]     [3]
            x |-> [4 5 6] x + [4]
                  [0 1 0]     [5]
            sage: g.matrix()
            [1 2 3|3]
            [4 5 6|4]
            [0 1 0|5]
            [-----+-]
            [0 0 0|1]
            sage: parent(g.matrix())
            Full MatrixSpace of 4 by 4 dense matrices over Finite Field of size 7
            sage: g.matrix() == matrix(g)
            True

        Composition of affine group elements equals multiplication of
        the matrices::

            sage: g1 = G.random_element()
            sage: g2 = G.random_element()
            sage: g1.matrix() * g2.matrix() == (g1*g2).matrix()
            True
        """
        A = self._A
        b = self._b
        parent = self.parent()
        d = parent.degree()
        from sage.matrix.constructor import matrix, zero_matrix, block_matrix
        zero = zero_matrix(parent.base_ring(), 1, d)
        one = matrix(parent.base_ring(), [[1]])
        m = block_matrix(2, 2, [A, b.column(), zero, one])
        m.set_immutable()
        return m
Esempio n. 16
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    EXAMPLES::
        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(12).det()
        2985984
        sage: 12^6
        2985984

    """
    N = ZZ(n/2)
    if is_prime(N-1) and (N-1)%4==1:
        p = N-1
    else:
        raise ValueError, "The order %s is not covered by the Paley type II construction."%n
    S = matrix(ZZ,[[H2(i,j,p) for i in range(N)] for j in range(N)])
    return block_matrix([[S+1,S-1],[S-1,-S-1]])
Esempio n. 17
0
    def _repr_(self):
        """
        Return a string representation.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep
            sage: H = Hrep2Vrep(QQ, 1, [(1,2)], [])
            sage: H._repr_()
            '[-1/2| 1/2|]'
        """
        from sage.matrix.constructor import block_matrix

        def make_matrix(rows):
             return matrix(self.base_ring, len(rows), self.dim, rows).transpose()
        V = make_matrix(self.vertices)
        R = make_matrix(self.rays)
        L = make_matrix(self.lines)
        return str(block_matrix([[V, R, L]]))
    def _repr_(self):
        """
        Return a string representation.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep
            sage: H = Hrep2Vrep(QQ, 1, [(1,2)], [])
            sage: H._repr_()
            '[-1/2| 1/2|]'
        """
        from sage.matrix.constructor import block_matrix

        def make_matrix(rows):
             return matrix(self.base_ring, len(rows), self.dim, rows).transpose()
        V = make_matrix(self.vertices)
        R = make_matrix(self.rays)
        L = make_matrix(self.lines)
        return str(block_matrix([[V, R, L]]))
def matrice_systeme(systeme, variables):
    """
    Renvoie une matrice par block représentant un programme linéaire sous forme standard.

    INPUT::

    - ``systeme`` -- Un programme linéaire sous forme standard
    - ``variables`` -- La liste des variables du système

    EXAMPLES::

        sage: x = x1,x2,x3 = var('x1,x2,x3')
        sage: Chvatal13 = [[2*x1 + 3*x2 +   x3 <=  5,
        ....:               4*x1 +   x2 + 2*x3 <= 11,
        ....:               3*x1 + 4*x2 + 2*x3 <=  8],
        ....:               5*x1 + 4*x2 + 3*x3]

        sage: m = matrice_systeme(Chvatal13, x); m
        [ z|s1 s2 s3|x1 x2 x3| 0]
        [--+--------+--------+--]
        [ 1| 0  0  0|-5 -4 -3| 0]
        [--+--------+--------+--]
        [ 0| 1  0  0| 2  3  1| 5]
        [ 0| 0  1  0| 4  1  2|11]
        [ 0| 0  0  1| 3  4  2| 8]
    """

    def liste_coeffs(expression):
        return [expression.coeff(v) for v in variables]

    inequations = systeme[0]
    m = matrix([liste_coeffs(ineq.lhs()) for ineq in inequations])
    rhs = vector(ineq.rhs() for ineq in inequations).column()
    slack = SR.var(",".join("s%s" % i for i in range(1, len(inequations) + 1)))
    z = SR.var("z")
    return block_matrix(
        [
            [z, matrix([slack]), matrix([variables]), ZZ(0)],
            [ZZ(1), ZZ(0), -matrix([liste_coeffs(systeme[1])]), ZZ(0)],
            [ZZ(0), ZZ(1), m, rhs],
        ]
    )
Esempio n. 20
0
    def _parity_check_matrix_vandermonde(self):
        """
        Return a parity check matrix for ``self`` using Vandermonde matrix.

        EXAMPLES::

            sage: F  = GF(2^3)
            sage: R.<x> = F[]
            sage: g = x^2 + x+ 1
            sage: L = [a for a in F.list() if g(a) != 0]
            sage: C = codes.GoppaCode(g, L)
            sage: C
            [8, 2] Goppa code over GF(2)
            sage: C._parity_check_matrix_vandermonde()
            [1 0 0 0 0 0 0 1]
            [0 0 1 0 1 1 1 0]
            [0 1 1 1 0 0 1 0]
            [---------------]
            [0 1 1 1 1 1 1 1]
            [0 1 0 1 1 0 1 0]
            [0 0 1 1 1 1 0 0]
        """
        L = self._defining_set
        g = self._generating_pol
        t = g.degree()

        from sage.matrix.constructor import matrix, diagonal_matrix, block_matrix

        V = matrix.vandermonde(L)
        V = V.transpose()
        GL = [g(i) for i in L]
        GLI = [j.inverse_of_unit() for j in GL]
        D = diagonal_matrix(GLI)
        VF = matrix([V.row(i) for i in range(t)])
        H = VF * D

        matrices = [matrix([vector(i) for i in H.row(j)]) for j in range(t)]
        matrices = [m.transpose() for m in matrices]

        m = block_matrix(t, 1, matrices)
        return m
Esempio n. 21
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det()
        2985984
        sage: 12^6
        2985984

    We note that the method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12)
        [ 1  1  1  1  1  1| 1  1  1  1  1  1]
        [ 1  1  1 -1 -1  1|-1 -1  1 -1 -1  1]
        [ 1  1  1  1 -1 -1|-1  1 -1  1 -1 -1]
        [ 1 -1  1  1  1 -1|-1 -1  1 -1  1 -1]
        [ 1 -1 -1  1  1  1|-1 -1 -1  1 -1  1]
        [ 1  1 -1 -1  1  1|-1  1 -1 -1  1 -1]
        [-----------------+-----------------]
        [ 1 -1 -1 -1 -1 -1|-1  1  1  1  1  1]
        [ 1 -1  1 -1 -1  1| 1 -1 -1  1  1 -1]
        [ 1  1 -1  1 -1 -1| 1 -1 -1 -1  1  1]
        [ 1 -1  1 -1  1 -1| 1  1 -1 -1 -1  1]
        [ 1 -1 -1  1 -1  1| 1  1  1 -1 -1 -1]
        [ 1  1 -1 -1  1 -1| 1 -1  1  1 -1 -1]
    """
    N = Integer(n / 2)
    p = N - 1
    if not (is_prime(p) and (p % 4 == 1)):
        raise ValueError(
            "The order %s is not covered by the Paley type II construction." %
            n)
    S = matrix(ZZ, [[H2(i, j, p) for i in range(N)] for j in range(N)])
    H = block_matrix([[S + 1, S - 1], [1 - S, S + 1]])
    # normalising H so that first row and column have only +1 entries.
    return normalise_hadamard(H)
    def _repr_(self):
        r"""
        Return a string representation.

        OUTPUT:

        String.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.double_description_inhomogeneous import Vrep2Hrep
            sage: V2H = Vrep2Hrep(QQ, 2, [(-1/2,0)], [(-1/2,2/3), (1/2,-1/3)], [])
            sage: V2H._repr_()
            '[1 2 3]\n[2 4 3]\n[-----]'
        """
        from sage.matrix.constructor import block_matrix

        def make_matrix(cols):
            return matrix(self.base_ring, len(cols), self.dim + 1, cols)
        I = make_matrix(self.inequalities)
        E = make_matrix(self.equations)
        return str(block_matrix([[I], [E]]))
Esempio n. 23
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det()
        2985984
        sage: 12^6
        2985984

    We note that the method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12)
        [ 1  1  1  1  1  1| 1  1  1  1  1  1]
        [ 1  1  1 -1 -1  1|-1 -1  1 -1 -1  1]
        [ 1  1  1  1 -1 -1|-1  1 -1  1 -1 -1]
        [ 1 -1  1  1  1 -1|-1 -1  1 -1  1 -1]
        [ 1 -1 -1  1  1  1|-1 -1 -1  1 -1  1]
        [ 1  1 -1 -1  1  1|-1  1 -1 -1  1 -1]
        [-----------------+-----------------]
        [ 1 -1 -1 -1 -1 -1|-1  1  1  1  1  1]
        [ 1 -1  1 -1 -1  1| 1 -1 -1  1  1 -1]
        [ 1  1 -1  1 -1 -1| 1 -1 -1 -1  1  1]
        [ 1 -1  1 -1  1 -1| 1  1 -1 -1 -1  1]
        [ 1 -1 -1  1 -1  1| 1  1  1 -1 -1 -1]
        [ 1  1 -1 -1  1 -1| 1 -1  1  1 -1 -1]
    """
    N = Integer(n/2)
    p = N - 1
    if not(is_prime(p) and (p % 4 == 1)):
        raise ValueError("The order %s is not covered by the Paley type II construction." % n)
    S = matrix(ZZ, [[H2(i, j, p) for i in range(N)] for j in range(N)])
    H = block_matrix([[S + 1, S - 1], [1 - S, S + 1]])
    # normalising H so that first row and column have only +1 entries.
    return normalise_hadamard(H)
Esempio n. 24
0
    def _repr_(self):
        """
        Return a string representation.

        OUTPUT:

        String.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.double_description_inhomogeneous import Vrep2Hrep
            sage: V2H = Vrep2Hrep(QQ, 2, [(-1/2,0)], [(-1/2,2/3), (1/2,-1/3)], [])
            sage: V2H._repr_()
            '[1 2 3]\n[2 4 3]\n[-----]'
        """
        from sage.matrix.constructor import block_matrix

        def make_matrix(cols):
            return matrix(self.base_ring, len(cols), self.dim + 1, cols)
        I = make_matrix(self.inequalities)
        E = make_matrix(self.equations)
        return str(block_matrix([[I], [E]]))
def matrice_systeme(systeme, variables):
    """
    Renvoie une matrice par block représentant un programme linéaire sous forme standard.

    INPUT::

    - ``systeme`` -- Un programme linéaire sous forme standard
    - ``variables`` -- La liste des variables du système

    EXAMPLES::

        sage: x = x1,x2,x3 = var('x1,x2,x3')
        sage: Chvatal13 = [[2*x1 + 3*x2 +   x3 <=  5,
        ....:               4*x1 +   x2 + 2*x3 <= 11,
        ....:               3*x1 + 4*x2 + 2*x3 <=  8],
        ....:               5*x1 + 4*x2 + 3*x3]

        sage: m = matrice_systeme(Chvatal13, x); m
        [ z|s1 s2 s3|x1 x2 x3| 0]
        [--+--------+--------+--]
        [ 1| 0  0  0|-5 -4 -3| 0]
        [--+--------+--------+--]
        [ 0| 1  0  0| 2  3  1| 5]
        [ 0| 0  1  0| 4  1  2|11]
        [ 0| 0  0  1| 3  4  2| 8]
    """
    def liste_coeffs(expression):
        return [expression.coeff(v) for v in variables]

    inequations = systeme[0]
    m = matrix([liste_coeffs(ineq.lhs()) for ineq in inequations])
    rhs = vector(ineq.rhs() for ineq in inequations).column()
    slack = SR.var(','.join("s%s" % i for i in range(1, len(inequations) + 1)))
    z = SR.var('z')
    return block_matrix(
        [[z, matrix([slack]), matrix([variables]),
          ZZ(0)], [ZZ(1),
                   ZZ(0), -matrix([liste_coeffs(systeme[1])]),
                   ZZ(0)], [ZZ(0), ZZ(1), m, rhs]])
Esempio n. 26
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
Esempio n. 27
0
    def mat_solve(m, v):
        """
        Given a matrix m and a vector v of (complex) intervals, returns
        the vector a such that v = m * a preserving interval
        arithmetics: if m' is a matrix with values in the intervals of m and 
        v' is a vector with values in the intervals of v, then the intervals
        of the result a returned by this method are guaranteed to contain
        the entries of m'^-1 * v'.

        Sage already provides a method for inverting matrices. However, it
        has a flaw and fails inverting interval matrices even though the
        interval determinant is far from containing zero (it returns
        unusable matrices with entries (-inf, inf).

        Our implementation improves on this by swapping rows to avoid
        diagonal entries close to zero during Gaussian elimination.

        Setup a complex interval for example::
        
            sage: RIF = RealIntervalField(80)
            sage: CIF = ComplexIntervalField(80)
            sage: fuzzy_four = CIF(RIF(3.9999,4.0001),RIF(-0.0001,0.0001))

        Construct a matrix/vector with complex interval coefficients. One entry
        is a complex interval with non-zero diameter::

            sage: m = matrix(CIF,
            ...      [  [ fuzzy_four, 3, 2, 3],
            ...         [          2, 3, 6, 2],
            ...         [          2, 4, 1, 6],
            ...         [          3, 2,-5, 2]])
            sage: v = vector(CIF, [fuzzy_four, 2, 0 ,1])
       
        Now compute the solutions a to v = m * a::

            sage: a = IntervalNewtonShapesEngine.mat_solve(m, v)
            sage: a  # doctest: +ELLIPSIS
            (1.5...? + 0.000?*I, -1.2...? + 0.000?*I, 0.34...? + 0.0000?*I, 0.24...? + 0.000?*I)
            sage: m * a  # doctest: +ELLIPSIS
            (4.0...? + 0.00?*I, 2.0...? + 0.00?*I, 0.0...? + 0.00?*I, 1.00? + 0.00?*I)

        The product actually contains the vector v, we check entry wise::
 
            sage: [s in t for s, t in zip(v, m * a)]
            [True, True, True, True]

        """

        # m = matrix(QQ,[[4,3,2,3],[2,3,6,2],[2,4,1,6],[3,2,-5,2]])
        # v = vector(QQ,[4,2,0,1])

        # For illustration, we use the following example of a matrix and
        # vector (which for simplicity are not intervals here):
        #
        #      [ 4  3  2  3]
        #  m = [ 2  3  6  2]       v = (4, 2, 0, 1)
        #      [ 2  4  1  6]
        #      [ 3  2 -5  2]
        #

        # Create a block matrix of the form
        # [ 4  3  2  3| 4]
        # [ 2  3  6  2| 2]
        # [ 2  4  1  6| 0]
        # [ 3  2 -5  2| 1]

        m1 = block_matrix([[m, v.column()]])

        # Iterate through the rows to apply row operations resulting
        # in the left part being the identity matrix.
        # After the i-th iteration the first i column will

        # For example, after the first iteration (i = 0), we get
        # [    1   3/4   1/2   3/4|    1]
        # [    0   3/2     5   1/2|    0]
        # [    0   5/2     0   9/2|   -2]
        # [    0  -1/4 -13/2  -1/4|   -2]

        # For example, after the second iteration (i = 1), we get
        # [    1     0   1/2  -3/5|  8/5]
        # [    0     1     0   9/5| -4/5]
        # [    0     0     5 -11/5|  6/5]
        # [    0     0 -13/2   1/5|-11/5]

        for i in range(len(v)):

            # Assume i = 2, then we have the above matrix at the start
            # of the iteration.

            # We look for the largest absolute value in the i-th column on or
            # below the diagonal and its index. In our example, the value
            # occurs in the last row, so max_index = 1 because -11/2 is
            # occurring at the spot one under the diagonal.
            #
            # Because we have intervals as input, we look for the interval
            # with the largest infimum of the absolute value.

            max_index, max_val = max(enumerate(m1.column(i)[i:]),
                                     key=lambda x: x[1].abs().lower())

            if max_val.contains_zero():
                raise ZeroDivisionError

            # For numerical stability, swap rows to avoid diagonal entries
            # that are close to zero. The results are still correct without
            # this swapping of rows but the intervals would be less narrow.

            # In the above example, we swap the last two rows:
            # [    1     0   1/2  -3/5|  8/5]
            # [    0     1     0   9/5| -4/5]
            # [    0     0 -13/2   1/5|-11/5]
            # [    0     0     5 -11/5|  6/5]

            if max_index != 0:
                m1[max_index + i], m1[i] = m1[i], m1[max_index + i]

            # Divide the i-th row so that its i-th coefficient becomes 1
            # [    1     0   1/2  -3/5|  8/5]
            # [    0     1     0   9/5| -4/5]
            # [    0     0     1 -2/65|22/65]
            # [    0     0     5 -11/5|  6/5]

            m1[i] /= m1[i][i]

            # Subtract multiples of the current row to make the i-th
            # entries of all other rows zero.

            # [      1       0       0  -38/65|  93/65]
            # [      0       1       0     9/5|   -4/5]
            # [      0       0       1   -2/65|  22/65]
            # [      0       0       0 -133/65| -32/65]

            for j in range(len(v)):
                if i != j:
                    m1[j] -= m1[j][i] * m1[i]

        # After iterations, we have
        # [       1        0        0        0|    11/7]
        # [       0        1        0        0|-164/133]
        # [       0        0        1        0|  46/133]
        # [       0        0        0        1|  32/133]

        # Return the last column
        # (11/7, -164/133, 46/133, 32/133)

        return m1.column(-1)
Esempio n. 28
0
    def _find_cyclic_isomorphism_matching_edge(self, polytope, polytope_origin,
                                               p_ray_left, p_ray_right):
        """
        Helper to find an isomorphism of polygons

        INPUT:

        - ``polytope`` -- the lattice polytope to compare to.

        - ``polytope_origin`` -- `\ZZ`-vector. a vertex of ``polytope``

        - ``p_ray_left`` - vector. the vector from ``polytope_origin``
          to one of its neighboring vertices.

        - ``p_ray_right`` - vector. the vector from
          ``polytope_origin`` to the other neighboring vertices.

        OUTPUT:

        The element of the lattice Euclidean group that maps ``self``
        to ``polytope`` with given origin and left/right neighboring
        vertex. A
        :class:`~sage.geometry.polyhedron.lattice_euclidean_group_element.LatticePolytopesNotIsomorphicError`
        is raised if no such isomorphism exists.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL
            sage: L1 = LatticePolytope_PPL((1,0),(0,1),(0,0))
            sage: L2 = LatticePolytope_PPL((1,0,3),(0,1,0),(0,0,1))
            sage: v0, v1, v2 = L2.vertices()
            sage: L1._find_cyclic_isomorphism_matching_edge(L2, v0, v1-v0, v2-v0)
            The map A*x+b with A=
            [ 0  1]
            [-1 -1]
            [ 1  3]
            b =
            (0, 1, 0)
        """
        from sage.geometry.polyhedron.lattice_euclidean_group_element import \
            LatticePolytopesNotIsomorphicError
        polytope_matrix = block_matrix(
            1, 2,
            [p_ray_left.column(), p_ray_right.column()])
        self_vertices = self.ordered_vertices()
        for i in range(len(self_vertices)):
            # three consecutive vertices
            v_left = self_vertices[(i + 0) % len(self_vertices)]
            v_origin = self_vertices[(i + 1) % len(self_vertices)]
            v_right = self_vertices[(i + 2) % len(self_vertices)]
            r_left = v_left - v_origin
            r_right = v_right - v_origin
            self_matrix = block_matrix(
                1, 2, [r_left.column(), r_right.column()])
            A = self_matrix.solve_left(polytope_matrix)
            b = polytope_origin - A * v_origin
            try:
                A = matrix(ZZ, A)
                b = vector(ZZ, b)
            except TypeError:
                continue
            if A.elementary_divisors()[0:2] != [1, 1]:
                continue
            hom = LatticeEuclideanGroupElement(A, b)
            if hom(self) == polytope:
                return hom
        raise LatticePolytopesNotIsomorphicError('different polygons')
Esempio n. 29
0
def SymplecticPolarGraph(d, q, algorithm=None):
    r"""
    Returns the Symplectic Polar Graph `Sp(d,q)`.

    The Symplectic Polar Graph `Sp(d,q)` is built from a projective space of dimension
    `d-1` over a field `F_q`, and a symplectic form `f`. Two vertices `u,v` are
    made adjacent if `f(u,v)=0`.

    See the page `on symplectic graphs on Andries Brouwer's website
    <http://www.win.tue.nl/~aeb/graphs/Sp.html>`_.

    INPUT:

    - ``d,q`` (integers) -- note that only even values of `d` are accepted by
      the function.

    - ``algorithm`` -- if set to 'gap' then the computation is carried via GAP
      library interface, computing totally singular subspaces, which is faster for `q>3`.
      Otherwise it is done directly.

    EXAMPLES:

    Computation of the spectrum of `Sp(6,2)`::

        sage: g = graphs.SymplecticGraph(6,2)
        doctest:...: DeprecationWarning: SymplecticGraph is deprecated. Please use sage.graphs.generators.classical_geometries.SymplecticPolarGraph instead.
        See http://trac.sagemath.org/19136 for details.
        sage: g.is_strongly_regular(parameters=True)
        (63, 30, 13, 15)
        sage: set(g.spectrum()) == {-5, 3, 30}
        True

    The parameters of `Sp(4,q)` are the same as of `O(5,q)`, but they are
    not isomorphic if `q` is odd::

        sage: G = graphs.SymplecticPolarGraph(4,3)
        sage: G.is_strongly_regular(parameters=True)
        (40, 12, 2, 4)
        sage: O=graphs.OrthogonalPolarGraph(5,3)
        sage: O.is_strongly_regular(parameters=True)
        (40, 12, 2, 4)
        sage: O.is_isomorphic(G)
        False
        sage: graphs.SymplecticPolarGraph(6,4,algorithm="gap").is_strongly_regular(parameters=True) # not tested (long time)
        (1365, 340, 83, 85)

    TESTS::

        sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True)
        (85, 20, 3, 5)
        sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True)
        (85, 20, 3, 5)
        sage: graphs.SymplecticPolarGraph(4,4,algorithm="blah")
        Traceback (most recent call last):
        ...
        ValueError: unknown algorithm!
    """
    if d < 1 or d % 2 != 0:
        raise ValueError("d must be even and greater than 2")

    if algorithm == "gap":  # faster for larger (q>3)  fields
        from sage.libs.gap.libgap import libgap
        G = _polar_graph(d, q, libgap.SymplecticGroup(d, q))

    elif algorithm == None:  # faster for small (q<4) fields
        from sage.rings.finite_rings.constructor import FiniteField
        from sage.modules.free_module import VectorSpace
        from sage.schemes.projective.projective_space import ProjectiveSpace
        from sage.matrix.constructor import identity_matrix, block_matrix, zero_matrix

        F = FiniteField(q, "x")
        M = block_matrix(F, 2, 2, [
            zero_matrix(F, d / 2),
            identity_matrix(F, d / 2), -identity_matrix(F, d / 2),
            zero_matrix(F, d / 2)
        ])

        V = VectorSpace(F, d)
        PV = list(ProjectiveSpace(d - 1, F))
        G = Graph([[tuple(_) for _ in PV], lambda x, y: V(x) *
                   (M * V(y)) == 0],
                  loops=False)

    else:
        raise ValueError("unknown algorithm!")

    G.name("Symplectic Polar Graph Sp(" + str(d) + "," + str(q) + ")")
    G.relabel()
    return G
Esempio n. 30
0
    def _find_cyclic_isomorphism_matching_edge(self, polytope,
                                               polytope_origin, p_ray_left,
                                               p_ray_right):
        """
        Helper to find an isomorphism of polygons

        INPUT:

        - ``polytope`` -- the lattice polytope to compare to.

        - ``polytope_origin`` -- `\ZZ`-vector. a vertex of ``polytope``

        - ``p_ray_left`` - vector. the vector from ``polytope_origin``
          to one of its neighboring vertices.

        - ``p_ray_right`` - vector. the vector from
          ``polytope_origin`` to the other neighboring vertices.

        OUTPUT:

        The element of the lattice Euclidean group that maps ``self``
        to ``polytope`` with given origin and left/right neighboring
        vertex. A
        :class:`~sage.geometry.polyhedron.lattice_euclidean_group_element.LatticePolytopesNotIsomorphicError`
        is raised if no such isomorphism exists.

        EXAMPLES::

            sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL
            sage: L1 = LatticePolytope_PPL((1,0),(0,1),(0,0))
            sage: L2 = LatticePolytope_PPL((1,0,3),(0,1,0),(0,0,1))
            sage: v0, v1, v2 = L2.vertices()
            sage: L1._find_cyclic_isomorphism_matching_edge(L2, v0, v1-v0, v2-v0)
            The map A*x+b with A=
            [ 0  1]
            [-1 -1]
            [ 1  3]
            b =
            (0, 1, 0)
        """
        from sage.geometry.polyhedron.lattice_euclidean_group_element import \
            LatticePolytopesNotIsomorphicError
        polytope_matrix = block_matrix(1, 2, [p_ray_left.column(),
                                              p_ray_right.column()])
        self_vertices = self.ordered_vertices()
        for i in range(len(self_vertices)):
            # three consecutive vertices
            v_left = self_vertices[(i+0) % len(self_vertices)]
            v_origin = self_vertices[(i+1) % len(self_vertices)]
            v_right = self_vertices[(i+2) % len(self_vertices)]
            r_left = v_left-v_origin
            r_right = v_right-v_origin
            self_matrix = block_matrix(1, 2, [r_left.column(),
                                              r_right.column()])
            A = self_matrix.solve_left(polytope_matrix)
            b = polytope_origin - A*v_origin
            try:
                A = matrix(ZZ, A)
                b = vector(ZZ, b)
            except TypeError:
                continue
            if A.elementary_divisors()[0:2] != [1, 1]:
                continue
            hom = LatticeEuclideanGroupElement(A, b)
            if hom(self) == polytope:
                return hom
        raise LatticePolytopesNotIsomorphicError('different polygons')
Esempio n. 31
0
        if abs(a-q) < abs(a): return (a-q)*-1
        else: return a*-1
    def minrep(a):
        if abs(a-q) < abs(a): return (a-q)
        else: return a
    A_prime = A[(n/2):(n+1)].lift().apply_map(minrep)
#    b_neg= A[(n):(n+1)].lift().apply_map(minrepnegative)
    Z_fixed=Z_mattop.lift().apply_map(minrep)
    print("Z_fixed={0}\n||Z_fixed||={1}".format(Z_fixed,float(Z_fixed[0].norm())))
    print('Z_fixed*A={0}\n\n'.format(Z_fixed*A))

    print("z_fixed[0].norm()={0}".format(float(Z_fixed[0].norm())))
#    B=block_matrix([[ZZ(q),ZZ.zero()],[A_neg,ZZ.one()]], subdivide=False)
#    B = block_matrix([[ZZ.one(), -A_prime.transpose()],
#                     [ZZ.zero(), ZZ(q)]], subdivide=False)
    B = block_matrix([[ZZ(q), ZZ.zero()], [-A_prime, ZZ.one()]], subdivide=False)
#    for i in range(m//2):
#        B.swap_rows(i,m-i-1)
    #    print("{0}\n".format(A_neg))
 #   B=block_matrix([[ZZ(q), ZZ.zero(),ZZ.zero()],[ZZ.one(),A_neg,ZZ.zero() ],[ZZ.zero(),b_neg,ZZ.one()]],
                     #  subdivide=False)
    #print("B=\n{0}".format(B))
    print("B*A=\n{0}\n\n".format(B*A))
    #print("A=\n{0}\n".format(A))
    def remap(x):
        return minrep((x*251)%251)
    BL=B.BKZ(block_size=n/2.)
    y=(BL.solve_left(Z_fixed))#.apply_map(remap))

#   print("y*B={0}".format(y*B))
    print("y:=B.solve_left(Z_fixed)={0}".format(y))
    def find_point(self, supports, roots, case, solution = 0):
        r"""
        Given a solubility certificate like in [HC2006]_, find a point on
        ``self``. Assumes ``self`` is in reduced form (see [HC2006] for a
        definition).

        If you don't have a solubility certificate and just want to find a
        point, use the function :meth:`has_rational_point` instead.
        
        INPUT:
        
        - ``self`` -- conic in reduced form.
        - ``supports`` -- 3-tuple where ``supports[i]`` is a list of all monic
          irreducible `p \in F[t]` that divide the `i`'th of the 3 coefficients.
        - ``roots`` -- 3-tuple containing lists of roots of all elements of
          ``supports[i]``, in the same order.
        - ``case`` -- 1 or 0, as in [HC2006]_.
        - ``solution`` -- (default: 0) a solution of (5) in [HC2006]_, if
          case = 0, 0 otherwise.
        
        OUTPUT:
        
        A point `(x,y,z) \in F(t)` of ``self``. Output is undefined when the
        input solubility certificate is incorrect.

        ALGORITMH:
        
        The algorithm used is the algorithm FindPoint in [HC2006]_, with
        a simplification from [ACKERMANS2016]_.
        
        EXAMPLES::
            
            sage: K.<t> = FractionField(QQ['t'])
            sage: C = Conic(K, [t^2-2, 2*t^3, -2*t^3-13*t^2-2*t+18])
            sage: C.has_rational_point(point=True) # indirect test
            (True, (-3 : (t + 1)/t : 1))

        Different solubility certificates give different points::

            sage: K.<t> = PolynomialRing(QQ, 't')
            sage: C = Conic(K, [t^2-2, 2*t, -2*t^3-13*t^2-2*t+18])
            sage: supp = [[t^2 - 2], [t], [t^3 + 13/2*t^2 + t - 9]]
            sage: tbar1 = QQ.extension(supp[0][0], 'tbar').gens()[0]
            sage: tbar2 = QQ.extension(supp[1][0], 'tbar').gens()[0]
            sage: tbar3 = QQ.extension(supp[2][0], 'tbar').gens()[0]
            sage: roots = [[tbar1 + 1], [1/3*tbar2^0], [2/3*tbar3^2 + 11/3*tbar3 - 3]]
            sage: C.find_point(supp, roots, 1)
            (3 : t + 1 : 1)
            sage: roots = [[-tbar1 - 1], [-1/3*tbar2^0], [-2/3*tbar3^2 - 11/3*tbar3 + 3]]
            sage: C.find_point(supp, roots, 1)
            (3 : -t - 1 : 1)
        """
        Ft = self.base().base()
        F = Ft.base()
        t, = Ft.gens()
        coefficients = [Ft(self.coefficients()[0]), Ft(self.coefficients()[3]),
            Ft(self.coefficients()[5])]
        deg = [coefficients[0].degree(), coefficients[1].degree(),
                coefficients[2].degree()]
        # definitions as in [HC2006] and [ACKERMANS2016]
        A = ((deg[1] + deg[2]) / 2).ceil() - case
        B = ((deg[2] + deg[0]) / 2).ceil() - case
        C = ((deg[0] + deg[1]) / 2).ceil() - case
        
        # For all roots as calculated by has_rational_point(), we create
        # a system of linear equations. As in [ACKERMANS2016], we do this
        # by calculating the matrices for all phi_p, with basis consisting
        # of monomials of x, y and z in the space V of potential solutions:
        # t^0, ..., t^A, t^0, ..., t^B and t^0, ..., t^C.
        phi = []
        for (i, p) in enumerate(supports[0]):
            # lift to F[t] and map to R, with R as defined above
            if roots[0][i].parent().is_finite():
                root = roots[0][i].polynomial()
            else:
                root = roots[0][i].lift()
            alpha = root.parent().hom([t])(root)
            d = p.degree()
            # Calculate y - alpha*z mod p for all basis vectors
            phi_p = [[] for i in range(A+B+C+4)]
            phi_p[0:A+1] = [vector(F, d)] * (A+1)
            phi_p[A+1] = vector(F, d, {0: F(1)})
            lastpoly = F(1)
            for n in range(B):
                lastpoly = (lastpoly * t) % p
                phi_p[A+2+n] = vector(F, d, lastpoly.dict())
            lastpoly = -alpha % p
            phi_p[A+B+2] = vector(F, d, lastpoly.dict())
            for n in range(C):
                lastpoly = (lastpoly * t) % p
                phi_p[A+B+3+n] = vector(F, d, lastpoly.dict())
            phi_p[A+B+C+3] = vector(F, d)
            phi.append(matrix(phi_p).transpose())
        for (i, p) in enumerate(supports[1]):
            if roots[1][i].parent().is_finite():
                root = roots[1][i].polynomial()
            else:
                root = roots[1][i].lift()
            alpha = root.parent().hom([t])(root)
            d = p.degree()
            # Calculate z - alpha*x mod p for all basis vectors
            phi_p = [[] for i in range(A+B+C+4)]
            phi_p[A+1:A+B+2] = [vector(F, d)] * (B+1)
            phi_p[A+B+2] = vector(F, d, {0: F(1)})
            lastpoly = F(1)
            for n in range(C):
                lastpoly = (lastpoly * t) % p
                phi_p[A+B+3+n] = vector(F, d, lastpoly.dict())
            lastpoly = -alpha % p
            phi_p[0] = vector(F, d, lastpoly.dict())
            for n in range(A):
                lastpoly = (lastpoly * t) % p
                phi_p[1+n] = vector(F, d, lastpoly.dict())
            phi_p[A+B+C+3] = vector(F, d)
            phi.append(matrix(phi_p).transpose())
        for (i, p) in enumerate(supports[2]):
            if roots[2][i].parent().is_finite():
                root = roots[2][i].polynomial()
            else:
                root = roots[2][i].lift()
            alpha = root.parent().hom([t])(root)
            d = p.degree()
            # Calculate x - alpha*y mod p for all basis vectors
            phi_p = [[] for i in range(A+B+C+4)]
            phi_p[A+B+2:A+B+C+3] = [vector(F, d)] * (C+1)
            phi_p[0] = vector(F, d, {0: F(1)})
            lastpoly = F(1)
            for n in range(A):
                lastpoly = (lastpoly * t) % p
                phi_p[1+n] = vector(F, d, lastpoly.dict())
            lastpoly = -alpha % p
            phi_p[A+1] = vector(F, d, lastpoly.dict())
            for n in range(B):
                lastpoly = (lastpoly * t) % p
                phi_p[A+2+n] = vector(F, d, lastpoly.dict())
            phi_p[A+B+C+3] = vector(F, d)
            phi.append(matrix(phi_p).transpose())
        if case == 0:
            # We need three more equations
            lx = Ft(solution[0]).leading_coefficient()
            ly = Ft(solution[1]).leading_coefficient()
            lz = Ft(solution[2]).leading_coefficient()
            phi.append(matrix([vector(F, A+B+C+4, {A:1, A+B+C+3:-lx}),
                vector(F, A+B+C+4, {A+B+1:1, A+B+C+3:-ly}),
                vector(F, A+B+C+4, {A+B+C+2: 1, A+B+C+3:-lz})]))
        # Create the final matrix which we will solve
        M = block_matrix(phi, ncols = 1, subdivide = False)
        solution_space = M.right_kernel()
        for v in solution_space.basis():
            if v[:A+B+C+3] != 0: # we don't want to return a trivial solution
                X = Ft(list(v[:A+1]))
                Y = Ft(list(v[A+1:A+B+2]))
                Z = Ft(list(v[A+B+2:A+B+C+3]))
                return self.point([X,Y,Z])

        raise RuntimeError("No solution has been found: possibly incorrect\
 solubility certificate.")
Esempio n. 33
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_()
Esempio n. 34
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det()
        2985984
        sage: 12^6
        2985984

    We note that the method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12)
        [ 1  1| 1  1| 1  1| 1  1| 1  1| 1  1]
        [ 1 -1|-1  1|-1  1|-1  1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1 -1| 1  1|-1 -1|-1 -1| 1  1]
        [ 1  1|-1 -1| 1 -1|-1  1|-1  1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1| 1 -1| 1  1|-1 -1|-1 -1]
        [ 1  1| 1 -1|-1 -1| 1 -1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1| 1  1| 1 -1| 1  1|-1 -1]
        [ 1  1|-1  1| 1 -1|-1 -1| 1 -1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1|-1 -1| 1  1| 1 -1| 1  1]
        [ 1  1|-1  1|-1  1| 1 -1|-1 -1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1|-1 -1|-1 -1| 1  1| 1 -1]
        [ 1  1| 1 -1|-1  1|-1  1| 1 -1|-1 -1]

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix_paleyII, is_hadamard_matrix)
        sage: test_cases = [2*(x+1) for x in range(50) if is_prime_power(x) and x%4==1]
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyII(n),normalized=True,verbose=True)
        ....:     for n in test_cases)
        True
    """
    q = n//2 - 1
    if not(n%2==0 and is_prime_power(q) and (q % 4 == 1)):
        raise ValueError("The order %s is not covered by the Paley type II construction." % n)

    from sage.rings.finite_rings.finite_field_constructor import FiniteField
    K = FiniteField(q,'x')
    K_list = list(K)
    K_list.insert(0,K.zero())
    H = matrix(ZZ, [[(1 if (x-y).is_square() else -1)
                     for x in K_list]
                    for y in K_list])
    for i in range(q+1):
        H[0,i] = 1
        H[i,0] = 1
        H[i,i] = 0

    tr = { 0: matrix(2,2,[ 1,-1,-1,-1]),
           1: matrix(2,2,[ 1, 1, 1,-1]),
          -1: matrix(2,2,[-1,-1,-1, 1])}

    H = block_matrix(q+1,q+1,[tr[v] for r in H for v in r])

    return normalise_hadamard(H)
Esempio n. 35
0
def rshcd_from_prime_power_and_conference_matrix(n):
    r"""
    Return a `((n-1)^2,1)`-RSHCD if `n` is prime power, and symmetric `(n-1)`-conference matrix exists

    The construction implemented here is Theorem 16 (and Corollary 17) from [WW72]_.

    In [SWW72]_ this construction (Theorem 5.15 and Corollary 5.16)
    is reproduced with a typo. Note that [WW72]_ refers to [Sz69]_ for the construction,
    provided by :func:`szekeres_difference_set_pair`,
    of complementary difference sets, and the latter has a typo.

    From a :func:`symmetric_conference_matrix`, we only need the Seidel
    adjacency matrix of the underlying strongly regular conference (i.e. Paley
    type) graph, which we construct directly.

    INPUT:

    - ``n`` -- an integer

    .. SEEALSO::

        :func:`regular_symmetric_hadamard_matrix_with_constant_diagonal`

    EXAMPLES:

    A 36x36 example ::

        sage: from sage.combinat.matrices.hadamard_matrix import rshcd_from_prime_power_and_conference_matrix
        sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix
        sage: H = rshcd_from_prime_power_and_conference_matrix(7); H
        36 x 36 dense matrix over Integer Ring (use the '.str()' method to see the entries)
        sage: H==H.T and is_hadamard_matrix(H) and H.diagonal()==[1]*36 and list(sum(H))==[6]*36
        True

    Bigger examples, only provided by this construction ::

        sage: H = rshcd_from_prime_power_and_conference_matrix(27)  # long time
        sage: H == H.T and is_hadamard_matrix(H)                    # long time
        True
        sage: H.diagonal()==[1]*676 and list(sum(H))==[26]*676      # long time
        True

    In this example the conference matrix is not Paley, as 45 is not a prime power ::

        sage: H = rshcd_from_prime_power_and_conference_matrix(47)  # not tested (long time)

    REFERENCE:

    .. [WW72] \J. Wallis and A.L. Whiteman,
      Some classes of Hadamard matrices with constant diagonal,
      Bull. Austral. Math. Soc. 7(1972), 233-249
    """
    from sage.graphs.strongly_regular_db import strongly_regular_graph as srg
    if is_prime_power(n) and 2 == (n - 1) % 4:
        try:
            M = srg(n - 2, (n - 3) // 2, (n - 7) // 4)
        except ValueError:
            return
        m = (n - 3) // 4
        Q, X, Y = szekeres_difference_set_pair(m)
        B = typeI_matrix_difference_set(Q, X)
        A = -typeI_matrix_difference_set(Q, Y)  # must be symmetric
        W = M.seidel_adjacency_matrix()
        f = J(1, 4 * m + 1)
        e = J(1, 2 * m + 1)
        JJ = J(2 * m + 1, 2 * m + 1)
        II = I(n - 2)
        Ib = I(2 * m + 1)
        J4m = J(4 * m + 1, 4 * m + 1)
        H34 = -(B + Ib).tensor_product(W) + Ib.tensor_product(J4m) + (
            Ib - JJ).tensor_product(II)
        A_t_W = A.tensor_product(W)
        e_t_f = e.tensor_product(f)
        H = block_matrix(
            [[J(1, 1), f, e_t_f, -e_t_f],
             [f.T, J4m,
              e.tensor_product(W - II),
              e.tensor_product(W + II)],
             [
                 e_t_f.T, (e.T).tensor_product(W - II),
                 A_t_W + JJ.tensor_product(II), H34
             ],
             [
                 -e_t_f.T, (e.T).tensor_product(W + II), H34.T,
                 -A_t_W + JJ.tensor_product(II)
             ]])
        return H
Esempio n. 36
0
def skew_hadamard_matrix(n, existence=False, skew_normalize=True, check=True):
    r"""
    Tries to construct a skew Hadamard matrix

    A Hadamard matrix `H` is called skew if `H=S-I`, for `I` the identity matrix
    and `-S=S^\top`. Currently constructions from Section 14.1 of [Ha83]_ and few
    more exotic ones are implemented.

    INPUT:

    - ``n`` (integer) -- dimension of the matrix

    - ``existence`` (boolean) -- whether to build the matrix or merely query if
      a construction is available in Sage. When set to ``True``, the function
      returns:

        - ``True`` -- meaning that Sage knows how to build the matrix

        - ``Unknown`` -- meaning that Sage does not know how to build the
          matrix, but that the design may exist (see :mod:`sage.misc.unknown`).

        - ``False`` -- meaning that the matrix does not exist.

    - ``skew_normalize`` (boolean) -- whether to make the 1st row all-one, and
      adjust the 1st column accordingly. Set to ``True`` by default.

    - ``check`` (boolean) -- whether to check that output is correct before
      returning it. As this is expected to be useless (but we are cautious
      guys), you may want to disable it whenever you want speed. Set to ``True``
      by default.

    EXAMPLES::

        sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix
        sage: skew_hadamard_matrix(12).det()
        2985984
        sage: 12^6
        2985984
        sage: skew_hadamard_matrix(1)
        [1]
        sage: skew_hadamard_matrix(2)
        [ 1  1]
        [-1  1]

    TESTS::

        sage: skew_hadamard_matrix(10,existence=True)
        False
        sage: skew_hadamard_matrix(12,existence=True)
        True
        sage: skew_hadamard_matrix(784,existence=True)
        True
        sage: skew_hadamard_matrix(10)
        Traceback (most recent call last):
        ...
        ValueError: A skew Hadamard matrix of order 10 does not exist
        sage: skew_hadamard_matrix(36)
        36 x 36 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(36)==skew_hadamard_matrix(36,skew_normalize=False)
        False
        sage: skew_hadamard_matrix(52)
        52 x 52 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(92)
        92 x 92 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(816)     # long time
        816 x 816 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(100)
        Traceback (most recent call last):
        ...
        ValueError: A skew Hadamard matrix of order 100 is not yet implemented.
        sage: skew_hadamard_matrix(100,existence=True)
        Unknown

    REFERENCES:

    .. [Ha83] \M. Hall,
      Combinatorial Theory,
      2nd edition,
      Wiley, 1983
    """
    def true():
        _skew_had_cache[n] = True
        return True

    M = None
    if existence and n in _skew_had_cache:
        return True
    if not (n % 4 == 0) and (n > 2):
        if existence:
            return False
        raise ValueError("A skew Hadamard matrix of order %s does not exist" %
                         n)
    if n == 2:
        if existence:
            return true()
        M = matrix([[1, 1], [-1, 1]])
    elif n == 1:
        if existence:
            return true()
        M = matrix([1])
    elif is_prime_power(n - 1) and ((n - 1) % 4 == 3):
        if existence:
            return true()
        M = hadamard_matrix_paleyI(n, normalize=False)

    elif n % 8 == 0:
        if skew_hadamard_matrix(n // 2,
                                existence=True):  # (Lemma 14.1.6 in [Ha83]_)
            if existence:
                return true()
            H = skew_hadamard_matrix(n // 2, check=False)
            M = block_matrix([[H, H], [-H.T, H.T]])

        else:  # try Williamson construction (Lemma 14.1.5 in [Ha83]_)
            for d in divisors(n)[2:-2]:  # skip 1, 2, n/2, and n
                n1 = n // d
                if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0)\
                    and skew_hadamard_matrix(n1,existence=True):
                    if existence:
                        return true()
                    H = skew_hadamard_matrix(n1, check=False) - I(n1)
                    U = matrix(ZZ, d, lambda i, j: -1 if i==j==0 else\
                                        1 if i==j==1 or (i>1 and j-1==d-i)\
                                          else 0)
                    A = block_matrix(
                        [[matrix([0]),
                          matrix(ZZ, 1, d - 1, [1] * (d - 1))],
                         [
                             matrix(ZZ, d - 1, 1, [-1] * (d - 1)),
                             _helper_payley_matrix(d - 1, zero_position=0)
                         ]]) + I(d)
                    M = A.tensor_product(I(n1)) + (U * A).tensor_product(H)
                    break
    if M is None:  # try Williamson-Goethals-Seidel construction
        if GS_skew_hadamard_smallcases(n, existence=True):
            if existence:
                return true()
            M = GS_skew_hadamard_smallcases(n)

        else:
            if existence:
                return Unknown
            raise ValueError(
                "A skew Hadamard matrix of order %s is not yet implemented." %
                n)
    if skew_normalize:
        dd = diagonal_matrix(M[0])
        M = dd * M * dd
    if check:
        assert is_hadamard_matrix(M, normalized=False, skew=True)
        if skew_normalize:
            from sage.modules.free_module_element import vector
            assert M[0] == vector([1] * n)
    _skew_had_cache[n] = True
    return M
Esempio n. 37
0
def rshcd_from_prime_power_and_conference_matrix(n):
    r"""
    Return a `((n-1)^2,1)`-RSHCD if `n` is prime power, and symmetric `(n-1)`-conference matrix exists

    The construction implemented here is Theorem 16 (and Corollary 17) from [WW72]_.

    In [SWW72]_ this construction (Theorem 5.15 and Corollary 5.16)
    is reproduced with a typo. Note that [WW72]_ refers to [Sz69]_ for the construction,
    provided by :func:`szekeres_difference_set_pair`,
    of complementary difference sets, and the latter has a typo.

    From a :func:`symmetric_conference_matrix`, we only need the Seidel
    adjacency matrix of the underlying strongly regular conference (i.e. Paley
    type) graph, which we construct directly.

    INPUT:

    - ``n`` -- an integer

    .. SEEALSO::

        :func:`regular_symmetric_hadamard_matrix_with_constant_diagonal`

    EXAMPLES:

    A 36x36 example ::

        sage: from sage.combinat.matrices.hadamard_matrix import rshcd_from_prime_power_and_conference_matrix
        sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix
        sage: H = rshcd_from_prime_power_and_conference_matrix(7); H
        36 x 36 dense matrix over Integer Ring (use the '.str()' method to see the entries)
        sage: H==H.T and is_hadamard_matrix(H) and H.diagonal()==[1]*36 and list(sum(H))==[6]*36
        True

    Bigger examples, only provided by this construction ::

        sage: H = rshcd_from_prime_power_and_conference_matrix(27)  # long time
        sage: H == H.T and is_hadamard_matrix(H)                    # long time
        True
        sage: H.diagonal()==[1]*676 and list(sum(H))==[26]*676      # long time
        True

    In this example the conference matrix is not Paley, as 45 is not a prime power ::

        sage: H = rshcd_from_prime_power_and_conference_matrix(47)  # not tested (long time)

    REFERENCE:

    .. [WW72] \J. Wallis and A.L. Whiteman,
      Some classes of Hadamard matrices with constant diagonal,
      Bull. Austral. Math. Soc. 7(1972), 233-249
    """
    from sage.graphs.strongly_regular_db import strongly_regular_graph as srg
    if is_prime_power(n) and 2==(n-1)%4:
        try:
            M = srg(n-2,(n-3)//2,(n-7)//4)
        except ValueError:
            return
        m = (n-3)//4
        Q,X,Y = szekeres_difference_set_pair(m)
        B = typeI_matrix_difference_set(Q,X)
        A = -typeI_matrix_difference_set(Q,Y) # must be symmetric
        W = M.seidel_adjacency_matrix()
        f = J(1,4*m+1)
        e = J(1,2*m+1)
        JJ = J(2*m+1, 2*m+1)
        II = I(n-2)
        Ib = I(2*m+1)
        J4m = J(4*m+1,4*m+1)
        H34 = -(B+Ib).tensor_product(W)+Ib.tensor_product(J4m)+(Ib-JJ).tensor_product(II)
        A_t_W = A.tensor_product(W)
        e_t_f = e.tensor_product(f)
        H = block_matrix([
            [J(1,1),                 f,                      e_t_f,                  -e_t_f],
            [f.T,                  J4m,     e.tensor_product(W-II),  e.tensor_product(W+II)],
            [ e_t_f.T, (e.T).tensor_product(W-II), A_t_W+JJ.tensor_product(II),         H34],
            [-e_t_f.T, (e.T).tensor_product(W+II), H34.T,      -A_t_W+JJ.tensor_product(II)]])
        return H
Esempio n. 38
0
def my_gen_lattice2(n=4, q=11, seed=None,
                quotient=None, dual=False, ntl=False, lattice=False, GuessStuff=True):
    """
    This is a modification of the code for the gen_lattice function from Sage
 
    Randomness can be set either with ``seed``, or by using
    :func:`sage.misc.randstate.set_random_seed`.
 
    INPUT:
 
    - ``type`` -- one of the following strings
        - ``'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`.
    - ``t`` -- BKZ Block Size
    - ``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:
 
 
 
    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 [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]
 
 
    """
    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
    from sage.modules.free_module_integer import IntegerLattice
       
    if seed is not None:
        from sage.misc.randstate import set_random_seed
        set_random_seed(seed)
 
 
    m=n+1
    ZZ = IntegerRing()
    ZZ_q = IntegerModRing(q)
 
 
 
    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(2*n, 'x'), 'x')
    g=x**(n/2)+1
    T=ZZ_q['x'].quotient(x**(n/2)+1)
 
   
    a_pol=R.random_element()

    s_pol=sample_noise(R)
    e_pol=sample_noise(R)
 
    s_pol2=T((s_pol))
    e_pol2=T((e_pol))
    print("s={0},e={1}".format(T(s_pol),T(e_pol)))

    
    Z_mat=e_pol2.matrix().augment(s_pol2.matrix())
    Z_mattop=Z_mat[0:1].augment(matrix(1,1,[ZZ.one()*-1]))
  
  
    b_pol=(a_pol*s_pol+e_pol)
    print("s_pol={0}\ne_pol={1}".format((s_pol2).list(),(e_pol2).list()))
    # Does a linear mapping change the shortest vector size for the rest?/
    a_pol=a_pol#*x_pol
    b_pol=b_pol#*x_pol

    a_pol2 = T(a_pol.list())# % S(g.list())
    b_pol2 = T((b_pol).list())# % S(g.list())
#    print("a={0}\nb={1}".format(a_pol2,b_pol2))
    A=identity_matrix(ZZ_q,n/2)
    A=A.stack(a_pol2.matrix())
    
    
    b_prime=b_pol2.matrix()[0:1]
    b_prime=b_prime - 11*A[8:9]
    A=A.stack(b_pol2.matrix()[0:1])

    
    
#    print("X=\n{0}".format(X))

#    A = A.stack(identity_matrix(ZZ_q, n/2))
 
    print("A=\n{0}\n".format(A))
    # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2
    def minrepnegative(a):
        if abs(a-q) < abs(a): return (a-q)*-1
        else: return a*-1
    def minrep(a):
        if abs(a-q) < abs(a): return (a-q)
        else: return a
    A_prime = A[(n/2):(n+1)].lift().apply_map(minrep)
#    b_neg= A[(n):(n+1)].lift().apply_map(minrepnegative)
    Z_fixed=Z_mattop.lift().apply_map(minrep)
    print("Z_fixed={0}\n||Z_fixed||={1}".format(Z_fixed,float(Z_fixed[0].norm())))
    print('Z_fixed*A={0}\n\n'.format(Z_fixed*A))

    print("z_fixed[0].norm()={0}".format(float(Z_fixed[0].norm())))
#    B=block_matrix([[ZZ(q),ZZ.zero()],[A_neg,ZZ.one()]], subdivide=False)
#    B = block_matrix([[ZZ.one(), -A_prime.transpose()],
#                     [ZZ.zero(), ZZ(q)]], subdivide=False)
    B = block_matrix([[ZZ(q), ZZ.zero()], [-A_prime, ZZ.one()]], subdivide=False)
#    for i in range(m//2):
#        B.swap_rows(i,m-i-1)
    #    print("{0}\n".format(A_neg))
 #   B=block_matrix([[ZZ(q), ZZ.zero(),ZZ.zero()],[ZZ.one(),A_neg,ZZ.zero() ],[ZZ.zero(),b_neg,ZZ.one()]],
                     #  subdivide=False)
    #print("B=\n{0}".format(B))
    print("B*A=\n{0}\n\n".format(B*A))
    #print("A=\n{0}\n".format(A))
    def remap(x):
        return minrep((x*251)%251)
    BL=B.BKZ(block_size=n/2.)
    y=(BL.solve_left(Z_fixed))#.apply_map(remap))

#   print("y*B={0}".format(y*B))
    print("y:=B.solve_left(Z_fixed)={0}".format(y))
#    BL=B.BKZ(block_size=n/2.)
    print(BL[0])
    print("shortest norm={0}".format(float(BL[0].norm())))
#    L = IntegerLattice(B)
#    p
#    v=L.shortest_vector()
#    print("L.shortest_vector={0}, norm={1}".format(v,float(v.norm())))
    if ntl and lattice:
        raise ValueError("Cannot specify ntl=True and lattice=True ")
    if ntl:
        return B._ntl_()
    elif lattice:
        from sage.modules.free_module_integer import IntegerLattice
        return IntegerLattice(B)
    else:
        return B
Esempio n. 39
0
    def cohomology_complex(self, m):
        r"""
        Return the "cohomology complex" `C^*(m)`

        See [Klyachko]_, equation 4.2.

        INPUT:

        - ``m`` -- tuple of integers or `M`-lattice point. A point in
          the dual lattice of the fan. Must be immutable.

        OUTPUT:

        The "cohomology complex" as a chain complex over the
        :meth:`base_ring`.

        EXAMPLES::

            sage: P3 = toric_varieties.P(3)
            sage: rays = [(1,0,0), (0,1,0), (0,0,1)]
            sage: F1 = FilteredVectorSpace(rays, {0:[0], 1:[2], 2:[1]})
            sage: F2 = FilteredVectorSpace(rays, {0:[1,2], 1:[0]})
            sage: r = P3.fan().rays()
            sage: V = P3.sheaves.Klyachko({r[0]:F1, r[1]:F2, r[2]:F2, r[3]:F2})
            sage: tau = Cone([(1,0,0), (0,1,0)])
            sage: sigma = Cone([(1, 0, 0)])
            sage: M = P3.fan().dual_lattice()
            sage: m = M(1, 1, 0); m.set_immutable()
            sage: V.cohomology_complex(m)
            Chain complex with at most 2 nonzero terms over Rational Field

            sage: F = CyclotomicField(3)
            sage: P3 = toric_varieties.P(3).change_ring(F)
            sage: V = P3.sheaves.Klyachko({r[0]:F1, r[1]:F2, r[2]:F2, r[3]:F2})
            sage: V.cohomology_complex(m)
            Chain complex with at most 2 nonzero terms over Cyclotomic
            Field of order 3 and degree 2
        """
        fan = self._variety.fan()
        C = fan.complex()
        CV = []
        F = self.base_ring()
        for dim in range(1,fan.dim()+1):
            codim = fan.dim() - dim
            d_C = C.differential(codim)
            d_V = []
            for j in range(0, d_C.ncols()):
                tau = fan(dim)[j]
                d_V_row = []
                for i in range(0, d_C.nrows()):
                    sigma = fan(dim-1)[i]
                    if sigma.is_face_of(tau):
                        pr = self.E_quotient_projection(sigma, tau, m)
                        d = d_C[i,j] * pr.matrix().transpose()
                    else:
                        E_sigma = self.E_quotient(sigma, m)
                        E_tau = self.E_quotient(tau, m)
                        d = zero_matrix(F, E_tau.dimension(), E_sigma.dimension())
                    d_V_row.append(d)
                d_V.append(d_V_row)
            d_V = block_matrix(d_V, ring=F)
            CV.append(d_V)
        from sage.homology.chain_complex import ChainComplex
        return ChainComplex(CV, base_ring=self.base_ring())
Esempio n. 40
0
def gen_lattice(type='modular', n=4, m=8, q=11, seed=None,
                quotient=None, dual=False, ntl=False, lattice=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`` -- 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 [R05]_.
    - ``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]
        [ 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]

    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]
        [ 4  1  4 -3  1  0  0  0]
        [-3  4  1  4  0  1  0  0]
        [ 4 -3  4  1  0  0  1  0]
        [ 1  4 -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

    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]

    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 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
Esempio n. 41
0
def rshcd_from_close_prime_powers(n):
    r"""
    Return a `(n^2,1)`-RSHCD when `n-1` and `n+1` are odd prime powers and `n=0\pmod{4}`.

    The construction implemented here appears in Theorem 4.3 from [GS70]_.

    Note that the authors of [SWW72]_ claim in Corollary 5.12 (page 342) to have
    proved the same result without the `n=0\pmod{4}` restriction with a *very*
    similar construction. So far, however, I (Nathann Cohen) have not been able
    to make it work.

    INPUT:

    - ``n`` -- an integer congruent to `0\pmod{4}`

    .. SEEALSO::

        :func:`regular_symmetric_hadamard_matrix_with_constant_diagonal`

    EXAMPLES::

        sage: from sage.combinat.matrices.hadamard_matrix import rshcd_from_close_prime_powers
        sage: rshcd_from_close_prime_powers(4)
        [-1 -1  1 -1  1 -1 -1  1 -1  1 -1 -1  1 -1  1 -1]
        [-1 -1  1  1 -1 -1 -1 -1 -1  1  1 -1 -1  1 -1  1]
        [ 1  1 -1  1  1 -1 -1 -1 -1 -1  1 -1 -1 -1  1 -1]
        [-1  1  1 -1  1  1 -1 -1 -1 -1 -1  1 -1 -1 -1  1]
        [ 1 -1  1  1 -1  1  1 -1 -1 -1 -1 -1  1 -1 -1 -1]
        [-1 -1 -1  1  1 -1  1  1 -1 -1 -1  1 -1  1 -1 -1]
        [-1 -1 -1 -1  1  1 -1 -1  1 -1  1 -1  1  1 -1 -1]
        [ 1 -1 -1 -1 -1  1 -1 -1 -1  1 -1  1 -1  1  1 -1]
        [-1 -1 -1 -1 -1 -1  1 -1 -1 -1  1  1  1 -1  1  1]
        [ 1  1 -1 -1 -1 -1 -1  1 -1 -1 -1 -1  1  1 -1  1]
        [-1  1  1 -1 -1 -1  1 -1  1 -1 -1 -1 -1  1  1 -1]
        [-1 -1 -1  1 -1  1 -1  1  1 -1 -1 -1 -1 -1  1  1]
        [ 1 -1 -1 -1  1 -1  1 -1  1  1 -1 -1 -1 -1 -1  1]
        [-1  1 -1 -1 -1  1  1  1 -1  1  1 -1 -1 -1 -1 -1]
        [ 1 -1  1 -1 -1 -1 -1  1  1 -1  1  1 -1 -1 -1 -1]
        [-1  1 -1  1 -1 -1 -1 -1  1  1 -1  1  1 -1 -1 -1]

    REFERENCE:

    .. [SWW72] A Street, W. Wallis, J. Wallis,
      Combinatorics: Room squares, sum-free sets, Hadamard matrices.
      Lecture notes in Mathematics 292 (1972).
    """
    if n%4:
        raise ValueError("n(={}) must be congruent to 0 mod 4")

    a,b = sorted([n-1,n+1],key=lambda x:-x%4)
    Sa  = _helper_payley_matrix(a)
    Sb  = _helper_payley_matrix(b)
    U   = matrix(a,[[int(i+j == a-1) for i in range(a)] for j in range(a)])

    K = (U*Sa).tensor_product(Sb) + U.tensor_product(J(b)-I(b)) - J(a).tensor_product(I(b))

    F = lambda x:diagonal_matrix([-(-1)**i for i in range(x)])
    G = block_diagonal_matrix([J(1),I(a).tensor_product(F(b))])
    e = matrix(a*b,[1]*(a*b))
    H = block_matrix(2,[-J(1),e.transpose(),e,K])

    HH = G*H*G
    assert len(set(map(sum,HH))) == 1
    assert HH**2 == n**2*I(n**2)
    return HH
Esempio n. 42
0
def SymplecticPolarGraph(d, q, algorithm=None):
    r"""
    Returns the Symplectic Polar Graph `Sp(d,q)`.

    The Symplectic Polar Graph `Sp(d,q)` is built from a projective space of dimension
    `d-1` over a field `F_q`, and a symplectic form `f`. Two vertices `u,v` are
    made adjacent if `f(u,v)=0`.

    See the page `on symplectic graphs on Andries Brouwer's website
    <http://www.win.tue.nl/~aeb/graphs/Sp.html>`_.

    INPUT:

    - ``d,q`` (integers) -- note that only even values of `d` are accepted by
      the function.

    - ``algorithm`` -- if set to 'gap' then the computation is carried via GAP
      library interface, computing totally singular subspaces, which is faster for `q>3`.
      Otherwise it is done directly.

    EXAMPLES:

    Computation of the spectrum of `Sp(6,2)`::

        sage: g = graphs.SymplecticGraph(6,2)
        doctest:...: DeprecationWarning: SymplecticGraph is deprecated. Please use sage.graphs.generators.classical_geometries.SymplecticPolarGraph instead.
        See http://trac.sagemath.org/19136 for details.
        sage: g.is_strongly_regular(parameters=True)
        (63, 30, 13, 15)
        sage: set(g.spectrum()) == {-5, 3, 30}
        True

    The parameters of `Sp(4,q)` are the same as of `O(5,q)`, but they are
    not isomorphic if `q` is odd::

        sage: G = graphs.SymplecticPolarGraph(4,3)
        sage: G.is_strongly_regular(parameters=True)
        (40, 12, 2, 4)
        sage: O=graphs.OrthogonalPolarGraph(5,3)
        sage: O.is_strongly_regular(parameters=True)
        (40, 12, 2, 4)
        sage: O.is_isomorphic(G)
        False
        sage: graphs.SymplecticPolarGraph(6,4,algorithm="gap").is_strongly_regular(parameters=True) # not tested (long time)
        (1365, 340, 83, 85)

    TESTS::

        sage: graphs.SymplecticPolarGraph(4,4,algorithm="gap").is_strongly_regular(parameters=True)
        (85, 20, 3, 5)
        sage: graphs.SymplecticPolarGraph(4,4).is_strongly_regular(parameters=True)
        (85, 20, 3, 5)
        sage: graphs.SymplecticPolarGraph(4,4,algorithm="blah")
        Traceback (most recent call last):
        ...
        ValueError: unknown algorithm!
    """
    if d < 1 or d%2 != 0:
        raise ValueError("d must be even and greater than 2")

    if algorithm == "gap":     # faster for larger (q>3)  fields
        from sage.libs.gap.libgap import libgap
        G = _polar_graph(d, q, libgap.SymplecticGroup(d, q))

    elif algorithm == None:    # faster for small (q<4) fields
        from sage.modules.free_module import VectorSpace
        from sage.schemes.projective.projective_space import ProjectiveSpace
        from sage.matrix.constructor import identity_matrix, block_matrix, zero_matrix

        F = FiniteField(q,"x")
        M = block_matrix(F, 2, 2,
                         [zero_matrix(F,d/2),
                          identity_matrix(F,d/2),
                          -identity_matrix(F,d/2),
                          zero_matrix(F,d/2)])

        V = VectorSpace(F,d)
        PV = list(ProjectiveSpace(d-1,F))
        G = Graph([[tuple(_) for _ in PV], lambda x,y:V(x)*(M*V(y)) == 0], loops = False)

    else:
        raise ValueError("unknown algorithm!")

    G.name("Symplectic Polar Graph Sp("+str(d)+","+str(q)+")")
    G.relabel()
    return G
Esempio n. 43
0
    def cohomology_complex(self, m):
        r"""
        Return the "cohomology complex" `C^*(m)`

        See [Klyachko]_, equation 4.2.

        INPUT:

        - ``m`` -- tuple of integers or `M`-lattice point. A point in
          the dual lattice of the fan. Must be immutable.

        OUTPUT:

        The "cohomology complex" as a chain complex over the
        :meth:`base_ring`.

        EXAMPLES::

            sage: P3 = toric_varieties.P(3)
            sage: rays = [(1,0,0), (0,1,0), (0,0,1)]
            sage: F1 = FilteredVectorSpace(rays, {0:[0], 1:[2], 2:[1]})
            sage: F2 = FilteredVectorSpace(rays, {0:[1,2], 1:[0]})
            sage: r = P3.fan().rays()
            sage: V = P3.sheaves.Klyachko({r[0]:F1, r[1]:F2, r[2]:F2, r[3]:F2})
            sage: tau = Cone([(1,0,0), (0,1,0)])
            sage: sigma = Cone([(1, 0, 0)])
            sage: M = P3.fan().dual_lattice()
            sage: m = M(1, 1, 0); m.set_immutable()
            sage: V.cohomology_complex(m)
            Chain complex with at most 2 nonzero terms over Rational Field

            sage: F = CyclotomicField(3)
            sage: P3 = toric_varieties.P(3).change_ring(F)
            sage: V = P3.sheaves.Klyachko({r[0]:F1, r[1]:F2, r[2]:F2, r[3]:F2})
            sage: V.cohomology_complex(m)
            Chain complex with at most 2 nonzero terms over Cyclotomic
            Field of order 3 and degree 2
        """
        fan = self._variety.fan()
        C = fan.complex()
        CV = []
        F = self.base_ring()
        for dim in range(1, fan.dim() + 1):
            codim = fan.dim() - dim
            d_C = C.differential(codim)
            d_V = []
            for j in range(d_C.ncols()):
                tau = fan(dim)[j]
                d_V_row = []
                for i in range(d_C.nrows()):
                    sigma = fan(dim - 1)[i]
                    if sigma.is_face_of(tau):
                        pr = self.E_quotient_projection(sigma, tau, m)
                        d = d_C[i, j] * pr.matrix().transpose()
                    else:
                        E_sigma = self.E_quotient(sigma, m)
                        E_tau = self.E_quotient(tau, m)
                        d = zero_matrix(F, E_tau.dimension(),
                                        E_sigma.dimension())
                    d_V_row.append(d)
                d_V.append(d_V_row)
            d_V = block_matrix(d_V, ring=F)
            CV.append(d_V)
        from sage.homology.chain_complex import ChainComplex
        return ChainComplex(CV, base_ring=self.base_ring())
Esempio n. 44
0
            ly = Ft(solution[1]).leading_coefficient()
            lz = Ft(solution[2]).leading_coefficient()
            phi.append(
                matrix([
                    vector(F, A + B + C + 4, {
                        A: 1,
                        A + B + C + 3: -lx
                    }),
                    vector(F, A + B + C + 4, {
                        A + B + 1: 1,
                        A + B + C + 3: -ly
                    }),
                    vector(F, A + B + C + 4, {
                        A + B + C + 2: 1,
                        A + B + C + 3: -lz
                    })
                ]))
        # Create the final matrix which we will solve
        M = block_matrix(phi, ncols=1, subdivide=False)
        solution_space = M.right_kernel()
        for v in solution_space.basis():
            if v[:A + B + C +
                 3] != 0:  # we don't want to return a trivial solution
                X = Ft(list(v[:A + 1]))
                Y = Ft(list(v[A + 1:A + B + 2]))
                Z = Ft(list(v[A + B + 2:A + B + C + 3]))
                return self.point([X, Y, Z])

        raise RuntimeError("No solution has been found: possibly incorrect\
 solubility certificate.")
Esempio n. 45
0
def skew_hadamard_matrix(n,existence=False, skew_normalize=True, check=True):
    r"""
    Tries to construct a skew Hadamard matrix

    A Hadamard matrix `H` is called skew if `H=S-I`, for `I` the identity matrix
    and `-S=S^\top`. Currently constructions from Section 14.1 of [Ha83]_ and few
    more exotic ones are implemented.

    INPUT:

    - ``n`` (integer) -- dimension of the matrix

    - ``existence`` (boolean) -- whether to build the matrix or merely query if
      a construction is available in Sage. When set to ``True``, the function
      returns:

        - ``True`` -- meaning that Sage knows how to build the matrix

        - ``Unknown`` -- meaning that Sage does not know how to build the
          matrix, but that the design may exist (see :mod:`sage.misc.unknown`).

        - ``False`` -- meaning that the matrix does not exist.

    - ``skew_normalize`` (boolean) -- whether to make the 1st row all-one, and
      adjust the 1st column accordingly. Set to ``True`` by default.

    - ``check`` (boolean) -- whether to check that output is correct before
      returning it. As this is expected to be useless (but we are cautious
      guys), you may want to disable it whenever you want speed. Set to ``True``
      by default.

    EXAMPLES::

        sage: from sage.combinat.matrices.hadamard_matrix import skew_hadamard_matrix
        sage: skew_hadamard_matrix(12).det()
        2985984
        sage: 12^6
        2985984
        sage: skew_hadamard_matrix(1)
        [1]
        sage: skew_hadamard_matrix(2)
        [ 1  1]
        [-1  1]

    TESTS::

        sage: skew_hadamard_matrix(10,existence=True)
        False
        sage: skew_hadamard_matrix(12,existence=True)
        True
        sage: skew_hadamard_matrix(784,existence=True)
        True
        sage: skew_hadamard_matrix(10)
        Traceback (most recent call last):
        ...
        ValueError: A skew Hadamard matrix of order 10 does not exist
        sage: skew_hadamard_matrix(36)
        36 x 36 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(36)==skew_hadamard_matrix(36,skew_normalize=False)
        False
        sage: skew_hadamard_matrix(52)
        52 x 52 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(92)
        92 x 92 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(816)     # long time
        816 x 816 dense matrix over Integer Ring...
        sage: skew_hadamard_matrix(100)
        Traceback (most recent call last):
        ...
        ValueError: A skew Hadamard matrix of order 100 is not yet implemented.
        sage: skew_hadamard_matrix(100,existence=True)
        Unknown

    REFERENCES:

    .. [Ha83] \M. Hall,
      Combinatorial Theory,
      2nd edition,
      Wiley, 1983
    """
    def true():
        _skew_had_cache[n]=True
        return True
    M = None
    if existence and n in _skew_had_cache:
        return True
    if not(n % 4 == 0) and (n > 2):
        if existence:
            return False
        raise ValueError("A skew Hadamard matrix of order %s does not exist" % n)
    if n == 2:
        if existence:
            return true()
        M = matrix([[1, 1], [-1, 1]])
    elif n == 1:
        if existence:
            return true()
        M = matrix([1])
    elif is_prime_power(n - 1) and ((n - 1) % 4 == 3):
        if existence:
            return true()
        M = hadamard_matrix_paleyI(n, normalize=False)

    elif n % 8 == 0:
        if skew_hadamard_matrix(n//2,existence=True): # (Lemma 14.1.6 in [Ha83]_)
            if existence:
                return true()
            H = skew_hadamard_matrix(n//2,check=False)
            M = block_matrix([[H,H], [-H.T,H.T]])

        else: # try Williamson construction (Lemma 14.1.5 in [Ha83]_)
            for d in divisors(n)[2:-2]: # skip 1, 2, n/2, and n
                n1 = n//d
                if is_prime_power(d - 1) and (d % 4 == 0) and (n1 % 4 == 0)\
                    and skew_hadamard_matrix(n1,existence=True):
                    if existence:
                        return true()
                    H = skew_hadamard_matrix(n1, check=False)-I(n1)
                    U = matrix(ZZ, d, lambda i, j: -1 if i==j==0 else\
                                        1 if i==j==1 or (i>1 and j-1==d-i)\
                                          else 0)
                    A = block_matrix([[matrix([0]), matrix(ZZ,1,d-1,[1]*(d-1))],
                                      [ matrix(ZZ,d-1,1,[-1]*(d-1)),
                                        _helper_payley_matrix(d-1,zero_position=0)]])+I(d)
                    M = A.tensor_product(I(n1))+(U*A).tensor_product(H)
                    break
    if M is None: # try Williamson-Goethals-Seidel construction
        if GS_skew_hadamard_smallcases(n, existence=True):
            if existence:
                return true()
            M = GS_skew_hadamard_smallcases(n)

        else:
            if existence:
                return Unknown
            raise ValueError("A skew Hadamard matrix of order %s is not yet implemented." % n)
    if skew_normalize:
        dd = diagonal_matrix(M[0])
        M = dd*M*dd
    if check:
        assert is_hadamard_matrix(M, normalized=False, skew=True)
        if skew_normalize:
            from sage.modules.free_module_element import vector
            assert M[0]==vector([1]*n)
    _skew_had_cache[n]=True
    return M
Esempio n. 46
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det()
        2985984
        sage: 12^6
        2985984

    We note that the method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12)
        [ 1  1| 1  1| 1  1| 1  1| 1  1| 1  1]
        [ 1 -1|-1  1|-1  1|-1  1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1 -1| 1  1|-1 -1|-1 -1| 1  1]
        [ 1  1|-1 -1| 1 -1|-1  1|-1  1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1| 1 -1| 1  1|-1 -1|-1 -1]
        [ 1  1| 1 -1|-1 -1| 1 -1|-1  1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1| 1  1| 1 -1| 1  1|-1 -1]
        [ 1  1|-1  1| 1 -1|-1 -1| 1 -1|-1  1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1|-1 -1|-1 -1| 1  1| 1 -1| 1  1]
        [ 1  1|-1  1|-1  1| 1 -1|-1 -1| 1 -1]
        [-----+-----+-----+-----+-----+-----]
        [ 1 -1| 1  1|-1 -1|-1 -1| 1  1| 1 -1]
        [ 1  1| 1 -1|-1  1|-1  1| 1 -1|-1 -1]

    TESTS::

        sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix_paleyII, is_hadamard_matrix)
        sage: test_cases = [2*(x+1) for x in range(50) if is_prime_power(x) and x%4==1]
        sage: all(is_hadamard_matrix(hadamard_matrix_paleyII(n),normalized=True,verbose=True)
        ....:     for n in test_cases)
        True
    """
    q = n // 2 - 1
    if not (n % 2 == 0 and is_prime_power(q) and (q % 4 == 1)):
        raise ValueError(
            "The order %s is not covered by the Paley type II construction." %
            n)

    from sage.rings.finite_rings.finite_field_constructor import FiniteField
    K = FiniteField(q, 'x')
    K_list = list(K)
    K_list.insert(0, K.zero())
    H = matrix(ZZ, [[(1 if (x - y).is_square() else -1) for x in K_list]
                    for y in K_list])
    for i in range(q + 1):
        H[0, i] = 1
        H[i, 0] = 1
        H[i, i] = 0

    tr = {
        0: matrix(2, 2, [1, -1, -1, -1]),
        1: matrix(2, 2, [1, 1, 1, -1]),
        -1: matrix(2, 2, [-1, -1, -1, 1])
    }

    H = block_matrix(q + 1, q + 1, [tr[v] for r in H for v in r])

    return normalise_hadamard(H)
Esempio n. 47
0
def rshcd_from_close_prime_powers(n):
    r"""
    Return a `(n^2,1)`-RSHCD when `n-1` and `n+1` are odd prime powers and `n=0\pmod{4}`.

    The construction implemented here appears in Theorem 4.3 from [GS70]_.

    Note that the authors of [SWW72]_ claim in Corollary 5.12 (page 342) to have
    proved the same result without the `n=0\pmod{4}` restriction with a *very*
    similar construction. So far, however, I (Nathann Cohen) have not been able
    to make it work.

    INPUT:

    - ``n`` -- an integer congruent to `0\pmod{4}`

    .. SEEALSO::

        :func:`regular_symmetric_hadamard_matrix_with_constant_diagonal`

    EXAMPLES::

        sage: from sage.combinat.matrices.hadamard_matrix import rshcd_from_close_prime_powers
        sage: rshcd_from_close_prime_powers(4)
        [-1 -1  1 -1  1 -1 -1  1 -1  1 -1 -1  1 -1  1 -1]
        [-1 -1  1  1 -1 -1 -1 -1 -1  1  1 -1 -1  1 -1  1]
        [ 1  1 -1  1  1 -1 -1 -1 -1 -1  1 -1 -1 -1  1 -1]
        [-1  1  1 -1  1  1 -1 -1 -1 -1 -1  1 -1 -1 -1  1]
        [ 1 -1  1  1 -1  1  1 -1 -1 -1 -1 -1  1 -1 -1 -1]
        [-1 -1 -1  1  1 -1  1  1 -1 -1 -1  1 -1  1 -1 -1]
        [-1 -1 -1 -1  1  1 -1 -1  1 -1  1 -1  1  1 -1 -1]
        [ 1 -1 -1 -1 -1  1 -1 -1 -1  1 -1  1 -1  1  1 -1]
        [-1 -1 -1 -1 -1 -1  1 -1 -1 -1  1  1  1 -1  1  1]
        [ 1  1 -1 -1 -1 -1 -1  1 -1 -1 -1 -1  1  1 -1  1]
        [-1  1  1 -1 -1 -1  1 -1  1 -1 -1 -1 -1  1  1 -1]
        [-1 -1 -1  1 -1  1 -1  1  1 -1 -1 -1 -1 -1  1  1]
        [ 1 -1 -1 -1  1 -1  1 -1  1  1 -1 -1 -1 -1 -1  1]
        [-1  1 -1 -1 -1  1  1  1 -1  1  1 -1 -1 -1 -1 -1]
        [ 1 -1  1 -1 -1 -1 -1  1  1 -1  1  1 -1 -1 -1 -1]
        [-1  1 -1  1 -1 -1 -1 -1  1  1 -1  1  1 -1 -1 -1]

    REFERENCE:

    .. [SWW72] A Street, W. Wallis, J. Wallis,
      Combinatorics: Room squares, sum-free sets, Hadamard matrices.
      Lecture notes in Mathematics 292 (1972).
    """
    if n % 4:
        raise ValueError("n(={}) must be congruent to 0 mod 4")

    a, b = sorted([n - 1, n + 1], key=lambda x: -x % 4)
    Sa = _helper_payley_matrix(a)
    Sb = _helper_payley_matrix(b)
    U = matrix(a, [[int(i + j == a - 1) for i in range(a)] for j in range(a)])

    K = (U * Sa).tensor_product(Sb) + U.tensor_product(J(b) - I(b)) - J(
        a).tensor_product(I(b))

    F = lambda x: diagonal_matrix([-(-1)**i for i in range(x)])
    G = block_diagonal_matrix([J(1), I(a).tensor_product(F(b))])
    e = matrix(a * b, [1] * (a * b))
    H = block_matrix(2, [-J(1), e.transpose(), e, K])

    HH = G * H * G
    assert len(set(map(sum, HH))) == 1
    assert HH**2 == n**2 * I(n**2)
    return HH