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
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
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
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]
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()
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)
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
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()
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"
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
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 ]])
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)
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
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
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)
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)
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")
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
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)
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
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
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
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
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
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})
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
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)
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())
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)
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
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
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())
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
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
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
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")
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)
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")
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
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)]
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
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)
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
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)
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()
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))
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))
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