예제 #1
0
    def is_start_of_basis_new(self, List):
        r"""
        Determines if the inputed list of OMS's can be extended to a basis of this space

        INPUT:

        - ``list`` -- a list of OMS's

        OUTPUT:

        - True/False
        """
        for Phi in List:
            assert Phi.valuation() >= 0, "Symbols must be integral"
        d = len(List)
        if d == 1:
            L = List[0].list_of_total_measures()
            for mu in L:
                if not mu.is_zero():
                    return True
            return False
        R = self.base()
        List = [Phi.list_of_total_measures() for Phi in List]
        A = Matrix(R.residue_field(), d, len(List[0]), List)
        return A.rank() == d
    class _FiniteBasisConverter:
        def __init__(self, P, comb_mod, basis):
            r"""
            Basis should be a finite set of polynomials
            """
            self._poly_ring = P
            self._module = comb_mod
            self._basis = basis

            max_deg = max([self._poly_ring(b).degree() for b in self._basis])
            monoms = []
            for b in self._basis:
                poly = self._poly_ring(b)
                monoms += poly.monomials()
            monoms_list = tuple(Set(monoms))

            # check if the basis represented in terms of Monomials is efficient
            degs = [self._poly_ring(m).degree() for m in monoms]
            min_deg, max_deg = min(degs), max(degs)
            monoms_obj = Monomials(self._poly_ring, (min_deg, max_deg + 1))

            if monoms_obj.cardinality() < 2 * len(monoms_list):
                computational_basis = monoms_obj
            else:
                computational_basis = monoms_list
            self._monomial_module = PolynomialFreeModule(
                P=self._poly_ring, basis=computational_basis)
            cols = [self._monomial_module(b).to_vector() for b in self._basis]
            self._basis_mat = Matrix(cols).transpose()
            if self._basis_mat.ncols() > self._basis_mat.rank():
                raise ValueError(
                    "Basis polynomials are not linearly independent")

        def convert(self, p):
            r"""
            Algorithm is to convert all polynomials into monomials and use
            linear algebra to solve for the appropriate coefficients in this
            common basis.
            """
            try:
                p_vect = self._monomial_module(p).to_vector()
                decomp = self._basis_mat.solve_right(p_vect)
            except ValueError:
                raise ValueError(
                    "Value %s is not spanned by the basis polynomials" % p)
            polys = [v[1] * self._module.monomial(v[0])
                     for v in zip(self._basis, decomp)]
            module_p = sum(polys, self._module.zero())
            return module_p
예제 #3
0
    def is_start_of_basis(self, List):
        r"""
        Determines if the inputed list of OMS families can be extended to a basis of this space.
        More precisely, it checks that the elements of ``List`` are linearly independent modulo
        the uniformizer (by checking the total measures).

        INPUT:

        - ``list`` -- a list of OMS's

        OUTPUT:

        - True/False
        """
        for Phi in List:
            assert Phi.valuation() >= 0, "Symbols must be integral"
        R = self.base().base()
        List = [Phi.list_of_total_measures_at_fixed_weight() for Phi in List]
        d = len(List)
        A = Matrix(R.residue_field(), d, len(List[0]), List)
        Verbose("A =", A)
        return A.rank() == d
예제 #4
0
def basis_of_short_vectors(self, show_lengths=False, safe_flag=True):
    """
    Return a basis for `ZZ^n` made of vectors with minimal lengths Q(`v`).

    The safe_flag allows us to select whether we want a copy of the
    output, or the original output.  By default safe_flag = True, so
    we return a copy of the cached information.  If this is set to
    False, then the routine is much faster but the return values are
    vulnerable to being corrupted by the user.

    OUTPUT:
        a list of vectors, and optionally a list of values for each vector.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q.basis_of_short_vectors()
        [(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)]
        sage: Q.basis_of_short_vectors(True)
        ([(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)], [1, 3, 5, 7])

    """
    ## Try to use the cached results
    try:
        ## Return the appropriate result
        if show_lengths:
            if safe_flag:
                return deep_copy(self.__basis_of_short_vectors), deepcopy(self.__basis_of_short_vectors_lengths)
            else:
                return self.__basis_of_short_vectors, self.__basis_of_short_vectors_lengths
        else:
            if safe_flag:
                return deepcopy(self.__basis_of_short_vectors)
            else:
                return deepcopy(self.__basis_of_short_vectors)
    except Exception:
        pass

    ## Set an upper bound for the number of vectors to consider
    Max_number_of_vectors = 10000

    ## Generate a PARI matrix string for the associated Hessian matrix
    M_str = str(gp(self.matrix()))

    ## Run through all possible minimal lengths to find a spanning set of vectors
    n = self.dim()
    # MS = MatrixSpace(QQ, n)
    M1 = Matrix([[0]])
    vec_len = 0
    while M1.rank() < n:

        ## DIAGONSTIC
        # print
        # print "Starting with vec_len = ", vec_len
        # print "M_str = ", M_str

        vec_len += 1
        gp_mat = gp.qfminim(M_str, vec_len, Max_number_of_vectors)[3].mattranspose()
        number_of_vecs = ZZ(gp_mat.matsize()[1])
        vector_list = []
        for i in range(number_of_vecs):
            # print "List at", i, ":", list(gp_mat[i+1,])
            new_vec = vector([ZZ(x) for x in list(gp_mat[i + 1,])])
            vector_list.append(new_vec)

        ## DIAGNOSTIC
        # print "number_of_vecs = ", number_of_vecs
        # print "vector_list = ", vector_list

        ## Make a matrix from the short vectors
        if len(vector_list) > 0:
            M1 = Matrix(vector_list)

        ## DIAGNOSTIC
        # print "matrix of vectors = \n", M1
        # print "rank of the matrix = ", M1.rank()

    # print " vec_len = ", vec_len
    # print M1

    ## Organize these vectors by length (and also introduce their negatives)
    max_len = vec_len / 2
    vector_list_by_length = [[] for _ in range(max_len + 1)]
    for v in vector_list:
        l = self(v)
        vector_list_by_length[l].append(v)
        vector_list_by_length[l].append(vector([-x for x in v]))

    ## Make a matrix from the column vectors (in order of ascending length).
    sorted_list = []
    for i in range(len(vector_list_by_length)):
        for v in vector_list_by_length[i]:
            sorted_list.append(v)
    sorted_matrix = Matrix(sorted_list).transpose()

    ## Determine a basis of vectors of minimal length
    pivots = sorted_matrix.pivots()
    basis = [sorted_matrix.column(i) for i in pivots]
    pivot_lengths = [self(v) for v in basis]

    ## DIAGNOSTIC
    # print "basis = ", basis
    # print "pivot_lengths = ", pivot_lengths

    ## Cache the result
    self.__basis_of_short_vectors = basis
    self.__basis_of_short_vectors_lenghts = pivot_lengths

    ## Return the appropriate result
    if show_lengths:
        return basis, pivot_lengths
    else:
        return basis
예제 #5
0
파일: constructor.py 프로젝트: CETHop/sage
def Conic(base_field, F=None, names=None, unique=True):
    r"""
    Return the plane projective conic curve defined by ``F``
    over ``base_field``.

    The input form ``Conic(F, names=None)`` is also accepted,
    in which case the fraction field of the base ring of ``F``
    is used as base field.

    INPUT:

    - ``base_field`` -- The base field of the conic.

    - ``names`` -- a list, tuple, or comma separated string
      of three variable names specifying the names
      of the coordinate functions of the ambient
      space `\Bold{P}^3`. If not specified or read
      off from ``F``, then this defaults to ``'x,y,z'``.

    - ``F`` -- a polynomial, list, matrix, ternary quadratic form,
      or list or tuple of 5 points in the plane.

                   If ``F`` is a polynomial or quadratic form,
                   then the output is the curve in the projective plane
                   defined by ``F = 0``.

                   If ``F`` is a polynomial, then it must be a polynomial
                   of degree at most 2 in 2 variables, or a homogeneous
                   polynomial in of degree 2 in 3 variables.

                   If ``F`` is a matrix, then the output is the zero locus
                   of `(x,y,z) F (x,y,z)^t`.

                   If ``F`` is a list of coefficients, then it has
                   length 3 or 6 and gives the coefficients of
                   the monomials `x^2, y^2, z^2` or all 6 monomials
                   `x^2, xy, xz, y^2, yz, z^2` in lexicographic order.

                   If ``F`` is a list of 5 points in the plane, then the output
                   is a conic through those points.

    - ``unique`` -- Used only if ``F`` is a list of points in the plane.
      If the conic through the points is not unique, then
      raise ``ValueError`` if and only if ``unique`` is True

    OUTPUT:

    A plane projective conic curve defined by ``F`` over a field.

    EXAMPLES:

    Conic curves given by polynomials ::

        sage: X,Y,Z = QQ['X,Y,Z'].gens()
        sage: Conic(X^2 - X*Y + Y^2 - Z^2)
        Projective Conic Curve over Rational Field defined by X^2 - X*Y + Y^2 - Z^2
        sage: x,y = GF(7)['x,y'].gens()
        sage: Conic(x^2 - x + 2*y^2 - 3, 'U,V,W')
        Projective Conic Curve over Finite Field of size 7 defined by U^2 + 2*V^2 - U*W - 3*W^2

    Conic curves given by matrices ::

        sage: Conic(matrix(QQ, [[1, 2, 0], [4, 0, 0], [7, 0, 9]]), 'x,y,z')
        Projective Conic Curve over Rational Field defined by x^2 + 6*x*y + 7*x*z + 9*z^2

        sage: x,y,z = GF(11)['x,y,z'].gens()
        sage: C = Conic(x^2+y^2-2*z^2); C
        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2
        sage: Conic(C.symmetric_matrix(), 'x,y,z')
        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2

    Conics given by coefficients ::

        sage: Conic(QQ, [1,2,3])
        Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + 3*z^2
        sage: Conic(GF(7), [1,2,3,4,5,6], 'X')
        Projective Conic Curve over Finite Field of size 7 defined by X0^2 + 2*X0*X1 - 3*X1^2 + 3*X0*X2 - 2*X1*X2 - X2^2

    The conic through a set of points ::

        sage: C = Conic(QQ, [[10,2],[3,4],[-7,6],[7,8],[9,10]]); C
        Projective Conic Curve over Rational Field defined by x^2 + 13/4*x*y - 17/4*y^2 - 35/2*x*z + 91/4*y*z - 37/2*z^2
        sage: C.rational_point()
        (10 : 2 : 1)
        sage: C.point([3,4])
        (3 : 4 : 1)

        sage: a=AffineSpace(GF(13),2)
        sage: Conic([a([x,x^2]) for x in range(5)])
        Projective Conic Curve over Finite Field of size 13 defined by x^2 - y*z
    """
    if not (is_IntegralDomain(base_field) or base_field == None):
        if names is None:
            names = F
        F = base_field
        base_field = None
    if isinstance(F, (list,tuple)):
        if len(F) == 1:
            return Conic(base_field, F[0], names)
        if names == None:
            names = 'x,y,z'
        if len(F) == 5:
            L=[]
            for f in F:
                if isinstance(f, SchemeMorphism_point_affine):
                    C = Sequence(f, universe = base_field)
                    if len(C) != 2:
                        raise TypeError, "points in F (=%s) must be planar"%F
                    C.append(1)
                elif isinstance(f, SchemeMorphism_point_projective_field):
                    C = Sequence(f, universe = base_field)
                elif isinstance(f, (list, tuple)):
                    C = Sequence(f, universe = base_field)
                    if len(C) == 2:
                        C.append(1)
                else:
                    raise TypeError, "F (=%s) must be a sequence of planar " \
                                      "points" % F
                if len(C) != 3:
                    raise TypeError, "points in F (=%s) must be planar" % F
                P = C.universe()
                if not is_IntegralDomain(P):
                    raise TypeError, "coordinates of points in F (=%s) must " \
                                     "be in an integral domain" % F
                L.append(Sequence([C[0]**2, C[0]*C[1], C[0]*C[2], C[1]**2,
                                   C[1]*C[2], C[2]**2], P.fraction_field()))
            M=Matrix(L)
            if unique and M.rank() != 5:
                raise ValueError, "points in F (=%s) do not define a unique " \
                                   "conic" % F
            con = Conic(base_field, Sequence(M.right_kernel().gen()), names)
            con.point(F[0])
            return con
        F = Sequence(F, universe = base_field)
        base_field = F.universe().fraction_field()
        temp_ring = PolynomialRing(base_field, 3, names)
        (x,y,z) = temp_ring.gens()
        if len(F) == 3:
            return Conic(F[0]*x**2 + F[1]*y**2 + F[2]*z**2)
        if len(F) == 6:
            return Conic(F[0]*x**2 + F[1]*x*y + F[2]*x*z + F[3]*y**2 + \
                         F[4]*y*z + F[5]*z**2)
        raise TypeError, "F (=%s) must be a sequence of 3 or 6" \
                         "coefficients" % F
    if is_QuadraticForm(F):
        F = F.matrix()
    if is_Matrix(F) and F.is_square() and F.ncols() == 3:
        if names == None:
            names = 'x,y,z'
        temp_ring = PolynomialRing(F.base_ring(), 3, names)
        F = vector(temp_ring.gens()) * F * vector(temp_ring.gens())

    if not is_MPolynomial(F):
        raise TypeError, "F (=%s) must be a three-variable polynomial or " \
                         "a sequence of points or coefficients" % F

    if F.total_degree() != 2:
        raise TypeError, "F (=%s) must have degree 2" % F

    if base_field == None:
        base_field = F.base_ring()
    if not is_IntegralDomain(base_field):
        raise ValueError, "Base field (=%s) must be a field" % base_field
    base_field = base_field.fraction_field()
    if names == None:
        names = F.parent().variable_names()
    pol_ring = PolynomialRing(base_field, 3, names)

    if F.parent().ngens() == 2:
        (x,y,z) = pol_ring.gens()
        F = pol_ring(F(x/z,y/z)*z**2)

    if F == 0:
        raise ValueError, "F must be nonzero over base field %s" % base_field

    if F.total_degree() != 2:
        raise TypeError, "F (=%s) must have degree 2 over base field %s" % \
                          (F, base_field)

    if F.parent().ngens() == 3:
        P2 = ProjectiveSpace(2, base_field, names)
        if is_PrimeFiniteField(base_field):
            return ProjectiveConic_prime_finite_field(P2, F)
        if is_FiniteField(base_field):
            return ProjectiveConic_finite_field(P2, F)
        if is_RationalField(base_field):
            return ProjectiveConic_rational_field(P2, F)
        if is_NumberField(base_field):
            return ProjectiveConic_number_field(P2, F)
        return ProjectiveConic_field(P2, F)

    raise TypeError, "Number of variables of F (=%s) must be 2 or 3" % F
예제 #6
0
def Conic(base_field, F=None, names=None, unique=True):
    r"""
    Return the plane projective conic curve defined by ``F``
    over ``base_field``.
    
    The input form ``Conic(F, names=None)`` is also accepted,
    in which case the fraction field of the base ring of ``F``
    is used as base field.

    INPUT:
    
    - ``base_field`` -- The base field of the conic.
    
    - ``names`` -- a list, tuple, or comma separated string
      of three variable names specifying the names
      of the coordinate functions of the ambient
      space `\Bold{P}^3`. If not specified or read
      off from ``F``, then this defaults to ``'x,y,z'``.

    - ``F`` -- a polynomial, list, matrix, ternary quadratic form,
      or list or tuple of 5 points in the plane.
                   
                   If ``F`` is a polynomial or quadratic form,
                   then the output is the curve in the projective plane
                   defined by ``F = 0``.

                   If ``F`` is a polynomial, then it must be a polynomial
                   of degree at most 2 in 2 variables, or a homogeneous
                   polynomial in of degree 2 in 3 variables.
                   
                   If ``F`` is a matrix, then the output is the zero locus
                   of `(x,y,z) F (x,y,z)^t`.
    
                   If ``F`` is a list of coefficients, then it has
                   length 3 or 6 and gives the coefficients of
                   the monomials `x^2, y^2, z^2` or all 6 monomials
                   `x^2, xy, xz, y^2, yz, z^2` in lexicographic order.

                   If ``F`` is a list of 5 points in the plane, then the output
                   is a conic through those points.
      
    - ``unique`` -- Used only if ``F`` is a list of points in the plane.
      If the conic through the points is not unique, then
      raise ``ValueError`` if and only if ``unique`` is True
                    
    OUTPUT:
    
    A plane projective conic curve defined by ``F`` over a field.
    
    EXAMPLES:
    
    Conic curves given by polynomials ::

        sage: X,Y,Z = QQ['X,Y,Z'].gens()
        sage: Conic(X^2 - X*Y + Y^2 - Z^2)
        Projective Conic Curve over Rational Field defined by X^2 - X*Y + Y^2 - Z^2
        sage: x,y = GF(7)['x,y'].gens()
        sage: Conic(x^2 - x + 2*y^2 - 3, 'U,V,W')
        Projective Conic Curve over Finite Field of size 7 defined by U^2 + 2*V^2 - U*W - 3*W^2

    Conic curves given by matrices ::

        sage: Conic(matrix(QQ, [[1, 2, 0], [4, 0, 0], [7, 0, 9]]), 'x,y,z')
        Projective Conic Curve over Rational Field defined by x^2 + 6*x*y + 7*x*z + 9*z^2

        sage: x,y,z = GF(11)['x,y,z'].gens()
        sage: C = Conic(x^2+y^2-2*z^2); C
        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2
        sage: Conic(C.symmetric_matrix(), 'x,y,z')
        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2

    Conics given by coefficients ::
    
        sage: Conic(QQ, [1,2,3])
        Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + 3*z^2
        sage: Conic(GF(7), [1,2,3,4,5,6], 'X')
        Projective Conic Curve over Finite Field of size 7 defined by X0^2 + 2*X0*X1 - 3*X1^2 + 3*X0*X2 - 2*X1*X2 - X2^2
    
    The conic through a set of points ::

        sage: C = Conic(QQ, [[10,2],[3,4],[-7,6],[7,8],[9,10]]); C
        Projective Conic Curve over Rational Field defined by x^2 + 13/4*x*y - 17/4*y^2 - 35/2*x*z + 91/4*y*z - 37/2*z^2
        sage: C.rational_point()
        (10 : 2 : 1)
        sage: C.point([3,4])
        (3 : 4 : 1)

        sage: a=AffineSpace(GF(13),2)
        sage: Conic([a([x,x^2]) for x in range(5)])
        Projective Conic Curve over Finite Field of size 13 defined by x^2 - y*z
    """
    if not (is_IntegralDomain(base_field) or base_field == None):
        if names is None:
            names = F
        F = base_field
        base_field = None
    if isinstance(F, (list,tuple)):
        if len(F) == 1:
            return Conic(base_field, F[0], names)
        if names == None:
            names = 'x,y,z'
        if len(F) == 5:
            L=[]
            for f in F:
                if isinstance(f, SchemeMorphism_point_affine):
                    C = Sequence(f, universe = base_field)
                    if len(C) != 2:
                        raise TypeError, "points in F (=%s) must be planar"%F
                    C.append(1)
                elif isinstance(f, SchemeMorphism_point_projective_field):
                    C = Sequence(f, universe = base_field)
                elif isinstance(f, (list, tuple)):
                    C = Sequence(f, universe = base_field)
                    if len(C) == 2:
                        C.append(1)
                else:
                    raise TypeError, "F (=%s) must be a sequence of planar " \
                                      "points" % F
                if len(C) != 3:
                    raise TypeError, "points in F (=%s) must be planar" % F
                P = C.universe()
                if not is_IntegralDomain(P):
                    raise TypeError, "coordinates of points in F (=%s) must " \
                                     "be in an integral domain" % F
                L.append(Sequence([C[0]**2, C[0]*C[1], C[0]*C[2], C[1]**2,
                                   C[1]*C[2], C[2]**2], P.fraction_field()))
            M=Matrix(L)
            if unique and M.rank() != 5:
                raise ValueError, "points in F (=%s) do not define a unique " \
                                   "conic" % F
            con = Conic(base_field, Sequence(M.right_kernel().gen()), names)
            con.point(F[0])
            return con
        F = Sequence(F, universe = base_field)
        base_field = F.universe().fraction_field()
        temp_ring = PolynomialRing(base_field, 3, names)
        (x,y,z) = temp_ring.gens()
        if len(F) == 3:
            return Conic(F[0]*x**2 + F[1]*y**2 + F[2]*z**2)
        if len(F) == 6:
            return Conic(F[0]*x**2 + F[1]*x*y + F[2]*x*z + F[3]*y**2 + \
                         F[4]*y*z + F[5]*z**2)
        raise TypeError, "F (=%s) must be a sequence of 3 or 6" \
                         "coefficients" % F
    if is_QuadraticForm(F):
        F = F.matrix()
    if is_Matrix(F) and F.is_square() and F.ncols() == 3:
        if names == None:
            names = 'x,y,z'
        temp_ring = PolynomialRing(F.base_ring(), 3, names)
        F = vector(temp_ring.gens()) * F * vector(temp_ring.gens())

    if not is_MPolynomial(F):
        raise TypeError, "F (=%s) must be a three-variable polynomial or " \
                         "a sequence of points or coefficients" % F

    if F.total_degree() != 2:
        raise TypeError, "F (=%s) must have degree 2" % F

    if base_field == None:
        base_field = F.base_ring()
    if not is_IntegralDomain(base_field):
        raise ValueError, "Base field (=%s) must be a field" % base_field
    base_field = base_field.fraction_field()
    if names == None:
        names = F.parent().variable_names()
    pol_ring = PolynomialRing(base_field, 3, names)

    if F.parent().ngens() == 2:
        (x,y,z) = pol_ring.gens()
        F = pol_ring(F(x/z,y/z)*z**2)    

    if F == 0:
        raise ValueError, "F must be nonzero over base field %s" % base_field

    if F.total_degree() != 2:
        raise TypeError, "F (=%s) must have degree 2 over base field %s" % \
                          (F, base_field)

    if F.parent().ngens() == 3:
        P2 = ProjectiveSpace(2, base_field, names)
        if is_PrimeFiniteField(base_field):
            return ProjectiveConic_prime_finite_field(P2, F)
        if is_FiniteField(base_field):
            return ProjectiveConic_finite_field(P2, F)
        if is_RationalField(base_field):
            return ProjectiveConic_rational_field(P2, F)
        if is_NumberField(base_field):
            return ProjectiveConic_number_field(P2, F)
        return ProjectiveConic_field(P2, F)

    raise TypeError, "Number of variables of F (=%s) must be 2 or 3" % F
def basis_of_short_vectors(self, show_lengths=False, safe_flag=True):
    """
    Return a basis for `ZZ^n` made of vectors with minimal lengths Q(`v`).

    The safe_flag allows us to select whether we want a copy of the
    output, or the original output.  By default safe_flag = True, so
    we return a copy of the cached information.  If this is set to
    False, then the routine is much faster but the return values are
    vulnerable to being corrupted by the user.

    OUTPUT:
        a list of vectors, and optionally a list of values for each vector.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q.basis_of_short_vectors()
        [(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)]
        sage: Q.basis_of_short_vectors(True)
        ([(1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)], [1, 3, 5, 7])

    """
    ## Try to use the cached results
    try:
        ## Return the appropriate result
        if show_lengths:
            if safe_flag:
                return deep_copy(self.__basis_of_short_vectors), deepcopy(self.__basis_of_short_vectors_lengths)
            else:
                return self.__basis_of_short_vectors, self.__basis_of_short_vectors_lengths
        else:
            if safe_flag:
                return deepcopy(self.__basis_of_short_vectors)
            else:
                return deepcopy(self.__basis_of_short_vectors)
    except Exception:
        pass


    ## Set an upper bound for the number of vectors to consider
    Max_number_of_vectors = 10000

    ## Generate a PARI matrix string for the associated Hessian matrix
    M_str = str(gp(self.matrix()))


    ## Run through all possible minimal lengths to find a spanning set of vectors
    n = self.dim()
    #MS = MatrixSpace(QQ, n)
    M1 = Matrix([[0]])
    vec_len = 0
    while M1.rank() < n:

        ## DIAGONSTIC
        #print
        #print "Starting with vec_len = ", vec_len
        #print "M_str = ", M_str

        vec_len += 1
        gp_mat = gp.qfminim(M_str, vec_len, Max_number_of_vectors)[3].mattranspose()
        number_of_vecs = ZZ(gp_mat.matsize()[1])
        vector_list = []
        for i in range(number_of_vecs):
            #print "List at", i, ":", list(gp_mat[i+1,])
            new_vec = vector([ZZ(x)  for x in list(gp_mat[i+1,])])
            vector_list.append(new_vec)


        ## DIAGNOSTIC
        #print "number_of_vecs = ", number_of_vecs
        #print "vector_list = ", vector_list


        ## Make a matrix from the short vectors
        if len(vector_list) > 0:
            M1 = Matrix(vector_list)


        ## DIAGNOSTIC
        #print "matrix of vectors = \n", M1
        #print "rank of the matrix = ", M1.rank()



    #print " vec_len = ", vec_len
    #print M1


    ## Organize these vectors by length (and also introduce their negatives)
    max_len = vec_len // 2
    vector_list_by_length = [[]  for _ in range(max_len + 1)]
    for v in vector_list:
        l = self(v)
        vector_list_by_length[l].append(v)
        vector_list_by_length[l].append(vector([-x  for x in v]))


    ## Make a matrix from the column vectors (in order of ascending length).
    sorted_list = []
    for i in range(len(vector_list_by_length)):
        for v in vector_list_by_length[i]:
            sorted_list.append(v)
    sorted_matrix = Matrix(sorted_list).transpose()


    ## Determine a basis of vectors of minimal length
    pivots = sorted_matrix.pivots()
    basis = [sorted_matrix.column(i) for i in pivots]
    pivot_lengths = [self(v)  for v in basis]


    ## DIAGNOSTIC
    #print "basis = ", basis
    #print "pivot_lengths = ", pivot_lengths


    ## Cache the result
    self.__basis_of_short_vectors = basis
    self.__basis_of_short_vectors_lenghts = pivot_lengths


    ## Return the appropriate result
    if show_lengths:
        return basis, pivot_lengths
    else:
        return basis
예제 #8
0
def basis_of_short_vectors(self, show_lengths=False, safe_flag=None):
    """
    Return a basis for `ZZ^n` made of vectors with minimal lengths Q(`v`).

    OUTPUT: a tuple of vectors, and optionally a tuple of values for
    each vector.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q.basis_of_short_vectors()
        ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))
        sage: Q.basis_of_short_vectors(True)
        (((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)), (1, 3, 5, 7))

    The returned vectors are immutable::

        sage: v = Q.basis_of_short_vectors()[0]
        sage: v
        (1, 0, 0, 0)
        sage: v[0] = 0
        Traceback (most recent call last):
        ...
        ValueError: vector is immutable; please change a copy instead (use copy())
    """
    if safe_flag is not None:
        from sage.misc.superseded import deprecation
        deprecation(
            18673,
            "The safe_flag argument to basis_of_short_vectors() is deprecated and no longer used"
        )

    ## Set an upper bound for the number of vectors to consider
    Max_number_of_vectors = 10000

    ## Generate a PARI matrix for the associated Hessian matrix
    M_pari = self._pari_()

    ## Run through all possible minimal lengths to find a spanning set of vectors
    n = self.dim()
    M1 = Matrix([[0]])
    vec_len = 0
    while M1.rank() < n:
        vec_len += 1
        pari_mat = M_pari.qfminim(vec_len, Max_number_of_vectors)[2]
        number_of_vecs = ZZ(pari_mat.matsize()[1])
        vector_list = []
        for i in range(number_of_vecs):
            new_vec = vector([ZZ(x) for x in list(pari_mat[i])])
            vector_list.append(new_vec)

        ## Make a matrix from the short vectors
        if len(vector_list) > 0:
            M1 = Matrix(vector_list)

    ## Organize these vectors by length (and also introduce their negatives)
    max_len = vec_len // 2
    vector_list_by_length = [[] for _ in range(max_len + 1)]
    for v in vector_list:
        l = self(v)
        vector_list_by_length[l].append(v)
        vector_list_by_length[l].append(vector([-x for x in v]))

    ## Make a matrix from the column vectors (in order of ascending length).
    sorted_list = []
    for i in range(len(vector_list_by_length)):
        for v in vector_list_by_length[i]:
            sorted_list.append(v)
    sorted_matrix = Matrix(sorted_list).transpose()

    ## Determine a basis of vectors of minimal length
    pivots = sorted_matrix.pivots()
    basis = tuple(sorted_matrix.column(i) for i in pivots)
    for v in basis:
        v.set_immutable()

    ## Return the appropriate result
    if show_lengths:
        pivot_lengths = tuple(self(v) for v in basis)
        return basis, pivot_lengths
    else:
        return basis
def basis_of_short_vectors(self, show_lengths=False, safe_flag=None):
    """
    Return a basis for `ZZ^n` made of vectors with minimal lengths Q(`v`).

    OUTPUT: a tuple of vectors, and optionally a tuple of values for
    each vector.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7])
        sage: Q.basis_of_short_vectors()
        ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))
        sage: Q.basis_of_short_vectors(True)
        (((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)), (1, 3, 5, 7))

    The returned vectors are immutable::

        sage: v = Q.basis_of_short_vectors()[0]
        sage: v
        (1, 0, 0, 0)
        sage: v[0] = 0
        Traceback (most recent call last):
        ...
        ValueError: vector is immutable; please change a copy instead (use copy())
    """
    if safe_flag is not None:
        from sage.misc.superseded import deprecation
        deprecation(18673, "The safe_flag argument to basis_of_short_vectors() is deprecated and no longer used")

    ## Set an upper bound for the number of vectors to consider
    Max_number_of_vectors = 10000

    ## Generate a PARI matrix for the associated Hessian matrix
    M_pari = self.__pari__()

    ## Run through all possible minimal lengths to find a spanning set of vectors
    n = self.dim()
    M1 = Matrix([[0]])
    vec_len = 0
    while M1.rank() < n:
        vec_len += 1
        pari_mat = M_pari.qfminim(vec_len, Max_number_of_vectors)[2]
        number_of_vecs = ZZ(pari_mat.matsize()[1])
        vector_list = []
        for i in range(number_of_vecs):
            new_vec = vector([ZZ(x) for x in list(pari_mat[i])])
            vector_list.append(new_vec)

        ## Make a matrix from the short vectors
        if len(vector_list) > 0:
            M1 = Matrix(vector_list)

    ## Organize these vectors by length (and also introduce their negatives)
    max_len = vec_len // 2
    vector_list_by_length = [[] for _ in range(max_len + 1)]
    for v in vector_list:
        l = self(v)
        vector_list_by_length[l].append(v)
        vector_list_by_length[l].append(vector([-x  for x in v]))

    ## Make a matrix from the column vectors (in order of ascending length).
    sorted_list = []
    for i in range(len(vector_list_by_length)):
        for v in vector_list_by_length[i]:
            sorted_list.append(v)
    sorted_matrix = Matrix(sorted_list).transpose()

    ## Determine a basis of vectors of minimal length
    pivots = sorted_matrix.pivots()
    basis = tuple(sorted_matrix.column(i) for i in pivots)
    for v in basis:
        v.set_immutable()

    ## Return the appropriate result
    if show_lengths:
        pivot_lengths = tuple(self(v) for v in basis)
        return basis, pivot_lengths
    else:
        return basis
예제 #10
0
    def polynomials(self, X=None, Y=None, degree=2, groebner=False):
        """
        Return a list of polynomials satisfying this S-box.

        First, a simple linear fitting is performed for the given
        ``degree`` (cf. for example [BC2003]_). If ``groebner=True`` a
        Groebner basis is also computed for the result of that
        process.

        INPUT:

        - ``X`` - input variables

        - ``Y`` - output variables

        - ``degree`` - integer > 0 (default: ``2``)

        - ``groebner`` - calculate a reduced Groebner basis of the
          spanning polynomials to obtain more polynomials (default:
          ``False``)

        EXAMPLES::

            sage: S = mq.SBox(7,6,0,4,2,5,1,3)
            sage: P = S.ring()

        By default, this method returns an indirect representation::

            sage: S.polynomials()
            [x0*x2 + x1 + y1 + 1,
             x0*x1 + x1 + x2 + y0 + y1 + y2 + 1,
             x0*y1 + x0 + x2 + y0 + y2,
             x0*y0 + x0*y2 + x1 + x2 + y0 + y1 + y2 + 1,
             x1*x2 + x0 + x1 + x2 + y2 + 1,
             x0*y0 + x1*y0 + x0 + x2 + y1 + y2,
             x0*y0 + x1*y1 + x1 + y1 + 1,
             x1*y2 + x1 + x2 + y0 + y1 + y2 + 1,
             x0*y0 + x2*y0 + x1 + x2 + y1 + 1,
             x2*y1 + x0 + y1 + y2,
             x2*y2 + x1 + y1 + 1,
             y0*y1 + x0 + x2 + y0 + y1 + y2,
             y0*y2 + x1 + x2 + y0 + y1 + 1,
             y1*y2 + x2 + y0]

        We can get a direct representation by computing a
        lexicographical Groebner basis with respect to the right
        variable ordering, i.e. a variable ordering where the output
        bits are greater than the input bits::

            sage: P.<y0,y1,y2,x0,x1,x2> = PolynomialRing(GF(2),6,order='lex')
            sage: S.polynomials([x0,x1,x2],[y0,y1,y2], groebner=True)
            [y0 + x0*x1 + x0*x2 + x0 + x1*x2 + x1 + 1,
             y1 + x0*x2 + x1 + 1,
             y2 + x0 + x1*x2 + x1 + x2 + 1]
        """
        def nterms(nvars, deg):
            """
            Return the number of monomials possible up to a given
            degree.

            INPUT:

            - ``nvars`` - number of variables

            - ``deg`` - degree

            TESTS::

                sage: S = mq.SBox(7,6,0,4,2,5,1,3)
                sage: F = S.polynomials(degree=3) # indirect doctest
            """
            total = 1
            divisor = 1
            var_choices = 1

            for d in range(1, deg + 1):
                var_choices *= (nvars - d + 1)
                divisor *= d
                total += var_choices / divisor
            return total

        m = self.m
        n = self.n
        F = self._F

        if X is None and Y is None:
            P = self.ring()
            X = P.gens()[:m]
            Y = P.gens()[m:]
        else:
            P = X[0].parent()

        gens = X + Y

        bits = []
        for i in range(1 << m):
            bits.append(self.to_bits(i, m) + self(self.to_bits(i, m)))

        ncols = (1 << m) + 1

        A = Matrix(P, nterms(m + n, degree), ncols)

        exponents = []
        for d in range(degree + 1):
            exponents += IntegerVectors(d,
                                        max_length=m + n,
                                        min_length=m + n,
                                        min_part=0,
                                        max_part=1).list()

        row = 0
        for exponent in exponents:
            A[row, ncols - 1] = mul(
                [gens[i]**exponent[i] for i in range(len(exponent))])
            for col in range(1 << m):
                A[row, col] = mul([
                    bits[col][i] for i in range(len(exponent)) if exponent[i]
                ])
            row += 1

        rankSize = A.rank() - 1

        for c in range(ncols):
            A[0, c] = 1

        RR = A.echelon_form(algorithm='row_reduction')

        # extract spanning stet
        gens = (RR.column(ncols - 1)[rankSize:]).list()

        if not groebner:
            return gens

        FI = set(FieldIdeal(P).gens())
        I = Ideal(gens + list(FI))
        gb = I.groebner_basis()

        gens = []
        for f in gb:
            if f not in FI:  # filter out field equations
                gens.append(f)
        return gens