예제 #1
0
def find_correct_matrix(M, N):
    r"""
    Given a matrix M1 that maps infinity to a/c this returns a matrix M2 Matrix([[A,B],[C,D]]) that maps infinity to a Gamma0(N)-equivalent cusp A/C and satisfies, C|N, C>0, (A,N)=1 and N|B.
    It also returns T^n = Matrix([[1,n],[0,1]]) such that M2*T^n*M1**(-1) is in Gamma0(N).
    """
    a, b, c, d = list(map(lambda x: ZZ(x), M.list()))
    if (c > 0 and c.divides(N) and gcd(a, N) == 1 and b % N == 0):
        return M, identity_matrix(2)
    if c == 0:
        return Matrix([[1, 0], [N, 1]]), identity_matrix(2)
    cusps = cusps_of_gamma0(N)
    for cusp in cusps:
        if Cusp(QQ(a) / QQ(c)).is_gamma0_equiv(cusp, N):
            break
    A, C = cusp.numerator(), cusp.denominator()
    _, D, b = xgcd(A, N * C)
    M2 = Matrix([[A, -N * b], [C, D]])
    n = 0
    T = Matrix([[1, 1], [0, 1]])
    tmp = identity_matrix(2)
    while True:
        if N.divides((M2 * tmp * M**(-1))[1][0]):
            return M2, tmp
        elif N.divides((M2 * tmp**(-1) * M**(-1))[1][0]):
            return M2, tmp**(-1)
        tmp = tmp * T
예제 #2
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
예제 #3
0
    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
예제 #4
0
    def init_sdp(self):
        """
		This method simply initializes the semidefinite program, 
		corresponding to the input data.
        """
        n = self.NumVars
        N = self.NumMonomials(n, 2 * self.Relaxation)
        self.MatSize = [self.NumMonomials(n, self.Relaxation), N]
        Blck = [[] for i in range(N)]
        C = []

        for idx in range(self.NumberOfConstraints):
            d = self.NumMonomials(n, self.Relaxation - self.HalfDegs[idx])
            h = Matrix(self.Field, d, d, 0)
            C.append(h)
            Mmnt = self.LocalizedMomentMatrix(idx)

            for i in range(N):
                p = self.Monomials[i]
                A = self.Calpha(p, Mmnt)
                Blck[i].append(A)

        for i in range(N):
            Blck[i].append(Matrix(self.Field, 1, 1, 0))
            Blck[i].append(Matrix(self.Field, 1, 1, 0))

        Blck[0][self.NumberOfConstraints][0] = 1
        Blck[0][self.NumberOfConstraints + 1][0] = -1
        C.append(Matrix(self.Field, 1, 1, 1))
        C.append(Matrix(self.Field, 1, 1, -1))

        self.Matrice = [C, self.PolyCoefFullVec(), Blck]
예제 #5
0
파일: homspace.py 프로젝트: yunboliu27/sage
    def discriminant(self):
        """
        Return the discriminant of this ring, which is the discriminant of
        the trace pairing.

        .. note::

           One knows that for modular abelian varieties, the
           endomorphism ring should be isomorphic to an order in a
           number field. However, the discriminant returned by this
           function will be `2^n` ( `n =`
           self.dimension()) times the discriminant of that order,
           since the elements are represented as 2d x 2d
           matrices. Notice, for example, that the case of a one
           dimensional abelian variety, whose endomorphism ring must
           be ZZ, has discriminant 2, as in the example below.

        EXAMPLES::

            sage: J0(33).endomorphism_ring().discriminant()
            -64800
            sage: J0(46).endomorphism_ring().discriminant()  # long time (6s on sage.math, 2011)
            24200000000
            sage: J0(11).endomorphism_ring().discriminant()
            2
        """
        g = self.gens()
        M = Matrix(ZZ,len(g), [ (g[i]*g[j]).trace()
                                for i in range(len(g)) for j in range(len(g)) ])
        return M.determinant()
예제 #6
0
    def __init__(self, F, Nbound = 50,Tbound = 5, prec = 500):
        self._F = F
        self._solved = False
        self._disc = self._F.discriminant()
        self._w = self._F.maximal_order().ring_generators()[0]
        self._eps = self._F.units()[0]
        self._Phi = self._F.real_embeddings(prec=prec)
        a = F.gen()
        self.Pointxy = namedtuple('Pointxy', 'x y')
        if self._disc % 2 ==0 :
            self._changebasismatrix = 1
        else:
            self._changebasismatrix = Matrix(IntegerRing(),2,2,[1,-1,0,2])

        # We assume here that Phi orders the embeddings to that
        # Phi[1] is the largest
        self._Rw = self._Phi[1](self._w)
        self._Rwconj = self._Phi[0](self._w)

        self._used_regions = []
        self._Nboundmin = 2
        self._Nboundmax = Nbound
        self._Nboundinc = 1
        self._Nbound = Nbound
        self._epsto = [self._F(1)]
        self._Dmax = self.embed(self._w)
        self._Tbound = Tbound
        self._ranget = sorted(range(-self._Tbound,self._Tbound+2),key=abs)
        self._M = ~Matrix(RealField(), 2, 2, [1,self._Rw,1,self._Rwconj])
        self.initialize_fundom()
        self._master_regs = Regions(self)
        self._maxdepth = 0
    def __init__(self, A, gens=None, given_by_matrix=False):
        """
        EXAMPLES::

            sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])])
            sage: I = A.ideal(A([0,1]))
            sage: TestSuite(I).run(skip="_test_category") # Currently ideals are not using the category framework
        """
        k = A.base_ring()
        n = A.degree()
        if given_by_matrix:
            self._basis_matrix = gens
            gens = gens.rows()
        elif gens is None:
            self._basis_matrix = Matrix(k, 0, n)
        elif isinstance(gens, (list, tuple)):
            B = [FiniteDimensionalAlgebraIdeal(A, x).basis_matrix() for x in gens]
            B = reduce(lambda x, y: x.stack(y), B, Matrix(k, 0, n))
            self._basis_matrix = B.echelon_form().image().basis_matrix()
        elif is_Matrix(gens):
            gens = FiniteDimensionalAlgebraElement(A, gens)
        elif isinstance(gens, FiniteDimensionalAlgebraElement):
            gens = gens.vector()
            B = Matrix([gens * b for b in A.table()])
            self._basis_matrix = B.echelon_form().image().basis_matrix()
        Ideal_generic.__init__(self, A, gens)
예제 #8
0
    def __init__(self, parent, val=0, check=True, normalize=False):
        ModuleElement.__init__(self, parent)
        self._parent = parent
        self._depth = self._parent._depth
        if not check:
            self._val = val
        else:
            if isinstance(val, self.__class__):
                if val._parent._depth == parent._depth:
                    self._val = val._val
                else:
                    d = min([val._parent._depth, parent._depth])
                    self._val = val._val.submatrix(0, 0, nrows=d)

            elif isinstance(val, Vector_integer_dense) or isinstance(
                    val, FreeModuleElement_generic_dense):
                self._val = MatrixSpace(self._parent._R, self._depth, 1)(0)
                for i, o in enumerate(val.list()):
                    self._val[i, 0] = o
            else:
                try:
                    self._val = Matrix(self._parent._R, self._depth, 1, val)
                except (TypeError, ValueError):
                    self._val = self._parent._R(val) * MatrixSpace(
                        self._parent._R, self._depth, 1)(1)
        self._moments = self._val
예제 #9
0
def p_adic_l_invariant_additive(logA,logB, alpha, beta, Tmatrix):
    K = logA.parent()
    logA, logB = K(logA), K(logB)
    x,y,z,t = Tmatrix.change_ring(K).list()
    M = Matrix(K,2,2,[alpha,x*alpha+z*beta,beta, y*alpha+t*beta])
    n  = Matrix(K,2,1,[logA, logB])
    return M.solve_right(n).list()
예제 #10
0
def HalfPeriodsInTermsOfLambdas(L1, L2, L3, lvec_and_Mlist = None, HP0 = None, prec = None, max_iters = 20):
    K = L1.parent()
    L0 = Matrix(K, 3, 1, [L1, L2, L3])
    if lvec_and_Mlist is None:
        assert prec is not None
        lvec, Mlist = load_lvec_and_Mlist(prec)
    else:
        lvec, Mlist = lvec_and_Mlist
    # Evaluates a matrix M with entries in Z[[x,y,z]] at points x0,y0,z0
    def ev(x0,y0,z0):
        return [lvec[0](x0,y0,z0), lvec[1](x0,y0,z0), ((1-z0)/(1+z0))**2 * lvec[2](x0,y0,z0)]
    if HP0 is None:
        HP0 = [K(0),K(0),K(0)]
    Pn = Matrix(K,3,1,HP0) # 0th approximation
    n_iters = 0
    while n_iters < 20:
        n_iters += 1
        Jinv = evaluate_twisted_jacobian_matrix(*Pn.list(),Mlist = Mlist).inverse()
        FPn = matrix(3,1, ev(*Pn.list()))
        Pnn = Pn - Jinv * (FPn - L0)
        print('(%s)'%n_iters, [(u-v).valuation() for u,v in zip(Pn.list(), Pnn.list())])
        if all([u == v for u,v in zip(Pn.list(), Pnn.list())]):
            return Pn
        Pn = Pnn
    raise RuntimeError,"Does not converge"
예제 #11
0
    def __init__(self,F,Nbound=_sage_const_50 ,Tbound=_sage_const_5 ):
        self._F=F
        self._solved=False
        self._disc=self._F.discriminant()
        self._w=self._F.maximal_order().ring_generators()[_sage_const_0 ]
        self._eps=self._F.units()[_sage_const_0 ]
        self._Phi=self._F.real_embeddings(prec=_sage_const_500 )
        a=F.gen()
        self.Pointxy=namedtuple('Pointxy','x y')
        if(self._disc%_sage_const_2 ==_sage_const_0 ):
            self._changebasismatrix=_sage_const_1 
        else:
            self._changebasismatrix=Matrix(IntegerRing(),_sage_const_2 ,_sage_const_2 ,[_sage_const_1 ,-_sage_const_1 ,_sage_const_0 ,_sage_const_2 ])

        # We assume here that Phi orders the embeddings to that
        # Phi[1] is the largest
        self._Rw=self._Phi[_sage_const_1 ](self._w)
        self._Rwconj=self._Phi[_sage_const_0 ](self._w)

        self._used_regions=[]
        self._Nboundmin=_sage_const_2 
        self._Nboundmax=Nbound
        self._Nboundinc=_sage_const_1 
        self._Nbound=Nbound
        self._epsto=[self._F(_sage_const_1 )]
        self._Dmax=self.embed(self._w)
        self._Tbound=Tbound
        self._ranget=sorted(range(-self._Tbound,self._Tbound+_sage_const_2 ),key=abs)
        self._M=Matrix(RealField(),_sage_const_2 ,_sage_const_2 ,[_sage_const_1 ,self._Rw,_sage_const_1 ,self._Rwconj]).inverse()
        self.initialize_fundom()
        self._master_regs=Regions(self)
        self._maxdepth=_sage_const_0 
예제 #12
0
    def symmetric_matrix(self):
        r"""
        The symmetric matrix `M` such that `(x y z) M (x y z)^t`
        is the defining equation of ``self``.

        EXAMPLES ::

            sage: R.<x, y, z> = QQ[]
            sage: C = Conic(x^2 + x*y/2 + y^2 + z^2)
            sage: C.symmetric_matrix()
            [  1 1/4   0]
            [1/4   1   0]
            [  0   0   1]

            sage: C = Conic(x^2 + 2*x*y + y^2 + 3*x*z + z^2)
            sage: v = vector([x, y, z])
            sage: v * C.symmetric_matrix() * v
            x^2 + 2*x*y + y^2 + 3*x*z + z^2
        """
        a, b, c, d, e, f = self.coefficients()
        if self.base_ring().characteristic() == 2:
            if b == 0 and c == 0 and e == 0:
                return Matrix([[a,0,0],[0,d,0],[0,0,f]])
            raise ValueError("The conic self (= %s) has no symmetric matrix " \
                              "because the base field has characteristic 2" % \
                              self)
        return Matrix([[  a , b/2, c/2 ],
                       [ b/2,  d , e/2 ],
                       [ c/2, e/2,  f  ]])
예제 #13
0
    def __init__(self, A, elt=None, check=True):
        """
        TESTS::

            sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])])
            sage: A(QQ(4))
            Traceback (most recent call last):
            ...
            TypeError: elt should be a vector, a matrix, or an element of the base field

            sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])])
            sage: elt = B(Matrix([[1,1], [-1,1]])); elt
            e0 + e1
            sage: TestSuite(elt).run()
            sage: B(Matrix([[0,1], [1,0]]))
            Traceback (most recent call last):
            ...
            ValueError: matrix does not define an element of the algebra
        """
        AlgebraElement.__init__(self, A)
        k = A.base_ring()
        n = A.degree()
        if elt is None:
            self._vector = vector(k, n)
            self._matrix = Matrix(k, n)
        else:
            if isinstance(elt, int):
                elt = Integer(elt)
            elif isinstance(elt, list):
                elt = vector(elt)
            if A == elt.parent():
                self._vector = elt._vector.base_extend(k)
                self._matrix = elt._matrix.base_extend(k)
            elif k.has_coerce_map_from(elt.parent()):
                e = k(elt)
                if e == 0:
                    self._vector = vector(k, n)
                    self._matrix = Matrix(k, n)
                elif A.is_unitary():
                    self._vector = A._one * e
                    self._matrix = Matrix.identity(k, n) * e
                else:
                    raise TypeError("algebra is not unitary")
            elif is_Vector(elt):
                self._vector = elt.base_extend(k)
                self._matrix = Matrix(
                    k, sum([elt[i] * A.table()[i] for i in range(n)]))
            elif is_Matrix(elt):
                if not A.is_unitary():
                    raise TypeError("algebra is not unitary")
                self._vector = A._one * elt
                if not check or sum(
                    [self._vector[i] * A.table()[i] for i in range(n)]) == elt:
                    self._matrix = elt
                else:
                    raise ValueError(
                        "matrix does not define an element of the algebra")
            else:
                raise TypeError("elt should be a vector, a matrix, " +
                                "or an element of the base field")
    def __init__(self, A, gens=None, given_by_matrix=False):
        """
        EXAMPLES::

            sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])])
            sage: I = A.ideal(A([0,1]))
            sage: TestSuite(I).run(skip="_test_category") # Currently ideals are not using the category framework
        """
        k = A.base_ring()
        n = A.degree()
        if given_by_matrix:
            self._basis_matrix = gens
            gens = gens.rows()
        elif gens is None:
            self._basis_matrix = Matrix(k, 0, n)
        elif isinstance(gens, (list, tuple)):
            B = [
                FiniteDimensionalAlgebraIdeal(A, x).basis_matrix()
                for x in gens
            ]
            B = reduce(lambda x, y: x.stack(y), B, Matrix(k, 0, n))
            self._basis_matrix = B.echelon_form().image().basis_matrix()
        elif is_Matrix(gens):
            gens = FiniteDimensionalAlgebraElement(A, gens)
        elif isinstance(gens, FiniteDimensionalAlgebraElement):
            gens = gens.vector()
            B = Matrix([gens * b for b in A.table()])
            self._basis_matrix = B.echelon_form().image().basis_matrix()
        Ideal_generic.__init__(self, A, gens)
예제 #15
0
파일: con_field.py 프로젝트: chos9/sage
    def diagonal_matrix(self):
        r"""
        Returns a diagonal matrix `D` and a matrix `T` such that `T^t A T = D`
        holds, where `(x, y, z) A (x, y, z)^t` is the defining polynomial
        of the conic ``self``.

        EXAMPLES:

        ::

            sage: c = Conic(QQ, [1,2,3,4,5,6])
            sage: d, t = c.diagonal_matrix(); d, t
            (
            [    1     0     0]  [   1   -1 -7/6]
            [    0     3     0]  [   0    1 -1/3]
            [    0     0 41/12], [   0    0    1]
            )
            sage: t.transpose()*c.symmetric_matrix()*t
            [    1     0     0]
            [    0     3     0]
            [    0     0 41/12]

        Diagonal matrices are only defined in characteristic different
        from `2`:

        ::

            sage: c = Conic(GF(4, 'a'), [0, 1, 1, 1, 1, 1])
            sage: c.is_smooth()
            True
            sage: c.diagonal_matrix()
            Traceback (most recent call last):
            ...
            ValueError: The conic self (= Projective Conic Curve over Finite Field in a of size 2^2 defined by x*y + y^2 + x*z + y*z + z^2) has no symmetric matrix because the base field has characteristic 2
        """
        A = self.symmetric_matrix()
        B = self.base_ring()
        basis = [vector(B,{2:0,i:1}) for i in range(3)]
        for i in range(3):
            zerovalue = (basis[i]*A*basis[i].column()== 0)
            if zerovalue:
                for j in range(i+1,3):
                    if basis[j]*A*basis[j].column() != 0:
                        b = basis[i]
                        basis[i] = basis[j]
                        basis[j] = b
                        zerovalue = False
            if zerovalue:
                for j in range(i+1,3):
                    if basis[i]*A*basis[j].column() != 0:
                        basis[i] = basis[i]+basis[j]
                        zerovalue = False
            if not zerovalue:
                l = (basis[i]*A*basis[i].column())
                for j in range(i+1,3):
                    basis[j] = basis[j] - \
                               (basis[i]*A*basis[j].column())/l * basis[i]
        T = Matrix(basis).transpose()
        return T.transpose()*A*T, T
예제 #16
0
    def diagonal_matrix(self):
        r"""
        Returns a diagonal matrix `D` and a matrix `T` such that `T^t A T = D`
        holds, where `(x, y, z) A (x, y, z)^t` is the defining polynomial
        of the conic ``self``.

        EXAMPLES:

        ::

            sage: c = Conic(QQ, [1,2,3,4,5,6])
            sage: d, t = c.diagonal_matrix(); d, t
            (
            [    1     0     0]  [   1   -1 -7/6]
            [    0     3     0]  [   0    1 -1/3]
            [    0     0 41/12], [   0    0    1]
            )
            sage: t.transpose()*c.symmetric_matrix()*t
            [    1     0     0]
            [    0     3     0]
            [    0     0 41/12]

        Diagonal matrices are only defined in characteristic different
        from `2`:

        ::

            sage: c = Conic(GF(4, 'a'), [0, 1, 1, 1, 1, 1])
            sage: c.is_smooth()
            True
            sage: c.diagonal_matrix()
            Traceback (most recent call last):
            ...
            ValueError: The conic self (= Projective Conic Curve over Finite Field in a of size 2^2 defined by x*y + y^2 + x*z + y*z + z^2) has no symmetric matrix because the base field has characteristic 2
        """
        A = self.symmetric_matrix()
        B = self.base_ring()
        basis = [vector(B,{2:0,i:1}) for i in range(3)]
        for i in range(3):
            zerovalue = (basis[i]*A*basis[i].column()== 0)
            if zerovalue:
                for j in range(i+1,3):
                    if basis[j]*A*basis[j].column() != 0:
                        b = basis[i]
                        basis[i] = basis[j]
                        basis[j] = b
                        zerovalue = False
            if zerovalue:
                for j in range(i+1,3):
                    if basis[i]*A*basis[j].column() != 0:
                        basis[i] = basis[i]+basis[j]
                        zerovalue = False
            if not zerovalue:
                l = (basis[i]*A*basis[i].column())
                for j in range(i+1,3):
                    basis[j] = basis[j] - \
                               (basis[i]*A*basis[j].column())/l * basis[i]
        T = Matrix(basis).transpose()
        return T.transpose()*A*T, T
예제 #17
0
    def apply_matrix(self, m, in_place=True, mapping=False):
        r"""
        Carry out the GL(2,R) action of m on this surface and return the result.
        
        If in_place=True, then this is done in place and changes the surface. 
        This can only be carried out if the surface is finite and mutable.
        
        If mapping=True, then we return a GL2RMapping between this surface and its image. 
        In this case in_place must be False.
        
        If in_place=False, then a copy is made before the deformation.
        """
        if mapping == True:
            assert in_place == False, "Can not modify in place and return a mapping."
            return GL2RMapping(self, m)
        if not in_place:
            if self.is_finite():
                from sage.structure.element import get_coercion_model
                cm = get_coercion_model()
                field = cm.common_parent(self.base_ring(), m.base_ring())
                s = self.copy(mutable=True, new_field=field)
                return s.apply_matrix(m)
            else:
                return m * self
        else:
            # Make sure m is in the right state
            from sage.matrix.constructor import Matrix
            m = Matrix(self.base_ring(), 2, 2, m)
            assert m.det() != self.base_ring().zero(
            ), "Can not deform by degenerate matrix."
            assert self.is_finite(
            ), "In place GL(2,R) action only works for finite surfaces."
            us = self.underlying_surface()
            assert us.is_mutable(
            ), "In place changes only work for mutable surfaces."
            for label in self.label_iterator():
                us.change_polygon(label, m * self.polygon(label))
            if m.det() < self.base_ring().zero():
                # Polygons were all reversed orientation. Need to redo gluings.

                # First pass record new gluings in a dictionary.
                new_glue = {}
                seen_labels = set()
                for p1 in self.label_iterator():
                    n1 = self.polygon(p1).num_edges()
                    for e1 in range(n1):
                        p2, e2 = self.opposite_edge(p1, e1)
                        n2 = self.polygon(p2).num_edges()
                        if p2 in seen_labels:
                            pass
                        elif p1 == p2 and e1 > e2:
                            pass
                        else:
                            new_glue[(p1, n1 - 1 - e1)] = (p2, n2 - 1 - e2)
                    seen_labels.add(p1)
                # Second pass: reassign gluings
                for (p1, e1), (p2, e2) in iteritems(new_glue):
                    us.change_edge_gluing(p1, e1, p2, e2)
            return self
예제 #18
0
    def LocalizedMomentMatrix(self, idx):
        """
        Returns localized moment matrix corresponding to $g_{idx}$
        """

        tmp_vec = self.MonomialsVec(self.Relaxation - self.HalfDegs[idx])
        m = Matrix(1, len(tmp_vec), tmp_vec)
        return self.Constraints[idx] * (m.transpose() * m)
예제 #19
0
 def LocalizedMomentMatrix(self, idx):
     """
     Returns localized moment matrix corresponding to $g_{idx}$
     """
     
     tmp_vec = self.MonomialsVec(self.Relaxation-self.HalfDegs[idx])
     m = Matrix(1, len(tmp_vec), tmp_vec)
     return self.Constraints[idx]* (m.transpose() * m)
예제 #20
0
    def linear_approximation_matrix(self):
        """
        Return linear approximation matrix ``A`` for this S-box.

        Let ``i_b`` be the ``b``-th bit of ``i`` and ``o_b`` the
        ``b``-th bit of ``o``. Then ``v = A[i,o]`` encodes the bias of
        the equation ``sum( i_b * x_i ) = sum( o_b * y_i )`` if
        ``x_i`` and ``y_i`` represent the input and output variables
        of the S-box.

        See [He2002]_ for an introduction to linear cryptanalysis.

        EXAMPLES::

            sage: from sage.crypto.sbox import SBox
            sage: S = SBox(7,6,0,4,2,5,1,3)
            sage: S.linear_approximation_matrix()
            [ 4  0  0  0  0  0  0  0]
            [ 0  0  0  0  2  2  2 -2]
            [ 0  0 -2 -2 -2  2  0  0]
            [ 0  0 -2  2  0  0 -2 -2]
            [ 0  2  0  2 -2  0  2  0]
            [ 0 -2  0  2  0  2  0  2]
            [ 0 -2 -2  0  0 -2  2  0]
            [ 0 -2  2  0 -2  0  0 -2]

        According to this matrix the first bit of the input is equal
        to the third bit of the output 6 out of 8 times::

            sage: for i in srange(8): print(S.to_bits(i)[0] == S.to_bits(S(i))[2])
            False
            True
            True
            True
            False
            True
            True
            True
        """
        m = self.m
        n = self.n

        nrows = 1<<m
        ncols = 1<<n

        B = BooleanFunction(self.m)
        L = []
        for j in range(ncols):
            for i in range(nrows):
                B[i] = ZZ(self(i)&j).popcount()
            L.append(B.walsh_hadamard_transform())

        A = Matrix(ZZ, ncols, nrows, L)
        A = -A.transpose()/2
        A.set_immutable()

        return A
예제 #21
0
파일: sbox.py 프로젝트: mcognetta/sage
    def linear_approximation_matrix(self):
        """
        Return linear approximation matrix ``A`` for this S-box.

        Let ``i_b`` be the ``b``-th bit of ``i`` and ``o_b`` the
        ``b``-th bit of ``o``. Then ``v = A[i,o]`` encodes the bias of
        the equation ``sum( i_b * x_i ) = sum( o_b * y_i )`` if
        ``x_i`` and ``y_i`` represent the input and output variables
        of the S-box.

        See [He2002]_ for an introduction to linear cryptanalysis.

        EXAMPLES::

            sage: from sage.crypto.sbox import SBox
            sage: S = SBox(7,6,0,4,2,5,1,3)
            sage: S.linear_approximation_matrix()
            [ 4  0  0  0  0  0  0  0]
            [ 0  0  0  0  2  2  2 -2]
            [ 0  0 -2 -2 -2  2  0  0]
            [ 0  0 -2  2  0  0 -2 -2]
            [ 0  2  0  2 -2  0  2  0]
            [ 0 -2  0  2  0  2  0  2]
            [ 0 -2 -2  0  0 -2  2  0]
            [ 0 -2  2  0 -2  0  0 -2]

        According to this matrix the first bit of the input is equal
        to the third bit of the output 6 out of 8 times::

            sage: for i in srange(8): print(S.to_bits(i)[0] == S.to_bits(S(i))[2])
            False
            True
            True
            True
            False
            True
            True
            True
        """
        m = self.m
        n = self.n

        nrows = 1<<m
        ncols = 1<<n

        B = BooleanFunction(self.m)
        L = []
        for j in range(ncols):
            for i in range(nrows):
                B[i] = ZZ(self(i)&j).popcount()
            L.append(B.walsh_hadamard_transform())

        A = Matrix(ZZ, ncols, nrows, L)
        A = -A.transpose()/2
        A.set_immutable()

        return A
    def __init__(self, A, elt=None, check=True):
        """
        TESTS::

            sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1,0], [0,1]]), Matrix([[0,1], [0,0]])])
            sage: A(QQ(4))
            Traceback (most recent call last):
            ...
            TypeError: elt should be a vector, a matrix, or an element of the base field

            sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])])
            sage: elt = B(Matrix([[1,1], [-1,1]])); elt
            e0 + e1
            sage: TestSuite(elt).run()
            sage: B(Matrix([[0,1], [1,0]]))
            Traceback (most recent call last):
            ...
            ValueError: matrix does not define an element of the algebra
        """
        AlgebraElement.__init__(self, A)
        k = A.base_ring()
        n = A.degree()
        if elt is None:
            self._vector = vector(k, n)
            self._matrix = Matrix(k, n)
        else:
            if isinstance(elt, int):
                elt = Integer(elt)
            elif isinstance(elt, list):
                elt = vector(elt)
            if A == elt.parent():
                self._vector = elt._vector.base_extend(k)
                self._matrix = elt._matrix.base_extend(k)
            elif k.has_coerce_map_from(elt.parent()):
                e = k(elt)
                if e == 0:
                    self._vector = vector(k, n)
                    self._matrix = Matrix(k, n)
                elif A.is_unitary():
                    self._vector = A._one * e
                    self._matrix = Matrix.identity(k, n) * e
                else:
                    raise TypeError("algebra is not unitary")
            elif is_Vector(elt):
                self._vector = elt.base_extend(k)
                self._matrix = Matrix(k, sum([elt[i] * A.table()[i] for i in xrange(n)]))
            elif is_Matrix(elt):
                if not A.is_unitary():
                    raise TypeError("algebra is not unitary")
                self._vector = A._one * elt
                if not check or sum([self._vector[i]*A.table()[i] for i in xrange(n)]) == elt:
                    self._matrix = elt
                else:
                    raise ValueError("matrix does not define an element of the algebra")
            else:
                raise TypeError("elt should be a vector, a matrix, " +
                                "or an element of the base field")
예제 #23
0
def angle_equations(M):
    """
    Given a snappy manifold M, returns the matrix of left-hand-sides
    of angle equations (that is, the tet, edge, and cusp equations).
    """
    num_tet = M.num_tetrahedra()
    G = M.gluing_equations()
    T = Matrix(ZZ, [tet_vector(i, num_tet) for i in range(num_tet)])
    return T.transpose().augment(G.transpose()).transpose()  # sigh
예제 #24
0
    def __init__(self, parent, val=0, check=True, normalize=False):
        """
        Initialisation function. Takes as input a vector val, which should have length equal to the 
        dimension of the space, which is the nth triangle number, where n is the depth. This corresponds
        to the ordered basis for distributions (namely, the dual basis to the basis 1, x, y, x^2, xy, ...).

        Input:
            - parent: BianchiDistributions object of depth n
            - val : vector of length n^2 encoding the moments of the distribution
        """
        ## Parents/precision
        ModuleElement.__init__(self, parent)
        self._parent = parent
        self._depth = self._parent._depth
        self._dimension = self._parent._dimension

        ## check multiple possibilities for input
        if not check:
            self._moments = val
        else:
            ## is input already a distribution?
            if isinstance(val, self.__class__):
                ## if depth is the same, then keep this
                if val._parent._depth == parent._depth:
                    self._moments = val._moments
                else:
                    ## depths are different, take the minimum
                    d = min([val.nrows(), parent.dimension()])
                    self._moments = val._moments.submatrix(0, 0, nrows=d)

            elif isinstance(val, int) or isinstance(val, Integer):
                ## Initialise distribution to be trivial, i.e. constant moment = input and rest = 0
                self._moments = MatrixSpace(self._parent._R, self._dimension,
                                            1)(0)
                self._moments[0, 0] = val

            ## input is a vector storing the moments
            elif isinstance(val, Vector_integer_dense) or isinstance(
                    val, FreeModuleElement_generic_dense):
                self._moments = MatrixSpace(self._parent._R, self._dimension,
                                            1)(0)
                for i, o in enumerate(val.list()):
                    self._moments[i, 0] = o

            ## input is a list storing the moments
            elif isinstance(val, list):
                self._moments = MatrixSpace(self._parent._R, self._dimension,
                                            1)(0)
                for i, o in enumerate(val):
                    self._moments[i, 0] = o
            else:
                try:
                    self._moments = Matrix(self._parent._R, self._depth, 1,
                                           val)
                except (TypeError, ValueError):
                    self._moments = self._parent._R(val) * MatrixSpace(
                        self._parent._R, self._dimension, 1)(1)
예제 #25
0
 def apply_matrix(self,m,in_place=True, mapping=False):
     r"""
     Carry out the GL(2,R) action of m on this surface and return the result.
     
     If in_place=True, then this is done in place and changes the surface. 
     This can only be carried out if the surface is finite and mutable.
     
     If mapping=True, then we return a GL2RMapping between this surface and its image. 
     In this case in_place must be False.
     
     If in_place=False, then a copy is made before the deformation.
     """
     if mapping==True:
         assert in_place==False, "Can not modify in place and return a mapping."
         return GL2RMapping(self, m)
     if not in_place:
         if self.is_finite():
             from sage.structure.element import get_coercion_model
             cm = get_coercion_model()
             field = cm.common_parent(self.base_ring(), m.base_ring())
             s=self.copy(mutable=True, new_field=field)
             return s.apply_matrix(m)
         else:
             return m*self
     else:
         # Make sure m is in the right state
         from sage.matrix.constructor import Matrix
         m=Matrix(self.base_ring(), 2, 2, m)
         assert m.det()!=self.base_ring().zero(), "Can not deform by degenerate matrix."
         assert self.is_finite(), "In place GL(2,R) action only works for finite surfaces."
         us=self.underlying_surface()
         assert us.is_mutable(), "In place changes only work for mutable surfaces."
         for label in self.label_iterator():
             us.change_polygon(label,m*self.polygon(label))
         if m.det()<self.base_ring().zero():
             # Polygons were all reversed orientation. Need to redo gluings.
             
             # First pass record new gluings in a dictionary.
             new_glue={}
             seen_labels=set()
             for p1 in self.label_iterator():
                 n1=self.polygon(p1).num_edges()
                 for e1 in xrange(n1):
                     p2,e2=self.opposite_edge(p1,e1)
                     n2=self.polygon(p2).num_edges()
                     if p2 in seen_labels:
                         pass
                     elif p1==p2 and e1>e2:
                         pass
                     else:
                         new_glue[(p1, n1-1-e1)]=(p2, n2-1-e2)
                 seen_labels.add(p1)
             # Second pass: reassign gluings
             for (p1,e1),(p2,e2) in new_glue.iteritems():
                 us.change_edge_gluing(p1,e1,p2,e2)
         return self
예제 #26
0
def projection_to_homology(tri,angle):
    non_tree_as_cycles = non_tree_edge_cycles(tri, angle)
    Q = Matrix(non_tree_as_cycles)
    S, U, V = faces_in_smith(tri,angle,[])
    rank, dimU, dimV = rank_of_quotient(S)
    U = Matrix(U)
    P = U.transpose().inverse()
    P = P.delete_rows(range(0, dimU-rank))
    A = P*Q
    return A
예제 #27
0
 def matrix_rep(self,B=None):
     r"""
     Returns a matrix representation of ``self``.
     """
     #Express the element in terms of the basis B
     if B is None:
         B = self._parent.basis()
     A=Matrix(self._parent._R,self._parent.dimension(),self._parent.dimension(),[[b._val[ii,0] for b in B] for ii in range(self._depth)])
     tmp=A.solve_right(self._val)
     return tmp
예제 #28
0
 def decompose(self):
     """
         Gives an SOS decomposition of f if exists as a list of polynomials
         of at most half degree of f.
         This method also fills the 'Info' as 'minimize' does. In addition,
         returns Info['is sos'] which is Boolean depending on the status of 
         sdp solver.
     """
     n = self.NumVars
     N0 = self.NumMonomials(n, self.MainPolyHlfDeg)
     N1 = self.NumMonomials(n, self.MainPolyTotDeg)
     self.MatSize = [N0, N1]
     
     vec = self.MonomialsVec(self.MainPolyHlfDeg)
     m = Matrix(1, N0, vec)
     Mmnt = m.transpose() * m
     Blck = [[] for i in range(N1)]
     C = []
     
     h = Matrix(self.Field, N0, N0, 0)
     C.append(h)
     decomp = []
     
     for i in range(N1):
         p = self.Monomials[i]
         A = self.Calpha(p, Mmnt)
         Blck[i].append(A)
     
     from SDP import SDP
     sos_sdp = SDP.sdp(solver = self.solver, Settings = {'detail':self.detail})
     sos_sdp.solve(C, self.PolyCoefFullVec(), Blck)
     
     if sos_sdp.Info['Status'] == 'Optimal':
         self.Info['status'] = 'Feasible'
         GramMtx = Matrix(sos_sdp.Info['X'][0])
         try:
             self.Info['Message'] = "A SOS decomposition of the polynomial were found."
             self.Info['is sos'] = True
             H1 = GramMtx.cholesky();
             tmpM = Matrix(1, N0, vec)
             decomp = list(tmpM*H1)[0]
             self.Info['Wall'] = sos_sdp.Info['Wall']
             self.Info['CPU'] = sos_sdp.Info['CPU']
         except:
             self.Info['Message'] = "The given polynomial seems to be a sum of squares, but no SOS decomposition were extracted."
             self.Info['is sos'] = False
             self.Info['Wall'] = sos_sdp.Info['Wall']
             self.Info['CPU'] = sos_sdp.Info['CPU']
     else:
         self.Info['Message'] = "The given polynomial is not a sum of squares."
         self.Info['status'] = 'Infeasible'
         self.Info['is sos']= False
     
     self.Info["Size"] = self.MatSize
     return decomp
예제 #29
0
    def matrix_rep(self,B=None):
        r"""
        Returns a matrix representation of ``self``.
        """
        #Express the element in terms of the basis B
        if B is None:
            B = self._parent.basis()

        A = Matrix(self._parent._R,self._parent.dimension(),self._parent.dimension(),[[b._moments[ii,0] for b in B] for ii in range(self._dimension)])
        tmp = A.solve_right(self._moments)
        return tmp
예제 #30
0
def monomial_multiplier(elts, ZH):
    if all(elt == 0 for elt in elts):
        # Zero (unlike other constants) has valuation -\infty.  This
        # can show up as an issue when computing the big polynomial.
        # For an example, compute ET for
        # "kLLLMPPkcdgfehijjijhshassqhdqr_1222011022"
        return ZH(1)
    elts = [ZH(elt) for elt in elts]
    A = Matrix(ZZ, join_lists([uniform_exponents(p) for p in elts]))
    min_exp = tuple([min(row) for row in A.transpose()])
    return ZH({min_exp: 1})
예제 #31
0
def Eij(i, j, N):
    #The matrix which just has one non-zero entry, 1, at (i+1,j+1).
    ei, ej = [], []
    for k in range(N):
        if k == i:
            ei.append([1])
        else:
            ei.append([0])
        if k == j:
            ej.append([1])
        else:
            ej.append([0])
    return Matrix(ei) * Matrix(ej).T
예제 #32
0
def taut_polynomial_via_smith(tri, angle, cycles = [], alpha = True, mode = "taut"):
    # set up
    assert tri.homology().rank() == 1 # need the polynomial ring to be a PID
    ZH = group_ring(tri, angle, cycles, alpha = alpha, ring = QQ) # ditto
    P = ZH.polynomial_ring()

    ET = edges_to_triangles_matrix(tri, angle, cycles, ZH, P, mode = mode)

    # compute via smith normal form
    ETs = ET.smith_form()[0]
    a = tri.countEdges()
    ETs_reduced = Matrix([row[:a] for row in ETs])
    return normalise_poly(ETs_reduced.determinant(), ZH, P)
예제 #33
0
def qexp_to_basis(f, E, p=None, check=True):
    ncols = len(list(f))
    try:
        R = f.parent().base_ring()
    except (AttributeError,TypeError):
        R = E.parent().base_ring()
    try:
        fmat = Matrix(R,1,len(f), f.list())
    except AttributeError:
        fmat = Matrix(R,1,len(f), f)
    verbose('R = %s'%R)
    verbose('E.parent() = %s'%E.parent())
    return vector(solve_xAb_echelon(E.submatrix(0,0,ncols = ncols),fmat,p,check=check).list())
예제 #34
0
    def _get_powers_and_mult(self, a, b, c, d, lambd, vect):
        r"""
        Compute the action of a matrix on the basis elements.

        EXAMPLES:

        ::

        """
        try:
            xnew = self._powers[(a, b, c, d)]
        except KeyError:
            R = self._PowerSeries
            r = R([b, a])
            s = R([d, c])
            n = self._n

            if self._depth == n + 1:
                rpows = [R(1)]
                spows = [R(1)]
                for ii in range(n):
                    rpows.append(r * rpows[ii])
                    spows.append(s * spows[ii])
                x = Matrix(self._Rmod, n + 1, n + 1, 0)
                for ii in range(n + 1):
                    y = rpows[ii] * spows[n - ii]
                    for jj in range(self._depth):
                        x[ii, jj] = y[jj]
            else:
                ratio = r * (s**(-1))
                y = s**n
                x = Matrix(self._Rmod, self._depth, self._depth, 0)
                for jj in range(self._depth):
                    x[0, jj] = y[jj]
                for ii in range(1, self._depth):
                    y *= ratio
                    for jj in range(self._depth):
                        x[ii, jj] = y[jj]

            xnew = x.change_ring(self._R)  #ZZ)
            # if self._Rmod is self._R:
            #     xnew = x
            # else:
            #     #xnew = x.change_ring(self._R)
            #     xnew = x.change_ring(ZZ)

            self._powers[(a, b, c, d)] = xnew

        tmp = xnew * vect
        return self._R(lambd) * tmp  #.change_ring(self._R)
예제 #35
0
    def _get_powers_and_mult(self,a,b,c,d,lambd,vect):
        r"""
        Compute the action of a matrix on the basis elements.

        EXAMPLES:

        ::

        """
        try:
            xnew = self._powers[(a,b,c,d)]
        except KeyError:
            R=self._PowerSeries
            r=R([b,a])
            s=R([d,c])
            n=self._n

            if self._depth == n+1:
                rpows=[R(1)]
                spows=[R(1)]
                for ii in range(n):
                    rpows.append(r*rpows[ii])
                    spows.append(s*spows[ii])
                x=Matrix(self._Rmod,n+1,n+1,0)
                for ii in range(n+1):
                    y=rpows[ii]*spows[n-ii]
                    for jj in range(self._depth):
                        x[ii,jj]=y[jj]
            else:
                ratio = r*(s**(-1))
                y = s**n
                x = Matrix(self._Rmod,self._depth,self._depth,0)
                for jj in range(self._depth):
                    x[0,jj] = y[jj]
                for ii in range(1,self._depth):
                    y *= ratio
                    for jj in range(self._depth):
                        x[ii,jj] = y[jj]

            xnew = x.change_ring(self._R) #ZZ)
            # if self._Rmod is self._R:
            #     xnew = x
            # else:
            #     #xnew = x.change_ring(self._R)
            #     xnew = x.change_ring(ZZ)

            self._powers[(a,b,c,d)] = xnew

        tmp = xnew*vect
        return self._R(lambd)*tmp #.change_ring(self._R)
    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
예제 #37
0
def solve_xAb_echelon(A,b, p=None, prec=None, check=False):
    r'''

    TESTS::

        sage: from functions import *
        sage: A = Matrix(ZZ,2,3,[1,0,2,0,2,3])
        sage: is_echelon(A)
        True
        sage: b = vector(QQ,3,[4,5,6])
        sage: solve_xAb_echelon(A,b)
        (4, 5/2)
        sage: _ * A - b
        (0, 0, 19/2)

    '''
    R = b.parent().base_ring()
    try:
        R = R.fraction_field()
    except (AttributeError,TypeError): pass
    if p is None:
        try:
            p = R.cardinality().factor()[0][0] # DEBUG
        except AttributeError:
            p = 0
    if check and not is_echelon(A):
        raise ValueError("Not in echelon form")
    hnew = try_lift(b.parent()(b))
    ell = A.nrows()
    A = try_lift(A)
    col_list = []
    for j in range(ell):
        ej = A.row(j)
        ejleadpos, val = first_nonzero_pos(ej,return_val=True)
        newcol = [hnew[i,ejleadpos] / val for i in range(hnew.nrows())]
        tmp1 = Matrix(hnew.parent().base_ring(), hnew.nrows(),1, newcol)
        tmp2 = Matrix(ej.parent().base_ring(),1,len(ej),ej.list())
        hnew -= tmp1 * tmp2
        col_list.append(newcol)

    alphas = Matrix(R,ell,hnew.nrows(),col_list).transpose()
    verbose('Check = %s, p = %s'%(check,p))
    if check and p > 0:
        verbose('Check with p = %s'%p)
        err = min([o.valuation(p) for o in (alphas * try_lift(A) - try_lift(b)).list()])
        if err < 5:
            verbose('Check not passed!')
            raise RuntimeError("System appears not to be solvable. Minimal valuation is %s"%err)
    return alphas
예제 #38
0
def c3_func(SUK, prec=106):
    r"""
    Return the constant `c_3` from Smart's 1995 TCDF paper, [Sma1995]_

    INPUT:

    - ``SUK`` -- a group of `S`-units
    - ``prec`` -- (default: 106) the precision of the real field

    OUTPUT:

    The constant ``c3``, as a real number

    EXAMPLES::

        sage: from sage.rings.number_field.S_unit_solver import c3_func
        sage: K.<xi> = NumberField(x^3-3)
        sage: SUK = UnitGroup(K, S=tuple(K.primes_above(3)))

        sage: c3_func(SUK) # abs tol 1e-29
        0.4257859134798034746197327286726

    .. NOTE::

        The numerator should be as close to 1 as possible, especially as the rank of the `S`-units grows large

    REFERENCES:

    - [Sma1995]_ p. 823

    """

    R = RealField(prec)

    all_places = list(SUK.primes()) + SUK.number_field().places(prec)
    Possible_U = Combinations(all_places, SUK.rank())
    c1 = R(0)
    for U in Possible_U:
        # first, build the matrix C_{i,U}
        columns_of_C = []
        for unit in SUK.fundamental_units():
            columns_of_C.append(column_Log(SUK, unit, U, prec))
        C = Matrix(SUK.rank(), SUK.rank(), columns_of_C)
        # Is it invertible?
        if abs(C.determinant()) > 10**(-10):
            poss_c1 = C.inverse().apply_map(abs).norm(Infinity)
            c1 = R(max(poss_c1, c1))
    return R(0.9999999) / (c1*SUK.rank())
예제 #39
0
    def decompose(self):
        """
            Gives an SOS decomposition of f if exists as a list of polynomials
            of at most half degree of f.
            This method also fills the 'Info' as 'minimize' does. In addition,
            returns Info['is sos'] which is Boolean depending on the status of 
            sdp solver.
        """
        n = self.NumVars
        N0 = self.NumMonomials(n, self.MainPolyHlfDeg)
        N1 = self.NumMonomials(n, self.MainPolyTotDeg)
        self.MatSize = [N0, N1]

        vec = self.MonomialsVec(self.MainPolyHlfDeg)
        m = Matrix(1, N0, vec)
        Mmnt = m.transpose() * m
        Blck = [[] for i in range(N1)]
        C = []

        h = Matrix(self.Field, N0, N0, 0)
        C.append(h)
        decomp = []

        for i in range(N1):
            p = self.Monomials[i]
            A = self.Calpha(p, Mmnt)
            Blck[i].append(A)

        from SDP import SDP
        sos_sdp = SDP.sdp(solver=self.solver, Settings={'detail': self.detail})
        sos_sdp.solve(C, self.PolyCoefFullVec(), Blck)

        if sos_sdp.Info['Status'] == 'Optimal':
            self.Info['status'] = 'Feasible'
            GramMtx = Matrix(sos_sdp.Info['X'][0])
            try:
                self.Info[
                    'Message'] = "A SOS decomposition of the polynomial were found."
                self.Info['is sos'] = True
                H1 = GramMtx.cholesky()
                tmpM = Matrix(1, N0, vec)
                decomp = list(tmpM * H1)[0]
                self.Info['Wall'] = sos_sdp.Info['Wall']
                self.Info['CPU'] = sos_sdp.Info['CPU']
            except:
                self.Info[
                    'Message'] = "The given polynomial seems to be a sum of squares, but no SOS decomposition were extracted."
                self.Info['is sos'] = False
                self.Info['Wall'] = sos_sdp.Info['Wall']
                self.Info['CPU'] = sos_sdp.Info['CPU']
        else:
            self.Info[
                'Message'] = "The given polynomial is not a sum of squares."
            self.Info['status'] = 'Infeasible'
            self.Info['is sos'] = False

        self.Info["Size"] = self.MatSize
        return decomp
예제 #40
0
def poly_dual_basis(P, poly_basis):
    r"""
    Return a collection of polynomials which are dual under the differential
    bilinear form to a given homogeneous collection

    INPUT:

    - ``P`` -- a polynomial ring
    - ``poly_basis`` -- a collection of polynomials in ``P`` which are
      homogeneous and linearly independent

    OUTPUT:

    - the dual basis of the polynomials in ``poly_basis`` in their span

    EXAMPLES:

        sage: P.<x, y> = PolynomialRing(QQ)
        sage: poly_basis = (1, x, x+y)
        sage: poly_dual_basis(P, poly_basis)
        [1, x - y, y]
        sage: poly_basis = (1, 2*x - y, x^2, x^2 + x*y)
        sage: poly_dual_basis(P, poly_basis)
        [1, 2/5*x - 1/5*y, 1/2*x^2 - x*y, x*y]
    """
    # recast poly_basis to ensure elements are all from P
    poly_basis = [P(p) for p in poly_basis]
    # compute max degree of basis polynomials for linear algebra computations
    deg = max([p.degree() for p in poly_basis])
    # construct polynomial free module for linear algebra computations
    monoms = Monomials(P, (0, deg))
    poly_module = PolynomialFreeModule(P, basis=monoms)
    # compute the values of the bilinear form <m|m> for basis monomials m
    bilinear_form_coeffs = []
    for b in poly_module.basis().keys():
        # each b is a monomial in P of degree at most deg
        b = P(b)
        bilinear_form_coeffs.append(prod(map(factorial, b.degrees())))
    # compute dual basis
    A = Matrix([poly_module(p).to_vector() for p in poly_basis])
    D = Matrix.diagonal(bilinear_form_coeffs, sparse=False)
    B = (A * D * A.transpose()).inverse()
    # reconstruct dual basis polynomials from corresponding vectors
    dual_basis = []
    for col in B.columns():
        q = sum([coeff * p for coeff, p in zip(col, poly_basis)])
        dual_basis.append(q)
    return dual_basis
예제 #41
0
    def __init__(self,segment,rho,rhoexp):
        """
        Initializes self.

        See ``AssociatedFactor`` for full documentation.

        """
        self.segment = segment
        self.rho = rho
        self.rhoexp = rhoexp
        self.Fplus = self.rho.degree()

        if self.segment.frame.is_first():
            # In the first frame, so FFbase is the residue class field of O
            self.FFbase = self.segment.frame.R
        else:
            # Not the first frame
            self.FFbase = self.segment.frame.prev.FF

        if self.Fplus == 1:
            self.FF = self.FFbase
            self.FFz = PolynomialRing(self.FF,'z'+str(self.segment.frame.depth))
            # rho is linear delta is the root of rho
            self.delta = self.rho.roots()[0][0]
        else:
            self.FF = GF(self.FFbase.order()**self.Fplus,'a'+str(self.segment.frame.depth))
            self.FFz = PolynomialRing(self.FF,'z'+str(self.segment.frame.depth))
            self.FFbase_gamma = (self.FFz(self.FFbase.modulus())).roots()[0][0]
            FFrho = self.FFz([self.FFbase_elt_to_FF(a) for a in list(rho)])
            self.gamma = FFrho.roots()[0][0]
            basis = [(self.gamma**j*self.FFbase_gamma**i).polynomial() for j in range(0,self.Fplus) for i in range(0,self.FFbase.degree())]
            self.basis_trans_mat = Matrix([self.FF(b)._vector_() for b in basis])
    def __call__(self, f, check=True, unitary=True):
        """
        Construct a homomorphism.

        .. TODO::

            Implement taking generator images and converting them to a matrix.

        EXAMPLES::

            sage: A = FiniteDimensionalAlgebra(QQ, [Matrix([1])])
            sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1, 0], [0, 1]]), Matrix([[0, 1], [0, 0]])])
            sage: H = Hom(A, B)
            sage: H(Matrix([[1, 0]]))
            Morphism from Finite-dimensional algebra of degree 1 over Rational Field to
             Finite-dimensional algebra of degree 2 over Rational Field given by matrix
            [1 0]
        """
        if isinstance(f, FiniteDimensionalAlgebraMorphism):
            if f.parent() is self:
                return f
            if f.parent() == self:
                return FiniteDimensionalAlgebraMorphism(
                    self, f._matrix, check, unitary)
        elif is_Matrix(f):
            return FiniteDimensionalAlgebraMorphism(self, f, check, unitary)
        try:
            from sage.matrix.constructor import Matrix
            return FiniteDimensionalAlgebraMorphism(self, Matrix(f), check,
                                                    unitary)
        except Exception:
            return RingHomset_generic.__call__(self, f, check)
    def incidence_matrix(self):
        """
        Return the incidence matrix `A` of the design. A is a `(v \times b)`
        matrix defined by: ``A[i,j] = 1`` if ``i`` is in block ``B_j`` and 0
        otherwise.

        EXAMPLES::

            sage: BD = IncidenceStructure(range(7),[[0,1,2],[0,3,4],[0,5,6],[1,3,5],[1,4,6],[2,3,6],[2,4,5]])
            sage: BD.block_sizes()
            [3, 3, 3, 3, 3, 3, 3]
            sage: BD.incidence_matrix()
            [1 1 1 0 0 0 0]
            [1 0 0 1 1 0 0]
            [1 0 0 0 0 1 1]
            [0 1 0 1 0 1 0]
            [0 1 0 0 1 0 1]
            [0 0 1 1 0 0 1]
            [0 0 1 0 1 1 0]
        """
        if not self._incidence_matrix is None:
            return self._incidence_matrix
        else:
            from sage.matrix.constructor import Matrix
            v = len(self.points())
            blks = self.blocks()
            b = len(blks)
            A = Matrix(ZZ, v, b, sparse=True)
            for j, b in enumerate(blks):
                for i in b:
                    A[i, j] = 1
            self._incidence_matrix = A
            return A
예제 #44
0
    def matrix_rep(self,B=None):
        r"""

        EXAMPLES:

        This example illustrates ...

        ::

        """
        #Express the element in terms of the basis B
        if(B is None):
            B=self._parent.basis()
        A=Matrix(self._parent._R,self._parent.dimension(),self._parent.dimension(),[[b._val[ii,0] for b in B] for ii in range(self._depth)])
        tmp=A.solve_right(self._val)
        return tmp
        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")
예제 #46
0
    def unitary_reflection(self, r, alpha=-1):
        S = self.complex_gram_matrix()
        r_conj = vector([x.galois_conjugate() for x in r])
        r_norm = r * S * r_conj
        if not r_norm:
            raise ValueError('Not a valid reflection')
        d = self._hds_to_ds()
        d_inv = self._ds_to_hds()
        r0 = ((1 - alpha) / r_norm) * (S * r_conj)
        g = self.base_field().gens()[0]
        w = self._w()
        w_conj = w.galois_conjugate()
        M = Matrix(ZZ, [[2, w + w_conj], [0, (w - w_conj) * g]]).inverse()

        def f(x):
            v = vector(d_inv[tuple(x)])
            v = v - (v * r0) * r
            x = [0] * (2 * len(v))
            for i, v in enumerate(v):
                v_conj = v.galois_conjugate()
                a, b = (v + v_conj), (v - v_conj) * g
                x[i + i], x[i + i + 1] = M * vector([a, b])
            return tuple(map(frac, x))

        return WeilRepAutomorphism(self, f)
예제 #47
0
    def reflections(self):
        """
        Return the reflections of ``self``.

        The reflections of a Coxeter group `W` are the conjugates of
        the simple reflections. They are in bijection with the positive
        roots, for given a positive root, we may have the reflection in
        the hyperplane orthogonal to it. This method returns a family
        indexed by the positive roots taking values in the reflections.
        This requires ``self`` to be a finite Weyl group.

        .. NOTE::

            Prior to :trac:`20027`, the reflections were the keys
            of the family and the values were the positive roots.

        EXAMPLES::

            sage: W = WeylGroup("B2", prefix="s")
            sage: refdict = W.reflections(); refdict
            Finite family {(1, -1): s1, (1, 1): s2*s1*s2, (1, 0): s1*s2*s1, (0, 1): s2}
            sage: [r+refdict[r].action(r) for r in refdict.keys()]
            [(0, 0), (0, 0), (0, 0), (0, 0)]

        """
        ret = {}
        try:
            for alp in self.domain().positive_roots():
                m = Matrix([self.domain().reflection(alp)(x).to_vector()
                            for x in self.domain().basis()])
                r = self(m)
                ret[alp] = r
            return Family(ret)
        except Exception:
            raise NotImplementedError("reflections are only implemented for finite Weyl groups")
예제 #48
0
 def acting_matrix(self, g, prec = None):
     dim = len(self.basis())
     ans = Matrix(self._V.base_ring(),dim, 0)
     for v in self.basis():
         gv = g * v
         gvlist = []
         for w in gv._val:
             try:
                 wlist = list(w)
             except TypeError:
                 wlist = list(w._moments)
             if prec is None:
                 gvlist.extend(wlist)
             else:
                 gvlist.extend(wlist[:prec])
         ans = ans.augment(Matrix(self._V.base_ring(),dim,1,gvlist))
     return ans
예제 #49
0
 def linear_relation(self, List, Psi, verbose=True, prec=None):
     for Phi in List:
         assert Phi.valuation() >= 0, "Symbols must be integral"
     assert Psi.valuation() >= 0
     R = self.base()
     Rbase = R.base()
     w = R.gen()
     d = len(List)
     if d == 0:
         if Psi.is_zero():
             return [None, R(1)]
         else:
             return [None, 0]
     if prec is None:
         M, var_prec = Psi.precision_absolute()
     else:
         M, var_prec = prec
     p = self.prime()
     V = R**d
     RSR = LaurentSeriesRing(Rbase, R.variable_name())
     VSR = RSR**self.source().ngens()
     List_TMs = [VSR(Phi.list_of_total_measures()) for Phi in List]
     Psi_TMs = VSR(Psi.list_of_total_measures())
     A = Matrix(RSR, List_TMs).transpose()
     try:
         sol = V([vv.power_series() for vv in A.solve_right(Psi_TMs)])
     except ValueError:
         #try "least squares"
         if verbose:
             print "Trying least squares."
         sol = (A.transpose() * A).solve_right(A.transpose() * Psi_TMs)
         #check precision (could make this better, checking each power of w)
         p_prec = M
         diff = Psi_TMs - sum([sol[i] * List_TMs[i] for i in range(len(List_TMs))])
         for i in diff:
             for j in i.list():
                 if p_prec > j.valuation():
                     p_prec = j.valuation()
         if verbose:
             print "p-adic precision is now", p_prec
         #Is this right?
         sol = V([R([j.add_bigoh(p_prec) for j in i.list()]) for i in sol])
     return [sol, R(-1)]
예제 #50
0
def solve_coefficient_system(Q, equations, vars):
    # NOTE: to make things easier (and uniform) in the univariate case a dummy
    # variable is added to the polynomial ring. See compute_bd()
    a = Q.gens()[:-1]
    B = Q.base_ring()

    # construct the coefficient system and right-hand side
    system = [[e.coefficient({ai:1}) for ai in a] for e in equations]
    rhs = [-e.constant_coefficient() for e in equations]
    system = Matrix(B, system)
    rhs = Matrix(B, rhs).transpose()

    # we only allow unique solutions. return None if there are infinitely many
    # solutions or if no solution exists. Sage will raise a ValueError in both
    # circumstances
    try:
        sol = system.solve_right(rhs)
    except ValueError:
        return None
    return sol
예제 #51
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
    def __init__(self, X, varNames="x", externalBasisMatrix=None):
        if externalBasisMatrix is None:
            externalBasisMatrix = X.column_space().basis_matrix().transpose()
        else:
            if X.column_space() != externalBasisMatrix.column_space():
                raise ValueError(
                    "ExternalZonotopalAlgebra: externalBasisMatrix must have"
                    " the same column space as X")

        AbstractZonotopalAlgebra.__init__(self, X, varNames)
        self._ext_basis_matrix = externalBasisMatrix
        self._ext_block_matrix = Matrix.block([[X, self._ext_basis_matrix]])
        self._embedding_central_za = CentralZonotopalAlgebra(
            self._ext_block_matrix, varNames)
예제 #53
0
    def __init__(self,parent,val = 0,check = True,normalize=False):
        ModuleElement.__init__(self,parent)
        self._parent = parent
        self._depth = self._parent._depth
        if not check:
            self._val = val
        else:
            if isinstance(val,self.__class__):
                if val._parent._depth == parent._depth:
                    self._val = val._val
                else:
                    d = min([val._parent._depth,parent._depth])
                    self._val = val._val.submatrix(0,0,nrows = d)

            elif isinstance(val, Vector_integer_dense) or isinstance(val, FreeModuleElement_generic_dense):
                self._val = MatrixSpace(self._parent._R, self._depth, 1)(0)
                for i,o in enumerate(val.list()):
                    self._val[i,0] = o
            else:
                try:
                    self._val = Matrix(self._parent._R,self._depth,1,val)
                except (TypeError, ValueError):
                    self._val= self._parent._R(val) * MatrixSpace(self._parent._R,self._depth,1)(1)
        self._moments = self._val
예제 #54
0
    def __init__(self, Lam):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: Lambda = RootSystem(['A',3,1]).weight_lattice(extended=true).fundamental_weights()
            sage: V = IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3])

        Some methods required by the category are not implemented::

            sage: TestSuite(V).run()  # known bug (#21387)
        """
        CategoryObject.__init__(self, base=ZZ, category=Modules(ZZ))

        self._Lam = Lam
        self._P = Lam.parent()
        self._Q = self._P.root_system.root_lattice()

        # Store some extra simple computations that appear in tight loops
        self._Lam_rho = self._Lam + self._P.rho()

        self._cartan_matrix = self._P.root_system.cartan_matrix()
        self._cartan_type = self._P.root_system.cartan_type()

        self._classical_rank = self._cartan_type.classical().rank()
        self._index_set = self._P.index_set()
        self._index_set_classical = self._cartan_type.classical().index_set()
        self._cminv = self._cartan_type.classical().cartan_matrix().inverse()

        self._ddict = {}
        self._mdict = {tuple(0 for i in self._index_set): 1}
        # Coerce a classical root into the root lattice Q
        from_cl_root = lambda h: self._Q._from_dict(h._monomial_coefficients)
        self._classical_roots = [from_cl_root(al)
                                 for al in self._Q.classical().roots()]
        self._classical_positive_roots = [from_cl_root(al)
                                          for al in self._Q.classical().positive_roots()]
        self._a = self._cartan_type.a() # This is not cached
        self._ac = self._cartan_type.dual().a() # This is not cached
        self._eps = {i: self._a[i] / self._ac[i] for i in self._index_set}
        E = Matrix.diagonal([self._eps[i] for i in self._index_set_classical])
        self._ip = (self._cartan_type.classical().cartan_matrix()*E).inverse()

        # Extra data for the twisted cases
        if not self._cartan_type.is_untwisted_affine():
            self._classical_short_roots = frozenset(al for al in self._classical_roots
                                                    if self._inner_qq(al,al) == 2)
예제 #55
0
    def is_unitary(self):
        """
        Return ``True`` if ``self`` has a two-sided multiplicative
        identity element.

        EXAMPLES::

            sage: A = FiniteDimensionalAlgebra(QQ, [])
            sage: A.is_unitary()
            True

            sage: B = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[0,1], [-1,0]])])
            sage: B.is_unitary()
            True

            sage: C = FiniteDimensionalAlgebra(QQ, [Matrix([[0,0], [0,0]]), Matrix([[0,0], [0,0]])])
            sage: C.is_unitary()
            False

            sage: D = FiniteDimensionalAlgebra(QQ, [Matrix([[1,0], [0,1]]), Matrix([[1,0], [0,1]])])
            sage: D.is_unitary()
            False

        .. NOTE::

            If a finite-dimensional algebra over a field admits a left identity,
            then this is the unique left identity, and it is also a
            right identity.
        """
        k = self.base_ring()
        n = self.degree()
        # B is obtained by concatenating the elements of
        # self.table(), and v by concatenating the rows of
        # the n times n identity matrix.
        B = reduce(lambda x, y: x.augment(y),
                   self.table(), Matrix(k, n, 0))
        v = vector(Matrix.identity(k, n).list())
        try:
            self._one = B.solve_left(v)
            return True
        except ValueError:
            return False
    def __init__(self, Lam):
        """
        Initialize ``self``.

        EXAMPLES::

            sage: Lambda = RootSystem(['A',3,1]).weight_lattice(extended=true).fundamental_weights()
            sage: V = IntegrableRepresentation(Lambda[1]+Lambda[2]+Lambda[3])
            sage: TestSuite(V).run()
        """
        CategoryObject.__init__(self, base=ZZ, category=Modules(ZZ))

        if not Lam.parent().cartan_type().is_affine() or not Lam.parent()._extended:
            raise ValueError("the parent of %s must be an extended affine root lattice"%Lam)
        self._Lam = Lam
        self._P = Lam.parent()
        self._Q = self._P.root_system.root_lattice()

        self._cartan_matrix = self._P.root_system.cartan_matrix()
        self._cartan_type = self._P.root_system.cartan_type()
        if not self._cartan_type.is_untwisted_affine():
            raise NotImplementedError("integrable representations are only implemented for untwisted affine types")
        self._classical_rank = self._cartan_type.classical().rank()
        self._index_set = self._P.index_set()
        self._index_set_classical = self._cartan_type.classical().index_set()
        self._cminv = self._cartan_type.classical().cartan_matrix().inverse()

        self._ddict = {}
        self._mdict = {tuple(0 for i in self._index_set): 1}
        # Coerce a classical root into the root lattice Q
        from_cl_root = lambda h: self._Q._from_dict(h._monomial_coefficients)
        self._classical_roots = [from_cl_root(al)
                                 for al in self._Q.classical().roots()]
        self._classical_positive_roots = [from_cl_root(al)
                                          for al in self._Q.classical().positive_roots()]
        self._a = self._cartan_type.a() # This is not cached
        self._ac = self._cartan_type.dual().a() # This is not cached
        self._eps = {i: self._a[i] / self._ac[i] for i in self._index_set}
        self._coxeter_number = sum(self._a)
        self._dual_coxeter_number = sum(self._ac)
        E = Matrix.diagonal([self._eps[i] for i in self._index_set_classical])
        self._ip = (self._cartan_type.classical().cartan_matrix()*E).inverse()
예제 #57
0
    def get_cocycle_from_elliptic_curve(self,E,sign = 1,use_magma = True):
        if sign == 0:
            return self.get_cocycle_from_elliptic_curve(E,1,use_magma) + self.get_cocycle_from_elliptic_curve(E,-1,use_magma)
        if not sign in [1, -1]:
            raise NotImplementedError
        F = self.group().base_ring()
        if F.signature()[1] == 0 or (F.signature() == (0,1) and 'G' not in self.group()._grouptype):
            K = (self.hecke_matrix(oo).transpose()-sign).kernel().change_ring(QQ)
        else:
            K = Matrix(QQ,self.dimension(),self.dimension(),0).kernel()
        disc = self.S_arithgroup().Gpn._O_discriminant
        discnorm = disc.norm()
        try:
            N = ZZ(discnorm.gen())
        except AttributeError:
            N = ZZ(discnorm)

        if F == QQ:
            x = QQ['x'].gen()
            F = NumberField(x,names='a')
            E = E.change_ring(F)

        def getap(q):
            if F == QQ:
                return E.ap(q)
            else:
                Q = F.ideal(q).factor()[0][0]
                return ZZ(Q.norm() + 1 - E.reduction(Q).count_points())

        q = ZZ(1)
        g0 = None
        while K.dimension() > 1:
            q = q.next_prime()
            for qq,e in F.ideal(q).factor():
                if  ZZ(qq.norm()).is_prime() and not qq.divides(F.ideal(disc.gens_reduced()[0])):
                    try:
                        ap = getap(qq)
                    except (ValueError,ArithmeticError):
                        continue
                    try:
                        K1 = (self.hecke_matrix(qq.gens_reduced()[0],g0 = g0,use_magma = use_magma).transpose()-ap).kernel()
                    except RuntimeError:
                        continue
                    K = K.intersection(K1)
        if K.dimension() != 1:
            raise ValueError,'Did not obtain a one-dimensional space corresponding to E'
        col = [ZZ(o) for o in (K.denominator()*K.matrix()).list()]
        return sum([a * self.gen(i) for i,a in enumerate(col) if a != 0],self(0))
예제 #58
0
    def get_rational_cocycle_from_ap(self,getap,sign = 1,use_magma = True):
        F = self.group().base_ring()
        if F.signature()[1] == 0 or (F.signature() == (0,1) and 'G' not in self.group()._grouptype):
            K = (self.hecke_matrix(oo).transpose()-sign).kernel().change_ring(QQ)
        else:
            K = Matrix(QQ,self.dimension(),self.dimension(),0).kernel()

        disc = self.S_arithgroup().Gpn._O_discriminant
        discnorm = disc.norm()
        try:
            N = ZZ(discnorm.gen())
        except AttributeError:
            N = ZZ(discnorm)

        if F == QQ:
            x = QQ['x'].gen()
            F = NumberField(x,names='a')
        q = ZZ(1)
        g0 = None
        while K.dimension() > 1:
            q = q.next_prime()
            for qq,e in F.ideal(q).factor():
                if  ZZ(qq.norm()).is_prime() and not qq.divides(F.ideal(disc.gens_reduced()[0])):
                    try:
                        ap = getap(qq)
                    except (ValueError,ArithmeticError):
                        continue
                    try:
                        K1 = (self.hecke_matrix(qq.gens_reduced()[0],g0 = g0,use_magma = use_magma).transpose()-ap).kernel()
                    except RuntimeError:
                        continue
                    K = K.intersection(K1)
        if K.dimension() != 1:
            raise ValueError,'Group does not have the required system of eigenvalues'

        col = [ZZ(o) for o in (K.denominator()*K.matrix()).list()]
        return sum([ a * self.gen(i) for i,a in enumerate(col) if a != 0], self(0))
예제 #59
0
def Matroid(groundset=None, data=None, **kwds):
    r"""
    Construct a matroid.

    Matroids are combinatorial structures that capture the abstract properties
    of (linear/algebraic/...) dependence. Formally, a matroid is a pair
    `M = (E, I)` of a finite set `E`, the *groundset*, and a collection of
    subsets `I`, the independent sets, subject to the following axioms:

    * `I` contains the empty set
    * If `X` is a set in `I`, then each subset of `X` is in `I`
    * If two subsets `X`, `Y` are in `I`, and `|X| > |Y|`, then there exists
      `x \in X - Y` such that `Y + \{x\}` is in `I`.

    See the :wikipedia:`Wikipedia article on matroids <Matroid>` for more
    theory and examples. Matroids can be obtained from many types of
    mathematical structures, and Sage supports a number of them.

    There are two main entry points to Sage's matroid functionality. For
    built-in matroids, do the following:

    * Within a Sage session, type "matroids." (Do not press "Enter", and do
      not forget the final period ".")
    * Hit "tab".

    You will see a list of methods which will construct matroids. For
    example::

        sage: F7 = matroids.named_matroids.Fano()
        sage: len(F7.nonspanning_circuits())
        7

    or::

        sage: U36 = matroids.Uniform(3, 6)
        sage: U36.equals(U36.dual())
        True

    To define your own matroid, use the function ``Matroid()``.
    This function attempts to interpret its arguments to create an appropriate
    matroid. The following named arguments are supported:

    INPUT:

    - ``groundset`` -- (optional) If provided, the groundset of the
      matroid. Otherwise, the function attempts to determine a groundset
      from the data.

    Exactly one of the following inputs must be given (where ``data``
    must be a positional argument and anything else must be a keyword
    argument):

    - ``data`` -- a graph or a matrix or a RevLex-Index string or a list
      of independent sets containing all bases or a matroid.
    - ``bases`` -- The list of bases (maximal independent sets) of the
      matroid.
    - ``independent_sets`` -- The list of independent sets of the matroid.
    - ``circuits`` -- The list of circuits of the matroid.
    - ``graph`` -- A graph, whose edges form the elements of the matroid.
    - ``matrix`` -- A matrix representation of the matroid.
    - ``reduced_matrix`` -- A reduced representation of the matroid: if
      ``reduced_matrix = A``
      then the matroid is represented by `[I\ \ A]` where `I` is an
      appropriately sized identity matrix.
    - ``rank_function`` -- A function that computes the rank of each subset.
      Can only be provided together with a groundset.
    - ``circuit_closures`` -- Either a list of tuples ``(k, C)`` with ``C``
      the closure of a circuit, and ``k`` the rank of ``C``, or a dictionary
      ``D`` with ``D[k]`` the set of closures of rank-``k`` circuits.
    - ``revlex`` -- the encoding as a string of ``0`` and ``*`` symbols.
      Used by [MatroidDatabase]_ and explained in [MMIB2012]_.
    - ``matroid`` -- An object that is already a matroid. Useful only with the
      ``regular`` option.

    Further options:

    - ``regular`` -- (default: ``False``) boolean. If ``True``,
      output a
      :class:`RegularMatroid <sage.matroids.linear_matroid.RegularMatroid>`
      instance such that, *if* the input defines a valid regular matroid, then
      the output represents this matroid. Note that this option can be
      combined with any type of input.
    - ``ring`` -- any ring. If provided, and the input is a ``matrix`` or
      ``reduced_matrix``, output will be a linear matroid over the ring or
      field ``ring``.
    - ``field`` -- any field. Same as ``ring``, but only fields are allowed.
    - ``check`` -- (default: ``True``) boolean. If ``True`` and
      ``regular`` is true, the output is checked to make sure it is a valid
      regular matroid.

    .. WARNING::

        Except for regular matroids, the input is not checked for validity. If
        your data does not correspond to an actual matroid, the behavior of
        the methods is undefined and may cause strange errors. To ensure you
        have a matroid, run
        :meth:`M.is_valid() <sage.matroids.matroid.Matroid.is_valid>`.

    .. NOTE::

        The ``Matroid()`` method will return instances of type
        :class:`BasisMatroid <sage.matroids.basis_matroid.BasisMatroid>`,
        :class:`CircuitClosuresMatroid <sage.matroids.circuit_closures_matroid.CircuitClosuresMatroid>`,
        :class:`LinearMatroid <sage.matroids.linear_matroid.LinearMatroid>`,
        :class:`BinaryMatroid <sage.matroids.linear_matroid.LinearMatroid>`,
        :class:`TernaryMatroid <sage.matroids.linear_matroid.LinearMatroid>`,
        :class:`QuaternaryMatroid <sage.matroids.linear_matroid.LinearMatroid>`,
        :class:`RegularMatroid <sage.matroids.linear_matroid.LinearMatroid>`, or
        :class:`RankMatroid <sage.matroids.rank_matroid.RankMatroid>`. To
        import these classes (and other useful functions) directly into Sage's
        main namespace, type::

            sage: from sage.matroids.advanced import *

        See :mod:`sage.matroids.advanced <sage.matroids.advanced>`.

    EXAMPLES:

    Note that in these examples we will often use the fact that strings are
    iterable in these examples. So we type ``'abcd'`` to denote the list
    ``['a', 'b', 'c', 'd']``.

    #.  List of bases:

        All of the following inputs are allowed, and equivalent::

            sage: M1 = Matroid(groundset='abcd', bases=['ab', 'ac', 'ad',
            ....:                                       'bc', 'bd', 'cd'])
            sage: M2 = Matroid(bases=['ab', 'ac', 'ad', 'bc', 'bd', 'cd'])
            sage: M3 = Matroid(['ab', 'ac', 'ad', 'bc', 'bd', 'cd'])
            sage: M4 = Matroid('abcd', ['ab', 'ac', 'ad', 'bc', 'bd', 'cd'])
            sage: M5 = Matroid('abcd', bases=[['a', 'b'], ['a', 'c'],
            ....:                             ['a', 'd'], ['b', 'c'],
            ....:                             ['b', 'd'], ['c', 'd']])
            sage: M1 == M2
            True
            sage: M1 == M3
            True
            sage: M1 == M4
            True
            sage: M1 == M5
            True

        We do not check if the provided input forms an actual matroid::

            sage: M1 = Matroid(groundset='abcd', bases=['ab', 'cd'])
            sage: M1.full_rank()
            2
            sage: M1.is_valid()
            False

        Bases may be repeated::

            sage: M1 = Matroid(['ab', 'ac'])
            sage: M2 = Matroid(['ab', 'ac', 'ab'])
            sage: M1 == M2
            True

    #.  List of independent sets:

        ::

            sage: M1 = Matroid(groundset='abcd',
            ....:              independent_sets=['', 'a', 'b', 'c', 'd', 'ab',
            ....:                               'ac', 'ad', 'bc', 'bd', 'cd'])

        We only require that the list of independent sets contains each basis
        of the matroid; omissions of smaller independent sets and
        repetitions are allowed::

            sage: M1 = Matroid(bases=['ab', 'ac'])
            sage: M2 = Matroid(independent_sets=['a', 'ab', 'b', 'ab', 'a',
            ....:                                'b', 'ac'])
            sage: M1 == M2
            True

    #.  List of circuits:

        ::

            sage: M1 = Matroid(groundset='abc', circuits=['bc'])
            sage: M2 = Matroid(bases=['ab', 'ac'])
            sage: M1 == M2
            True

        A matroid specified by a list of circuits gets converted to a
        :class:`BasisMatroid <sage.matroids.basis_matroid.BasisMatroid>`
        internally::

            sage: M = Matroid(groundset='abcd', circuits=['abc', 'abd', 'acd',
            ....:                                         'bcd'])
            sage: type(M)
            <... 'sage.matroids.basis_matroid.BasisMatroid'>

        Strange things can happen if the input does not satisfy the circuit
        axioms, and these are not always caught by the
        :meth:`is_valid() <sage.matroids.matroid.Matroid.is_valid>` method. So
        always check whether your input makes sense!

        ::

            sage: M = Matroid('abcd', circuits=['ab', 'acd'])
            sage: M.is_valid()
            True
            sage: [sorted(C) for C in M.circuits()]
            [['a']]



    #.  Graph:

        Sage has great support for graphs, see :mod:`sage.graphs.graph`.

        ::

            sage: G = graphs.PetersenGraph()
            sage: Matroid(G)
            Graphic matroid of rank 9 on 15 elements

        If each edge has a unique label, then those are used as the ground set
        labels::

            sage: G = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'c')])
            sage: M = Matroid(G)
            sage: sorted(M.groundset())
            ['a', 'b', 'c']

        If there are parallel edges, then integers are used for the ground set.
        If there are no edges in parallel, and is not a complete list of labels,
        or the labels are not unique, then vertex tuples are used::

            sage: G = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'b')])
            sage: M = Matroid(G)
            sage: sorted(M.groundset())
            [(0, 1), (0, 2), (1, 2)]
            sage: H = Graph([(0, 1, 'a'), (0, 2, 'b'), (1, 2, 'b'), (1, 2, 'c')], multiedges=True)
            sage: N = Matroid(H)
            sage: sorted(N.groundset())
            [0, 1, 2, 3]

        The GraphicMatroid object forces its graph to be connected. If a
        disconnected graph is used as input, it will connect the components.

            sage: G1 = graphs.CycleGraph(3); G2 = graphs.DiamondGraph()
            sage: G = G1.disjoint_union(G2)
            sage: M = Matroid(G)
            sage: M
            Graphic matroid of rank 5 on 8 elements
            sage: M.graph()
            Looped multi-graph on 6 vertices
            sage: M.graph().is_connected()
            True
            sage: M.is_connected()
            False


        If the keyword ``regular`` is set to ``True``, the output will instead
        be an instance of ``RegularMatroid``.

        ::

            sage: G = Graph([(0, 1), (0, 2), (1, 2)])
            sage: M = Matroid(G, regular=True); M
            Regular matroid of rank 2 on 3 elements with 3 bases

        Note: if a groundset is specified, we assume it is in the same order
        as
        :meth:`G.edge_iterator() <sage.graphs.generic_graph.GenericGraph.edge_iterator>`
        provides::

            sage: G = Graph([(0, 1), (0, 2), (0, 2), (1, 2)], multiedges=True)
            sage: M = Matroid('abcd', G)
            sage: M.rank(['b', 'c'])
            1

        As before,
        if no edge labels are present and the graph is simple, we use the
        tuples ``(i, j)`` of endpoints. If that fails, we simply use a list
        ``[0..m-1]`` ::

            sage: G = Graph([(0, 1), (0, 2), (1, 2)])
            sage: M = Matroid(G, regular=True)
            sage: sorted(M.groundset())
            [(0, 1), (0, 2), (1, 2)]

            sage: G = Graph([(0, 1), (0, 2), (0, 2), (1, 2)], multiedges=True)
            sage: M = Matroid(G, regular=True)
            sage: sorted(M.groundset())
            [0, 1, 2, 3]

        When the ``graph`` keyword is used, a variety of inputs can be
        converted to a graph automatically. The following uses a graph6 string
        (see the :class:`Graph <sage.graphs.graph.Graph>` method's
        documentation)::

            sage: Matroid(graph=':I`AKGsaOs`cI]Gb~')
            Graphic matroid of rank 9 on 17 elements

        However, this method is no more clever than ``Graph()``::

            sage: Matroid(graph=41/2)
            Traceback (most recent call last):
            ...
            ValueError: This input cannot be turned into a graph

    #.  Matrix:

        The basic input is a
        :mod:`Sage matrix <sage.matrix.constructor>`::

            sage: A = Matrix(GF(2), [[1, 0, 0, 1, 1, 0],
            ....:                    [0, 1, 0, 1, 0, 1],
            ....:                    [0, 0, 1, 0, 1, 1]])
            sage: M = Matroid(matrix=A)
            sage: M.is_isomorphic(matroids.CompleteGraphic(4))
            True

        Various shortcuts are possible::

            sage: M1 = Matroid(matrix=[[1, 0, 0, 1, 1, 0],
            ....:                      [0, 1, 0, 1, 0, 1],
            ....:                      [0, 0, 1, 0, 1, 1]], ring=GF(2))
            sage: M2 = Matroid(reduced_matrix=[[1, 1, 0],
            ....:                              [1, 0, 1],
            ....:                              [0, 1, 1]], ring=GF(2))
            sage: M3 = Matroid(groundset=[0, 1, 2, 3, 4, 5],
            ....:              matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:              ring=GF(2))
            sage: A = Matrix(GF(2), [[1, 1, 0], [1, 0, 1], [0, 1, 1]])
            sage: M4 = Matroid([0, 1, 2, 3, 4, 5], A)
            sage: M1 == M2
            True
            sage: M1 == M3
            True
            sage: M1 == M4
            True

        However, with unnamed arguments the input has to be a ``Matrix``
        instance, or the function will try to interpret it as a set of bases::

            sage: Matroid([0, 1, 2], [[1, 0, 1], [0, 1, 1]])
            Traceback (most recent call last):
            ...
            ValueError: basis has wrong cardinality.

        If the groundset size equals number of rows plus number of columns, an
        identity matrix is prepended. Otherwise the groundset size must equal
        the number of columns::

            sage: A = Matrix(GF(2), [[1, 1, 0], [1, 0, 1], [0, 1, 1]])
            sage: M = Matroid([0, 1, 2], A)
            sage: N = Matroid([0, 1, 2, 3, 4, 5], A)
            sage: M.rank()
            2
            sage: N.rank()
            3

        We automatically create an optimized subclass, if available::

            sage: Matroid([0, 1, 2, 3, 4, 5],
            ....:         matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:         field=GF(2))
            Binary matroid of rank 3 on 6 elements, type (2, 7)
            sage: Matroid([0, 1, 2, 3, 4, 5],
            ....:         matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:         field=GF(3))
            Ternary matroid of rank 3 on 6 elements, type 0-
            sage: Matroid([0, 1, 2, 3, 4, 5],
            ....:         matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:         field=GF(4, 'x'))
            Quaternary matroid of rank 3 on 6 elements
            sage: Matroid([0, 1, 2, 3, 4, 5],
            ....:         matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:         field=GF(2), regular=True)
            Regular matroid of rank 3 on 6 elements with 16 bases

        Otherwise the generic LinearMatroid class is used::

            sage: Matroid([0, 1, 2, 3, 4, 5],
            ....:         matrix=[[1, 1, 0], [1, 0, 1], [0, 1, 1]],
            ....:         field=GF(83))
            Linear matroid of rank 3 on 6 elements represented over the Finite
            Field of size 83

        An integer matrix is automatically converted to a matrix over `\QQ`.
        If you really want integers, you can specify the ring explicitly::

            sage: A = Matrix([[1, 1, 0], [1, 0, 1], [0, 1, -1]])
            sage: A.base_ring()
            Integer Ring
            sage: M = Matroid([0, 1, 2, 3, 4, 5], A)
            sage: M.base_ring()
            Rational Field
            sage: M = Matroid([0, 1, 2, 3, 4, 5], A, ring=ZZ)
            sage: M.base_ring()
            Integer Ring

    #.  Rank function:

        Any function mapping subsets to integers can be used as input::

            sage: def f(X):
            ....:     return min(len(X), 2)
            sage: M = Matroid('abcd', rank_function=f)
            sage: M
            Matroid of rank 2 on 4 elements
            sage: M.is_isomorphic(matroids.Uniform(2, 4))
            True

    #.  Circuit closures:

        This is often a really concise way to specify a matroid. The usual way
        is a dictionary of lists::

            sage: M = Matroid(circuit_closures={3: ['edfg', 'acdg', 'bcfg',
            ....:     'cefh', 'afgh', 'abce', 'abdf', 'begh', 'bcdh', 'adeh'],
            ....:     4: ['abcdefgh']})
            sage: M.equals(matroids.named_matroids.P8())
            True

        You can also input tuples `(k, X)` where `X` is the closure of a
        circuit, and `k` the rank of `X`::

            sage: M = Matroid(circuit_closures=[(2, 'abd'), (3, 'abcdef'),
            ....:                               (2, 'bce')])
            sage: M.equals(matroids.named_matroids.Q6())
            True

    #.  RevLex-Index:

        This requires the ``groundset`` to be given and also needs a
        additional keyword argument ``rank`` to specify the rank of the
        matroid::

            sage: M = Matroid("abcdef", "000000******0**", rank=4); M
            Matroid of rank 4 on 6 elements with 8 bases
            sage: list(M.bases())
            [frozenset({'a', 'b', 'd', 'f'}),
             frozenset({'a', 'c', 'd', 'f'}),
             frozenset({'b', 'c', 'd', 'f'}),
             frozenset({'a', 'b', 'e', 'f'}),
             frozenset({'a', 'c', 'e', 'f'}),
             frozenset({'b', 'c', 'e', 'f'}),
             frozenset({'b', 'd', 'e', 'f'}),
             frozenset({'c', 'd', 'e', 'f'})]

        Only the ``0`` symbols really matter, any symbol can be used
        instead of ``*``:

            sage: Matroid("abcdefg", revlex="0++++++++0++++0+++++0+--++----+--++", rank=4)
            Matroid of rank 4 on 7 elements with 31 bases

        It is checked that the input makes sense (but not that it
        defines a matroid)::

            sage: Matroid("abcdef", "000000******0**")
            Traceback (most recent call last):
            ...
            TypeError: for RevLex-Index, the rank needs to be specified
            sage: Matroid("abcdef", "000000******0**", rank=3)
            Traceback (most recent call last):
            ...
            ValueError: expected string of length 20 (6 choose 3), got 15
            sage: M = Matroid("abcdef", "*0000000000000*", rank=4); M
            Matroid of rank 4 on 6 elements with 2 bases
            sage: M.is_valid()
            False

    #.  Matroid:

        Most of the time, the matroid itself is returned::

            sage: M = matroids.named_matroids.Fano()
            sage: N = Matroid(M)
            sage: N is M
            True

        But it can be useful with the ``regular`` option::

            sage: M = Matroid(circuit_closures={2:['adb', 'bec', 'cfa',
            ....:                                  'def'], 3:['abcdef']})
            sage: N = Matroid(M, regular=True)
            sage: N
            Regular matroid of rank 3 on 6 elements with 16 bases
            sage: Matrix(N)
            [1 0 0 1 1 0]
            [0 1 0 1 1 1]
            [0 0 1 0 1 1]

    The ``regular`` option::

        sage: M = Matroid(reduced_matrix=[[1, 1, 0],
        ....:                             [1, 0, 1],
        ....:                             [0, 1, 1]], regular=True)
        sage: M
        Regular matroid of rank 3 on 6 elements with 16 bases

        sage: M.is_isomorphic(matroids.CompleteGraphic(4))
        True

    By default we check if the resulting matroid is actually regular. To
    increase speed, this check can be skipped::

        sage: M = matroids.named_matroids.Fano()
        sage: N = Matroid(M, regular=True)
        Traceback (most recent call last):
        ...
        ValueError: input is not a valid regular matroid
        sage: N = Matroid(M, regular=True, check=False)
        sage: N
        Regular matroid of rank 3 on 7 elements with 32 bases

        sage: N.is_valid()
        False

    Sometimes the output is regular, but represents a different matroid
    from the one you intended::

        sage: M = Matroid(Matrix(GF(3), [[1, 0, 1, 1], [0, 1, 1, 2]]))
        sage: N = Matroid(Matrix(GF(3), [[1, 0, 1, 1], [0, 1, 1, 2]]),
        ....:             regular=True)
        sage: N.is_valid()
        True
        sage: N.is_isomorphic(M)
        False

    TESTS::

        sage: Matroid()
        Traceback (most recent call last):
        ...
        TypeError: no input data given for Matroid()
        sage: Matroid("abc", bases=["abc"], foo="bar")
        Traceback (most recent call last):
        ...
        TypeError: Matroid() got an unexpected keyword argument 'foo'
        sage: Matroid(data=["x"], matrix=Matrix(1,1))
        Traceback (most recent call last):
        ...
        TypeError: Matroid() got an unexpected keyword argument 'matrix'
        sage: Matroid(bases=["x"], matrix=Matrix(1,1))
        Traceback (most recent call last):
        ...
        TypeError: Matroid() got an unexpected keyword argument 'matrix'
        sage: Matroid(Matrix(1,1), ring=ZZ, field=QQ)
        Traceback (most recent call last):
        ...
        TypeError: Matroid() got an unexpected keyword argument 'ring'
        sage: Matroid(rank_function=lambda X: len(X))
        Traceback (most recent call last):
        ...
        TypeError: for rank functions, the groundset needs to be specified
        sage: Matroid(matroid="rubbish")
        Traceback (most recent call last):
        ...
        TypeError: input 'rubbish' is not a matroid
    """
    # process options
    want_regular = kwds.pop('regular', False)
    check = kwds.pop('check', True)

    base_ring = None
    if 'field' in kwds:
        base_ring = kwds.pop('field')
        if check and not base_ring.is_field():
            raise TypeError("{} is not a field".format(base_ring))
    elif 'ring' in kwds:
        base_ring = kwds.pop('ring')
        if check and not base_ring.is_ring():
            raise TypeError("{} is not a ring".format(base_ring))

    # "key" is the kind of data we got
    key = None
    if data is None:
        for k in ['bases', 'independent_sets', 'circuits', 'graph',
                'matrix', 'reduced_matrix', 'rank_function', 'revlex',
                'circuit_closures', 'matroid']:
            if k in kwds:
                data = kwds.pop(k)
                key = k
                break
        else:
            # Assume that the single positional argument was actually
            # the data (instead of the groundset)
            data = groundset
            groundset = None

    if key is None:
        if isinstance(data, sage.graphs.graph.Graph):
            key = 'graph'
        elif is_Matrix(data):
            key = 'matrix'
        elif isinstance(data, sage.matroids.matroid.Matroid):
            key = 'matroid'
        elif isinstance(data, str):
            key = 'revlex'
        elif data is None:
            raise TypeError("no input data given for Matroid()")
        else:
            key = 'independent_sets'

    # Bases:
    if key == 'bases':
        if groundset is None:
            groundset = set()
            for B in data:
                groundset.update(B)
        M = BasisMatroid(groundset=groundset, bases=data)

    # Independent sets:
    elif key == 'independent_sets':
        # Convert to list of bases first
        rk = -1
        bases = []
        for I in data:
            if len(I) == rk:
                bases.append(I)
            elif len(I) > rk:
                bases = [I]
                rk = len(I)
        if groundset is None:
            groundset = set()
            for B in bases:
                groundset.update(B)
        M = BasisMatroid(groundset=groundset, bases=bases)

    # Circuits:
    elif key == 'circuits':
        # Convert to list of bases first
        # Determine groundset (note that this cannot detect coloops)
        if groundset is None:
            groundset = set()
            for C in data:
                groundset.update(C)
        # determine the rank by computing a basis element
        b = set(groundset)
        for C in data:
            I = b.intersection(C)
            if len(I) >= len(C):
                b.discard(I.pop())
        rk = len(b)
        # Construct the basis matroid of appropriate rank. Note: slow!
        BB = [frozenset(B) for B in combinations(groundset, rk) if not any([frozenset(C).issubset(B) for C in data])]
        M = BasisMatroid(groundset=groundset, bases=BB)

    # Graphs:

    elif key == 'graph':
        if isinstance(data, sage.graphs.generic_graph.GenericGraph):
            G = data
        else:
            G = Graph(data)
        # Decide on the groundset
        m = G.num_edges()
        if groundset is None:
            # 1. Attempt to use edge labels.
            sl = G.edge_labels()
            if len(sl) == len(set(sl)):
                groundset = sl
                # 2. If simple, use vertex tuples
            elif not G.has_multiple_edges():
                groundset = [(i, j) for i, j, k in G.edge_iterator()]
            else:
                # 3. Use numbers
                groundset = list(range(m))
        if want_regular:
        # Construct the incidence matrix
        # NOTE: we are not using Sage's built-in method because
        # 1) we would need to fix the loops anyway
        # 2) Sage will sort the columns, making it impossible to keep labels!
            V = G.vertices()
            n = G.num_verts()
            A = Matrix(ZZ, n, m, 0)
            mm = 0
            for i, j, k in G.edge_iterator():
                A[V.index(i), mm] = -1
                A[V.index(j), mm] += 1  # So loops get 0
                mm += 1
            M = RegularMatroid(matrix=A, groundset=groundset)
            want_regular = False  # Save some time, since result is already regular
        else:
            M = GraphicMatroid(G, groundset=groundset)

    # Matrices:
    elif key in ['matrix', 'reduced_matrix']:
        A = data
        is_reduced = (key == 'reduced_matrix')

        # Fix the representation
        if not is_Matrix(A):
            if base_ring is not None:
                A = Matrix(base_ring, A)
            else:
                A = Matrix(A)

        # Fix the ring
        if base_ring is not None:
            if A.base_ring() is not base_ring:
                A = A.change_ring(base_ring)
        elif A.base_ring() is ZZ and not want_regular:  # Usually a rational matrix is intended, we presume.
            A = A.change_ring(QQ)
            base_ring = QQ
        else:
            base_ring = A.base_ring()

        # Check groundset
        if groundset is not None:
            if not is_reduced:
                if len(groundset) == A.ncols():
                    pass
                elif len(groundset) == A.nrows() + A.ncols():
                    is_reduced = True
                else:
                    raise ValueError("groundset size does not correspond to matrix size")
            elif is_reduced:
                if len(groundset) == A.nrows() + A.ncols():
                    pass
                else:
                    raise ValueError("groundset size does not correspond to matrix size")

        if is_reduced:
            kw = dict(groundset=groundset, reduced_matrix=A)
        else:
            kw = dict(groundset=groundset, matrix=A)

        if isinstance(base_ring, FiniteField):
            q = base_ring.order()
        else:
            q = 0

        if q == 2:
            M = BinaryMatroid(**kw)
        elif q == 3:
            M = TernaryMatroid(**kw)
        elif q == 4:
            M = QuaternaryMatroid(**kw)
        else:
            M = LinearMatroid(ring=base_ring, **kw)

    # Rank functions:
    elif key == 'rank_function':
        if groundset is None:
            raise TypeError('for rank functions, the groundset needs to be specified')
        M = RankMatroid(groundset=groundset, rank_function=data)

    # RevLex-Index:
    elif key == "revlex":
        if groundset is None:
            raise TypeError('for RevLex-Index, the groundset needs to be specified')
        try:
            rk = kwds.pop("rank")
        except KeyError:
            raise TypeError('for RevLex-Index, the rank needs to be specified')

        groundset = tuple(groundset)
        data = tuple(data)
        rk = int(rk)
        N = len(groundset)

        def revlex_sort_key(s):
            return tuple(reversed(s))
        subsets = sorted(combinations(range(N), rk), key=revlex_sort_key)
        if len(data) != len(subsets):
            raise ValueError("expected string of length %s (%s choose %s), got %s" %
                (len(subsets), N, rk, len(data)))
        bases = []
        for i, x in enumerate(data):
            if x != '0':
                bases.append([groundset[c] for c in subsets[i]])
        M = BasisMatroid(groundset=groundset, bases=bases)

    # Circuit closures:
    elif key == 'circuit_closures':
        if isinstance(data, dict):
            CC = data
        else:
            # Convert to dictionary
            CC = {}
            for X in data:
                if X[0] not in CC:
                    CC[X[0]] = []
                CC[X[0]].append(X[1])

        if groundset is None:
            groundset = set()
            for X in itervalues(CC):
                for Y in X:
                    groundset.update(Y)

        M = CircuitClosuresMatroid(groundset=groundset, circuit_closures=CC)

    # Matroids:
    elif key == 'matroid':
        if not isinstance(data, sage.matroids.matroid.Matroid):
            raise TypeError("input {!r} is not a matroid".format(data))
        M = data

    else:
        raise AssertionError("unknown key %r" % key)

    # All keywords should be used
    for k in kwds:
        raise TypeError("Matroid() got an unexpected keyword argument '{}'".format(k))

    if want_regular:
        M = sage.matroids.utilities.make_regular_matroid_from_matroid(M)
        if check and not M.is_valid():
            raise ValueError('input is not a valid regular matroid')

    return M