def DuadicCodeOddPair(F, S1, S2): """ Constructs the "odd pair" of duadic codes associated to the "splitting" S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import _is_a_splitting sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: _is_a_splitting(S1,S2,11) True sage: codes.DuadicCodeOddPair(GF(q),S1,S2) ([11, 6] Cyclic Code over GF(3), [11, 6] Cyclic Code over GF(3)) This is consistent with Theorem 6.1.3 in [HP2003]_. """ from sage.misc.stopgap import stopgap stopgap( "The function DuadicCodeOddPair has several issues which may cause wrong results", 25896) from .cyclic_code import CyclicCode n = len(S1) + len(S2) + 1 if not _is_a_splitting(S1, S2, n): raise TypeError("%s, %s must be a splitting of %s." % (S1, S2, n)) q = F.order() k = Mod(q, n).multiplicative_order() FF = GF(q**k, "z") z = FF.gen() zeta = z**((q**k - 1) / n) P1 = PolynomialRing(FF, "x") x = P1.gen() g1 = prod([x - zeta**i for i in S1 + [0]]) g2 = prod([x - zeta**i for i in S2 + [0]]) j = sum([x**i / n for i in range(n)]) P2 = PolynomialRing(F, "x") x = P2.gen() coeffs1 = [ _lift2smallest_field(c)[0] for c in (g1 + j).coefficients(sparse=False) ] coeffs2 = [ _lift2smallest_field(c)[0] for c in (g2 + j).coefficients(sparse=False) ] gg1 = P2(coeffs1) gg2 = P2(coeffs2) gg1 = gcd(gg1, x**n - 1) gg2 = gcd(gg2, x**n - 1) C1 = CyclicCode(length=n, generator_pol=gg1) C2 = CyclicCode(length=n, generator_pol=gg2) return C1, C2
def DuadicCodeOddPair(F, S1, S2): """ Constructs the "odd pair" of duadic codes associated to the "splitting" S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import is_a_splitting sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: is_a_splitting(S1,S2,11) True sage: codes.DuadicCodeOddPair(GF(q),S1,S2) (Linear code of length 11, dimension 6 over Finite Field of size 3, Linear code of length 11, dimension 6 over Finite Field of size 3) This is consistent with Theorem 6.1.3 in [HP]_. """ n = len(S1) + len(S2) + 1 if not is_a_splitting(S1, S2, n): raise TypeError("%s, %s must be a splitting of %s." % (S1, S2, n)) q = F.order() k = Mod(q, n).multiplicative_order() FF = GF(q**k, "z") z = FF.gen() zeta = z**((q**k - 1) / n) P1 = PolynomialRing(FF, "x") x = P1.gen() g1 = prod([x - zeta**i for i in S1 + [0]]) g2 = prod([x - zeta**i for i in S2 + [0]]) j = sum([x**i / n for i in range(n)]) P2 = PolynomialRing(F, "x") x = P2.gen() coeffs1 = [ lift2smallest_field(c)[0] for c in (g1 + j).coefficients(sparse=False) ] coeffs2 = [ lift2smallest_field(c)[0] for c in (g2 + j).coefficients(sparse=False) ] gg1 = P2(coeffs1) gg2 = P2(coeffs2) C1 = CyclicCodeFromGeneratingPolynomial(n, gg1) C2 = CyclicCodeFromGeneratingPolynomial(n, gg2) return C1, C2
def DuadicCodeEvenPair(F, S1, S2): r""" Constructs the "even pair" of duadic codes associated to the "splitting" (see the docstring for ``_is_a_splitting`` for the definition) S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import _is_a_splitting sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: _is_a_splitting(S1,S2,11) True sage: codes.DuadicCodeEvenPair(GF(q),S1,S2) ([11, 5] Cyclic Code over GF(3), [11, 5] Cyclic Code over GF(3)) """ from sage.misc.stopgap import stopgap stopgap( "The function DuadicCodeEvenPair has several issues which may cause wrong results", 25896) from .cyclic_code import CyclicCode n = len(S1) + len(S2) + 1 if not _is_a_splitting(S1, S2, n): raise TypeError("%s, %s must be a splitting of %s." % (S1, S2, n)) q = F.order() k = Mod(q, n).multiplicative_order() FF = GF(q**k, "z") z = FF.gen() zeta = z**((q**k - 1) / n) P1 = PolynomialRing(FF, "x") x = P1.gen() g1 = prod([x - zeta**i for i in S1 + [0]]) g2 = prod([x - zeta**i for i in S2 + [0]]) P2 = PolynomialRing(F, "x") x = P2.gen() gg1 = P2( [_lift2smallest_field(c)[0] for c in g1.coefficients(sparse=False)]) gg2 = P2( [_lift2smallest_field(c)[0] for c in g2.coefficients(sparse=False)]) C1 = CyclicCode(length=n, generator_pol=gg1) C2 = CyclicCode(length=n, generator_pol=gg2) return C1, C2
def mutate_initial(self, k): r""" Mutate ``self`` in direction `k` at the initial cluster. INPUT: - ``k`` -- integer in between 0 and ``self.rk`` """ n = self.rk if k not in xrange(n): raise ValueError('Cannot mutate in direction %s, please try a value between 0 and %s.'%(str(k),str(n-1))) #modify self._path_dict using Nakanishi-Zelevinsky (4.1) and self._F_poly_dict using CA-IV (6.21) new_path_dict = dict() new_F_dict = dict() new_path_dict[tuple(identity_matrix(n).column(k))] = [] new_F_dict[tuple(identity_matrix(n).column(k))] = self._U(1) poly_ring = PolynomialRing(ZZ,'u') h_subs_tuple = tuple([poly_ring.gen(0)**(-1) if j==k else poly_ring.gen(0)**max(-self._B0[k][j],0) for j in xrange(n)]) F_subs_tuple = tuple([self._U.gen(k)**(-1) if j==k else self._U.gen(j)*self._U.gen(k)**max(-self._B0[k][j],0)*(1+self._U.gen(k))**(self._B0[k][j]) for j in xrange(n)]) for g_vect in self._path_dict: #compute new path path = self._path_dict[g_vect] if g_vect == tuple(identity_matrix(n).column(k)): new_path = [k] elif path != []: if path[0] != k: new_path = [k] + path else: new_path = path[1:] else: new_path = [] #compute new g-vector new_g_vect = vector(g_vect) - 2*g_vect[k]*identity_matrix(n).column(k) for i in xrange(n): new_g_vect += max(sign(g_vect[k])*self._B0[i,k],0)*g_vect[k]*identity_matrix(n).column(i) new_path_dict[tuple(new_g_vect)] = new_path #compute new F-polynomial h = 0 trop = tropical_evaluation(self._F_poly_dict[g_vect](h_subs_tuple)) if trop != 1: h = trop.denominator().exponents()[0]-trop.numerator().exponents()[0] new_F_dict[tuple(new_g_vect)] = self._F_poly_dict[g_vect](F_subs_tuple)*self._U.gen(k)**h*(self._U.gen(k)+1)**g_vect[k] self._path_dict = new_path_dict self._F_poly_dict = new_F_dict self._B0.mutate(k)
def DuadicCodeOddPair(F,S1,S2): """ Constructs the "odd pair" of duadic codes associated to the "splitting" S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import _is_a_splitting sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: _is_a_splitting(S1,S2,11) True sage: codes.DuadicCodeOddPair(GF(q),S1,S2) ([11, 6] Cyclic Code over GF(3), [11, 6] Cyclic Code over GF(3)) This is consistent with Theorem 6.1.3 in [HP2003]_. """ from .cyclic_code import CyclicCode n = len(S1) + len(S2) + 1 if not _is_a_splitting(S1,S2,n): raise TypeError("%s, %s must be a splitting of %s."%(S1,S2,n)) q = F.order() k = Mod(q,n).multiplicative_order() FF = GF(q**k,"z") z = FF.gen() zeta = z**((q**k-1)/n) P1 = PolynomialRing(FF,"x") x = P1.gen() g1 = prod([x-zeta**i for i in S1+[0]]) g2 = prod([x-zeta**i for i in S2+[0]]) j = sum([x**i/n for i in range(n)]) P2 = PolynomialRing(F,"x") x = P2.gen() coeffs1 = [_lift2smallest_field(c)[0] for c in (g1+j).coefficients(sparse=False)] coeffs2 = [_lift2smallest_field(c)[0] for c in (g2+j).coefficients(sparse=False)] gg1 = P2(coeffs1) gg2 = P2(coeffs2) gg1 = gcd(gg1, x**n - 1) gg2 = gcd(gg2, x**n - 1) C1 = CyclicCode(length = n, generator_pol = gg1) C2 = CyclicCode(length = n, generator_pol = gg2) return C1,C2
def DuadicCodeOddPair(F,S1,S2): """ Constructs the "odd pair" of duadic codes associated to the "splitting" S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import is_a_splitting sage: n = 11; q = 3 sage: C = cyclotomic_cosets(q,n); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: is_a_splitting(S1,S2,11) (True, 2) sage: DuadicCodeOddPair(GF(q),S1,S2) (Linear code of length 11, dimension 6 over Finite Field of size 3, Linear code of length 11, dimension 6 over Finite Field of size 3) This is consistent with Theorem 6.1.3 in [HP]_. """ n = max(S1+S2)+1 if not(is_a_splitting(S1,S2,n)): raise TypeError, "%s, %s must be a splitting of %s."%(S1,S2,n) q = F.order() k = Mod(q,n).multiplicative_order() FF = GF(q**k,"z") z = FF.gen() zeta = z**((q**k-1)/n) P1 = PolynomialRing(FF,"x") x = P1.gen() g1 = prod([x-zeta**i for i in S1+[0]]) g2 = prod([x-zeta**i for i in S2+[0]]) j = sum([x**i/n for i in range(n)]) P2 = PolynomialRing(F,"x") x = P2.gen() coeffs1 = [lift2smallest_field(c)[0] for c in (g1+j).coeffs()] coeffs2 = [lift2smallest_field(c)[0] for c in (g2+j).coeffs()] gg1 = P2(coeffs1) gg2 = P2(coeffs2) C1 = CyclicCodeFromGeneratingPolynomial(n,gg1) C2 = CyclicCodeFromGeneratingPolynomial(n,gg2) return C1,C2
def conv(N): file = "data/%s" % N if not os.path.exists(file): raise RuntimeError, "Data for level %s does not exist." % N F = open(file).read() i = F.find(":=") if i == -1: raise RuntimeError, "Syntax error in file for level %s." % N F = F[i + 2:] TRANS = [("[*", "["), ("*]", "]"), ("<","["), (">","]"), \ (";",""), ("\n",""), ("^","**")] for z, w in TRANS: F = F.replace(z, w) X = [] # Define x so the eval below works. R = PolynomialRing(RationalField()) x = R.gen() print "starting eval." #print "F = ", F for f in eval(F): print "creating object from f=", f[:4] cp = {} disc = 0 for z in f[5]: g = R(z[1]) disc = GCD(disc, g.discriminant()) cp[z[0]] = g X.append(ModularForm(f[0], f[1], f[2], f[3], f[4], cp, disc)) return X
def dependence_polynomial(self, t=None): r""" Return dependence polynomial. The polynomial is defined as follows: `\sum{i}{(-1)^i c_i t^i}`, where `c_i` equals to number of full subgraphs of size `i` in the independence graph. OUTPUT: A rational function in ``t`` with coefficients in the integer ring. EXAMPLES:: sage: from sage.monoids.trace_monoid import TraceMonoid sage: I = (('a','d'), ('d','a'), ('b','c'), ('c','b')) sage: M.<a,b,c,d> = TraceMonoid(I=I) sage: M.dependence_polynomial() 1/(2*t^2 - 4*t + 1) """ if t is None: R = PolynomialRing(ZZ, 't') t = R.gen() clique_seq = self.independence_graph().clique_polynomial( ).coefficients() return ~sum( (-1)**i * coeff * (t**i) for i, coeff in enumerate(clique_seq))
def conv(N): file = "data/%s"%N if not os.path.exists(file): raise RuntimeError, "Data for level %s does not exist."%N F = open(file).read() i = F.find(":=") if i == -1: raise RuntimeError, "Syntax error in file for level %s."%N F = F[i+2:] TRANS = [("[*", "["), ("*]", "]"), ("<","["), (">","]"), \ (";",""), ("\n",""), ("^","**")] for z,w in TRANS: F = F.replace(z,w) X = [] # Define x so the eval below works. R = PolynomialRing(RationalField()) x = R.gen() print "starting eval." #print "F = ", F for f in eval(F): print "creating object from f=",f[:4] cp = {} disc = 0 for z in f[5]: g = R(z[1]) disc = GCD(disc,g.discriminant()) cp[z[0]] = g X.append(ModularForm(f[0],f[1],f[2],f[3],f[4],cp,disc)) return X
class SiegelModularFormG2VVRepresentation(SageObject): def __init__(self, K): self.__K = K self.__R = PolynomialRing(K, ['x', 'y']) self.__x = self.__R.gen(0) self.__y = self.__R.gen(1) def from_module(self, R): assert R == PolynomialRing(R.base_ring(), ['x', 'y']) return SiegelModularFormG2VVRepresentation(R.base_ring()) def base_ring(self): return self.__K def codomain(self): return self.__R def base_extend(self, L): if L.has_coerce_map_from(self.__K): return SiegelModularFormG2VVRepresentation(L) raise ValueError("Base extension of representation is not defined") def extends(self, other): if isinstance(other, TrivialRepresentation): return self.__K.has_coerce_map_from(other.codomain()) elif type(self) != type(other): return False return self.__K.has_coerce_map_from(other.__K) def group(self): return "GL(2,ZZ)" def _apply_function(self): return self.apply def apply(self, g, a): return a(g[0] * self.__x + g[1] * self.__y, g[2] * self.__x + g[3] * self.__y) def __cmp__(self, other): c = cmp(type(self), type(other)) if c == 0: c = cmp(self.__K, other.__K) return c def __hash__(self): return hash(self.__K) def _repr_(self): return "Siegel modular form degree 2 vector valued representation on %s" % ( self.__K) def _latex_(self): return "Siegel modular form degree 2 vector valued representation on %s" % ( latex(self.__K))
def upper_components(self): r""" Return the list of all upper components lying above this lower component. This lower component corresponds to a discrete valuation `v` on a rational function field `L(x)` extending the valuation `v_L`, where `L/K` is some finite extension of the base field `K`. The upper components correspond to the extensions of v to the function field of `Y_L` (which is a finite extension of `L(x)`). Since the computation of all extensions of a nonstandard valuation on a function field to a finite extension is not yet part of Sage, we have to appeal to the MacLane algorithm ourselves. EXAMPLES: This example shows that extending valuations also works if the equation is not integral wrt the valuation v :: sage: from mclf import * sage: R.<x> = QQ[] sage: Y = SuperellipticCurve(5*x^3 + 1, 2) sage: Y2 = SemistableModel(Y, QQ.valuation(5)) sage: Y2.is_semistable() # indirect doctest True """ from sage.geometry.newton_polygon import NewtonPolygon from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing v = self.valuation() FY = self.reduction_tree().curve().function_field() FYL = base_change_of_function_field(FY, self.base_field()) FXL = FYL.rational_function_field() assert v.domain() == FXL G = FYL.polynomial() # now FYL = FXL(y| G(y) = 0) # we first have to make G integral with respect to v np = NewtonPolygon([(i,v(G[i])) for i in range(G.degree() + 1)]) r = np.slopes()[-1] # the largest slope if r <= 0: # G is integral w.r.t. v upper_valuations = [FYL.valuation(w) for w in v.mac_lane_approximants(FYL.polynomial(), require_incomparability=True)] else: # G is not integral vK = self.reduction_tree().base_valuation() pi = vK.uniformizer() # we construct a function field FYL1 k = QQ(r/v(pi)).ceil() # isomorphic to FYL, but with R1 = PolynomialRing(FXL, 'y1') # integral equation G_1 y1 = R1.gen() G1 = G(pi**(-k)*y1).monic() assert all([v(c) >= 0 for c in G1.coefficients()]), "new G is not integral!" FYL1 = FXL.extension(G1, 'y1') y1 = FYL1.gen() V = v.mac_lane_approximants(G1, require_incomparability=True) V = [FYL1.valuation(w) for w in V] # the extensions of v to FYL1 upper_valuations = [FYL.valuation((w, FYL.hom(y1/pi**k), FYL1.hom(pi**k*FYL.gen()))) for w in V] # made into valuations on FYL return [UpperComponent(self, w) for w in upper_valuations]
def DuadicCodeEvenPair(F, S1, S2): r""" Constructs the "even pair" of duadic codes associated to the "splitting" (see the docstring for ``is_a_splitting`` for the definition) S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import is_a_splitting sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: is_a_splitting(S1,S2,11) True sage: codes.DuadicCodeEvenPair(GF(q),S1,S2) (Linear code of length 11, dimension 5 over Finite Field of size 3, Linear code of length 11, dimension 5 over Finite Field of size 3) """ n = len(S1) + len(S2) + 1 if not is_a_splitting(S1, S2, n): raise TypeError("%s, %s must be a splitting of %s." % (S1, S2, n)) q = F.order() k = Mod(q, n).multiplicative_order() FF = GF(q**k, "z") z = FF.gen() zeta = z**((q**k - 1) / n) P1 = PolynomialRing(FF, "x") x = P1.gen() g1 = prod([x - zeta**i for i in S1 + [0]]) g2 = prod([x - zeta**i for i in S2 + [0]]) P2 = PolynomialRing(F, "x") x = P2.gen() gg1 = P2( [lift2smallest_field(c)[0] for c in g1.coefficients(sparse=False)]) gg2 = P2( [lift2smallest_field(c)[0] for c in g2.coefficients(sparse=False)]) C1 = CyclicCodeFromGeneratingPolynomial(n, gg1) C2 = CyclicCodeFromGeneratingPolynomial(n, gg2) return C1, C2
def comp_prod(P, Q): n = Q.degree() K = P.base_ring() A = PolynomialRing(K, 'X') X = A.gen() AA = PolynomialRing(K, 'Y,Z') Y, Z = AA.gens() return P(Y).resultant(AA(Y**n * Q(Z/Y)), Y)(1,X)
def DuadicCodeEvenPair(F,S1,S2): r""" Constructs the "even pair" of duadic codes associated to the "splitting" (see the docstring for ``_is_a_splitting`` for the definition) S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import _is_a_splitting sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: _is_a_splitting(S1,S2,11) True sage: codes.DuadicCodeEvenPair(GF(q),S1,S2) ([11, 5] Cyclic Code over GF(3), [11, 5] Cyclic Code over GF(3)) """ from .cyclic_code import CyclicCode n = len(S1) + len(S2) + 1 if not _is_a_splitting(S1,S2,n): raise TypeError("%s, %s must be a splitting of %s."%(S1,S2,n)) q = F.order() k = Mod(q,n).multiplicative_order() FF = GF(q**k,"z") z = FF.gen() zeta = z**((q**k-1)/n) P1 = PolynomialRing(FF,"x") x = P1.gen() g1 = prod([x-zeta**i for i in S1+[0]]) g2 = prod([x-zeta**i for i in S2+[0]]) P2 = PolynomialRing(F,"x") x = P2.gen() gg1 = P2([_lift2smallest_field(c)[0] for c in g1.coefficients(sparse=False)]) gg2 = P2([_lift2smallest_field(c)[0] for c in g2.coefficients(sparse=False)]) C1 = CyclicCode(length = n, generator_pol = gg1) C2 = CyclicCode(length = n, generator_pol = gg2) return C1,C2
class SiegelModularFormG2VVRepresentation ( SageObject ) : def __init__(self, K) : self.__K = K self.__R = PolynomialRing(K, ['x', 'y']) self.__x = self.__R.gen(0) self.__y = self.__R.gen(1) def from_module(self, R) : assert R == PolynomialRing(R.base_ring(), ['x', 'y']) return SiegelModularFormG2VVRepresentation(R.base_ring()) def base_ring(self) : return self.__K def codomain(self) : return self.__R def base_extend(self, L) : if L.has_coerce_map_from(self.__K) : return SiegelModularFormG2VVRepresentation( L ) raise ValueError, "Base extension of representation is not defined" def extends(self, other) : if isinstance(other, TrivialRepresentation) : return self.__K.has_coerce_map_from(other.codomain()) elif type(self) != type(other) : return False return self.__K.has_coerce_map_from(other.__K) def group(self) : return "GL(2,ZZ)" def _apply_function(self) : return self.apply def apply(self, g, a) : return a(g[0]*self.__x + g[1]*self.__y, g[2]*self.__x + g[3]*self.__y) def __cmp__(self, other) : c = cmp(type(self), type(other)) if c == 0 : c = cmp(self.__K, other.__K) return c def __hash__(self) : return hash(self.__K) def _repr_(self) : return "Siegel modular form degree 2 vector valued representation on %s" % (self.__K) def _latex_(self) : return "Siegel modular form degree 2 vector valued representation on %s" % (latex(self.__K))
def has_rep(self, n, restrict=None, force=False): """ Returns `True` if there exists an `n`-dimensional representation of `self`, and `False` otherwise. The optional argument `restrict` may be used to restrict the possible images of the generators. To do so, `restrict` must be a tuple with entries of `None`, `'diagonal'`, `'lower'`, or `'upper'`. Its length must match the number of generators of `self`. Use `force=True` if the function does not recognize the base field as computable, but the field is computable. """ if (not force and self.base_field() not in NumberFields and self.base_field() not in FiniteFields): raise TypeError( 'Base field must be computable. If %s is computable' % self.base_field() + ' then use force=True to bypass this.') if n not in ZZ or n < 1: raise ValueError('Dimension must be a positive integer.') from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing import math B = PolynomialRing(self.base_field(), (self.ngens() * n**2 + 1), 'x', order='deglex') M = MatrixSpace(B, n, sparse=True) gen_matrix = list() if not isinstance(restrict, (tuple, list)): restrict = [None for i in range(self.ngens())] if len(restrict) != self.ngens(): raise ValueError( 'Length of restrict does not match number of generators.') for i in range(self.ngens()): ith_gen_matrix = [] for j in range(n): for k in range(n): if restrict[i] == 'upper' and j > k: ith_gen_matrix.append(B.zero()) elif restrict[i] == 'lower' and j < k: ith_gen_matrix.append(B.zero()) elif restrict[i] == 'diagonal' and j != k: ith_gen_matrix.append(B.zero()) else: ith_gen_matrix.append(B.gen(j + (j + 1) * k + i * n**2)) gen_matrix.append(M(ith_gen_matrix)) relB_list = list() for i in range(self.nrels()): relB_list += self._to_matrix(self.rel(i), M, gen_matrix).list() relB = B.ideal(relB_list) if relB.dimension() == -1: return False else: return True
def DuadicCodeEvenPair(F,S1,S2): r""" Constructs the "even pair" of duadic codes associated to the "splitting" (see the docstring for ``is_a_splitting`` for the definition) S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import is_a_splitting sage: n = 11; q = 3 sage: C = cyclotomic_cosets(q,n); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: is_a_splitting(S1,S2,11) (True, 2) sage: DuadicCodeEvenPair(GF(q),S1,S2) (Linear code of length 11, dimension 5 over Finite Field of size 3, Linear code of length 11, dimension 5 over Finite Field of size 3) """ n = max(S1+S2)+1 if not(is_a_splitting(S1,S2,n)): raise TypeError, "%s, %s must be a splitting of %s."%(S1,S2,n) q = F.order() k = Mod(q,n).multiplicative_order() FF = GF(q**k,"z") z = FF.gen() zeta = z**((q**k-1)/n) P1 = PolynomialRing(FF,"x") x = P1.gen() g1 = prod([x-zeta**i for i in S1+[0]]) g2 = prod([x-zeta**i for i in S2+[0]]) P2 = PolynomialRing(F,"x") x = P2.gen() gg1 = P2([lift2smallest_field(c)[0] for c in g1.coeffs()]) gg2 = P2([lift2smallest_field(c)[0] for c in g2.coeffs()]) C1 = CyclicCodeFromGeneratingPolynomial(n,gg1) C2 = CyclicCodeFromGeneratingPolynomial(n,gg2) return C1,C2
def from_recurrence(cls, coefficients, values): """ Create a C-finite sequence given the coefficients $c$ and starting values $a$ of a homogenous linear recurrence. .. MATH:: a_{n+d} = c_0a_n + c_1a_{n+1} + \cdots + c_{d-1}a_{n+d-1}, \quad d\ge0. INPUT: - ``coefficients`` -- a list of rationals - ``values`` -- start values, a list of rationals OUTPUT: - A CFiniteSequence object EXAMPLES:: sage: R.<x> = QQ[] sage: CFiniteSequence.from_recurrence([1,1],[0,1]) # Fibonacci numbers C-finite sequence, generated by x/(-x^2 - x + 1) sage: CFiniteSequence.from_recurrence([-1,2],[0,1]) # natural numbers C-finite sequence, generated by x/(x^2 - 2*x + 1) sage: r = CFiniteSequence.from_recurrence([-1],[1]) sage: s = CFiniteSequence.from_recurrence([-1],[1,-1]) sage: r == s True sage: r = CFiniteSequence(x^3/(1-x-x^2)) sage: s = CFiniteSequence.from_recurrence([1,1],[0,0,0,1,1]) sage: r == s True sage: CFiniteSequence.from_recurrence(1,1) Traceback (most recent call last): ... ValueError: Wrong type for recurrence coefficient list. """ if not isinstance(coefficients, list): raise ValueError("Wrong type for recurrence coefficient list.") if not isinstance(values, list): raise ValueError("Wrong type for recurrence start value list.") deg = len(coefficients) co = coefficients[::-1] co.extend([0] * (len(values) - deg)) R = PolynomialRing(QQ, 'x') x = R.gen() den = -1 + sum([x ** (n + 1) * co[n] for n in range(deg)]) num = -values[0] + sum([x ** n * (-values[n] + sum([values[k] * co[n - 1 - k] for k in range(n)])) for n in range(1, len(values))]) return cls(num / den)
def sorted_roots(R, f, p=None): H = PolynomialRing(R, names='x') x = H.gen() if p is None: p = R.prime() k = f.weight() chi = f.character() pol = H([R(chi(p) * p**(k - 1)), R(-f.coefficients([p])[0]), R(1)]) alpha, beta = [o[0] for o in pol.roots()] if alpha.valuation() > beta.valuation(): alpha, beta = beta, alpha return alpha, beta
def _step_upper_bound_low_mem(r, m, q, generating_function): r""" Low memory implementation of :func:`_step_upper_bound_internal`. Significantly slower, but the memory footprint does not significantly increase even if the series coefficients need to be computed to very high degree terms. """ L = LieAlgebra(ZZ, ['X_%d' % k for k in range(r)]).Lyndon() dim_fm = L.graded_dimension(m) PR = PolynomialRing(ZZ, 't') t = PR.gen() a = (1 - dim_fm * (1 - t**q)) * t**m b = PR.one() for k in range(1, m): b *= (1 - t**k)**L.graded_dimension(k) # extract initial coefficients from a symbolic series expansion bd = b.degree() id = max(a.degree() + 1, bd) offset = id - bd quot = SR(a / b) sym_t = SR(t) qs = quot.series(sym_t, id) # check if partial sum is positive already within series expansion # store the last offset...id terms to start the linear recurrence coeffs = deque() cumul = ZZ.zero() for s in range(id): c = ZZ(qs.coefficient(sym_t, s)) cumul += c if s >= offset: coeffs.append(c) if cumul > 0: if generating_function: return s, quot return s # the rest of the coefficients are defined by a recurrence relation multipliers = [-b.monomial_coefficient(t**(bd - k)) for k in range(bd)] while cumul <= 0: c_next = sum(c * m for c, m in zip(coeffs, multipliers)) cumul += c_next s += 1 coeffs.append(c_next) coeffs.popleft() if generating_function: return s, quot return s
def logp(p, p_prec): """ Returns the (integral) power series for log_p(1+z) as a polynomial in y over the rationals of degree < p_prec. EXAMPLES:: sage: from sage.modular.pollack_stevens.families_util import logp sage: logp(11, 5) -1/4*y^4 + 1/3*y^3 - 1/2*y^2 + y """ SS = PolynomialRing(QQ, 'y') y = SS.gen() return sum([((-1)**(m - 1)) * (y**m) / m for m in range(1, p_prec)])
def logp(p, p_prec): """ Returns the (integral) power series for log_p(1+z) as a polynomial in y over the rationals of degree < p_prec. EXAMPLES:: sage: from sage.modular.pollack_stevens.families_util import logp sage: logp(11, 5) -1/4*y^4 + 1/3*y^3 - 1/2*y^2 + y """ SS = PolynomialRing(QQ, 'y') y = SS.gen() return sum([((-1) ** (m - 1)) * (y ** m) / m for m in range(1, p_prec)])
def __init__(self,lambda_squared=None, field=None): if lambda_squared==None: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R=PolynomialRing(ZZ,'x') x = R.gen() field=NumberField(x**3-ZZ(5)*x**2+ZZ(4)*x-ZZ(1), 'r', embedding=AA(ZZ(4))) self._l=field.gen() else: if field is None: self._l=lambda_squared field=lambda_squared.parent() else: self._l=field(lambda_squared) Surface.__init__(self,field, ZZ.zero(), finite=False)
def F(z,level = 0,method = 'moments'): R = PolynomialRing(z.parent(),'x,y').fraction_field() Rx = PolynomialRing(z.parent(),'x1').fraction_field() x1 = Rx.gen() subst = R.hom([x1,z],codomain = Rx) x,y = R.gens() center = self.parent()._source._BT.find_containing_affinoid(z) zbar = z.trace()-z f = R(1)/(x-y) k = self.parent()._n+2 V = [f] for ii in range(order): V = [v.derivative(y) for v in V]+[k/(y-zbar)*v for v in V] k += 2 return sum([self.integrate(subst(v),center,level,method) for v in V])
def bw_shift_rec(dop, shift=ZZ.zero()): Pols_n = PolynomialRing(dop.base_ring().base_ring(), 'n') # XXX: name Rops = ore_algebra.OreAlgebra(Pols_n, 'Sn') # Using the primitive part here would break the computation of residuals! # TODO: add test (arctan); better fix? # Other interesting cases: operators of the for P(Θ) (with constant # coefficients) #rop = dop.to_S(Rops).primitive_part().numerator() rop = dop.to_S(Rops) ordrec = rop.order() coeff = [ rop[ordrec - k](Pols_n.gen() - ordrec + shift) for k in xrange(ordrec + 1) ] return BwShiftRec(coeff)
def F(z): R=PolynomialRing(z.parent(),'x,y').fraction_field() Rx=PolynomialRing(z.parent(),'x1').fraction_field() x1=Rx.gen() subst=R.hom([x1,z],codomain=Rx) x,y=R.gens() center=self._parent._X._BT.find_containing_affinoid(z) zbar=z.trace()-z f=R(1)/(x-y) k=self._parent._k V=[f] for ii in range(order): V=[v.derivative(y) for v in V]+[k/(y-zbar)*v for v in V] k+=2 return sum([self.riemann_sum(subst(v),center,level) for v in V])
def __init__(self, lambda_squared=None, field=None): if lambda_squared == None: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(ZZ, 'x') x = R.gen() field = NumberField(x**3 - ZZ(5) * x**2 + ZZ(4) * x - ZZ(1), 'r', embedding=AA(ZZ(4))) self._l = field.gen() else: if field is None: self._l = lambda_squared field = lambda_squared.parent() else: self._l = field(lambda_squared) Surface.__init__(self, field, ZZ.zero(), finite=False)
def test_01(self): order = 2**8 F = FiniteField(order, 'a') P = PolynomialRing(F, 'x') n = 7 deg = 2 poly = F.fetch_int(42) for i in range(1, deg+1): poly += F.random_element() * P.gen()**i # evaluate polynomial at different points (shares) print(poly) points = [(F.fetch_int(i), poly(F.fetch_int(i))) for i in range(1, n+1)] points[0] = (points[0][0], points[0][1] + F.fetch_int(9)) print(points) assert poly == berlekamp_welsh(deg, points)
def _raise(self, p, level, weight): """ Helper function for :meth:`raise_level` and :meth:`raise_weight`. """ from eigenform_collection import EigenformCollection F = self.base_ring() R = PolynomialRing(F, 't') t = R.gen() chi = self.character() poly = t**2 - self.coefficient(p) * t + chi(p) * p**(self.weight() - 1) roots = poly.roots(multiplicities=False) apdict = copy(self._apdict) C = EigenformCollection(Gamma1(level), weight, F, chi.extend(level)) for a in roots: apdict[p] = a yield C(apdict)
def test_01(self): order = 2**8 F = FiniteField(order, 'a') P = PolynomialRing(F, 'x') n = 7 deg = 2 poly = F.fetch_int(42) for i in range(1, deg + 1): poly += F.random_element() * P.gen()**i # evaluate polynomial at different points (shares) print(poly) points = [(F.fetch_int(i), poly(F.fetch_int(i))) for i in range(1, n + 1)] points[0] = (points[0][0], points[0][1] + F.fetch_int(9)) print(points) assert poly == berlekamp_welsh(deg, points)
def __init__(self,lambda_squared=None, field=None): TranslationSurface_generic.__init__(self) if lambda_squared==None: from sage.rings.number_field.number_field import NumberField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R=PolynomialRing(ZZ,'x') x = R.gen() from sage.rings.qqbar import AA self._field=NumberField(x**3-ZZ(5)*x**2+ZZ(4)*x-ZZ(1), 'r', embedding=AA(ZZ(4))) self._l=self._field.gen() else: if field is None: self._l=lambda_squared self._field=lambda_squared.parent() else: self._field=field self._l=field(lambda_squared)
def component_jumps(xi0, xi1): r""" Helper function for ``permanent_completion``. """ from sage.geometry.newton_polygon import NewtonPolygon from mclf.berkovich.berkovich_line import valuations_from_inequality from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from mclf.berkovich.berkovich_line import TypeIIPointOnBerkovichLine assert xi0.is_leq(xi1), "xi0 has to be an ancestor of xi1" X = xi0.berkovich_line() vK = X.base_valuation() v0 = xi0.pseudovaluation_on_polynomial_ring() v1 = xi1.pseudovaluation_on_polynomial_ring() y = xi1.parameter() if hasattr(v1, "phi"): phi = v1.phi() # v1 is an inductive valuation else: phi = v1._G # v1 is a limit valuation assert v0(phi) < v1(phi), "xi0 is not an ancestor of xi1!" R = phi.parent() x = R.gen() S = PolynomialRing(R, 'T') T = S.gen() G = phi(x + T) NP = NewtonPolygon([(i, v1(G[i])) for i in range(G.degree() + 1)]) V = [] vertices = NP.vertices() for k in range(len(vertices) - 1): i, ai = vertices[k] j, aj = vertices[k + 1] a0 = aj - j * (ai - aj) / (i - j) # print("a0 = ", a0) V += valuations_from_inequality(vK, phi, a0, v0) ret = [TypeIIPointOnBerkovichLine(X, (v, y)) for v in V] """ if xi1.is_in_unit_disk(): ret = [X.point_from_polynomial_pseudovaluation(v) for v in V] else: ret = [X.point_from_polynomial_pseudovaluation(v, in_unit_disk=False) for v in V] """ return [xi for xi in ret if (xi0.is_leq(xi) and xi.is_leq(xi1))]
def generating_series(self, var='z'): r""" Return `1 / (1-z)`. EXAMPLES:: sage: N = SetsWithGrading().example(); N Non negative integers sage: f = N.generating_series(); f 1/(-z + 1) sage: LaurentSeriesRing(ZZ,'z')(f) 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + z^8 + z^9 + z^10 + z^11 + z^12 + z^13 + z^14 + z^15 + z^16 + z^17 + z^18 + z^19 + O(z^20) """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer R = PolynomialRing(IntegerRing(), var) z = R.gen() return Integer(1) / (Integer(1) - z)
def Tokuyama_formula(self, name='t'): r""" Return the Tokuyama formula of ``self``. Following the exposition of [BBF]_, Tokuyama's formula asserts .. MATH:: \sum_{G} (t+1)^{s(G)} t^{l(G)} z_1^{d_{n+1}} z_2^{d_{n}-d_{n+1}} \cdots z_{n+1}^{d_1-d_2} = s_{\lambda} (z_1, \ldots, z_{n+1}) \prod_{i<j} (z_j+tz_i), where the sum is over all strict Gelfand-Tsetlin patterns with fixed top row `\lambda+\rho`, with `\lambda` a partition with at most `n+1` parts and `\rho = (n,n-1,\dots,1,0)`, and `s_{\lambda}` is a Schur function. INPUT: - ``name`` -- (Default: ``'t'``) An alternative name for the variable `t`. EXAMPLES:: sage: GT = GelfandTsetlinPatterns(top_row=[2,1,0],strict=True) sage: GT.Tokuyama_formula() t^3*x1^2*x2 + t^2*x1*x2^2 + t^2*x1^2*x3 + t^2*x1*x2*x3 + t*x1*x2*x3 + t*x2^2*x3 + t*x1*x3^2 + x2*x3^2 sage: GT = GelfandTsetlinPatterns(top_row=[3,2,1],strict=True) sage: GT.Tokuyama_formula() t^3*x1^3*x2^2*x3 + t^2*x1^2*x2^3*x3 + t^2*x1^3*x2*x3^2 + t^2*x1^2*x2^2*x3^2 + t*x1^2*x2^2*x3^2 + t*x1*x2^3*x3^2 + t*x1^2*x2*x3^3 + x1*x2^2*x3^3 sage: GT = GelfandTsetlinPatterns(top_row=[1,1,1],strict=True) sage: GT.Tokuyama_formula() 0 """ n = self._n variables = [name] + ["x%d" % i for i in range(1, n + 1)] R = PolynomialRing(ZZ, names=variables) t = R.gen(0) x = R.gens()[1:] GT = GelfandTsetlinPatterns(top_row=self._row, strict=True) return sum((t + 1)**(gt.number_of_special_entries()) * t**(gt.number_of_boxes()) * prod(x[i]**gt.weight()[i] for i in range(n)) for gt in GT)
def Tokuyama_coefficient(self, name='t'): r""" Return the Tokuyama coefficient attached to ``self``. Following the exposition of [BBF]_, Tokuyama's formula asserts .. MATH:: \sum_{G} (t+1)^{s(G)} t^{l(G)} z_1^{d_{n+1}} z_2^{d_{n}-d_{n+1}} \cdots z_{n+1}^{d_1-d_2} = s_{\lambda}(z_1,\dots,z_{n+1}) \prod_{i<j} (z_j+tz_i), where the sum is over all strict Gelfand-Tsetlin patterns with fixed top row `\lambda + \rho`, with `\lambda` a partition with at most `n+1` parts and `\rho = (n, n-1, \ldots, 1, 0)`, and `s_\lambda` is a Schur function. INPUT: - ``name`` -- (Default: ``'t'``) An alternative name for the variable `t`. EXAMPLES:: sage: P = GelfandTsetlinPattern([[3,2,1],[2,2],[2]]) sage: P.Tokuyama_coefficient() 0 sage: G = GelfandTsetlinPattern([[3,2,1],[3,1],[2]]) sage: G.Tokuyama_coefficient() t^2 + t sage: G = GelfandTsetlinPattern([[2,1,0],[1,1],[1]]) sage: G.Tokuyama_coefficient() 0 sage: G = GelfandTsetlinPattern([[5,3,2,1,0],[4,3,2,0],[4,2,1],[3,2],[3]]) sage: G.Tokuyama_coefficient() t^8 + 3*t^7 + 3*t^6 + t^5 """ R = PolynomialRing(ZZ, name) t = R.gen(0) if self.is_strict() == False: return R(0) return (t + 1)**(self.number_of_special_entries()) * t**( self.number_of_boxes())
def generating_series(self, var='z'): r""" Returns `1 / (1-z)`. EXAMPLES:: sage: N = SetsWithGrading().example(); N Non negative integers sage: f = N.generating_series(); f 1/(-z + 1) sage: LaurentSeriesRing(ZZ,'z')(f) 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + z^7 + z^8 + z^9 + z^10 + z^11 + z^12 + z^13 + z^14 + z^15 + z^16 + z^17 + z^18 + z^19 + O(z^20) """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.integer import Integer R = PolynomialRing(IntegerRing(), var) z = R.gen() return Integer(1) / (Integer(1)-z)
def Tokuyama_coefficient(self, name='t'): r""" Return the Tokuyama coefficient attached to ``self``. Following the exposition of [BBF]_, Tokuyama's formula asserts .. MATH:: \sum_{G} (t+1)^{s(G)} t^{l(G)} z_1^{d_{n+1}} z_2^{d_{n}-d_{n+1}} \cdots z_{n+1}^{d_1-d_2} = s_{\lambda}(z_1,\dots,z_{n+1}) \prod_{i<j} (z_j+tz_i), where the sum is over all strict Gelfand-Tsetlin patterns with fixed top row `\lambda + \rho`, with `\lambda` a partition with at most `n+1` parts and `\rho = (n, n-1, \ldots, 1, 0)`, and `s_\lambda` is a Schur function. INPUT: - ``name`` -- (Default: ``'t'``) An alternative name for the variable `t`. EXAMPLES:: sage: P = GelfandTsetlinPattern([[3,2,1],[2,2],[2]]) sage: P.Tokuyama_coefficient() 0 sage: G = GelfandTsetlinPattern([[3,2,1],[3,1],[2]]) sage: G.Tokuyama_coefficient() t^2 + t sage: G = GelfandTsetlinPattern([[2,1,0],[1,1],[1]]) sage: G.Tokuyama_coefficient() 0 sage: G = GelfandTsetlinPattern([[5,3,2,1,0],[4,3,2,0],[4,2,1],[3,2],[3]]) sage: G.Tokuyama_coefficient() t^8 + 3*t^7 + 3*t^6 + t^5 """ R = PolynomialRing(ZZ, name) t = R.gen(0) if self.is_strict() == False: return R(0) return (t+1)**(self.number_of_special_entries()) * t**(self.number_of_boxes())
def Tokuyama_formula(self, name='t'): r""" Return the Tokuyama formula of ``self``. Following the exposition of [BBF]_, Tokuyama's formula asserts .. MATH:: \sum_{G} (t+1)^{s(G)} t^{l(G)} z_1^{d_{n+1}} z_2^{d_{n}-d_{n+1}} \cdots z_{n+1}^{d_1-d_2} = s_{\lambda} (z_1, \ldots, z_{n+1}) \prod_{i<j} (z_j+tz_i), where the sum is over all strict Gelfand-Tsetlin patterns with fixed top row `\lambda+\rho`, with `\lambda` a partition with at most `n+1` parts and `\rho = (n,n-1,\dots,1,0)`, and `s_{\lambda}` is a Schur function. INPUT: - ``name`` -- (Default: ``'t'``) An alternative name for the variable `t`. EXAMPLES:: sage: GT = GelfandTsetlinPatterns(top_row=[2,1,0],strict=True) sage: GT.Tokuyama_formula() t^3*x1^2*x2 + t^2*x1*x2^2 + t^2*x1^2*x3 + t^2*x1*x2*x3 + t*x1*x2*x3 + t*x2^2*x3 + t*x1*x3^2 + x2*x3^2 sage: GT = GelfandTsetlinPatterns(top_row=[3,2,1],strict=True) sage: GT.Tokuyama_formula() t^3*x1^3*x2^2*x3 + t^2*x1^2*x2^3*x3 + t^2*x1^3*x2*x3^2 + t^2*x1^2*x2^2*x3^2 + t*x1^2*x2^2*x3^2 + t*x1*x2^3*x3^2 + t*x1^2*x2*x3^3 + x1*x2^2*x3^3 sage: GT = GelfandTsetlinPatterns(top_row=[1,1,1],strict=True) sage: GT.Tokuyama_formula() 0 """ n = self._n variables = [name] + ["x%d"%i for i in range(1,n+1)] R = PolynomialRing(ZZ,names=variables) t = R.gen(0) x = R.gens()[1:] GT = GelfandTsetlinPatterns(top_row=self._row, strict=True) return sum((t+1)**(gt.number_of_special_entries()) * t**(gt.number_of_boxes()) * prod(x[i]**gt.weight()[i] for i in range(n)) for gt in GT)
def _kohnen_rho_polynomial(self, t, p): P = PolynomialRing(ZZ, 'x') x = P.gen(0) #tc = self._minimal_isotropic_subspace_complement_mod_p(t, p) if t[0, 0] != 0: return (1 - x**2) for i in range(t.nrows()): if t[i, i] != 0: break if i % 2 == 0: ## Since we have semi definite indices Kohnen's lambda simplifies lambda_p = 1 if t == 0 else -1 ## For we multiply x in the second factor by p**(1/2) to make all coefficients rational. return (1 - x**2) * (1 + lambda_p * p**((i + 1) // 2) * x) * \ prod(1 - p**(2*j - 1) * x**2 for j in range(1, i // 2)) else: return (1 - x**2) * \ prod(1 - p**(2*j - 1) * x**2 for j in range(1, i // 2))
def _kohnen_rho_polynomial(self, t, p) : P = PolynomialRing(ZZ, 'x') x = P.gen(0) #tc = self._minimal_isotropic_subspace_complement_mod_p(t, p) if t[0,0] != 0 : return (1 - x**2) for i in xrange(t.nrows()) : if t[i,i] != 0 : break if i % 2 == 0 : ## Since we have semi definite indices Kohnen's lambda simplifies lambda_p = 1 if t == 0 else -1 ## For we multiply x in the second factor by p**(1/2) to make all coefficients rational. return (1 - x**2) * (1 + lambda_p * p**((i + 1) // 2) * x) * \ prod(1 - p**(2*j - 1) * x**2 for j in xrange(1, i // 2)) else : return (1 - x**2) * \ prod(1 - p**(2*j - 1) * x**2 for j in xrange(1, i // 2))
def jorder4(p): r""" Produce a particularly complicated example of polynomials for factorization over Zp(p). This method exists to test p-adic polynomial factorization. INPUT: - ``p`` -- a prime number OUTPUT: - A p-adic polynomial over Zp(``p``) EXAMPLES:: sage: from sage.rings.polynomial.padics.factor.factoring import jorder4 sage: jorder4(3) (1 + O(3^20))*x^24 + (24 + O(3^20))*x^23 + (276 + O(3^20))*x^22 + (2048 + O(3^20))*x^21 + (11310 + O(3^20))*x^20 + (51180 + O(3^20))*x^19 + (201652 + O(3^20))*x^18 + (709092 + O(3^20))*x^17 + (2228787 + O(3^20))*x^16 + (6232484 + O(3^20))*x^15 + (15469950 + O(3^20))*x^14 + (34143276 + O(3^20))*x^13 + (67323664 + O(3^20))*x^12 + (119268300 + O(3^20))*x^11 + (190652502 + O(3^20))*x^10 + (275456480 + O(3^20))*x^9 + (359189415 + O(3^20))*x^8 + (420635664 + O(3^20))*x^7 + (438402286 + O(3^20))*x^6 + (400618284 + O(3^20))*x^5 + (313569267 + O(3^20))*x^4 + (203945072 + O(3^20))*x^3 + (105227142 + O(3^20))*x^2 + (38341248 + O(3^20))*x + (10912597 + O(3^20)) Input must be prime:: sage: jorder4(4) Traceback (most recent call last): ... ValueError: p must be prime """ K = ZpFM(p,20,print_mode='terse') Kx = PolynomialRing(K,names='x') x = Kx.gen() f1 = (x+1)**3+p; f2 = f1**2+p**2*(x+1); f3 = f2**2+4*p**3*f1*(x+1)**2; f4 = f3**2+20*p**2*f3*f2*(x+1)**2+64*p**9*f1; return f4;
def Chow_form(self): r""" Returns the Chow form associated to this subscheme. For a `k`-dimensional subvariety of `\mathbb{P}^N` of degree `D`. The `(N-k-1)`-dimensional projective linear subspaces of `\mathbb{P}^N` meeting `X` form a hypersurface in the Grassmannian `G(N-k-1,N)`. The homogeneous form of degree `D` defining this hypersurface in Plucker coordinates is called the Chow form of `X`. The base ring needs to be a number field, finite field, or `\QQbar`. ALGORITHM: For a `k`-dimension subscheme `X` consider the `k+1` linear forms `l_i = u_{i0}x_0 + \cdots + u_{in}x_n`. Let `J` be the ideal in the polynomial ring `K[x_i,u_{ij}]` defined by the equations of `X` and the `l_i`. Let `J'` be the saturation of `J` with respect to the irrelevant ideal of the ambient projective space of `X`. The elimination ideal `I = J' \cap K[u_{ij}]` is a principal ideal, let `R` be its generator. The Chow form is obtained by writing `R` as a polynomial in Plucker coordinates (i.e. bracket polynomials). [DalbecSturmfels]_. OUTPUT: a homogeneous polynomial. REFERENCES: .. [DalbecSturmfels] J. Dalbec and B. Sturmfels. Invariant methods in discrete and computational geometry, chapter Introduction to Chow forms, pages 37-58. Springer Netherlands, 1994. EXAMPLES:: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(GF(17), 3) sage: X = P.subscheme([x3+x1,x2-x0,x2-x3]) sage: X.Chow_form() t0 - t1 + t2 + t3 :: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(QQ,3) sage: X = P.subscheme([x3^2 -101*x1^2 - 3*x2*x0]) sage: X.Chow_form() t0^2 - 101*t2^2 - 3*t1*t3 :: sage: P.<x0,x1,x2,x3>=ProjectiveSpace(QQ,3) sage: X = P.subscheme([x0*x2-x1^2, x0*x3-x1*x2, x1*x3-x2^2]) sage: Ch = X.Chow_form(); Ch t2^3 + 2*t2^2*t3 + t2*t3^2 - 3*t1*t2*t4 - t1*t3*t4 + t0*t4^2 + t1^2*t5 sage: Y = P.subscheme_from_Chow_form(Ch, 1); Y Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: x2^2*x3 - x1*x3^2, -x2^3 + x0*x3^2, -x2^2*x3 + x1*x3^2, x1*x2*x3 - x0*x3^2, 3*x1*x2^2 - 3*x0*x2*x3, -2*x1^2*x3 + 2*x0*x2*x3, -3*x1^2*x2 + 3*x0*x1*x3, x1^3 - x0^2*x3, x2^3 - x1*x2*x3, -3*x1*x2^2 + 2*x1^2*x3 + x0*x2*x3, 2*x0*x2^2 - 2*x0*x1*x3, 3*x1^2*x2 - 2*x0*x2^2 - x0*x1*x3, -x0*x1*x2 + x0^2*x3, -x0*x1^2 + x0^2*x2, -x1^3 + x0*x1*x2, x0*x1^2 - x0^2*x2 sage: I = Y.defining_ideal() sage: I.saturation(I.ring().ideal(list(I.ring().gens())))[0] Ideal (x2^2 - x1*x3, x1*x2 - x0*x3, x1^2 - x0*x2) of Multivariate Polynomial Ring in x0, x1, x2, x3 over Rational Field """ I = self.defining_ideal() P = self.ambient_space() R = P.coordinate_ring() N = P.dimension() + 1 d = self.dimension() # create the ring for the generic linear hyperplanes # u0x0 + u1x1 + ... SS = PolynomialRing(R.base_ring(), 'u', N * (d + 1), order='lex') vars = SS.variable_names() + R.variable_names() S = PolynomialRing(R.base_ring(), vars, order='lex') n = S.ngens() newcoords = [S.gen(n - N + t) for t in range(N)] # map the generators of the subscheme into the ring with the hyperplane variables phi = R.hom(newcoords, S) phi(self.defining_polynomials()[0]) # create the dim(X)+1 linear hyperplanes l = [] for i in range(d + 1): t = 0 for j in range(N): t += S.gen(N * i + j) * newcoords[j] l.append(t) # intersect the hyperplanes with X J = phi(I) + S.ideal(l) # saturate the ideal with respect to the irrelevant ideal J2 = J.saturation(S.ideal([phi(u) for u in R.gens()]))[0] # eliminate the original variables to be left with the hyperplane coefficients 'u' E = J2.elimination_ideal(newcoords) # create the plucker coordinates D = binomial(N, N - d - 1) #number of plucker coordinates tvars = [str('t') + str(i) for i in range(D)] #plucker coordinates T = PolynomialRing(R.base_ring(), tvars + list(S.variable_names()), order='lex') L = [] coeffs = [ T.gen(i) for i in range(0 + len(tvars), N * (d + 1) + len(tvars)) ] M = matrix(T, d + 1, N, coeffs) i = 0 for c in M.minors(d + 1): L.append(T.gen(i) - c) i += 1 # create the ideal that we can use for eliminating to get a polynomial # in the plucker coordinates (brackets) br = T.ideal(L) # create a mapping into a polynomial ring over the plucker coordinates # and the hyperplane coefficients psi = S.hom(coeffs + [0 for _ in range(N)], T) E2 = T.ideal([psi(u) for u in E.gens()] + br) # eliminate the hyperplane coefficients CH = E2.elimination_ideal(coeffs) # CH should be a principal ideal, but because of the relations among # the plucker coordinates, the elimination will probably have several generators # get the relations among the plucker coordinates rel = br.elimination_ideal(coeffs) # reduce CH with respect to the relations reduced = [] for f in CH.gens(): reduced.append(f.reduce(rel)) # find the principal generator # polynomial ring in just the plucker coordinates T2 = PolynomialRing(R.base_ring(), tvars) alp = T.hom(tvars + (N * (d + 1) + N) * [0], T2) # get the degrees of the reduced generators of CH degs = [u.degree() for u in reduced] mind = max(degs) # need the smallest degree form that did not reduce to 0 for d in degs: if d < mind and d > 0: mind = d ind = degs.index(mind) CF = reduced[ind] #this should be the Chow form of X # check that it is correct (i.e., it is a principal generator for CH + the relations) rel2 = rel + [CF] assert all(f in rel2 for f in CH.gens()), "did not find a principal generator" return alp(CF)
def Min(Fun, p, ubRes, conj, all_orbits=False): r""" Local loop for Affine_minimal, where we check minimality at the prime p. First we bound the possible k in our transformations A = zp^k + b. See Theorems 3.3.2 and 3.3.3 in [Molnar]_. INPUT: - ``Fun`` -- a dynamical system on projective space - ``p`` - a prime - ``ubRes`` -- integer, the upper bound needed for Th. 3.3.3 in [Molnar]_ - ``conj`` -- a 2x2 matrix keeping track of the conjugation - ``all_orbits`` -- boolean; whether or not to use ``==`` in the inequalities to find all orbits OUTPUT: - boolean -- ``True`` if ``Fun`` is minimal at ``p``, ``False`` otherwise - a dynamical system on projective space minimal at ``p`` EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([149*x^2 + 39*x*y + y^2, -8*x^2 + 137*x*y + 33*y^2]) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import Min sage: Min(f, 3, -27000000, matrix(QQ,[[1, 0],[0, 1]])) [ Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (157*x^2 + 72*x*y + 3*y^2 : -24*x^2 + 121*x*y + 54*y^2) , <BLANKLINE> [3 1] [0 1] ] """ d = Fun.degree() AffFun = Fun.dehomogenize(1) R = AffFun.coordinate_ring() if R.is_field(): #want the polynomial ring not the fraction field R = R.ring() F = R(AffFun[0].numerator()) G = R(AffFun[0].denominator()) dG = G.degree() # all_orbits scales bounds for >= and <= if searching for orbits instead of min model if dG > (d + 1) / 2: lowerBound = (-2 * (G[dG]).valuation(p) / (2 * dG - d + 1) + 1).floor() - int(all_orbits) else: lowerBound = (-2 * (F[d]).valuation(p) / (d - 1) + 1).floor() - int(all_orbits) upperBound = 2 * (ubRes.valuation(p)) + int(all_orbits) if upperBound < lowerBound: # There are no possible transformations to reduce the resultant. if not all_orbits: return [Fun, conj] return [] # Looping over each possible k, we search for transformations to reduce # the resultant of F/G all_found = [] k = lowerBound Qb = PolynomialRing(QQ, 'b') b = Qb.gen(0) Q = PolynomialRing(Qb, 'z') z = Q.gen(0) while k <= upperBound: A = (p**k) * z + b Ft = Q(F(A) - b * G(A)) Gt = Q((p**k) * G(A)) Fcoeffs = Ft.coefficients(sparse=False) Gcoeffs = Gt.coefficients(sparse=False) coeffs = Fcoeffs + Gcoeffs RHS = (d + 1) * k / 2 # If there is some b such that Res(phi^A) < Res(phi), we must have # ord_p(c) > RHS for each c in coeffs. # Make sure constant coefficients in coeffs satisfy the inequality. if all( QQ(c).valuation(p) > RHS - int(all_orbits) for c in coeffs if c.degree() == 0): # Constant coefficients in coeffs have large enough valuation, so # check the rest. We start by checking if simply picking b=0 works. if all(c(0).valuation(p) > RHS - int(all_orbits) for c in coeffs): # A = z*p^k satisfies the inequalities, and F/G is not minimal # "Conjugating by", p,"^", k, "*z +", 0 newconj = matrix(QQ, 2, 2, [p**k, 0, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: return [minFun, conj * newconj] all_found.append([p, k, 0]) # Otherwise we search if any value of b will work. We start by # finding a minimum bound on the valuation of b that is necessary. # See Theorem 3.3.5 in [Molnar, M.Sc. thesis]. bval = max( bCheck(coeff, RHS, p, b) for coeff in coeffs if coeff.degree() > 0) # We scale the coefficients in coeffs, so that we may assume # ord_p(b) is at least 0 scaledCoeffs = [coeff(b * (p**bval)) for coeff in coeffs] # We now scale the inequalities, ord_p(coeff) > RHS, so that # coeff is in ZZ[b] scale = QQ(max(coeff.denominator() for coeff in scaledCoeffs)) normalizedCoeffs = [coeff * scale for coeff in scaledCoeffs] scaleRHS = RHS + scale.valuation(p) # We now search for integers that satisfy the inequality # ord_p(coeff) > RHS. See Lemma 3.3.6 in [Molnar, M.Sc. thesis]. bound = (scaleRHS + 1 - int(all_orbits)).floor() all_blift = blift(normalizedCoeffs, bound, p, k, all_orbits=all_orbits) # If bool is true after lifting, we have a solution b, and F/G # is not minimal. for boolval, sol in all_blift: if boolval: #Rescale, conjugate and return new map bsol = QQ(sol * (p**bval)) #only add 'minimal orbit element' while bsol.abs() >= p**k: if bsol < 0: bsol += p**k else: bsol -= p**k #"Conjugating by ", p,"^", k, "*z +", bsol newconj = matrix(QQ, 2, 2, [p**k, bsol, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: return [minFun, conj * newconj] if [p, k, bsol] not in all_found: all_found.append([p, k, bsol]) k = k + 1 if not all_orbits: return [Fun, conj] return all_found
def BCHCode(n,delta,F,b=0): r""" A 'Bose-Chaudhuri-Hockenghem code' (or BCH code for short) is the largest possible cyclic code of length n over field F=GF(q), whose generator polynomial has zeros (which contain the set) `Z = \{a^{b},a^{b+1}, ..., a^{b+delta-2}\}`, where a is a primitive `n^{th}` root of unity in the splitting field `GF(q^m)`, b is an integer `0\leq b\leq n-delta+1` and m is the multiplicative order of q modulo n. (The integers `b,...,b+delta-2` typically lie in the range `1,...,n-1`.) The integer `delta \geq 1` is called the "designed distance". The length n of the code and the size q of the base field must be relatively prime. The generator polynomial is equal to the least common multiple of the minimal polynomials of the elements of the set `Z` above. Special cases are b=1 (resulting codes are called 'narrow-sense' BCH codes), and `n=q^m-1` (known as 'primitive' BCH codes). It may happen that several values of delta give rise to the same BCH code. The largest one is called the Bose distance of the code. The true minimum distance, d, of the code is greater than or equal to the Bose distance, so `d\geq delta`. EXAMPLES:: sage: FF.<a> = GF(3^2,"a") sage: x = PolynomialRing(FF,"x").gen() sage: L = [b.minpoly() for b in [a,a^2,a^3]]; g = LCM(L) sage: f = x^(8)-1 sage: g.divides(f) True sage: C = codes.CyclicCode(8,g); C Linear code of length 8, dimension 4 over Finite Field of size 3 sage: C.minimum_distance() 4 sage: C = codes.BCHCode(8,3,GF(3),1); C Linear code of length 8, dimension 4 over Finite Field of size 3 sage: C.minimum_distance() 4 sage: C = codes.BCHCode(8,3,GF(3)); C Linear code of length 8, dimension 5 over Finite Field of size 3 sage: C.minimum_distance() 3 sage: C = codes.BCHCode(26, 5, GF(5), b=1); C Linear code of length 26, dimension 10 over Finite Field of size 5 """ from sage.misc.misc import srange q = F.order() R = IntegerModRing(n) m = R(q).multiplicative_order() FF = GF(q**m,"z") z = FF.gen() e = z.multiplicative_order()/n a = z**e # order n P = PolynomialRing(F,"x") x = P.gen() cosets = Set([]) for i in srange(b,b+delta-1): cosets = cosets.union(Set(cyclotomic_cosets(q, n, i))) L0 = [a**j for j in cosets] L1 = [P(ai.minpoly()) for ai in L0] g = P(LCM(L1)) #print cosets, "\n", g, "\n", (x**n-1).factor(), "\n", L1, "\n", g.divides(x**n-1) if not(g.divides(x**n-1)): raise ValueError, "BCH codes does not exist with the given input." return CyclicCodeFromGeneratingPolynomial(n,g)
def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, return_seqs=False, return_pari_objects=True): r""" This function enumerates (primitive) totally real field extensions of degree `m>1` of the totally real field F with discriminant `d \leq B`; optionally one can specify the first few coefficients, where the sequence ``a`` corresponds to a polynomial by :: a[d]*x^n + ... + a[0]*x^(n-d) if ``length(a) = d+1``, so in particular always ``a[d] = 1``. .. note:: This is guaranteed to give all primitive such fields, and seems in practice to give many imprimitive ones. INPUT: - ``F`` -- number field, the base field - ``m`` -- integer, the degree - ``B`` -- integer, the discriminant bound - ``a`` -- list (default: []), the coefficient list to begin with - ``verbose`` -- boolean or nonnegative integer or string (default: 0) give a verbose description of the computations being performed. If ``verbose`` is set to ``2`` or more then it outputs some extra information. If ``verbose`` is a string then it outputs to a file specified by ``verbose`` - ``return_seqs`` -- (boolean, default False) If ``True``, then return the polynomials as sequences (for easier exporting to a file). This also returns a list of four numbers, as explained in the OUTPUT section below. - ``return_pari_objects`` -- (boolean, default: True) if both ``return_seqs`` and ``return_pari_objects`` are ``False`` then it returns the elements as Sage objects; otherwise it returns pari objects. OUTPUT: - the list of fields with entries ``[d,fabs,f]``, where ``d`` is the discriminant, ``fabs`` is an absolute defining polynomial, and ``f`` is a defining polynomial relative to ``F``, sorted by discriminant. - if ``return_seqs`` is ``True``, then the first field of the list is a list containing the count of four items as explained below - the first entry gives the number of polynomials tested - the second entry gives the number of polynomials with its discriminant having a large enough square divisor - the third entry is the number of irreducible polynomials - the fourth entry is the number of irreducible polynomials with discriminant at most ``B`` EXAMPLES:: sage: ZZx = ZZ['x'] sage: F.<t> = NumberField(x^2-2) sage: enumerate_totallyreal_fields_rel(F, 1, 2000) [[1, [-2, 0, 1], xF - 1]] sage: enumerate_totallyreal_fields_rel(F, 2, 2000) [[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]] sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True) [[9, 6, 5, 0], [[1600, [4, 0, -6, 0, 1], [-1, 1, 1]]]] TESTS: Each of the outputs must be elements of Sage if ``return_pari_objects`` is set to ``False``:: sage: type(enumerate_totallyreal_fields_rel(F, 2, 2000)[0][1]) <type 'cypari2.gen.Gen'> sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][0].parent() Integer Ring sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][1].parent() Univariate Polynomial Ring in x over Rational Field sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][2].parent() Univariate Polynomial Ring in xF over Number Field in t with defining polynomial x^2 - 2 sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True)[1][0][1][0].parent() Rational Field AUTHORS: - John Voight (2007-11-01) """ if not isinstance(m, Integer): try: m = Integer(m) except TypeError: raise TypeError("cannot coerce m (= %s) to an integer" % m) if (m < 1): raise ValueError("m must be at least 1.") n = F.degree() * m # Initialize S = {} # dictionary of the form {(d, fabs): f, ...} dB_odlyzko = odlyzko_bound_totallyreal(n) dB = math.ceil(40000 * dB_odlyzko**n) counts = [0, 0, 0, 0] # Trivial case if m == 1: g = pari(F.defining_polynomial()).polrecip().Vec() if return_seqs: return [[0, 0, 0, 0], [1, [-1, 1], g]] elif return_pari_objects: return [[1, g, pari('xF-1')]] else: Px = PolynomialRing(QQ, 'xF') return [[ZZ(1), [QQ(_) for _ in g], Px.gen() - 1]] if verbose: saveout = sys.stdout if isinstance(verbose, str): fsock = open(verbose, 'w') sys.stdout = fsock # Else, print to screen f_out = [0] * m + [1] T = tr_data_rel(F, m, B, a) if verbose == 2: T.incr(f_out, verbose) else: T.incr(f_out) Fx = PolynomialRing(F, 'xF') nfF = pari( str(F.defining_polynomial()).replace('x', str(F.primitive_element()))) parit = pari(str(F.primitive_element())) while f_out[m] != 0: counts[0] += 1 if verbose: print("==>", f_out, end="") f_str = '' for i in range(len(f_out)): f_str += '(' + str(f_out[i]) + ')*x^' + str(i) if i < len(f_out) - 1: f_str += '+' nf = pari(f_str) if nf.poldegree('t') == 0: nf = nf.subst('x', 'x-t') nf = nf.polresultant(nfF, parit) d = nf.poldisc() #counts[0] += 1 if d > 0 and nf.polsturm() == n: da = int_has_small_square_divisor(Integer(d)) if d > dB or d <= B * da: counts[1] += 1 if nf.polisirreducible(): counts[2] += 1 [zk, d] = nf.nfbasis_d() if d <= B: if verbose: print("has discriminant", d, end="") # Find a minimal lattice element counts[3] += 1 ng = pari([nf, zk]).polredabs() # Check if K is contained in the list. if (d, ng) in S: if verbose: print("but is not new") else: if verbose: print("and is new!") S[(d, ng)] = Fx(f_out) else: if verbose: print("has discriminant", abs(d), "> B") else: if verbose: print("is not absolutely irreducible") else: if verbose: print("has discriminant", abs(d), "with no large enough square divisor") else: if verbose: if d == 0: print("is not squarefree") else: print("is not totally real") if verbose == 2: T.incr(f_out, verbose=verbose) else: T.incr(f_out) # In the application of Smyth's theorem above, we exclude finitely # many possibilities which we must now throw back in. if m == 2: if Fx([-1, 1, 1]).is_irreducible(): K = F.extension(Fx([-1, 1, 1]), 'tK') Kabs = K.absolute_field('tKabs') Kabs_pari = pari(Kabs.defining_polynomial()) d = K.absolute_discriminant() if abs(d) <= B: ng = Kabs_pari.polredabs() S[(d, ng)] = Fx([-1, 1, 1]) elif F.degree() == 2: for ff in [[1, -7, 13, -7, 1], [1, -8, 14, -7, 1]]: f = Fx(ff).factor()[0][0] K = F.extension(f, 'tK') Kabs = K.absolute_field('tKabs') Kabs_pari = pari(Kabs.defining_polynomial()) d = K.absolute_discriminant() if abs(d) <= B: ng = Kabs_pari.polredabs() S[(d, ng)] = f elif m == 3: if Fx([-1, 6, -5, 1]).is_irreducible(): K = F.extension(Fx([-1, 6, -5, 1]), 'tK') Kabs = K.absolute_field('tKabs') Kabs_pari = pari(Kabs.defining_polynomial()) d = K.absolute_discriminant() if abs(d) <= B: ng = Kabs_pari.polredabs() S[(d, ng)] = Fx([-1, 6, -5, 1]) # Convert S to a sorted list of triples [d, fabs, f], taking care # not to use the comparison operators on PARI polynomials. S = [[s[0], s[1], t] for s, t in S.items()] S.sort(key=lambda x: (x[0], [QQ(cf) for cf in x[1].polrecip().Vec()])) # Now check for isomorphic fields weed_fields(S) # Output. if verbose: print("=" * 80) print("Polynomials tested: {}".format(counts[0])) print("Polynomials with discriminant with large enough square" " divisor: {}".format(counts[1])) print("Irreducible polynomials: {}".format(counts[2])) print("Polynomials with nfdisc <= B: {}".format(counts[3])) for i in range(len(S)): print(S[i]) if isinstance(verbose, str): fsock.close() sys.stdout = saveout # Make sure to return elements that belong to Sage if return_seqs: return [[ZZ(x) for x in counts], [[ s[0], [QQ(x) for x in s[1].polrecip().Vec()], s[2].coefficients(sparse=False) ] for s in S]] elif return_pari_objects: return S else: Px = PolynomialRing(QQ, 'x') return [[s[0], Px([QQ(_) for _ in s[1].list()]), s[2]] for s in S]
class PseudoConwayLattice(WithEqualityById, SageObject): r""" A pseudo-Conway lattice over a given finite prime field. The Conway polynomial `f_n` of degree `n` over `\Bold{F}_p` is defined by the following four conditions: - `f_n` is irreducible. - In the quotient field `\Bold{F}_p[x]/(f_n)`, the element `x\bmod f_n` generates the multiplicative group. - The minimal polynomial of `(x\bmod f_n)^{\frac{p^n-1}{p^m-1}}` equals the Conway polynomial `f_m`, for every divisor `m` of `n`. - `f_n` is lexicographically least among all such polynomials, under a certain ordering. The final condition is needed only in order to make the Conway polynomial unique. We define a pseudo-Conway lattice to be any family of polynomials, indexed by the positive integers, satisfying the first three conditions. INPUT: - ``p`` -- prime number - ``use_database`` -- boolean. If ``True``, use actual Conway polynomials whenever they are available in the database. If ``False``, always compute pseudo-Conway polynomials. EXAMPLES:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.polynomial(3) x^3 + x + 1 TESTS:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(3) sage: hash(PCL) # random 8738829832350 sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PseudoConwayLattice(3) == PseudoConwayLattice(3) False sage: PseudoConwayLattice(3) != PseudoConwayLattice(3) True sage: P = PseudoConwayLattice(5) sage: P == P True sage: P != P False """ def __init__(self, p, use_database=True): """ TESTS:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(3) sage: PCL.polynomial(3) x^3 + 2*x + 1 sage: PCL = PseudoConwayLattice(5, use_database=False) sage: PCL.polynomial(12) x^12 + 4*x^11 + 2*x^10 + 4*x^9 + 2*x^8 + 2*x^7 + 4*x^6 + x^5 + 2*x^4 + 2*x^2 + x + 2 sage: PCL.polynomial(6) x^6 + x^5 + 4*x^4 + 3*x^3 + 3*x^2 + 2*x + 2 sage: PCL.polynomial(11) x^11 + x^6 + 3*x^3 + 4*x + 3 """ self.p = p from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing self.ring = PolynomialRing(FiniteField(p), 'x') if use_database: C = sage.databases.conway.ConwayPolynomials() self.nodes = {n: self.ring(C.polynomial(p, n)) for n in C.degrees(p)} else: self.nodes = {} def polynomial(self, n): r""" Return the pseudo-Conway polynomial of degree `n` in this lattice. INPUT: - ``n`` -- positive integer OUTPUT: - a pseudo-Conway polynomial of degree `n` for the prime `p`. ALGORITHM: Uses an algorithm described in [HL99]_, modified to find pseudo-Conway polynomials rather than Conway polynomials. The major difference is that we stop as soon as we find a primitive polynomial. REFERENCE: .. [HL99] \L. Heath and N. Loehr (1999). New algorithms for generating Conway polynomials over finite fields. Proceedings of the tenth annual ACM-SIAM symposium on discrete algorithms, pp. 429-437. EXAMPLES:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.polynomial(3) x^3 + x + 1 sage: PCL.polynomial(4) x^4 + x^3 + 1 sage: PCL.polynomial(60) x^60 + x^59 + x^58 + x^55 + x^54 + x^53 + x^52 + x^51 + x^48 + x^46 + x^45 + x^42 + x^41 + x^39 + x^38 + x^37 + x^35 + x^32 + x^31 + x^30 + x^28 + x^24 + x^22 + x^21 + x^18 + x^17 + x^16 + x^15 + x^14 + x^10 + x^8 + x^7 + x^5 + x^3 + x^2 + x + 1 """ if n in self.nodes: return self.nodes[n] p = self.p n = Integer(n) if n == 1: f = self.ring.gen() - FiniteField(p).multiplicative_generator() self.nodes[1] = f return f # Work in an arbitrary field K of order p**n. K = FiniteField(p**n, names='a') # TODO: something like the following # gcds = [n.gcd(d) for d in self.nodes.keys()] # xi = { m: (...) for m in gcds } xi = {q: self.polynomial(n//q).any_root(K, -n//q, assume_squarefree=True) for q in n.prime_divisors()} # The following is needed to ensure that in the concrete instantiation # of the "new" extension all previous choices are compatible. _frobenius_shift(K, xi) # Construct a compatible element having order the lcm of orders q, x = xi.popitem() v = p**(n//q) - 1 for q, xitem in six.iteritems(xi): w = p**(n//q) - 1 g, alpha, beta = v.xgcd(w) x = x**beta * xitem**alpha v = v.lcm(w) r = p**n - 1 # Get the missing part of the order to be primitive g = r // v # Iterate through g-th roots of x until a primitive one is found z = x.nth_root(g) root = K.multiplicative_generator()**v while z.multiplicative_order() != r: z *= root # The following should work but tries to create a huge list # whose length overflows Python's ints for large parameters #Z = x.nth_root(g, all=True) #for z in Z: # if z.multiplicative_order() == r: # break f = z.minimal_polynomial() self.nodes[n] = f return f def check_consistency(self, n): """ Check that the pseudo-Conway polynomials of degree dividing `n` in this lattice satisfy the required compatibility conditions. EXAMPLES:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.check_consistency(6) sage: PCL.check_consistency(60) # long time """ p = self.p K = FiniteField(p**n, modulus = self.polynomial(n), names='a') a = K.gen() for m in n.divisors(): assert (a**((p**n-1)//(p**m-1))).minimal_polynomial() == self.polynomial(m)
def epsinv(F, target, prec=53, target_tol=0.001, z=None, emb=None): """ Compute a bound on the hyperbolic distance. The true minimum will be within the computed bound. It is computed as the inverse of epsilon_F from [HS2018]_. INPUT: - ``F`` -- binary form of degree at least 3 with no multiple roots - ``target`` -- positive real number. The value we want to attain, i.e., the value we are taking the inverse of - ``prec``-- positive integer. precision to use in CC - ``target_tol`` -- positive real number. The tolerance with which we attain the target value. - ``z`` -- complex number. ``z_0`` covariant for F. - ``emb`` -- embedding into CC OUTPUT: a real number delta satisfying target + target_tol > eps_F(delta) > target. EXAMPLES:: sage: from sage.rings.polynomial.binary_form_reduce import epsinv sage: R.<x,y> = QQ[] sage: epsinv(-2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3, 31.5022020249597) # tol 1e-12 4.02520895942207 """ def coshdelta(z): #The cosh of the hyperbolic distance from z = t+uj to j return (z.norm() + 1) / (2 * z.imag()) def RQ(delta): # this is the quotient R(F_0,z)/R(F_0,z(F)) for a generic z # at distance delta from j. See Lemma 4.2 in [HS2018]. cd = cosh(delta).n(prec=prec) sd = sinh(delta).n(prec=prec) return prod( [cd + (cost * phi[0] + sint * phi[1]) * sd for phi in phis]) def epsF(delta): pol = RQ(delta) #get R quotient in terms of z S = PolynomialRing(C, 'v') g = S([(i - d) * pol[i - d] for i in range(2 * d + 1)]) # take derivative drts = [ e for e in g.roots(ring=C, multiplicities=False) if (e.norm() - 1).abs() < 0.1 ] # find min return min([pol(r / r.abs()).real() for r in drts]) C = ComplexField(prec=prec) R = F.parent() d = F.degree() if z is None: z, th = covariant_z0(F, prec=prec, emb=emb) else: #need to do our own input checking if R.ngens() != 2 or any(sum(t) != d for t in F.exponents()): raise TypeError('must be a binary form') if d < 3: raise ValueError('must be at least degree 3') f = F.subs({R.gen(1): 1}).univariate_polynomial() #now we have a single variable polynomial if (max([ex for p,ex in f.roots(ring=C)]) >= QQ(d)/2)\ or (f.degree() < QQ(d)/2): raise ValueError('cannot have root with multiplicity >= deg(F)/2') R = RealField(prec=prec) PR = PolynomialRing(R, 't') t = PR.gen(0) # compute phi_1, ..., phi_k # first find F_0 and its roots # this change of variables on f moves z(f) to j, i.e. produces F_0 rts = f(z.imag() * t + z.real()).roots(ring=C) phis = [] # stereographic projection of roots for r, e in rts: phis.extend( [[2 * r.real() / (r.norm() + 1), (r.norm() - 1) / (r.norm() + 1)]]) if d != f.degree(): # include roots at infinity phis.extend([(d - f.degree()) * [0, 1]]) # for writing RQ in terms of generic z to minimize LC = LaurentSeriesRing(C, 'u', default_prec=2 * d + 2) u = LC.gen(0) cost = (u + u**(-1)) / 2 sint = (u - u**(-1)) / (2 * C.gen(0)) # first find an interval containing the desired value # then use regula falsi on log eps_F # d -> delta value in interval [0,1] # v in value in interval [1,epsF(1)] dl = R(0.0) vl = R(1.0) du = R(1.0) vu = epsF(du) while vu < target: # compute the next value of epsF for delta = 2*delta dl = du vl = vu du *= 2 vu = epsF(du) # now dl < delta <= du logt = target.log() l2 = (vu.log() - logt).n(prec=prec) l1 = (vl.log() - logt).n(prec=prec) dn = (dl * l2 - du * l1) / (l2 - l1) vn = epsF(dn) dl = du vl = vu du = dn vu = vn while (du - dl).abs() >= target_tol or max(vl, vu) < target: l2 = (vu.log() - logt).n(prec=prec) l1 = (vl.log() - logt).n(prec=prec) dn = (dl * l2 - du * l1) / (l2 - l1) vn = epsF(dn) dl = du vl = vu du = dn vu = vn return max(dl, du)
def permanental_minor_polynomial(A, permanent_only=False, var='t', prec=None): r""" Return the polynomial of the sums of permanental minors of ``A``. INPUT: - `A` -- a matrix - `permanent_only` -- if True, return only the permanent of `A` - `var` -- name of the polynomial variable - `prec` -- if prec is not None, truncate the polynomial at precision `prec` The polynomial of the sums of permanental minors is .. MATH:: \sum_{i=0}^{min(nrows, ncols)} p_i(A) x^i where `p_i(A)` is the `i`-th permanental minor of `A` (that can also be obtained through the method :meth:`~sage.matrix.matrix2.Matrix.permanental_minor` via ``A.permanental_minor(i)``). The algorithm implemented by that function has been developed by P. Butera and M. Pernici, see [ButPer]. Its complexity is `O(2^n m^2 n)` where `m` and `n` are the number of rows and columns of `A`. Moreover, if `A` is a banded matrix with width `w`, that is `A_{ij}=0` for `|i - j| > w` and `w < n/2`, then the complexity of the algorithm is `O(4^w (w+1) n^2)`. INPUT: - ``A`` -- matrix - ``permanent_only`` -- optional boolean. If ``True``, only the permanent is computed (might be faster). - ``var`` -- a variable name EXAMPLES:: sage: from sage.matrix.matrix_misc import permanental_minor_polynomial sage: m = matrix([[1,1],[1,2]]) sage: permanental_minor_polynomial(m) 3*t^2 + 5*t + 1 sage: permanental_minor_polynomial(m, permanent_only=True) 3 sage: permanental_minor_polynomial(m, prec=2) 5*t + 1 :: sage: M = MatrixSpace(ZZ,4,4) sage: A = M([1,0,1,0,1,0,1,0,1,0,10,10,1,0,1,1]) sage: permanental_minor_polynomial(A) 84*t^3 + 114*t^2 + 28*t + 1 sage: [A.permanental_minor(i) for i in range(5)] [1, 28, 114, 84, 0] An example over `\QQ`:: sage: M = MatrixSpace(QQ,2,2) sage: A = M([1/5,2/7,3/2,4/5]) sage: permanental_minor_polynomial(A, True) 103/175 An example with polynomial coefficients:: sage: R.<a> = PolynomialRing(ZZ) sage: A = MatrixSpace(R,2)([[a,1], [a,a+1]]) sage: permanental_minor_polynomial(A, True) a^2 + 2*a A usage of the ``var`` argument:: sage: m = matrix(ZZ,4,[0,1,2,3,1,2,3,0,2,3,0,1,3,0,1,2]) sage: permanental_minor_polynomial(m, var='x') 164*x^4 + 384*x^3 + 172*x^2 + 24*x + 1 ALGORITHM: The permanent `perm(A)` of a `n \times n` matrix `A` is the coefficient of the `x_1 x_2 \ldots x_n` monomial in .. MATH:: \prod_{i=1}^n \left( \sum_{j=1}^n A_{ij} x_j \right) Evaluating this product one can neglect `x_i^2`, that is `x_i` can be considered to be nilpotent of order `2`. To formalize this procedure, consider the algebra `R = K[\eta_1, \eta_2, \ldots, \eta_n]` where the `\eta_i` are commuting, nilpotent of order `2` (i.e. `\eta_i^2 = 0`). Formally it is the quotient ring of the polynomial ring in `\eta_1, \eta_2, \ldots, \eta_n` quotiented by the ideal generated by the `\eta_i^2`. We will mostly consider the ring `R[t]` of polynomials over `R`. We denote a generic element of `R[t]` by `p(\eta_1, \ldots, \eta_n)` or `p(\eta_{i_1}, \ldots, \eta_{i_k})` if we want to emphasize that some monomials in the `\eta_i` are missing. Introduce an "integration" operation `\langle p \rangle` over `R` and `R[t]` consisting in the sum of the coefficients of the non-vanishing monomials in `\eta_i` (i.e. the result of setting all variables `\eta_i` to `1`). Let us emphasize that this is *not* a morphism of algebras as `\langle \eta_1 \rangle^2 = 1` while `\langle \eta_1^2 \rangle = 0`! Let us consider an example of computation. Let `p_1 = 1 + t \eta_1 + t \eta_2` and `p_2 = 1 + t \eta_1 + t \eta_3`. Then .. MATH:: p_1 p_2 = 1 + 2t \eta_1 + t (\eta_2 + \eta_3) + t^2 (\eta_1 \eta_2 + \eta_1 \eta_3 + \eta_2 \eta_3) and .. MATH:: \langle p_1 p_2 \rangle = 1 + 4t + 3t^2 In this formalism, the permanent is just .. MATH:: perm(A) = \langle \prod_{i=1}^n \sum_{j=1}^n A_{ij} \eta_j \rangle A useful property of `\langle . \rangle` which makes this algorithm efficient for band matrices is the following: let `p_1(\eta_1, \ldots, \eta_n)` and `p_2(\eta_j, \ldots, \eta_n)` be polynomials in `R[t]` where `j \ge 1`. Then one has .. MATH:: \langle p_1(\eta_1, \ldots, \eta_n) p_2 \rangle = \langle p_1(1, \ldots, 1, \eta_j, \ldots, \eta_n) p_2 \rangle where `\eta_1,..,\eta_{j-1}` are replaced by `1` in `p_1`. Informally, we can "integrate" these variables *before* performing the product. More generally, if a monomial `\eta_i` is missing in one of the terms of a product of two terms, then it can be integrated in the other term. Now let us consider an `m \times n` matrix with `m \leq n`. The *sum of permanental `k`-minors of `A`* is .. MATH:: perm(A, k) = \sum_{r,c} perm(A_{r,c}) where the sum is over the `k`-subsets `r` of rows and `k`-subsets `c` of columns and `A_{r,c}` is the submatrix obtained from `A` by keeping only the rows `r` and columns `c`. Of course `perm(A, \min(m,n)) = perm(A)` and note that `perm(A,1)` is just the sum of all entries of the matrix. The generating function of these sums of permanental minors is .. MATH:: g(t) = \left\langle \prod_{i=1}^m \left(1 + t \sum_{j=1}^n A_{ij} \eta_j\right) \right\rangle In fact the `t^k` coefficient of `g(t)` corresponds to choosing `k` rows of `A`; `\eta_i` is associated to the i-th column; nilpotency avoids having twice the same column in a product of `A`'s. For more details, see the article [ButPer]. From a technical point of view, the product in `K[\eta_1, \ldots, \eta_n][t]` is implemented as a subroutine in :func:`prm_mul`. The indices of the rows and columns actually start at `0`, so the variables are `\eta_0, \ldots, \eta_{n-1}`. Polynomials are represented in dictionary form: to a variable `\eta_i` is associated the key `2^i` (or in Python ``1 << i``). The keys associated to products are obtained by considering the development in base `2`: to the monomial `\eta_{i_1} \ldots \eta_{i_k}` is associated the key `2^{i_1} + \ldots + 2^{i_k}`. So the product `\eta_1 \eta_2` corresponds to the key `6 = (110)_2` while `\eta_0 \eta_3` has key `9 = (1001)_2`. In particular all operations on monomials are implemented via bitwise operations on the keys. REFERENCES: .. [ButPer] \P. Butera and M. Pernici "Sums of permanental minors using Grassmann algebra", :arxiv:`1406.5337` """ if permanent_only: prec = None elif prec is not None: prec = int(prec) if prec == 0: raise ValueError('the argument `prec` must be a positive integer') K = PolynomialRing(A.base_ring(), var) nrows = A.nrows() ncols = A.ncols() A = A.rows() p = {0: K.one()} t = K.gen() vars_to_do = range(ncols) for i in range(nrows): # build the polynomial p1 = 1 + t sum A_{ij} eta_j if permanent_only: p1 = {} else: p1 = {0: K.one()} a = A[i] # the i-th row of A for j in range(len(a)): if a[j]: p1[1 << j] = a[j] * t # make the product with the preceding polynomials, taking care of # variables that can be integrated mask_free = 0 j = 0 while j < len(vars_to_do): jj = vars_to_do[j] if all(A[k][jj] == 0 for k in range(i + 1, nrows)): mask_free += 1 << jj vars_to_do.remove(jj) else: j += 1 p = prm_mul(p, p1, mask_free, prec) if not p: return K.zero() if len(p) != 1 or 0 not in p: raise RuntimeError( "Something is wrong! Certainly a problem in the" " algorithm... please contact [email protected]") p = p[0] return p[min(nrows, ncols)] if permanent_only else p
def BCHCode(n,delta,F,b=0): r""" A 'Bose-Chaudhuri-Hockenghem code' (or BCH code for short) is the largest possible cyclic code of length n over field F=GF(q), whose generator polynomial has zeros (which contain the set) `Z = \{a^{b},a^{b+1}, ..., a^{b+delta-2}\}`, where a is a primitive `n^{th}` root of unity in the splitting field `GF(q^m)`, b is an integer `0\leq b\leq n-delta+1` and m is the multiplicative order of q modulo n. (The integers `b,...,b+delta-2` typically lie in the range `1,...,n-1`.) The integer `delta \geq 1` is called the "designed distance". The length n of the code and the size q of the base field must be relatively prime. The generator polynomial is equal to the least common multiple of the minimal polynomials of the elements of the set `Z` above. Special cases are b=1 (resulting codes are called 'narrow-sense' BCH codes), and `n=q^m-1` (known as 'primitive' BCH codes). It may happen that several values of delta give rise to the same BCH code. The largest one is called the Bose distance of the code. The true minimum distance, d, of the code is greater than or equal to the Bose distance, so `d\geq delta`. EXAMPLES:: sage: FF.<a> = GF(3^2,"a") sage: x = PolynomialRing(FF,"x").gen() sage: L = [b.minpoly() for b in [a,a^2,a^3]]; g = LCM(L) sage: f = x^(8)-1 sage: g.divides(f) True sage: C = codes.CyclicCode(8,g); C Linear code of length 8, dimension 4 over Finite Field of size 3 sage: C.minimum_distance() 4 sage: C = codes.BCHCode(8,3,GF(3),1); C Linear code of length 8, dimension 4 over Finite Field of size 3 sage: C.minimum_distance() 4 sage: C = codes.BCHCode(8,3,GF(3)); C Linear code of length 8, dimension 5 over Finite Field of size 3 sage: C.minimum_distance() 3 sage: C = codes.BCHCode(26, 5, GF(5), b=1); C Linear code of length 26, dimension 10 over Finite Field of size 5 """ q = F.order() R = IntegerModRing(n) m = R(q).multiplicative_order() FF = GF(q**m,"z") z = FF.gen() e = z.multiplicative_order()/n a = z**e # order n P = PolynomialRing(F,"x") x = P.gen() L1 = [] for coset in R.cyclotomic_cosets(q, range(b,b+delta-1)): L1.extend(P((a**j).minpoly()) for j in coset) g = P(LCM(L1)) #print cosets, "\n", g, "\n", (x**n-1).factor(), "\n", L1, "\n", g.divides(x**n-1) if not(g.divides(x**n-1)): raise ValueError("BCH codes does not exist with the given input.") return CyclicCodeFromGeneratingPolynomial(n,g)
def enumerate_totallyreal_fields_rel(F, m, B, a = [], verbose=0, return_seqs=False, return_pari_objects=True): r""" This function enumerates (primitive) totally real field extensions of degree `m>1` of the totally real field F with discriminant `d \leq B`; optionally one can specify the first few coefficients, where the sequence ``a`` corresponds to a polynomial by :: a[d]*x^n + ... + a[0]*x^(n-d) if ``length(a) = d+1``, so in particular always ``a[d] = 1``. .. note:: This is guaranteed to give all primitive such fields, and seems in practice to give many imprimitive ones. INPUT: - ``F`` -- number field, the base field - ``m`` -- integer, the degree - ``B`` -- integer, the discriminant bound - ``a`` -- list (default: []), the coefficient list to begin with - ``verbose`` -- boolean or nonnegative integer or string (default: 0) give a verbose description of the computations being performed. If ``verbose`` is set to ``2`` or more then it outputs some extra information. If ``verbose`` is a string then it outputs to a file specified by ``verbose`` - ``return_seqs`` -- (boolean, default False) If ``True``, then return the polynomials as sequences (for easier exporting to a file). This also returns a list of four numbers, as explained in the OUTPUT section below. - ``return_pari_objects`` -- (boolean, default: True) if both ``return_seqs`` and ``return_pari_objects`` are ``False`` then it returns the elements as Sage objects; otherwise it returns pari objects. OUTPUT: - the list of fields with entries ``[d,fabs,f]``, where ``d`` is the discriminant, ``fabs`` is an absolute defining polynomial, and ``f`` is a defining polynomial relative to ``F``, sorted by discriminant. - if ``return_seqs`` is ``True``, then the first field of the list is a list containing the count of four items as explained below - the first entry gives the number of polynomials tested - the second entry gives the number of polynomials with its discriminant having a large enough square divisor - the third entry is the number of irreducible polynomials - the fourth entry is the number of irreducible polynomials with discriminant at most ``B`` EXAMPLES:: sage: ZZx = ZZ['x'] sage: F.<t> = NumberField(x^2-2) sage: enumerate_totallyreal_fields_rel(F, 1, 2000) [[1, [-2, 0, 1], xF - 1]] sage: enumerate_totallyreal_fields_rel(F, 2, 2000) [[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]] sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True) [[9, 6, 5, 0], [[1600, [4, 0, -6, 0, 1], [-1, 1, 1]]]] TESTS: Each of the outputs must be elements of Sage if ``return_pari_objects`` is set to ``False``:: sage: enumerate_totallyreal_fields_rel(F, 2, 2000)[0][1].parent() Interface to the PARI C library sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][0].parent() Integer Ring sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][1].parent() Univariate Polynomial Ring in x over Rational Field sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][2].parent() Univariate Polynomial Ring in xF over Number Field in t with defining polynomial x^2 - 2 sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True)[1][0][1][0].parent() Rational Field AUTHORS: - John Voight (2007-11-01) """ if not isinstance(m, Integer): try: m = Integer(m) except TypeError: raise TypeError("cannot coerce m (= %s) to an integer" % m) if (m < 1): raise ValueError("m must be at least 1.") n = F.degree()*m # Initialize S = {} # dictionary of the form {(d, fabs): f, ...} dB_odlyzko = odlyzko_bound_totallyreal(n) dB = math.ceil(40000*dB_odlyzko**n) counts = [0,0,0,0] # Trivial case if m == 1: g = pari(F.defining_polynomial()).polrecip().Vec() if return_seqs: return [[0,0,0,0], [1, [-1, 1], g]] elif return_pari_objects: return [[1, g, pari('xF-1')]] else: Px = PolynomialRing(QQ, 'xF') return [[ZZ(1), [QQ(_) for _ in g], Px.gen()-1]] if verbose: saveout = sys.stdout if isinstance(verbose, str): fsock = open(verbose, 'w') sys.stdout = fsock # Else, print to screen f_out = [0]*m + [1] T = tr_data_rel(F,m,B,a) if verbose == 2: T.incr(f_out,verbose) else: T.incr(f_out) Fx = PolynomialRing(F, 'xF') nfF = pari(str(F.defining_polynomial()).replace('x', str(F.primitive_element()) ) ) parit = pari(str(F.primitive_element())) while f_out[m] != 0: counts[0] += 1 if verbose: print "==>", f_out, f_str = '' for i in range(len(f_out)): f_str += '(' + str(f_out[i]) + ')*x^' + str(i) if i < len(f_out)-1: f_str += '+' nf = pari(f_str) if nf.poldegree('t') == 0: nf = nf.subst('x', 'x-t') nf = nf.polresultant(nfF, parit) d = nf.poldisc() #counts[0] += 1 if d > 0 and nf.polsturm() == n: da = int_has_small_square_divisor(Integer(d)) if d > dB or d <= B*da: counts[1] += 1 if nf.polisirreducible(): counts[2] += 1 [zk,d] = nf.nfbasis_d() if d <= B: if verbose: print "has discriminant", d, # Find a minimal lattice element counts[3] += 1 ng = pari([nf,zk]).polredabs() # Check if K is contained in the list. if (d, ng) in S: if verbose: print "but is not new" else: if verbose: print "and is new!" S[(d, ng)] = Fx(f_out) else: if verbose: print "has discriminant", abs(d), "> B" else: if verbose: print "is not absolutely irreducible" else: if verbose: print "has discriminant", abs(d), "with no large enough square divisor" else: if verbose: if d == 0: print "is not squarefree" else: print "is not totally real" if verbose == 2: T.incr(f_out,verbose=verbose) else: T.incr(f_out) # In the application of Smyth's theorem above, we exclude finitely # many possibilities which we must now throw back in. if m == 2: if Fx([-1,1,1]).is_irreducible(): K = F.extension(Fx([-1,1,1]), 'tK') Kabs = K.absolute_field('tKabs') Kabs_pari = pari(Kabs.defining_polynomial()) d = K.absolute_discriminant() if abs(d) <= B: ng = Kabs_pari.polredabs() S[(d, ng)] = Fx([-1,1,1]) elif F.degree() == 2: for ff in [[1,-7,13,-7,1],[1,-8,14,-7,1]]: f = Fx(ff).factor()[0][0] K = F.extension(f, 'tK') Kabs = K.absolute_field('tKabs') Kabs_pari = pari(Kabs.defining_polynomial()) d = K.absolute_discriminant() if abs(d) <= B: ng = Kabs_pari.polredabs() S[(d, ng)] = f elif m == 3: if Fx([-1,6,-5,1]).is_irreducible(): K = F.extension(Fx([-1,6,-5,1]), 'tK') Kabs = K.absolute_field('tKabs') Kabs_pari = pari(Kabs.defining_polynomial()) d = K.absolute_discriminant() if abs(d) <= B: ng = Kabs_pari.polredabs() S[(d, ng)] = Fx([-1,6,-5,1]) # Convert S to a sorted list of triples [d, fabs, f], taking care # to use cmp() and not the comparison operators on PARI polynomials. S = [[s[0], s[1], t] for s, t in S.items()] S.sort(cmp=lambda x, y: cmp(x[0], y[0]) or cmp(x[1], y[1])) # Now check for isomorphic fields weed_fields(S) # Output. if verbose: print "="*80 print "Polynomials tested: {}".format(counts[0]) print ( "Polynomials with discriminant with large enough square" " divisor: {}".format(counts[1])) print "Irreducible polynomials: {}".format(counts[2]) print "Polynomials with nfdisc <= B: {}".format(counts[3]) for i in range(len(S)): print S[i] if isinstance(verbose, str): fsock.close() sys.stdout = saveout # Make sure to return elements that belong to Sage if return_seqs: return [[ZZ(x) for x in counts], [[s[0], [QQ(x) for x in s[1].polrecip().Vec()], s[2].coefficients(sparse=False)] for s in S] ] elif return_pari_objects: return S else: Px = PolynomialRing(QQ, 'x') return [[s[0], Px([QQ(_) for _ in s[1].list()]), s[2]] for s in S]
def coleman(self,t1,t2,poly = None, E = None,method = 'moments',mult = False,level = 0, branch = 0): r""" If ``self`` is a `p`-adic automorphic form that corresponds to a rigid modular form, then this computes the coleman integral of this form between two points on the boundary `\PP^1(\QQ_p)` of the `p`-adic upper half plane. INPUT: - ``t1``, ``t2`` - elements of `\PP^1(\QQ_p)` (the endpoints of integration) - ``E`` - (Default: None). If specified, will not compute the covering adapted to ``t1`` and ``t2`` and instead use the given one. In that case, ``E`` should be a list of matrices corresponding to edges describing the open balls to be considered. - ``method`` - string (Default: 'moments'). Tells which algorithm to use (alternative is 'riemann_sum', which is unsuitable for computations requiring high precision) - ``mult`` - boolean (Default: False). Whether to use the multiplicative version. - ``poly`` - polynomial (Default: None) - ``level`` - integer (Default: 0) OUTPUT: The result of the coleman integral EXAMPLES:: sage: p = 7 sage: lev = 2 sage: prec = 20 sage: X = BTQuotient(p,lev, use_magma = True) # optional - magma sage: k = 2 # optional - magma sage: M = HarmonicCocycles(X,k,prec) # optional - magma sage: B = M.basis() # optional - magma sage: f = 3*M.decomposition()[0].gen(0) # optional - magma sage: MM = pAutomorphicForms(X,k,prec,overconvergent = True) # optional - magma sage: D = -11 # optional - magma sage: X.is_admissible(D) # optional - magma True sage: K.<a> = QuadraticField(D) # optional - magma sage: CM = X.get_CM_points(D,prec = prec) # optional - magma sage: P = CM[0] # optional - magma sage: Q = P.trace()-P # optional - magma sage: F = MM.lift(f, verbose = False) # long time optional - magma sage: J0 = F.coleman(P,Q,mult = True) # long time optional - magma sage: E = EllipticCurve([1,0,1,4,-6]) # optional - magma sage: T = E.tate_curve(p) # optional - magma sage: xx,yy = getcoords(T,J0,prec) # long time optional -magma sage: P = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); P # long time optional - magma (7/11 : 58/121*a - 9/11 : 1) sage: p = 13 # optional - magma sage: lev = 2 # optional - magma sage: prec = 20 # optional - magma sage: Y = BTQuotient(p,lev, use_magma = True) # optional - magma sage: k = 2 # optional - magma sage: M = HarmonicCocycles(Y,k,prec) # optional - magma sage: B = M.basis() # optional - magma sage: f = M.decomposition()[1].gen(0) # optional - magma sage: g = M.decomposition()[0].gen(0) # optional - magma sage: MM = pAutomorphicForms(Y,k,prec,overconvergent = True) # optional - magma sage: D = -11 # optional - magma sage: Y.is_admissible(D) # optional - magma True sage: K.<a> = QuadraticField(D) # optional - magma sage: CM = Y.get_CM_points(D,prec = prec) # optional - magma sage: P = CM[0] # optional - magma sage: Q = P.trace()-P # optional - magma sage: F = MM.lift(f, verbose = False) # long time optional - magma sage: J11 = F.coleman(P,Q,mult = True) # long time optional - magma sage: E = EllipticCurve('26a2') # optional - magma sage: T = E.tate_curve(p) # optional - magma sage: xx,yy = getcoords(T,J11,prec) # long time optional - magma sage: HP = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); HP # long time optional - magma (-137/11 : 2/121*a + 63/11 : 1) AUTHORS: - Cameron Franc (2012-02-20) - Marc Masdeu (2012-02-20) """ p = self.parent().prime() K = t1.parent() if mult: branch = 0 R = PolynomialRing(K,'x') x = R.gen() R1 = LaurentSeriesRing(K,'r1') r1 = R1.gen() if E is None: E = self.parent()._source._BT.find_covering(t1,t2,level) print 'Got %s open balls.'%len(E) value = K(0) ii = 0 value_exp = K(1) wt = self.parent()._U.weight() dim = self.parent()._U.dimension() if(method == 'riemann_sum'): R1.set_default_prec(wt+1) for e in E: ii += 1 b = e[0,1] d = e[1,1] y = (b-d*t1)/(b-d*t2) pol = R1(y.log(branch = branch)) c_e = self.evaluate(e) new = c_e.evaluate(pol) value += new if mult: value_exp *= K.teichmuller(y)**Integer(c_e[0].rational_reconstruction()) elif method == 'moments': R1.set_default_prec(dim) for e in E: ii += 1 f = (x-t1)/(x-t2) a,b,c,d = e.list() y0 = f((a*r1+b)/(c*r1+d)) pol = y0(0).log(branch = branch)+((y0.derivative()/y0).integral()) if poly is not None: pol *= poly(r1) #((r1-t1)**delta*(r1-t2)**(self.parent()._n-delta)) c_e = self.evaluate(e) new = c_e.evaluate(pol) value += new if mult: base = ((b-d*t1)/(b-d*t2)) pwr = ZZ(c_e[0].rational_reconstruction()) value_exp *= base**pwr else: print 'The available methods are either "moments" or "riemann_sum". The latter is only provided for consistency check, and should not be used in practice.' return False if mult: a = value_exp.valuation(p) print 'a=',a return p**a*K.teichmuller(p**(-a)*value_exp) * value.exp(prec = 2*dim) +O(p**(dim+a)) return value +O(p**(dim+value.valuation(p)))
def coleman(self,t1,t2,E=None,method='moments',mult=False,delta=-1,level=0): r""" If ``self`` is a `p`-adic automorphic form that corresponds to a rigid modular form, then this computes the coleman integral of this form between two points on the boundary `\PP^1(\QQ_p)` of the `p`-adic upper half plane. INPUT: - ``t1``, ``t2`` - elements of `\PP^1(\QQ_p)` (the endpoints of integration) - ``E`` - (Default: None). If specified, will not compute the covering adapted to ``t1`` and ``t2`` and instead use the given one. In that case, ``E`` should be a list of matrices corresponding to edges describing the open balls to be considered. - ``method`` - string (Default: 'moments'). Tells which algorithm to use (alternative is 'riemann_sum', which is unsuitable for computations requiring high precision) - ``mult`` - boolean (Default: False). Whether to use the multiplicative version. - ``delta`` - integer (Default: -1) - ``level`` - integer (Default: 0) OUTPUT: The result of the coleman integral EXAMPLES: This example illustrates ... :: TESTS: :: sage: p = 7 sage: lev = 2 sage: prec = 20 sage: X = BTQuotient(p,lev, use_magma = True) # optional - magma sage: k = 2 # optional - magma sage: M = HarmonicCocycles(X,k,prec) # optional - magma sage: B = M.basis() # optional - magma sage: f = 3*B[0] # optional - magma sage: MM = pAutomorphicForms(X,k,prec,overconvergent=True) # optional - magma sage: D = -11 # optional - magma sage: X.is_admissible(D) # optional - magma True sage: K.<a> = QuadraticField(D) # optional - magma sage: CM = X.get_CM_points(D,prec=prec) # optional - magma sage: Kp = CM[0].parent() # optional - magma sage: P=CM[0] # optional - magma sage: Q=P.trace()-P # optional - magma sage: F=MM.lift(f, verbose = False) # long time optional - magma sage: J0=F.coleman(P,Q,mult=True) # long time optional - magma sage: E=EllipticCurve([1,0,1,4,-6]) # optional - magma sage: T=E.tate_curve(p) # optional - magma sage: xx,yy=getcoords(T,J0,prec) # long time optional -magma sage: P = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); P # long time optional - magma (7/11 : 58/121*a - 9/11 : 1) sage: p = 13 # optional - magma sage: lev = 2 # optional - magma sage: prec = 20 # optional - magma sage: Y = BTQuotient(p,lev, use_magma = True) # optional - magma sage: k = 2 # optional - magma sage: M=HarmonicCocycles(Y,k,prec) # optional - magma sage: B=M.basis() # optional - magma sage: f = B[1] # optional - magma sage: g = -4*B[0]+3*B[1] # optional - magma sage: MM = pAutomorphicForms(Y,k,prec,overconvergent=True) # optional - magma sage: D = -11 # optional - magma sage: Y.is_admissible(D) # optional - magma True sage: K.<a> = QuadraticField(D) # optional - magma sage: CM = Y.get_CM_points(D,prec=prec) # optional - magma sage: Kp = parent(CM[0]) # optional - magma sage: P = CM[0] # optional - magma sage: Q = P.trace()-P # optional - magma sage: F = MM.lift(f, verbose = False) # long time optional - magma sage: J11 = F.coleman(P,Q,mult = True) # long time optional - magma sage: E = EllipticCurve('26a2') # optional - magma sage: T = E.tate_curve(p) # optional - magma sage: xx,yy = getcoords(T,J11,prec) # long time optional - magma sage: HP = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); HP # long time optional - magma (-137/11 : 2/121*a + 63/11 : 1) AUTHORS: - Cameron Franc (2012-02-20) - Marc Masdeu (2012-02-20) """ if(mult and delta>=0): raise NotImplementedError, "Need to figure out how to implement the multiplicative part." p=self._parent._X._p K=t1.parent() R=PolynomialRing(K,'x') x=R.gen() R1=LaurentSeriesRing(K,'r1') r1=R1.gen() if(E is None): E=self._parent._X._BT.find_covering(t1,t2) # print 'Got %s open balls.'%len(E) value=0 ii=0 value_exp=K(1) if(method=='riemann_sum'): R1.set_default_prec(self._parent._U.weight()+1) for e in E: ii+=1 b=e[0,1] d=e[1,1] y=(b-d*t1)/(b-d*t2) poly=R1(y.log()) #R1(our_log(y)) c_e=self.evaluate(e) new=c_e.evaluate(poly) value+=new if mult: value_exp *= K.teichmuller(y)**Integer(c_e[0].rational_reconstruction()) elif(method=='moments'): R1.set_default_prec(self._parent._U.dimension()) for e in E: ii+=1 f=(x-t1)/(x-t2) a,b,c,d=e.list() y0=f(R1([b,a])/R1([d,c])) #f( (ax+b)/(cx+d) ) y0=p**(-y0(0).valuation())*y0 mu=K.teichmuller(y0(0)) y=y0/mu-1 poly=R1(0) ypow=y for jj in range(1,R1.default_prec()+10): poly+=(-1)**(jj+1)*ypow/jj ypow*=y if(delta>=0): poly*=((r1-t1)**delta*(r1-t2)**(self._parent._n-delta)) c_e=self.evaluate(e) new=c_e.evaluate(poly) value+=new if mult: value_exp *= K.teichmuller((b-d*t1)/(b-d*t2))**Integer(c_e[0].rational_reconstruction()) else: print 'The available methods are either "moments" or "riemann_sum". The latter is only provided for consistency check, and should not be used in practice.' return False if mult: return value_exp * value.exp() return value
def segre_embedding(self, PP=None): r""" Return the Segre embedding of this subscheme into the appropriate projective space. INPUT: - ``PP`` -- (default: ``None``) ambient image projective space; this is constructed if it is not given. OUTPUT: Hom from this subscheme to the appropriate subscheme of projective space EXAMPLES:: sage: X.<x,y,z,w,u,v> = ProductProjectiveSpaces([2,2], QQ) sage: P = ProjectiveSpace(QQ,8,'t') sage: L = (-w - v)*x + (-w*y - u*z) sage: Q = (-u*w - v^2)*x^2 + ((-w^2 - u*w + (-u*v - u^2))*y + (-w^2 - u*v)*z)*x + \ ((-w^2 - u*w - u^2)*y^2 + (-u*w - v^2)*z*y + (-w^2 + (-v - u)*w)*z^2) sage: W = X.subscheme([L,Q]) sage: phi = W.segre_embedding(P) sage: phi.codomain().ambient_space() == P True :: sage: PP.<x,y,u,v,s,t> = ProductProjectiveSpaces([1,1,1], CC) sage: PP.subscheme([]).segre_embedding() Scheme morphism: From: Closed subscheme of Product of projective spaces P^1 x P^1 x P^1 over Complex Field with 53 bits of precision defined by: (no polynomials) To: Closed subscheme of Projective Space of dimension 7 over Complex Field with 53 bits of precision defined by: -u5*u6 + u4*u7, -u3*u6 + u2*u7, -u3*u4 + u2*u5, -u3*u5 + u1*u7, -u3*u4 + u1*u6, -u3*u4 + u0*u7, -u2*u4 + u0*u6, -u1*u4 + u0*u5, -u1*u2 + u0*u3 Defn: Defined by sending (x : y , u : v , s : t) to (x*u*s : x*u*t : x*v*s : x*v*t : y*u*s : y*u*t : y*v*s : y*v*t). :: sage: PP.<x,y,z,u,v,s,t> = ProductProjectiveSpaces([2,1,1], ZZ) sage: PP.subscheme([x^3, u-v, s^2-t^2]).segre_embedding() Scheme morphism: From: Closed subscheme of Product of projective spaces P^2 x P^1 x P^1 over Integer Ring defined by: x^3, u - v, s^2 - t^2 To: Closed subscheme of Projective Space of dimension 11 over Integer Ring defined by: u10^2 - u11^2, u9 - u11, u8 - u10, -u7*u10 + u6*u11, u6*u10 - u7*u11, u6^2 - u7^2, u5 - u7, u4 - u6, u3^3, -u3*u10 + u2*u11, u2*u10 - u3*u11, -u3*u6 + u2*u7, u2*u6 - u3*u7, u2*u3^2, u2^2 - u3^2, u1 - u3, u0 - u2 Defn: Defined by sending (x : y : z , u : v , s : t) to (x*u*s : x*u*t : x*v*s : x*v*t : y*u*s : y*u*t : y*v*s : y*v*t : z*u*s : z*u*t : z*v*s : z*v*t). """ AS = self.ambient_space() CR = AS.coordinate_ring() N = AS.dimension_relative_components() M = prod([n + 1 for n in N]) - 1 vars = list(AS.coordinate_ring().variable_names()) + [ 'u' + str(i) for i in range(M + 1) ] R = PolynomialRing(AS.base_ring(), AS.ngens() + M + 1, vars, order='lex') #set-up the elimination for the segre embedding mapping = [] k = AS.ngens() index = AS.num_components() * [0] for count in range(M + 1): mapping.append( R.gen(k + count) - prod([CR(AS[i].gen(index[i])) for i in range(len(index))])) for i in range(len(index) - 1, -1, -1): if index[i] == N[i]: index[i] = 0 else: index[i] += 1 break #only increment once #change the defining ideal of the subscheme into the variables I = R.ideal(list(self.defining_polynomials()) + mapping) J = I.groebner_basis() s = set(R.gens()[:AS.ngens()]) n = len(J) - 1 L = [] while s.isdisjoint(J[n].variables()): L.append(J[n]) n = n - 1 #create new subscheme if PP is None: PS = ProjectiveSpace(self.base_ring(), M, R.gens()[AS.ngens():]) Y = PS.subscheme(L) else: if PP.dimension_relative() != M: raise ValueError( "projective space %s must be dimension %s") % (PP, M) S = PP.coordinate_ring() psi = R.hom([0] * k + list(S.gens()), S) L = [psi(l) for l in L] Y = PP.subscheme(L) #create embedding for points mapping = [] index = AS.num_components() * [0] for count in range(M + 1): mapping.append( prod([CR(AS[i].gen(index[i])) for i in range(len(index))])) for i in range(len(index) - 1, -1, -1): if index[i] == N[i]: index[i] = 0 else: index[i] += 1 break #only increment once phi = self.hom(mapping, Y) return phi
def logpp(p, p_prec): """returns the (integral) power series for log_p(1+p*z) -- extra p here!""" SS = PolynomialRing(QQ, 'y') y = SS.gen() return sum([((-1) ** (m - 1)) * ((p * y) ** m) / m for m in range(1, p_prec)])
def _forward_image(self, f, check=True): r""" Compute the forward image of this subscheme by the morphism ``f``. The forward image is computed through elimination and ``f`` must be a morphism for this to be well defined. In particular, let $X = V(h_1,\ldots, h_t)$ and define the ideal $I = (h_1,\ldots,h_t,y_0-f_0(\bar{x}), \ldots, y_n-f_n(\bar{x}))$. Then the elimination ideal $I_{n+1} = I \cap K[y_0,\ldots,y_n]$ is a homogeneous ideal and $self(X) = V(I_{n+1})$. INPUT: - ``f`` -- a map whose domain contains ``self`` - ``check`` -- Boolean, if `False` no input checking is done OUTPUT: - a subscheme in the codomain of ``f``. EXAMPLES:: sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = End(PS) sage: f = H([x^2, y^2-2*z^2, z^2]) sage: X = PS.subscheme(y-2*z) sage: X._forward_image(f) Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: y - 2*z :: sage: set_verbose(None) sage: PS.<x,y,z,w> = ProjectiveSpace(ZZ, 3) sage: H = End(PS) sage: f = H([y^2, x^2, w^2, z^2]) sage: X = PS.subscheme([z^2+y*w, x-w]) sage: f(X) Closed subscheme of Projective Space of dimension 3 over Integer Ring defined by: y - z, x*z - w^2 :: sage: PS.<x,y,z,w> = ProjectiveSpace(CC, 3) sage: H = End(PS) sage: f = H([x^2 + y^2, y^2, z^2-y^2, w^2]) sage: X = PS.subscheme([z-2*w]) sage: f(X) Closed subscheme of Projective Space of dimension 3 over Complex Field with 53 bits of precision defined by: y + z + (-4.00000000000000)*w :: sage: R.<t> = PolynomialRing(QQ) sage: P.<x,y,z> = ProjectiveSpace(FractionField(R), 2) sage: H = End(P) sage: f = H([x^2 + 2*y*z, t^2*y^2, z^2]) sage: f([t^2*y-z]) Closed subscheme of Projective Space of dimension 2 over Fraction Field of Univariate Polynomial Ring in t over Rational Field defined by: y + (-1/t^2)*z :: sage: set_verbose(-1) sage: PS.<x,y,z> = ProjectiveSpace(Qp(3), 2) sage: H = End(PS) sage: f = H([x^2,2*y^2,z^2]) sage: X = PS.subscheme([2*x-y,z]) sage: f(X) Closed subscheme of Projective Space of dimension 2 over 3-adic Field with capped relative precision 20 defined by: z, x + (1 + 3^2 + 3^4 + 3^6 + 3^8 + 3^10 + 3^12 + 3^14 + 3^16 + 3^18 + O(3^20))*y :: sage: R.<y0,y1,y2,y3> = PolynomialRing(QQ) sage: P.<x,y,z> = ProjectiveSpace(FractionField(R), 2) sage: H = End(P) sage: f = H([y0*x^2+y1*z^2, y2*y^2+y3*z^2, z^2]) sage: X = P.subscheme(x*z) sage: X._forward_image(f) Closed subscheme of Projective Space of dimension 2 over Fraction Field of Multivariate Polynomial Ring in y0, y1, y2, y3 over Rational Field defined by: x*z + (-y1)*z^2 :: sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) sage: P5.<z0,z1,z2,z3,z4,z5> = ProjectiveSpace(QQ, 5) sage: H = Hom(P2, P5) sage: f = H([x^2,x*y,x*z,y^2,y*z,z^2]) #Veronese map sage: X = P2.subscheme([]) sage: f(X) Closed subscheme of Projective Space of dimension 5 over Rational Field defined by: -z4^2 + z3*z5, -z2*z4 + z1*z5, -z2*z3 + z1*z4, -z2^2 + z0*z5, -z1*z2 + z0*z4, -z1^2 + z0*z3 :: sage: P2.<x,y,z>=ProjectiveSpace(QQ, 2) sage: P3.<u,v,w,t>=ProjectiveSpace(QQ, 3) sage: H = Hom(P2, P3) sage: X = P2.subscheme([x-y,x-z]) sage: f = H([x^2,y^2,z^2,x*y]) sage: f(X) Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: w - t, v - t, u - t :: sage: P1.<u,v> = ProjectiveSpace(QQ, 1) sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2) sage: H = Hom(P2,P1) sage: f = H([x^2,y*z]) sage: X = P2.subscheme([x-y]) sage: f(X) Traceback (most recent call last): ... TypeError: map must be a morphism :: sage: PS.<x,y,z> = ProjectiveSpace(ZZ, 2) sage: H = End(PS) sage: f = H([x^3, x*y^2, x*z^2]) sage: X = PS.subscheme([x-y]) sage: X._forward_image(f) Traceback (most recent call last): ... TypeError: map must be a morphism :: sage: PS.<x,y,z> = ProjectiveSpace(QQ, 2) sage: P1.<u,v> = ProjectiveSpace(QQ, 1) sage: Y = P1.subscheme([u-v]) sage: H = End(PS) sage: f = H([x^2, y^2, z^2]) sage: Y._forward_image(f) Traceback (most recent call last): ... TypeError: subscheme must be in ambient space of domain of map """ dom = f.domain() codom = f.codomain() if check: if not f.is_morphism(): raise TypeError("map must be a morphism") if self.ambient_space() != dom: raise TypeError( "subscheme must be in ambient space of domain of map") CR_dom = dom.coordinate_ring() CR_codom = codom.coordinate_ring() n = CR_dom.ngens() m = CR_codom.ngens() #can't call eliminate if the base ring is polynomial so we do it ourselves #with a lex ordering R = PolynomialRing(f.base_ring(), n + m, 'tempvar', order='lex') Rvars = R.gens()[0:n] phi = CR_dom.hom(Rvars, R) zero = n * [0] psi = R.hom(zero + list(CR_codom.gens()), CR_codom) #set up ideal L = R.ideal([phi(t) for t in self.defining_polynomials()] + [R.gen(n + i) - phi(f[i]) for i in range(m)]) G = L.groebner_basis() #eliminate newL = [] #get only the elimination ideal portion for i in range(len(G) - 1, 0, -1): v = G[i].variables() if all(Rvars[j] not in v for j in range(n)): newL.append(psi(G[i])) return (codom.subscheme(newL))
def dynatomic_polynomial(self,period): r""" For a map `f:\mathbb{A}^1 \to \mathbb{A}^1` this function computes the (affine) dynatomic polynomial. The dynatomic polynomial is the analog of the cyclotomic polynomial and its roots are the points of formal period `n`. ALGORITHM: Homogenize to a map `f:\mathbb{P}^1 \to \mathbb{P}^1` and compute the dynatomic polynomial there. Then, dehomogenize. INPUT: - ``period`` -- a positive integer or a list/tuple `[m,n]` where `m` is the preperiod and `n` is the period OUTPUT: - If possible, a single variable polynomial in the coordinate ring of ``self``. Otherwise a fraction field element of the coordinate ring of ``self`` EXAMPLES:: sage: A.<x,y>=AffineSpace(QQ,2) sage: H=Hom(A,A) sage: f=H([x^2+y^2,y^2]) sage: f.dynatomic_polynomial(2) Traceback (most recent call last): ... TypeError: Does not make sense in dimension >1 :: sage: A.<x>=AffineSpace(ZZ,1) sage: H=Hom(A,A) sage: f=H([(x^2+1)/x]) sage: f.dynatomic_polynomial(4) 2*x^12 + 18*x^10 + 57*x^8 + 79*x^6 + 48*x^4 + 12*x^2 + 1 :: sage: A.<x>=AffineSpace(CC,1) sage: H=Hom(A,A) sage: f=H([(x^2+1)/(3*x)]) sage: f.dynatomic_polynomial(3) 13.0000000000000*x^6 + 117.000000000000*x^4 + 78.0000000000000*x^2 + 1.00000000000000 :: sage: A.<x>=AffineSpace(QQ,1) sage: H=Hom(A,A) sage: f=H([x^2-10/9]) sage: f.dynatomic_polynomial([2,1]) 531441*x^4 - 649539*x^2 - 524880 """ if self.domain() != self.codomain(): raise TypeError("Must have same domain and codomain to iterate") from sage.schemes.affine.affine_space import is_AffineSpace if is_AffineSpace(self.domain())==False: raise NotImplementedError("Not implemented for subschemes") if self.domain().dimension_relative()>1: raise TypeError("Does not make sense in dimension >1") F=self.homogenize(1).dynatomic_polynomial(period) if F.denominator()==1: R=F.parent() Vars=list(R.variable_names()) Vars.pop() S=PolynomialRing(R.base_ring(),Vars) phi=R.hom([S.gen(0),1],S) return(phi(F)) else: R=F.numerator().parent() Vars=list(R.variable_names()) Vars.pop() S=PolynomialRing(R.base_ring(),Vars) phi=R.hom([S.gen(0),1],S) return(phi(F.numerator())/phi(F.denominator()))
def markov_chain_transition_matrix(self, action = 'promotion', labeling = 'identity'): r""" Returns the transition matrix of the Markov chain for the action of generalized promotion or tau on ``self`` INPUT: - ``action`` -- 'promotion' or 'tau' (default: 'promotion') - ``labeling`` -- 'identity' or 'source' (default: 'identity') This method yields the transition matrix of the Markov chain defined by the action of the generalized promotion operator `\partial_i` (resp. `\tau_i`) on the set of linear extensions of a finite poset. Here the transition from the linear extension `\pi` to `\pi'`, where `\pi' = \pi \partial_i` (resp. `\pi'= \pi \tau_i`) is counted with weight `x_i` (resp. `x_{\pi_i}` if ``labeling`` is set to ``source``). EXAMPLES:: sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]), linear_extension = True) sage: L = P.linear_extensions() sage: L.markov_chain_transition_matrix() [-x0 - x1 - x2 x2 x0 + x1 0 0] [ x1 + x2 -x0 - x1 - x2 0 x0 0] [ 0 x1 -x0 - x1 0 x0] [ 0 x0 0 -x0 - x1 - x2 x1 + x2] [ x0 0 0 x1 + x2 -x0 - x1 - x2] sage: L.markov_chain_transition_matrix(labeling = 'source') [-x0 - x1 - x2 x3 x0 + x3 0 0] [ x1 + x2 -x0 - x1 - x3 0 x1 0] [ 0 x1 -x0 - x3 0 x1] [ 0 x0 0 -x0 - x1 - x2 x0 + x3] [ x0 0 0 x0 + x2 -x0 - x1 - x3] sage: L.markov_chain_transition_matrix(action = 'tau') [ -x0 - x2 x2 0 x0 0] [ x2 -x0 - x1 - x2 x1 0 x0] [ 0 x1 -x1 0 0] [ x0 0 0 -x0 - x2 x2] [ 0 x0 0 x2 -x0 - x2] sage: L.markov_chain_transition_matrix(action = 'tau', labeling = 'source') [ -x0 - x2 x3 0 x1 0] [ x2 -x0 - x1 - x3 x3 0 x1] [ 0 x1 -x3 0 0] [ x0 0 0 -x1 - x2 x3] [ 0 x0 0 x2 -x1 - x3] .. seealso:: :meth:`markov_chain_digraph`, :meth:`promotion`, :meth:`tau` """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.matrix.constructor import matrix L = self.list() n = self.poset().cardinality() R = PolynomialRing(QQ, 'x', n) x = [R.gen(i) for i in range(n)] l = self.cardinality() M = dict([(i,j),0] for i in range(l) for j in range(l)) if labeling == 'source': for i in range(l): perm = [ self.poset().unwrap(k) for k in L[i] ] for j in range(n-1): p = getattr(L[i], action)(j+1) M[(L.index(p),i)] += x[perm[j]-1] else: for i in range(l): for j in range(n-1): p = getattr(L[i], action)(j+1) M[(L.index(p),i)] += x[j] for i in range(l): M[(i,i)] += -sum(M[(j,i)] for j in range(l)) return matrix(l,l,lambda x,y : M[(x,y)])
def molien_series(self, chi=None, return_series=True, prec=20, variable='t'): r""" Compute the Molien series of this finite group with respect to the character ``chi``. It can be returned either as a rational function in one variable or a power series in one variable. The base field must be a finite field, the rationals, or a cyclotomic field. Note that the base field characteristic cannot divide the group order (i.e., the non-modular case). ALGORITHM: For a finite group `G` in characteristic zero we construct the Molien series as .. MATH:: \frac{1}{|G|}\sum_{g \in G} \frac{\chi(g)}{\text{det}(I-tg)}, where `I` is the identity matrix and `t` an indeterminate. For characteristic `p` not dividing the order of `G`, let `k` be the base field and `N` the order of `G`. Define `\lambda` as a primitive `N`-th root of unity over `k` and `\omega` as a primitive `N`-th root of unity over `\QQ`. For each `g \in G` define `k_i(g)` to be the positive integer such that `e_i = \lambda^{k_i(g)}` for each eigenvalue `e_i` of `g`. Then the Molien series is computed as .. MATH:: \frac{1}{|G|}\sum_{g \in G} \frac{\chi(g)}{\prod_{i=1}^n(1 - t\omega^{k_i(g)})}, where `t` is an indeterminant. [Dec1998]_ INPUT: - ``chi`` -- (default: trivial character) a linear group character of this group - ``return_series`` -- boolean (default: ``True``) if ``True``, then returns the Molien series as a power series, ``False`` as a rational function - ``prec`` -- integer (default: 20); power series default precision - ``variable`` -- string (default: ``'t'``); Variable name for the Molien series OUTPUT: single variable rational function or power series with integer coefficients EXAMPLES:: sage: MatrixGroup(matrix(QQ,2,2,[1,1,0,1])).molien_series() Traceback (most recent call last): ... NotImplementedError: only implemented for finite groups sage: MatrixGroup(matrix(GF(3),2,2,[1,1,0,1])).molien_series() Traceback (most recent call last): ... NotImplementedError: characteristic cannot divide group order Tetrahedral Group:: sage: K.<i> = CyclotomicField(4) sage: Tetra = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [0,i, -i,0]) sage: Tetra.molien_series(prec=30) 1 + t^8 + 2*t^12 + t^16 + 2*t^20 + 3*t^24 + 2*t^28 + O(t^30) sage: mol = Tetra.molien_series(return_series=False); mol (t^8 - t^4 + 1)/(t^16 - t^12 - t^4 + 1) sage: mol.parent() Fraction Field of Univariate Polynomial Ring in t over Integer Ring sage: chi = Tetra.character(Tetra.character_table()[1]) sage: Tetra.molien_series(chi, prec=30, variable='u') u^6 + u^14 + 2*u^18 + u^22 + 2*u^26 + 3*u^30 + 2*u^34 + O(u^36) sage: chi = Tetra.character(Tetra.character_table()[2]) sage: Tetra.molien_series(chi) t^10 + t^14 + t^18 + 2*t^22 + 2*t^26 + O(t^30) :: sage: S3 = MatrixGroup(SymmetricGroup(3)) sage: mol = S3.molien_series(prec=10); mol 1 + t + 2*t^2 + 3*t^3 + 4*t^4 + 5*t^5 + 7*t^6 + 8*t^7 + 10*t^8 + 12*t^9 + O(t^10) sage: mol.parent() Power Series Ring in t over Integer Ring Octahedral Group:: sage: K.<v> = CyclotomicField(8) sage: a = v-v^3 #sqrt(2) sage: i = v^2 sage: Octa = MatrixGroup([(-1+i)/2,(-1+i)/2, (1+i)/2,(-1-i)/2], [(1+i)/a,0, 0,(1-i)/a]) sage: Octa.molien_series(prec=30) 1 + t^8 + t^12 + t^16 + t^18 + t^20 + 2*t^24 + t^26 + t^28 + O(t^30) Icosahedral Group:: sage: K.<v> = CyclotomicField(10) sage: z5 = v^2 sage: i = z5^5 sage: a = 2*z5^3 + 2*z5^2 + 1 #sqrt(5) sage: Ico = MatrixGroup([[z5^3,0, 0,z5^2], [0,1, -1,0], [(z5^4-z5)/a, (z5^2-z5^3)/a, (z5^2-z5^3)/a, -(z5^4-z5)/a]]) sage: Ico.molien_series(prec=40) 1 + t^12 + t^20 + t^24 + t^30 + t^32 + t^36 + O(t^40) :: sage: G = MatrixGroup(CyclicPermutationGroup(3)) sage: chi = G.character(G.character_table()[1]) sage: G.molien_series(chi, prec=10) t + 2*t^2 + 3*t^3 + 5*t^4 + 7*t^5 + 9*t^6 + 12*t^7 + 15*t^8 + 18*t^9 + 22*t^10 + O(t^11) :: sage: K = GF(5) sage: S = MatrixGroup(SymmetricGroup(4)) sage: G = MatrixGroup([matrix(K,4,4,[K(y) for u in m.list() for y in u])for m in S.gens()]) sage: G.molien_series(return_series=False) 1/(t^10 - t^9 - t^8 + 2*t^5 - t^2 - t + 1) :: sage: i = GF(7)(3) sage: G = MatrixGroup([[i^3,0,0,-i^3],[i^2,0,0,-i^2]]) sage: chi = G.character(G.character_table()[4]) sage: G.molien_series(chi) 3*t^5 + 6*t^11 + 9*t^17 + 12*t^23 + O(t^25) """ if not self.is_finite(): raise NotImplementedError("only implemented for finite groups") if chi is None: chi = self.trivial_character() M = self.matrix_space() R = FractionField(self.base_ring()) N = self.order() if R.characteristic() == 0: P = PolynomialRing(R, variable) t = P.gen() #it is possible the character is over a larger cyclotomic field K = chi.values()[0].parent() if K.degree() != 1: if R.degree() != 1: L = K.composite_fields(R)[0] else: L = K else: L = R mol = P(0) for g in self: mol += L(chi(g)) / (M.identity_matrix()-t*g.matrix()).det().change_ring(L) elif R.characteristic().divides(N): raise NotImplementedError("characteristic cannot divide group order") else: #char p>0 #find primitive Nth roots of unity over base ring and QQ F = cyclotomic_polynomial(N).change_ring(R) w = F.roots(ring=R.algebraic_closure(), multiplicities=False)[0] #don't need to extend further in this case since the order of #the roots of unity in the character divide the order of the group L = CyclotomicField(N, 'v') v = L.gen() #construct Molien series P = PolynomialRing(L, variable) t = P.gen() mol = P(0) for g in self: #construct Phi phi = L(chi(g)) for e in g.matrix().eigenvalues(): #find power such that w**n = e n = 1 while w**n != e and n < N+1: n += 1 #raise v to that power phi *= (1-t*v**n) mol += P(1)/phi #We know the coefficients will be integers mol = mol.numerator().change_ring(ZZ) / mol.denominator().change_ring(ZZ) #divide by group order mol /= N if return_series: PS = PowerSeriesRing(ZZ, variable, default_prec=prec) return PS(mol) return mol
class PseudoConwayLattice(WithEqualityById, SageObject): r""" A pseudo-Conway lattice over a given finite prime field. The Conway polynomial `f_n` of degree `n` over `\Bold{F}_p` is defined by the following four conditions: - `f_n` is irreducible. - In the quotient field `\Bold{F}_p[x]/(f_n)`, the element `x\bmod f_n` generates the multiplicative group. - The minimal polynomial of `(x\bmod f_n)^{\frac{p^n-1}{p^m-1}}` equals the Conway polynomial `f_m`, for every divisor `m` of `n`. - `f_n` is lexicographically least among all such polynomials, under a certain ordering. The final condition is needed only in order to make the Conway polynomial unique. We define a pseudo-Conway lattice to be any family of polynomials, indexed by the positive integers, satisfying the first three conditions. INPUT: - ``p`` -- prime number - ``use_database`` -- boolean. If ``True``, use actual Conway polynomials whenever they are available in the database. If ``False``, always compute pseudo-Conway polynomials. EXAMPLES:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.polynomial(3) x^3 + x + 1 TESTS:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(3) sage: hash(PCL) # random 8738829832350 sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PseudoConwayLattice(3) == PseudoConwayLattice(3) False sage: PseudoConwayLattice(3) != PseudoConwayLattice(3) True sage: P = PseudoConwayLattice(5) sage: P == P True sage: P != P False """ def __init__(self, p, use_database=True): """ TESTS:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(3) sage: PCL.polynomial(3) x^3 + 2*x + 1 sage: PCL = PseudoConwayLattice(5, use_database=False) sage: PCL.polynomial(12) x^12 + 4*x^11 + 2*x^10 + 4*x^9 + 2*x^8 + 2*x^7 + 4*x^6 + x^5 + 2*x^4 + 2*x^2 + x + 2 sage: PCL.polynomial(6) x^6 + x^5 + 4*x^4 + 3*x^3 + 3*x^2 + 2*x + 2 sage: PCL.polynomial(11) x^11 + x^6 + 3*x^3 + 4*x + 3 """ self.p = p from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing self.ring = PolynomialRing(FiniteField(p), 'x') if use_database: C = sage.databases.conway.ConwayPolynomials() self.nodes = { n: self.ring(C.polynomial(p, n)) for n in C.degrees(p) } else: self.nodes = {} def polynomial(self, n): r""" Return the pseudo-Conway polynomial of degree `n` in this lattice. INPUT: - ``n`` -- positive integer OUTPUT: - a pseudo-Conway polynomial of degree `n` for the prime `p`. ALGORITHM: Uses an algorithm described in [HL1999]_, modified to find pseudo-Conway polynomials rather than Conway polynomials. The major difference is that we stop as soon as we find a primitive polynomial. EXAMPLES:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.polynomial(3) x^3 + x + 1 sage: PCL.polynomial(4) x^4 + x^3 + 1 sage: PCL.polynomial(60) x^60 + x^59 + x^58 + x^55 + x^54 + x^53 + x^52 + x^51 + x^48 + x^46 + x^45 + x^42 + x^41 + x^39 + x^38 + x^37 + x^35 + x^32 + x^31 + x^30 + x^28 + x^24 + x^22 + x^21 + x^18 + x^17 + x^16 + x^15 + x^14 + x^10 + x^8 + x^7 + x^5 + x^3 + x^2 + x + 1 """ if n in self.nodes: return self.nodes[n] p = self.p n = Integer(n) if n == 1: f = self.ring.gen() - FiniteField(p).multiplicative_generator() self.nodes[1] = f return f # Work in an arbitrary field K of order p**n. K = FiniteField(p**n, names='a') # TODO: something like the following # gcds = [n.gcd(d) for d in self.nodes.keys()] # xi = { m: (...) for m in gcds } xi = { q: self.polynomial(n // q).any_root(K, -n // q, assume_squarefree=True) for q in n.prime_divisors() } # The following is needed to ensure that in the concrete instantiation # of the "new" extension all previous choices are compatible. _frobenius_shift(K, xi) # Construct a compatible element having order the lcm of orders q, x = xi.popitem() v = p**(n // q) - 1 for q, xitem in xi.items(): w = p**(n // q) - 1 g, alpha, beta = v.xgcd(w) x = x**beta * xitem**alpha v = v.lcm(w) r = p**n - 1 # Get the missing part of the order to be primitive g = r // v # Iterate through g-th roots of x until a primitive one is found z = x.nth_root(g) root = K.multiplicative_generator()**v while z.multiplicative_order() != r: z *= root # The following should work but tries to create a huge list # whose length overflows Python's ints for large parameters #Z = x.nth_root(g, all=True) #for z in Z: # if z.multiplicative_order() == r: # break f = z.minimal_polynomial() self.nodes[n] = f return f def check_consistency(self, n): """ Check that the pseudo-Conway polynomials of degree dividing `n` in this lattice satisfy the required compatibility conditions. EXAMPLES:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.check_consistency(6) sage: PCL.check_consistency(60) # long time """ p = self.p K = FiniteField(p**n, modulus=self.polynomial(n), names='a') a = K.gen() for m in n.divisors(): assert (a**((p**n - 1) // (p**m - 1))).minimal_polynomial() == self.polynomial(m)
def Min(Fun, p, ubRes, conj, all_orbits=False): r""" Local loop for Affine_minimal, where we check minimality at the prime p. First we bound the possible k in our transformations A = zp^k + b. See Theorems 3.3.2 and 3.3.3 in [Molnar]_. INPUT: - ``Fun`` -- a dynamical system on projective space - ``p`` - a prime - ``ubRes`` -- integer, the upper bound needed for Th. 3.3.3 in [Molnar]_ - ``conj`` -- a 2x2 matrix keeping track of the conjugation - ``all_orbits`` -- boolean; whether or not to use ``==`` in the inequalities to find all orbits OUTPUT: - boolean -- ``True`` if ``Fun`` is minimal at ``p``, ``False`` otherwise - a dynamical system on projective space minimal at ``p`` EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([149*x^2 + 39*x*y + y^2, -8*x^2 + 137*x*y + 33*y^2]) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import Min sage: Min(f, 3, -27000000, matrix(QQ,[[1, 0],[0, 1]])) [ Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (157*x^2 + 72*x*y + 3*y^2 : -24*x^2 + 121*x*y + 54*y^2) , <BLANKLINE> [3 1] [0 1] ] """ d = Fun.degree() AffFun = Fun.dehomogenize(1) R = AffFun.coordinate_ring() if R.is_field(): #want the polynomial ring not the fraction field R = R.ring() F = R(AffFun[0].numerator()) G = R(AffFun[0].denominator()) dG = G.degree() # all_orbits scales bounds for >= and <= if searching for orbits instead of min model if dG > (d+1)/2: lowerBound = (-2*(G[dG]).valuation(p)/(2*dG - d + 1) + 1).floor() - int(all_orbits) else: lowerBound = (-2*(F[d]).valuation(p)/(d-1) + 1).floor() - int(all_orbits) upperBound = 2*(ubRes.valuation(p)) + int(all_orbits) if upperBound < lowerBound: # There are no possible transformations to reduce the resultant. if not all_orbits: return [Fun, conj] return [] # Looping over each possible k, we search for transformations to reduce # the resultant of F/G all_found = [] k = lowerBound Qb = PolynomialRing(QQ,'b') b = Qb.gen(0) Q = PolynomialRing(Qb,'z') z = Q.gen(0) while k <= upperBound: A = (p**k)*z + b Ft = Q(F(A) - b*G(A)) Gt = Q((p**k)*G(A)) Fcoeffs = Ft.coefficients(sparse=False) Gcoeffs = Gt.coefficients(sparse=False) coeffs = Fcoeffs + Gcoeffs RHS = (d + 1) * k / 2 # If there is some b such that Res(phi^A) < Res(phi), we must have # ord_p(c) > RHS for each c in coeffs. # Make sure constant coefficients in coeffs satisfy the inequality. if all(QQ(c).valuation(p) > RHS - int(all_orbits) for c in coeffs if c.degree() == 0): # Constant coefficients in coeffs have large enough valuation, so # check the rest. We start by checking if simply picking b=0 works. if all(c(0).valuation(p) > RHS - int(all_orbits) for c in coeffs): # A = z*p^k satisfies the inequalities, and F/G is not minimal # "Conjugating by", p,"^", k, "*z +", 0 newconj = matrix(QQ, 2, 2, [p**k, 0, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: return [minFun, conj*newconj] all_found.append([p, k, 0]) # Otherwise we search if any value of b will work. We start by # finding a minimum bound on the valuation of b that is necessary. # See Theorem 3.3.5 in [Molnar, M.Sc. thesis]. bval = max(bCheck(coeff, RHS, p, b) for coeff in coeffs if coeff.degree() > 0) # We scale the coefficients in coeffs, so that we may assume # ord_p(b) is at least 0 scaledCoeffs = [coeff(b*(p**bval)) for coeff in coeffs] # We now scale the inequalities, ord_p(coeff) > RHS, so that # coeff is in ZZ[b] scale = QQ(max(coeff.denominator() for coeff in scaledCoeffs)) normalizedCoeffs = [coeff * scale for coeff in scaledCoeffs] scaleRHS = RHS + scale.valuation(p) # We now search for integers that satisfy the inequality # ord_p(coeff) > RHS. See Lemma 3.3.6 in [Molnar, M.Sc. thesis]. bound = (scaleRHS + 1 - int(all_orbits)).floor() all_blift = blift(normalizedCoeffs, bound, p, k, all_orbits=all_orbits) # If bool is true after lifting, we have a solution b, and F/G # is not minimal. for boolval, sol in all_blift: if boolval: #Rescale, conjugate and return new map bsol = QQ(sol * (p**bval)) #only add 'minimal orbit element' while bsol.abs() >= p**k: if bsol < 0: bsol += p**k else: bsol -= p**k #"Conjugating by ", p,"^", k, "*z +", bsol newconj = matrix(QQ, 2, 2, [p**k, bsol, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: return [minFun, conj*newconj] if [p,k,bsol] not in all_found: all_found.append([p, k, bsol]) k = k + 1 if not all_orbits: return [Fun, conj] return all_found