def generator_relations(self, K) : """ An ideal `I` in the attach polynomial ring `R`, such that the ring of modular forms is a quotient of `R / I`. This ideal must be unique for `K`. INPUT: - `K` -- A ring or module; The ring of Fourier coefficients. OUTPUT: An ideal in a polynomial ring. TESTS:: sage: from hermitianmodularforms import * sage: HermitianModularFormD2_Gamma(-3).generator_relations(QQ) Ideal (0) of Multivariate Polynomial Ring in HE4, HE6, HE10, HE12, Hphi9 over Rational Field sage: HermitianModularFormD2_Gamma(-3).generator_relations(GF(2)) Traceback (most recent call last): ... NotImplementedError: Only Fourier coefficients in a number fields are implemented. """ if self.__D == -3 : if K is QQ or K in NumberFields() : R = PolynomialRing(K, self._generator_names(K)) return R.ideal(0) raise NotImplementedError( "Only Fourier coefficients in a number fields are implemented." ) raise NotImplementedError( "Discriminant %s is not implemented." % (self.__D,) )
class TestHomogeneousWieghts(unittest.TestCase): def setUp(self): self.poly_ring = PolynomialRing(QQ,"x",3); self.x = self.poly_ring.gens()[0]; self.y = self.poly_ring.gens()[1]; self.z = self.poly_ring.gens()[2]; def test_homogenous(self): x = self.x y = self.y z = self.z divisor = x*y*z + x**3 + z**3 wieghts = homogenous_wieghts(divisor) #Test this works with a homogenous divisor self.assertEquals(wieghts,[3,1,1,1]); def test_weighted_homogenous(self): x = self.x y = self.y z = self.z divisor = x**2*y-z**2 wieghts = homogenous_wieghts(divisor) #Test this works with a weighted homogenous divisor self.assertEquals(wieghts,[4,1,2,2]) def test_not_homogenous(self): x = self.x y = self.y z = self.z divisor = x**2*y-x**3 + z +y**2; self.assertRaises(NotWieghtHomogeneousException,homogenous_wieghts,divisor)
class TestMonomialsOfOrder(unittest.TestCase): def setUp(self): self.poly_ring = PolynomialRing(QQ,"x",3); self.x = self.poly_ring.gens()[0]; self.y = self.poly_ring.gens()[1]; self.z = self.poly_ring.gens()[2]; def test_zero(self): mons = [mon for mon in monomials_of_order(0,self.poly_ring,[1,1,1])] self.assertEqual(mons,[self.poly_ring.one()]) def test_homogeneous_3(self): x = self.x; y = self.y; z = self.z; true_mons = Set([x**3,y**3,z**3,x**2*y,x**2*z,y**2*x,y**2*z,z**2*x,z**2*y,x*y*z]) mons = [mon for mon in monomials_of_order(3,self.poly_ring,[1,1,1])] self.assertEqual(true_mons,Set(mons)) def test_non_homogeneous_4(self): x = self.x; y = self.y; z = self.z; true_mons = Set([x**4,x**2*y,x*z,y**2]) mons = [mon for mon in monomials_of_order(4,self.poly_ring,[1,2,3])] self.assertEqual(true_mons,Set(mons))
def automorphy_factor_vector(p, a, c, k, chi, p_prec, var_prec, R): """ EXAMPLES:: sage: from sage.modular.pollack_stevens.families_util import automorphy_factor_vector sage: automorphy_factor_vector(3, 1, 3, 0, None, 4, 3, PowerSeriesRing(ZpCA(3), 'w')) [1 + O(3^20), O(3^21) + (3 + 3^2 + 2*3^3 + O(3^21))*w + (3^2 + 2*3^3 + O(3^22))*w^2, O(3^22) + (3^2 + 2*3^3 + O(3^22))*w + (2*3^2 + O(3^22))*w^2, O(3^22) + (3^2 + 3^3 + O(3^22))*w + (2*3^3 + O(3^23))*w^2] """ S = PolynomialRing(R, 'z') z = S.gens()[0] w = R.gen() aut = S(1) for n in range(1, var_prec): LB = logpp_binom(n, p, p_prec) ta = ZZ(Qp(p, 2 * max(p_prec, var_prec)).teichmuller(a)) arg = (a / ta - 1) / p + c / (p * ta) * z aut += LB(arg) * (w ** n) aut *= (ta ** k) if not (chi is None): aut *= chi(a) aut = aut.list() len_aut = len(aut) if len_aut == p_prec: return aut elif len_aut > p_prec: return aut[:p_prec] return aut + [R.zero_element()] * (p_prec - len_aut)
class TestWeightedMinDegree(unittest.TestCase): def setUp(self): self.poly_ring = PolynomialRing(QQ,"x",3); self.x = self.poly_ring.gens()[0]; self.y = self.poly_ring.gens()[1]; self.z = self.poly_ring.gens()[2]; def test_zero(self): self.assertEqual(wieghted_min_degree(self.poly_ring.zero(),[1,1,1]),0); def test_homogeneous(self): x = self.x; y = self.y; z = self.z; f = x**4 + 4*y*z**3 - z**2; self.assertEqual(wieghted_min_degree(f,[1,1,1]),2); def test_non_homogeneous(self): x = self.x; y = self.y; z = self.z; f = x**4 + 4*y*z**3 - z**2; self.assertEqual(wieghted_min_degree(f,[2,1,2]),4); def test_negative_wieghts(self): x = self.x; y = self.y; z = self.z; f = x**4 + 4*y*z**3 - z**2; self.assertEqual(wieghted_min_degree(f,[-1,-1,1]),-4);
def rand_w_hom_divisor(n,degs=None,mon_num=None,var="z"): if degs==None: degs = [randrange(2,6) for _ in range(n)] deg = sum(degs) if mon_num==None: mon_num = randrange(2,8) poly_ring = PolynomialRing(QQ,n,var) div = poly_ring.zero() min_w = min(degs) for i in range(mon_num): expo = [0]*n cur_deg = 0 while cur_deg!=deg: if cur_deg>deg: expo = [0]*n cur_deg = 0 if deg-cur_deg<min_w: expo = [0]*n cur_deg = 0 next_g = randrange(0,n) expo[next_g] += 1 cur_deg += degs[next_g] coeff = randrange(-n,n)/n mon = poly_ring.one() for i,e in enumerate(expo): mon *= poly_ring.gens()[i]**e div += coeff*mon return div
def quantum_group(self, q=None, c=None): r""" Return the quantum group of ``self``. The corresponding quantum group is the :class:`~sage.algebras.lie_algebras.onsager.QuantumOnsagerAlgebra`. The parameter `c` must be such that `c(1) = 1` INPUT: - ``q`` -- (optional) the quantum parameter; the default is `q \in R(q)`, where `R` is the base ring of ``self`` - ``c`` -- (optional) the parameter `c`; the default is ``q`` EXAMPLES:: sage: O = lie_algebras.OnsagerAlgebra(QQ) sage: Q = O.quantum_group() sage: Q q-Onsager algebra with c=q over Fraction Field of Univariate Polynomial Ring in q over Rational Field """ if q is None: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing q = PolynomialRing(self.base_ring(), 'q').fraction_field().gen() if c is None: c = q else: c = q.parent()(c) return QuantumOnsagerAlgebra(self, q, c)
class TestConvertSymToPoly(unittest.TestCase): def setUp(self): self.poly_ring = PolynomialRing(QQ,"x",3); self.x = self.poly_ring.gens()[0]; self.y = self.poly_ring.gens()[1]; self.z = self.poly_ring.gens()[2]; self.vars = var('x,y,z') def test_zero(self): zero = 0*self.vars[0] poly = convert_symbolic_to_polynomial(zero,self.poly_ring,self.vars) self.assertEqual(poly,self.poly_ring.zero()) def test_convert(self): x = self.x y = self.y z = self.z sym_poly = 4*self.vars[0]**4 + self.vars[1]*self.vars[0]**12*self.vars[1]-self.vars[2] poly = convert_symbolic_to_polynomial(sym_poly,self.poly_ring,self.vars) self.assertEqual(poly,4*x**4+y*x**12*y-z) def test_convert_univarient(self): y = self.y sym_poly = 4*self.vars[1]**4 + self.vars[1]*self.vars[1]**12*self.vars[1]-self.vars[1] poly = convert_symbolic_to_polynomial(sym_poly,self.poly_ring,self.vars) self.assertEqual(poly,4*y**4+y*y**12*y-y) def test_convert_partial(self): y = self.y z = self.z sym_poly = 4*self.vars[2]**4 + self.vars[1]*self.vars[1]**12*self.vars[1]-self.vars[1] poly = convert_symbolic_to_polynomial(sym_poly,self.poly_ring,self.vars) self.assertEqual(poly,4*z**4+y*y**12*y-y)
def genus(self): """ Return the genus of this function field For now, the genus is computed using singular EXAMPLES:: sage: K.<x> = FunctionField(QQ); R.<y> = K[] sage: L.<y> = K.extension(y^3 - (x^3 + 2*x*y + 1/x)) sage: L.genus() 3 """ # unfortunately singular can not compute the genus with the polynomial_ring()._singular_ # object because genus method only accepts a ring of transdental degree 2 over a prime field # not a ring of transdental degree 1 over a rational function field of one variable if is_RationalFunctionField(self._base_field) and self._base_field.constant_field().is_prime_field(): #Making the auxiliary ring which only has polynomials with integral coefficients. tmpAuxRing = PolynomialRing(self._base_field.constant_field(), str(self._base_field.gen())+','+str(self._ring.gen())) intMinPoly, d = self._make_monic_integral(self._polynomial) curveIdeal = tmpAuxRing.ideal(intMinPoly) singular.lib('normal.lib') #loading genus method in singular return int(curveIdeal._singular_().genus()) else: raise NotImplementedError("Computation of genus over this rational function field not implemented yet")
def _roots_univariate_polynomial(self, p, ring=None, multiplicities=None, algorithm=None): r""" Return a list of pairs ``(root,multiplicity)`` of roots of the polynomial ``p``. If the argument ``multiplicities`` is set to ``False`` then return the list of roots. .. SEEALSO:: :meth:`_factor_univariate_polynomial` EXAMPLES:: sage: R.<x> = PolynomialRing(GF(5),'x') sage: K = GF(5).algebraic_closure('t') sage: sorted((x^6 - 1).roots(K,multiplicities=False)) [1, 4, 2*t2 + 1, 2*t2 + 2, 3*t2 + 3, 3*t2 + 4] sage: ((K.gen(2)*x - K.gen(3))**2).roots(K) [(3*t6^5 + 2*t6^4 + 2*t6^2 + 3, 2)] sage: for _ in range(10): ....: p = R.random_element(degree=randint(2,8)) ....: for r in p.roots(K, multiplicities=False): ....: assert p(r).is_zero(), "r={} is not a root of p={}".format(r,p) """ from sage.arith.all import lcm from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing # first build a polynomial over some finite field coeffs = [v.as_finite_field_element(minimal=True) for v in p.list()] l = lcm([c[0].degree() for c in coeffs]) F, phi = self.subfield(l) P = p.parent().change_ring(F) new_coeffs = [self.inclusion(c[0].degree(), l)(c[1]) for c in coeffs] polys = [(g,m,l,phi) for g,m in P(new_coeffs).factor()] roots = [] # a list of pair (root,multiplicity) while polys: g,m,l,phi = polys.pop() if g.degree() == 1: # found a root r = phi(-g.constant_coefficient()) roots.append((r,m)) else: # look at the extension of degree g.degree() which contains at # least one root of g ll = l * g.degree() psi = self.inclusion(l, ll) FF, pphi = self.subfield(ll) # note: there is no coercion from the l-th subfield to the ll-th # subfield. The line below does the conversion manually. g = PolynomialRing(FF, 'x')([psi(_) for _ in g]) polys.extend((gg,m,ll,pphi) for gg,_ in g.factor()) if multiplicities: return roots else: return [r[0] for r in roots]
def whitney_divisor(var=None): if var: poly_ring = PolynomialRing(QQ,3,var) else: poly_ring = PolynomialRing(QQ,3,"xyz") gens = poly_ring.gens() return gens[0]**2*gens[1]-gens[2]**2
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 _interpolate(evaluation, num_of_var, order): if num_of_var == 0 or order == 0: return evaluation[0] base_field = polynomial_ring.base_ring() q = base_field.cardinality() n_by_q = q**(num_of_var - 1) d = min(order + 1, q) multipoint_evaluation_list = [] uni_poly_ring = PolynomialRing(base_field, 'x') base_field_zero = base_field.zero() for k in range(n_by_q): iterator = iter(base_field) points = [] for i in range(d): xcoordinate = next(iterator) points.append((xcoordinate, evaluation[k + i * n_by_q])) polyVector = uni_poly_ring.lagrange_polynomial( points).coefficients(sparse=False) if len(polyVector) < d: # adding zeros to represet a (d-1) degree polynomial polyVector += [base_field_zero] * (d - len(polyVector)) multipoint_evaluation_list.append(polyVector) poly = polynomial_ring.zero() z = 1 x = polynomial_ring.gen(num_of_var - 1) for k in range(d): # computing the polynomial poly = poly + z * _interpolate([multipoint_evaluation_list[i][k] for i in range(n_by_q)], num_of_var - 1, order - k) z *= x return poly
def braid_divisor(n,var="z"): poly_ring = PolynomialRing(QQ,n,var) div = poly_ring.one() gens = poly_ring.gens() for i in range(n): for j in range(i+1,n): div *= (gens[i]-gens[j]) return div
def breiskorn_pham_divisor(n,var="z"): poly_ring = PolynomialRing(QQ,n,var) for i,g in enumerate(poly_ring.gens()): if i==0: div = g**3 else: div += g**2 return div
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 eu(p): """ local euler factor """ f = rho.local_factor(p) co = [ZZ(round(x)) for x in f.coeffs()] R = PolynomialRing(QQ, "T") T = R.gens()[0] return sum( co[n] * T**n for n in range(len(co)))
def test_p_module_n_crossing(self): #Make sure this doesnt throw an error - fix bug for i in range(4,5): p_ring = PolynomialRing(QQ,i,"z") crossing = p_ring.one() for g in p_ring.gens(): crossing *= g logdf = LogarithmicDifferentialForms(crossing) logdf.p_module(i-1)
def BezoutianQuadraticForm(f, g): r""" Compute the Bezoutian of two polynomials defined over a common base ring. This is defined by .. MATH:: {\rm Bez}(f, g) := \frac{f(x) g(y) - f(y) g(x)}{y - x} and has size defined by the maximum of the degrees of `f` and `g`. INPUT: - `f`, `g` -- polynomials in `R[x]`, for some ring `R` OUTPUT: a quadratic form over `R` EXAMPLES:: sage: R = PolynomialRing(ZZ, 'x') sage: f = R([1,2,3]) sage: g = R([2,5]) sage: Q = BezoutianQuadraticForm(f, g) ; Q Quadratic form in 2 variables over Integer Ring with coefficients: [ 1 -12 ] [ * -15 ] AUTHORS: - Fernando Rodriguez-Villegas, Jonathan Hanke -- added on 11/9/2008 """ ## Check that f and g are polynomials with a common base ring if not is_Polynomial(f) or not is_Polynomial(g): raise TypeError("Oops! One of your inputs is not a polynomial. =(") if f.base_ring() != g.base_ring(): ## TO DO: Change this to allow coercion! raise TypeError("Oops! These polynomials are not defined over the same coefficient ring.") ## Initialize the quadratic form R = f.base_ring() P = PolynomialRing(R, ['x','y']) a, b = P.gens() n = max(f.degree(), g.degree()) Q = QuadraticForm(R, n) ## Set the coefficients of Bezoutian bez_poly = (f(a) * g(b) - f(b) * g(a)) // (b - a) ## Truncated (exact) division here for i in range(n): for j in range(i, n): if i == j: Q[i,j] = bez_poly.coefficient({a:i,b:j}) else: Q[i,j] = bez_poly.coefficient({a:i,b:j}) * 2 return Q
def _eta_relations_helper(eta1, eta2, degree, qexp_terms, labels, verbose): r""" Helper function used by eta_poly_relations. Finds a basis for the space of linear relations between the first qexp_terms of the `q`-expansions of the monomials `\eta_1^i * \eta_2^j` for `0 \le i,j < degree`, and calculates a Groebner basis for the ideal generated by these relations. Liable to return meaningless results if qexp_terms isn't at least `1 + d*(m_1,m_2)` where .. math:: m_i = min(0, {\text degree of the pole of $\eta_i$ at $\infty$}) as then 1 will be in the ideal. EXAMPLE:: sage: from sage.modular.etaproducts import _eta_relations_helper sage: r,s = EtaGroup(4).basis() sage: _eta_relations_helper(r,s,4,100,['a','b'],False) [a*b - a + 16] sage: _eta_relations_helper(EtaProduct(26, {2:2,13:2,26:-2,1:-2}),EtaProduct(26, {2:4,13:2,26:-4,1:-2}),3,12,['a','b'],False) # not enough terms, will return rubbish [1] """ indices = [(i,j) for j in range(degree) for i in range(degree)] inf = CuspFamily(eta1.level(), 1) pole_at_infinity = -(min([0, eta1.order_at_cusp(inf)]) + min([0,eta2.order_at_cusp(inf)]))*degree if verbose: print "Trying all coefficients from q^%s to q^%s inclusive" % (-pole_at_infinity, -pole_at_infinity + qexp_terms - 1) rows = [] for j in xrange(qexp_terms): rows.append([]) for i in indices: func = (eta1**i[0]*eta2**i[1]).qexp(qexp_terms) for j in xrange(qexp_terms): rows[j].append(func[j - pole_at_infinity]) M = matrix(rows) V = M.right_kernel() if V.dimension() == 0: if verbose: print "No polynomial relation of order %s valid for %s terms" % (degree, qexp_terms) return None if V.dimension() >= 1: #print "Found relation: " R = PolynomialRing(QQ, 2, labels) x,y = R.gens() relations = [] for c in V.basis(): relations.append(sum( [ c[v] * x**indices[v][0] * y**indices[v][1] for v in xrange(len(indices))])) #print relations[-1], " = 0" id = R.ideal(relations) return id.groebner_basis()
def new_automorphy_factor_vector(p, a, c, k, chi, p_prec, var_prec, R): #if not R.is_capped_relative(): # Rcr = if p_prec > R.precision_cap(): raise ValueError("Specified p-adic precision, p_prec, should be at most that of R.") S = PolynomialRing(R, 'z') z = S.gens()[0] w = R.gen() aut = S(R1, p_prec) ta = R.teichmuller(R(a, p_prec))
def generator_relations(self, K) : r""" An ideal `I` in a polynomial ring `R`, such that the associated ring is `R / I`. This ideal must be unique for `K`. """ if K is QQ or K in NumberFields() : R = PolynomialRing(K, self._generator_names(K)) return R.ideal(0) raise NotImplementedError
def generator_relations(self, K) : r""" An ideal I in a polynomial ring R, such that the associated module is (R / I)_1. """ if K is QQ or K in NumberFields() : R = PolynomialRing(K, self._generator_names(K)) return R.ideal(0) raise NotImplementedError
def _roots_univariate_polynomial(self, p, ring=None, multiplicities=None, algorithm=None): r""" Return a list of pairs ``(root,multiplicity)`` of roots of the polynomial ``p``. If the argument ``multiplicities`` is set to ``False`` then return the list of roots. .. SEEALSO:: :meth:`_factor_univariate_polynomial` EXAMPLES:: sage: R.<x> = PolynomialRing(GF(5),'x') sage: K = GF(5).algebraic_closure('t') sage: sorted((x^6 - 1).roots(K,multiplicities=False)) [1, 4, 2*t2 + 1, 2*t2 + 2, 3*t2 + 3, 3*t2 + 4] sage: ((K.gen(2)*x - K.gen(3))**2).roots(K) [(3*t6^5 + 2*t6^4 + 2*t6^2 + 3, 2)] sage: for _ in xrange(10): ....: p = R.random_element(degree=randint(2,8)) ....: for r in p.roots(K, multiplicities=False): ....: assert p(r).is_zero() """ from sage.rings.arith import lcm from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing # first build a polynomial over some finite field coeffs = [v.as_finite_field_element(minimal=True) for v in p.list()] l = lcm([c[0].degree() for c in coeffs]) F, phi = self.subfield(l) P = p.parent().change_ring(F) new_coeffs = [self.inclusion(c[0].degree(), l)(c[1]) for c in coeffs] roots = [] # a list of pair (root,multiplicity) for g, m in P(new_coeffs).factor(): if g.degree() == 1: r = phi(-g.constant_coefficient()) roots.append((r,m)) else: ll = l * g.degree() psi = self.inclusion(l, ll) FF, pphi = self.subfield(ll) gg = PolynomialRing(FF, 'x')(map(psi, g)) for r, _ in gg.roots(): # note: we know that multiplicity is 1 roots.append((pphi(r), m)) if multiplicities: return roots else: return [r[0] for r in roots]
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 expand(self, n, alphabet='x'): r""" Expands the quasi-symmetric function written in the monomial basis in `n` variables. INPUT: - ``n`` -- an integer - ``alphabet`` -- (default:'x') a string OUTPUT: - The quasi-symmetric function ``self`` expressed in the ``n`` variables described by ``alphabet``. .. TODO:: accept an *alphabet* as input EXAMPLES:: sage: M = QuasiSymmetricFunctions(QQ).Monomial() sage: M[4,2].expand(3) x0^4*x1^2 + x0^4*x2^2 + x1^4*x2^2 One can use a different set of variable by using the optional argument ``alphabet``:: sage: M=QuasiSymmetricFunctions(QQ).Monomial() sage: M[2,1,1].expand(4,alphabet='y') y0^2*y1*y2 + y0^2*y1*y3 + y0^2*y2*y3 + y1^2*y2*y3 TESTS:: sage: (3*M([])).expand(2) 3 sage: M[4,2].expand(0) 0 sage: M([]).expand(0) 1 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing M = self.parent() P = PolynomialRing(M.base_ring(), n, alphabet) x = P.gens() def on_basis(comp, i): if not comp: return P.one() elif len(comp) > i: return P.zero() else: return x[i-1]**comp[-1] * on_basis(comp[:-1], i-1) + \ on_basis(comp, i-1) return M._apply_module_morphism(self, lambda comp: on_basis(comp,n), codomain = P)
def Fourier_coefficients( self, det_list): fcs = DB.find( { 'owner_id': self.__id, 'data_type': 'fc', 'det': { '$in': [ str(d) for d in det_list]} }) P = PolynomialRing( self.__field, names = 'x,y') loc = P.gens_dict() loc.update ( self.__field.gens_dict()) return dict( (Integer(fcd['det']), dict( (tuple( eval(f)), sage_eval( fcd['data'][f], locals = loc)) for f in fcd['data'] )) for fcd in fcs)
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 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 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 __init__(self, code, polynomial_ring=None): r""" TESTS: If ``code`` is not a Reed-Muller code, an error is raised:: sage: C = codes.random_linear_code(GF(11), 10, 4) sage: codes.encoders.ReedMullerPolynomialEncoder(C) Traceback (most recent call last): ... ValueError: the code has to be a Reed-Muller code If the polynomial ring passed is not according to the requirement (over a different field or different number of variables) then an error is raised:: sage: F=GF(59) sage: R.<x,y,z,w>=F[] sage: C=codes.ReedMullerCode(F, 2, 3) sage: E=codes.encoders.ReedMullerPolynomialEncoder(C, R) Traceback (most recent call last): ... ValueError: The Polynomial ring should be on Finite Field of size 59 and should have 3 variables """ if not (isinstance(code, QAryReedMullerCode) or isinstance(code, BinaryReedMullerCode)): raise ValueError("the code has to be a Reed-Muller code") super(ReedMullerPolynomialEncoder, self).__init__(code) if polynomial_ring is None: self._polynomial_ring = PolynomialRing(code.base_field(), code.number_of_variables(), 'x') else: if (polynomial_ring.base_ring() == code.base_field()) and (len( polynomial_ring.variable_names()) == code.number_of_variables()): self._polynomial_ring = polynomial_ring else: raise ValueError( "The Polynomial ring should be on %s and should have %s variables" % (code.base_field(), code.number_of_variables()))
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
def polynomial_ring(self, names='E2, E4, E6'): r""" Return a multivariate polynomial ring isomorphic to the given graded quasimodular forms ring. In the case of the full modular group, this ring is `R[E_2, E_4, E_6]` where `E_2`, `E_4` and `E_6` have degrees 2, 4 and 6 respectively. INPUT: - ``names`` (str, default: ``'E2, E4, E6'``) -- a list or tuple of names (strings), or a comma separated string. Correspond to the names of the variables. OUTPUT: A multivariate polynomial ring in the variables ``names`` EXAMPLES: sage: QM = QuasiModularForms(1) sage: P.<E2, E4, E6> = QM.polynomial_ring(); P Multivariate Polynomial Ring in E2, E4, E6 over Rational Field sage: E2.degree() 2 sage: E4.degree() 4 sage: E6.degree() 6 sage: P.<x, y, z, w> = QQ[] sage: QM.from_polynomial(x+y+z+w) Traceback (most recent call last): ... ValueError: the number of variables (4) of the given polynomial cannot exceed the number of generators (3) of the quasimodular forms ring """ return PolynomialRing( self.base_ring(), 3, names, order=TermOrder('wdeglex', [ZZ(2), ZZ(4), ZZ(6)]))
def __init__(self, field = None): """ Create a shrinking generator cryptosystem. INPUT: A string monoid over a binary alphabet. OUTPUT: EXAMPLES:: sage: E = ShrinkingGeneratorCryptosystem() sage: E Shrinking generator cryptosystem over Finite Field of size 2 """ if field is None: field = FiniteField(2) if field.cardinality() != 2: raise NotImplementedError("Not yet implemented.") S = BinaryStrings() P = PolynomialRing(field, 'x') SymmetricKeyCryptosystem.__init__(self, S, S, None) self._field = field
def defining_polynomial(self, i, j, u=None): r""" Return the defining polynomial of ``i`` and ``j``. The defining polynomial is given by: .. MATH:: T_{ij}(u) = \delta_{ij} u^{\ell} + \sum_{k=1}^{\ell} t_{ij}^{(k)} u^{\ell-k}. EXAMPLES:: sage: Y = Yangian(QQ, 3, 5) sage: Y.defining_polynomial(3, 2) t(1)[3,2]*u^4 + t(2)[3,2]*u^3 + t(3)[3,2]*u^2 + t(4)[3,2]*u + t(5)[3,2] sage: Y.defining_polynomial(1, 1) u^5 + t(1)[1,1]*u^4 + t(2)[1,1]*u^3 + t(3)[1,1]*u^2 + t(4)[1,1]*u + t(5)[1,1] """ if u is None: u = PolynomialRing(self.base_ring(), 'u').gen(0) ell = self._level return sum(self.gen(k, i, j) * u**(ell - k) for k in range(ell + 1))
def ring(self): """ Create, return and cache a polynomial ring for S-box polynomials. EXAMPLE:: sage: S = mq.SBox(7,6,0,4,2,5,1,3) sage: S.ring() Multivariate Polynomial Ring in x0, x1, x2, y0, y1, y2 over Finite Field of size 2 """ try: return self._ring except AttributeError: pass m = self.m n = self.n X = range(m) Y = range(n) self._ring = PolynomialRing(self._F, m+n, ["x%d"%i for i in X] + ["y%d"%i for i in Y]) return self._ring
def _init_ring(self, term_order): r""" Construct the ambient polynomial ring. INPUT: - ``term_order`` -- string. The order of the variables, for example ``'neglex'`` and ``'degrevlex'``. OUTPUT: A polynomial ring with the given term order. .. NOTE:: Reverse lexicographic ordering is equivalent to negative lexicographic order with the reversed list of variables. We are using the latter in the implementation of the Hosten/Sturmfels algorithm. EXAMPLES:: sage: A = matrix([[1,1,1],[0,1,2]]) sage: IA = ToricIdeal(A) sage: R = IA._init_ring('neglex'); R Multivariate Polynomial Ring in z0, z1, z2 over Rational Field sage: R.term_order() Negative lexicographic term order sage: R.inject_variables() Defining z0, z1, z2 sage: z0 < z1 and z1 < z2 True """ return PolynomialRing(self._base_ring, self._names, self.nvariables(), order=term_order)
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: 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 = 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 cardinality(self): """ Return the cardinality of the point set. OUTPUT: Integer. The number of points. EXAMPLES:: sage: fan = NormalFan(ReflexivePolytope(2, 0)) sage: X.<u,v,w> = ToricVariety(fan, base_ring=GF(7)) sage: Y = X.subscheme(u^3 + v^3 + w^3 + u*v*w) sage: point_set = Y.point_set() sage: list(point_set) [[0 : 1 : 3], [1 : 0 : 3], [1 : 3 : 0], [1 : 1 : 6], [1 : 1 : 4], [1 : 3 : 2], [1 : 3 : 5]] sage: ffe = point_set._enumerator() sage: ffe.cardinality() 7 """ n = 0 for cone, nonzero_coordinates, cokernel in self.ambient.cone_points_iter( ): R = PolynomialRing(self.ambient.ring, cokernel.ngens(), 't') inhomogeneous = self.inhomogeneous_equations( R, nonzero_coordinates, cokernel) for log_t in self.solutions(inhomogeneous, map(range, cokernel.invariants())): n += 1 return n
def eval_method(self, tgt): if utilities.is_QQi(self.Scalars) and isinstance( tgt, ComplexBallField): ZZn = PolynomialRing(ZZ, 'n') re_im = [(ZZn([c.real() for c in pol]), ZZn([c.imag() for c in pol])) for pol in self.coeff] if utilities.has_new_ComplexBall_constructor(): def ev(point): return [ ComplexBall(tgt, re(point), im(point)) for re, im in re_im ] else: def ev(point): return [tgt(re(point), im(point)) for re, im in re_im] else: def ev(point): return [tgt(pol(point)) for pol in self.coeff] return ev
def __init__(self, R, n, r, inert=0): names = ["x%s%s" % (i, j) for i in range(r) for j in range(n)] + [ "theta%s%s" % (i, j) for i in range(inert) for j in range(n) ] P = PolynomialRing(R, n * (r + inert), names) self._n = n self._r = r self._inert = inert vars = P.gens() self._P = P self._R = R self._Q = PolynomialRing(QQ, 'q', r) self._grading_set = cartesian_product([ZZ for i in range(r)]) self._hilbert_parent = PolynomialRing(ZZ, r, 'q') self._vars = matrix([[vars[i * n + j] for j in range(n)] for i in range(r + inert)]) self._X = matrix([[vars[i * n + j] for j in range(n)] for i in range(r)]) self._Theta = matrix([[vars[i * n + j] for j in range(n)] for i in range(r, r + inert)]) Parent.__init__(self, facade=(P, ), category=Algebras(QQ).Commutative())
def __init__(self, collection, name): dct = {'collection': collection, 'name': name} smple = find_sample(dct) assert smple, '%s: sample does not exist' % dct self.__collection = collection self.__name = name weight = smple.get('weight') field = smple.get('field') fcs = smple.get('Fourier_coefficients') evs = smple.get('eigenvalues') self.__weight = Integer(weight) if weight else weight R = PolynomialRing(IntegerRing(), name='x') self.__field = sage_eval(field, locals=R.gens_dict()) if field else field loc_f = self.__field.gens_dict() P = PolynomialRing(self.__field, names='x,y') loc = P.gens_dict() loc.update(loc_f) self.__fcs = dict((tuple(eval(f)), sage_eval(fcs[f], locals=loc)) for f in fcs) if fcs else fcs loc = self.field().gens_dict() self.__evs = dict( (eval(l), sage_eval( evs[l], locals=loc_f)) for l in evs)\ if evs else evs self.__explicit_formula = smple.get('explicit_formula')
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 blift(LF, Li, p, k, S=None, all_orbits=False): r""" Search for a solution to the given list of inequalities. If found, lift the solution to an appropriate valuation. See Lemma 3.3.6 in [Molnar]_ INPUT: - ``LF`` -- a list of integer polynomials in one variable (the normalized coefficients) - ``Li`` -- an integer, the bound on coefficients - ``p`` -- a prime - ``k`` -- the scaling factor that makes the solution a ``p``-adic integer - ``S`` -- polynomial ring to use - ``all_orbits`` -- boolean; whether or not to use ``==`` in the inequalities to find all orbits OUTPUT: - boolean -- whether or not the lift is successful - integer -- the lift EXAMPLES:: sage: R.<b> = PolynomialRing(QQ) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import blift sage: blift([8*b^3 + 12*b^2 + 6*b + 1, 48*b^2 + 483*b + 117, 72*b + 1341,\ ....: -24*b^2 + 411*b + 99, -144*b + 1233, -216*b], 2, 3, 2) [[True, 4]] """ P = LF[0].parent() #Determine which inequalities are trivial, and scale the rest, so that we only lift #as many times as needed. keepScaledIneqs = [scale(P(coeff), Li, p) for coeff in LF if coeff != 0] keptVals = [i[2] for i in keepScaledIneqs if i[0]] if keptVals != []: #Determine the valuation to lift until. liftval = max(keptVals) else: #All inequalities are satisfied. if all_orbits: return [[True, t] for t in range(p)] return [[True, 1]] if S is None: S = PolynomialRing(Zmod(p), 'b') keptScaledIneqs = [S(i[1]) for i in keepScaledIneqs if i[0]] #We need a solution for each polynomial on the left hand side of the inequalities, #so we need only find a solution for their gcd. g = gcd(keptScaledIneqs) rts = g.roots(multiplicities=False) good = [] for r in rts: #Recursively try to lift each root r_initial = QQ(r) newInput = P([r_initial, p]) LG = [F(newInput) for F in LF] new_good = blift(LG, Li, p, k, S=S) for lift, lifted in new_good: if lift: #Lift successful. if not all_orbits: return [[True, r_initial + p * lifted]] #only need up to SL(2,ZZ) equivalence #this helps control the size of the resulting coefficients if r_initial + p * lifted < p**k: good.append([True, r_initial + p * lifted]) else: new_r = r_initial + p * lifted - p**k while new_r > p**k: new_r -= p**k if [True, new_r] not in good: good.append([True, new_r]) if good: return good #Lift non successful. return [[False, 0]]
def LaurentPolynomialRing(base_ring, *args, **kwds): r""" Return the globally unique univariate or multivariate Laurent polynomial ring with given properties and variable name or names. There are four ways to call the Laurent polynomial ring constructor: 1. ``LaurentPolynomialRing(base_ring, name, sparse=False)`` 2. ``LaurentPolynomialRing(base_ring, names, order='degrevlex')`` 3. ``LaurentPolynomialRing(base_ring, name, n, order='degrevlex')`` 4. ``LaurentPolynomialRing(base_ring, n, name, order='degrevlex')`` The optional arguments sparse and order *must* be explicitly named, and the other arguments must be given positionally. INPUT: - ``base_ring`` -- a commutative ring - ``name`` -- a string - ``names`` -- a list or tuple of names, or a comma separated string - ``n`` -- a positive integer - ``sparse`` -- bool (default: False), whether or not elements are sparse - ``order`` -- string or :class:`~sage.rings.polynomial.term_order.TermOrder`, e.g., - ``'degrevlex'`` (default) -- degree reverse lexicographic - ``'lex'`` -- lexicographic - ``'deglex'`` -- degree lexicographic - ``TermOrder('deglex',3) + TermOrder('deglex',3)`` -- block ordering OUTPUT: ``LaurentPolynomialRing(base_ring, name, sparse=False)`` returns a univariate Laurent polynomial ring; all other input formats return a multivariate Laurent polynomial ring. UNIQUENESS and IMMUTABILITY: In Sage there is exactly one single-variate Laurent polynomial ring over each base ring in each choice of variable and sparseness. There is also exactly one multivariate Laurent polynomial ring over each base ring for each choice of names of variables and term order. :: sage: R.<x,y> = LaurentPolynomialRing(QQ,2); R Multivariate Laurent Polynomial Ring in x, y over Rational Field sage: f = x^2 - 2*y^-2 You can't just globally change the names of those variables. This is because objects all over Sage could have pointers to that polynomial ring. :: sage: R._assign_names(['z','w']) Traceback (most recent call last): ... ValueError: variable names cannot be changed after object creation. EXAMPLES: 1. ``LaurentPolynomialRing(base_ring, name, sparse=False)`` :: sage: LaurentPolynomialRing(QQ, 'w') Univariate Laurent Polynomial Ring in w over Rational Field Use the diamond brackets notation to make the variable ready for use after you define the ring:: sage: R.<w> = LaurentPolynomialRing(QQ) sage: (1 + w)^3 1 + 3*w + 3*w^2 + w^3 You must specify a name:: sage: LaurentPolynomialRing(QQ) Traceback (most recent call last): ... TypeError: you must specify the names of the variables sage: R.<abc> = LaurentPolynomialRing(QQ, sparse=True); R Univariate Laurent Polynomial Ring in abc over Rational Field sage: R.<w> = LaurentPolynomialRing(PolynomialRing(GF(7),'k')); R Univariate Laurent Polynomial Ring in w over Univariate Polynomial Ring in k over Finite Field of size 7 Rings with different variables are different:: sage: LaurentPolynomialRing(QQ, 'x') == LaurentPolynomialRing(QQ, 'y') False 2. ``LaurentPolynomialRing(base_ring, names, order='degrevlex')`` :: sage: R = LaurentPolynomialRing(QQ, 'a,b,c'); R Multivariate Laurent Polynomial Ring in a, b, c over Rational Field sage: S = LaurentPolynomialRing(QQ, ['a','b','c']); S Multivariate Laurent Polynomial Ring in a, b, c over Rational Field sage: T = LaurentPolynomialRing(QQ, ('a','b','c')); T Multivariate Laurent Polynomial Ring in a, b, c over Rational Field All three rings are identical. :: sage: (R is S) and (S is T) True There is a unique Laurent polynomial ring with each term order:: sage: R = LaurentPolynomialRing(QQ, 'x,y,z', order='degrevlex'); R Multivariate Laurent Polynomial Ring in x, y, z over Rational Field sage: S = LaurentPolynomialRing(QQ, 'x,y,z', order='invlex'); S Multivariate Laurent Polynomial Ring in x, y, z over Rational Field sage: S is LaurentPolynomialRing(QQ, 'x,y,z', order='invlex') True sage: R == S False 3. ``LaurentPolynomialRing(base_ring, name, n, order='degrevlex')`` If you specify a single name as a string and a number of variables, then variables labeled with numbers are created. :: sage: LaurentPolynomialRing(QQ, 'x', 10) Multivariate Laurent Polynomial Ring in x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 over Rational Field sage: LaurentPolynomialRing(GF(7), 'y', 5) Multivariate Laurent Polynomial Ring in y0, y1, y2, y3, y4 over Finite Field of size 7 sage: LaurentPolynomialRing(QQ, 'y', 3, sparse=True) Multivariate Laurent Polynomial Ring in y0, y1, y2 over Rational Field By calling the :meth:`~sage.structure.category_object.CategoryObject.inject_variables` method, all those variable names are available for interactive use:: sage: R = LaurentPolynomialRing(GF(7),15,'w'); R Multivariate Laurent Polynomial Ring in w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 over Finite Field of size 7 sage: R.inject_variables() Defining w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14 sage: (w0 + 2*w8 + w13)^2 w0^2 + 4*w0*w8 + 4*w8^2 + 2*w0*w13 + 4*w8*w13 + w13^2 """ from sage.rings.polynomial.polynomial_ring import is_PolynomialRing from sage.rings.polynomial.multi_polynomial_ring_generic import is_MPolynomialRing R = PolynomialRing(base_ring, *args, **kwds) if R in _cache: return _cache[R] # put () here to re-enable weakrefs if is_PolynomialRing(R): # univariate case P = LaurentPolynomialRing_univariate(R) else: assert is_MPolynomialRing(R) P = LaurentPolynomialRing_mpair(R) _cache[R] = P return P
def enumerate_totallyreal_fields_rel(F, m, B, a = [], verbose=0, return_seqs=False): 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``. If verbose == 1 (or 2), then print to the screen (really) verbosely; if verbose is a string, then print verbosely to the file specified by verbose. If return_seqs, then return the polynomials as sequences (for easier exporting to a file). 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 string (default: 0) - ``return_seqs`` -- boolean (default: False) 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. EXAMPLES:: sage: ZZx = ZZ['x'] sage: F.<t> = NumberField(x^2-2) sage: enumerate_totallyreal_fields_rel(F, 2, 2000) [[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]] 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 T = tr_data_rel(F,m,B,a) S = [] Srel = [] 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()).reverse().Vec() if return_seqs: return [[0,0,0,0],[1,g,[-1,1]]] else: return [[1,pari('x-1'),g]] if verbose: saveout = sys.stdout if type(verbose) == str: fsock = open(verbose, 'w') sys.stdout = fsock # Else, print to screen f_out = [0]*m + [1] 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_full() == 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. found = False ind = bisect.bisect_left(S, [d,ng]) while ind < len(S) and S[ind][0] == d: if S[ind][1] == ng: if verbose: print "but is not new" found = True break ind += 1 if not found: if verbose: print "and is new!" S.insert(ind, [d,ng]) Srel.insert(ind, 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() ind = bisect.bisect_left(S, [d,ng]) S.insert(ind, [d,ng]) Srel.insert(ind, 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() ind = bisect.bisect_left(S, [d,ng]) S.insert(ind, [d,ng]) Srel.insert(ind, 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() ind = bisect.bisect_left(S, [d,ng]) S.insert(ind, [d,ng]) Srel.insert(ind, Fx([-1,6,-5,1])) # Now check for isomorphic fields S = [[S[i][0],S[i][1],Srel[i]] for i in range(len(S))] weed_fields(S) # Output. if verbose: print "="*80 print "Polynomials tested:", counts[0] print "Irreducible polynomials:", counts[1] print "Polynomials with nfdisc <= B:", counts[2] for i in range(len(S)): print S[i] if type(verbose) == str: fsock.close() sys.stdout = saveout if return_seqs: return [counts,[[s[0],s[1].reverse().Vec(),s[2].coeffs()] for s in S]] else: return S
artin_location = ("limbo", "artrep20130430") galois_group_location = ("limbo", "nfgal20130430") from type_generation import String, Array, Dict, Int, Anything, Float from standard_types import PolynomialAsString, PermutationAsList,\ TooLargeInt, LabelString, FiniteSequence, FiniteSet, PrimeIndexedSequence, AlgebraicNumberPolynomialString, \ PolynomialAsString, AlgebraicNumberString_Root, PolynomialAsSequenceInt, PolynomialAsSequenceTooLargeInt from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ Polynomial_X_QQ_AsString = PolynomialAsString( PolynomialRing(QQ, "x", sparse=False)) Polynomial_X_ZZ_AsString = PolynomialAsString( PolynomialRing(ZZ, "x", sparse=False)) Polynomial_a_ZZ_AsString = PolynomialAsString( PolynomialRing(ZZ, "a", sparse=False)) from bind_collection import bind_collection Dokchitser_AlgebraicNumber_MinPol = PolynomialAsString( PolynomialRing(PolynomialRing(ZZ, "x", sparse=False), "a", sparse=False)) Dokchitser_AlgebraicNumber_Root = AlgebraicNumberString_Root class Dokchitser_AlgorithmLabel(LabelString): pass
def q_dimension(self, q=None, prec=None, use_product=False): r""" Return the `q`-dimension of ``self``. Let `B(\lambda)` denote a highest weight crystal. Recall that the degree of the `\mu`-weight space of `B(\lambda)` (under the principal gradation) is equal to `\langle \rho^{\vee}, \lambda - \mu \rangle` where `\langle \rho^{\vee}, \alpha_i \rangle = 1` for all `i \in I` (in particular, take `\rho^{\vee} = \sum_{i \in I} h_i`). The `q`-dimension of a highest weight crystal `B(\lambda)` is defined as .. MATH:: \dim_q B(\lambda) := \sum_{j \geq 0} \dim(B_j) q^j, where `B_j` denotes the degree `j` portion of `B(\lambda)`. This can be expressed as the product .. MATH:: \dim_q B(\lambda) = \prod_{\alpha^{\vee} \in \Delta_+^{\vee}} \left( \frac{1 - q^{\langle \lambda + \rho, \alpha^{\vee} \rangle}}{1 - q^{\langle \rho, \alpha^{\vee} \rangle}} \right)^{\mathrm{mult}\, \alpha}, where `\Delta_+^{\vee}` denotes the set of positive coroots. Taking the limit as `q \to 1` gives the dimension of `B(\lambda)`. For more information, see [Ka1990]_ Section 10.10. INPUT: - ``q`` -- the (generic) parameter `q` - ``prec`` -- (default: ``None``) The precision of the power series ring to use if the crystal is not known to be finite (i.e. the number of terms returned). If ``None``, then the result is returned as a lazy power series. - ``use_product`` -- (default: ``False``) if we have a finite crystal and ``True``, use the product formula EXAMPLES:: sage: C = crystals.Tableaux(['A',2], shape=[2,1]) sage: qdim = C.q_dimension(); qdim q^4 + 2*q^3 + 2*q^2 + 2*q + 1 sage: qdim(1) 8 sage: len(C) == qdim(1) True sage: C.q_dimension(use_product=True) == qdim True sage: C.q_dimension(prec=20) q^4 + 2*q^3 + 2*q^2 + 2*q + 1 sage: C.q_dimension(prec=2) 2*q + 1 sage: R.<t> = QQ[] sage: C.q_dimension(q=t^2) t^8 + 2*t^6 + 2*t^4 + 2*t^2 + 1 sage: C = crystals.Tableaux(['A',2], shape=[5,2]) sage: C.q_dimension() q^10 + 2*q^9 + 4*q^8 + 5*q^7 + 6*q^6 + 6*q^5 + 6*q^4 + 5*q^3 + 4*q^2 + 2*q + 1 sage: C = crystals.Tableaux(['B',2], shape=[2,1]) sage: qdim = C.q_dimension(); qdim q^10 + 2*q^9 + 3*q^8 + 4*q^7 + 5*q^6 + 5*q^5 + 5*q^4 + 4*q^3 + 3*q^2 + 2*q + 1 sage: qdim == C.q_dimension(use_product=True) True sage: C = crystals.Tableaux(['D',4], shape=[2,1]) sage: C.q_dimension() q^16 + 2*q^15 + 4*q^14 + 7*q^13 + 10*q^12 + 13*q^11 + 16*q^10 + 18*q^9 + 18*q^8 + 18*q^7 + 16*q^6 + 13*q^5 + 10*q^4 + 7*q^3 + 4*q^2 + 2*q + 1 We check with a finite tensor product:: sage: TP = crystals.TensorProduct(C, C) sage: TP.cardinality() 25600 sage: qdim = TP.q_dimension(use_product=True); qdim # long time q^32 + 2*q^31 + 8*q^30 + 15*q^29 + 34*q^28 + 63*q^27 + 110*q^26 + 175*q^25 + 276*q^24 + 389*q^23 + 550*q^22 + 725*q^21 + 930*q^20 + 1131*q^19 + 1362*q^18 + 1548*q^17 + 1736*q^16 + 1858*q^15 + 1947*q^14 + 1944*q^13 + 1918*q^12 + 1777*q^11 + 1628*q^10 + 1407*q^9 + 1186*q^8 + 928*q^7 + 720*q^6 + 498*q^5 + 342*q^4 + 201*q^3 + 117*q^2 + 48*q + 26 sage: qdim(1) # long time 25600 sage: TP.q_dimension() == qdim # long time True The `q`-dimensions of infinite crystals are returned as formal power series:: sage: C = crystals.LSPaths(['A',2,1], [1,0,0]) sage: C.q_dimension(prec=5) 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + O(q^5) sage: C.q_dimension(prec=10) 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 + 9*q^7 + 13*q^8 + 16*q^9 + O(q^10) sage: qdim = C.q_dimension(); qdim 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 + 9*q^7 + 13*q^8 + 16*q^9 + 22*q^10 + O(x^11) sage: qdim.compute_coefficients(15) sage: qdim 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 + 9*q^7 + 13*q^8 + 16*q^9 + 22*q^10 + 27*q^11 + 36*q^12 + 44*q^13 + 57*q^14 + 70*q^15 + O(x^16) """ from sage.rings.all import ZZ WLR = self.weight_lattice_realization() I = self.index_set() mg = self.highest_weight_vectors() max_deg = float('inf') if prec is None else prec - 1 def iter_by_deg(gens): next = set(gens) deg = -1 while next and deg < max_deg: deg += 1 yield len(next) todo = next next = set([]) while todo: x = todo.pop() for i in I: y = x.f(i) if y is not None: next.add(y) # def iter_by_deg from sage.categories.finite_crystals import FiniteCrystals if self in FiniteCrystals(): if q is None: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing q = PolynomialRing(ZZ, 'q').gen(0) if use_product: # Since we are in the classical case, all roots occur with multiplicity 1 pos_coroots = [ x.associated_coroot() for x in WLR.positive_roots() ] rho = WLR.rho() P = q.parent() ret = P.zero() for v in self.highest_weight_vectors(): hw = v.weight() ret += P.prod((1 - q**(rho + hw).scalar(ac)) / (1 - q**rho.scalar(ac)) for ac in pos_coroots) # We do a cast since the result would otherwise live in the fraction field return P(ret) elif prec is None: # If we're here, we may not be a finite crystal. # In fact, we're probably infinite. from sage.combinat.species.series import LazyPowerSeriesRing if q is None: P = LazyPowerSeriesRing(ZZ, names='q') else: P = q.parent() if not isinstance(P, LazyPowerSeriesRing): raise TypeError( "the parent of q must be a lazy power series ring") ret = P(iter_by_deg(mg)) ret.compute_coefficients(10) return ret from sage.rings.power_series_ring import PowerSeriesRing, PowerSeriesRing_generic if q is None: q = PowerSeriesRing(ZZ, 'q', default_prec=prec).gen(0) P = q.parent() ret = P.sum(c * q**deg for deg, c in enumerate(iter_by_deg(mg))) if ret.degree() == max_deg and isinstance(P, PowerSeriesRing_generic): ret = P(ret, prec) return ret
def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, impl=None, proof=None, check_irreducible=True, prefix=None, repr=None, elem_cache=None, **kwds): """ EXAMPLES:: sage: GF.create_key_and_extra_args(9, 'a') ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True), {}) We do not take invalid keyword arguments and raise a value error to better ensure uniqueness:: sage: GF.create_key_and_extra_args(9, 'a', foo='value') Traceback (most recent call last): ... TypeError: create_key_and_extra_args() got an unexpected keyword argument 'foo' Moreover, ``repr`` and ``elem_cache`` are ignored when not using givaro:: sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', repr='poly') ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None), {}) sage: GF.create_key_and_extra_args(16, 'a', impl='ntl', elem_cache=False) ((16, ('a',), x^4 + x + 1, 'ntl', 2, 4, True, None, None, None), {}) sage: GF(16, impl='ntl') is GF(16, impl='ntl', repr='foo') True We handle extra arguments for the givaro finite field and create unique objects for their defaults:: sage: GF(25, impl='givaro') is GF(25, impl='givaro', repr='poly') True sage: GF(25, impl='givaro') is GF(25, impl='givaro', elem_cache=True) True sage: GF(625, impl='givaro') is GF(625, impl='givaro', elem_cache=False) True We explicitly take ``structure``, ``implementation`` and ``prec`` attributes for compatibility with :class:`~sage.categories.pushout.AlgebraicExtensionFunctor` but we ignore them as they are not used, see :trac:`21433`:: sage: GF.create_key_and_extra_args(9, 'a', structure=None) ((9, ('a',), x^2 + 2*x + 2, 'givaro', 3, 2, True, None, 'poly', True), {}) """ import sage.arith.all from sage.structure.proof.all import WithProof, arithmetic if proof is None: proof = arithmetic() for key, val in kwds.items(): if key not in ['structure', 'implementation', 'prec', 'embedding']: raise TypeError( "create_key_and_extra_args() got an unexpected keyword argument '%s'" % key) if not (val is None or isinstance(val, list) and all(c is None for c in val)): raise NotImplementedError( "ring extension with prescribed %s is not implemented" % key) with WithProof('arithmetic', proof): order = Integer(order) if order <= 1: raise ValueError( "the order of a finite field must be at least 2") if order.is_prime(): p = order n = Integer(1) if impl is None: impl = 'modn' name = ('x', ) # Ignore name # Every polynomial of degree 1 is irreducible check_irreducible = False elif order.is_prime_power(): if names is not None: name = names if name is not None: name = normalize_names(1, name) p, n = order.factor()[0] if name is None: if prefix is None: prefix = 'z' name = prefix + str(n) if modulus is not None: raise ValueError( "no modulus may be specified if variable name not given" ) # Fpbar will have a strong reference, since algebraic_closure caches its results, # and the coefficients of modulus lie in GF(p) Fpbar = GF(p).algebraic_closure(prefix) # This will give a Conway polynomial if p,n is small enough to be in the database # and a pseudo-Conway polynomial if it's not. modulus = Fpbar._get_polynomial(n) check_irreducible = False if impl is None: if order < zech_log_bound: impl = 'givaro' elif p == 2: impl = 'ntl' else: impl = 'pari_ffelt' else: raise ValueError( "the order of a finite field must be a prime power") # Determine modulus. # For the 'modn' implementation, we use the following # optimization which we also need to avoid an infinite loop: # a modulus of None is a shorthand for x-1. if modulus is not None or impl != 'modn': R = PolynomialRing(FiniteField(p), 'x') if modulus is None: modulus = R.irreducible_element(n) if isinstance(modulus, str): # A string specifies an algorithm to find a suitable modulus. modulus = R.irreducible_element(n, algorithm=modulus) else: if sage.rings.polynomial.polynomial_element.is_Polynomial( modulus): modulus = modulus.change_variable_name('x') modulus = R(modulus).monic() if modulus.degree() != n: raise ValueError( "the degree of the modulus does not equal the degree of the field" ) if check_irreducible and not modulus.is_irreducible(): raise ValueError( "finite field modulus must be irreducible but it is not" ) # If modulus is x - 1 for impl="modn", set it to None if impl == 'modn' and modulus[0] == -1: modulus = None # Check extra arguments for givaro and setup their defaults # TODO: ntl takes a repr, but ignores it if impl == 'givaro': if repr is None: repr = 'poly' if elem_cache is None: elem_cache = (order < 500) else: # This has the effect of ignoring these keywords repr = None elem_cache = None return (order, name, modulus, impl, p, n, proof, prefix, repr, elem_cache), {}
def __getitem__(self, arg): """ Extend this ring by one or several elements to create a polynomial ring, a power series ring, or an algebraic extension. This is a convenience method intended primarily for interactive use. .. SEEALSO:: :func:`~sage.rings.polynomial.polynomial_ring_constructor.PolynomialRing`, :func:`~sage.rings.power_series_ring.PowerSeriesRing`, :meth:`~sage.rings.ring.Ring.extension`, :meth:`sage.rings.integer_ring.IntegerRing_class.__getitem__`, :meth:`sage.rings.matrix_space.MatrixSpace.__getitem__`, :meth:`sage.structure.parent.Parent.__getitem__` EXAMPLES: We create several polynomial rings:: sage: ZZ['x'] Univariate Polynomial Ring in x over Integer Ring sage: QQ['x'] Univariate Polynomial Ring in x over Rational Field sage: GF(17)['abc'] Univariate Polynomial Ring in abc over Finite Field of size 17 sage: GF(17)['a,b,c'] Multivariate Polynomial Ring in a, b, c over Finite Field of size 17 sage: GF(17)['a']['b'] Univariate Polynomial Ring in b over Univariate Polynomial Ring in a over Finite Field of size 17 We can create skew polynomial rings:: sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: k['x',Frob] Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 We can also create power series rings by using double brackets:: sage: QQ[['t']] Power Series Ring in t over Rational Field sage: ZZ[['W']] Power Series Ring in W over Integer Ring sage: ZZ[['x,y,z']] Multivariate Power Series Ring in x, y, z over Integer Ring sage: ZZ[['x','T']] Multivariate Power Series Ring in x, T over Integer Ring Use :func:`~sage.rings.fraction_field.Frac` or :meth:`~sage.rings.ring.CommutativeRing.fraction_field` to obtain the fields of rational functions and Laurent series:: sage: Frac(QQ['t']) Fraction Field of Univariate Polynomial Ring in t over Rational Field sage: Frac(QQ[['t']]) Laurent Series Ring in t over Rational Field sage: QQ[['t']].fraction_field() Laurent Series Ring in t over Rational Field Note that the same syntax can be used to create number fields:: sage: QQ[I] Number Field in I with defining polynomial x^2 + 1 sage: QQ[I].coerce_embedding() Generic morphism: From: Number Field in I with defining polynomial x^2 + 1 To: Complex Lazy Field Defn: I -> 1*I :: sage: QQ[sqrt(2)] Number Field in sqrt2 with defining polynomial x^2 - 2 sage: QQ[sqrt(2)].coerce_embedding() Generic morphism: From: Number Field in sqrt2 with defining polynomial x^2 - 2 To: Real Lazy Field Defn: sqrt2 -> 1.414213562373095? :: sage: QQ[sqrt(2),sqrt(3)] Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field and orders in number fields:: sage: ZZ[I] Order in Number Field in I with defining polynomial x^2 + 1 sage: ZZ[sqrt(5)] Order in Number Field in sqrt5 with defining polynomial x^2 - 5 sage: ZZ[sqrt(2)+sqrt(3)] Order in Number Field in a with defining polynomial x^4 - 10*x^2 + 1 Embeddings are found for simple extensions (when that makes sense):: sage: QQi.<i> = QuadraticField(-1, 'i') sage: QQ[i].coerce_embedding() Generic morphism: From: Number Field in i with defining polynomial x^2 + 1 To: Complex Lazy Field Defn: i -> 1*I TESTS: A few corner cases:: sage: QQ[()] Multivariate Polynomial Ring in no variables over Rational Field sage: QQ[[]] Traceback (most recent call last): ... TypeError: power series rings must have at least one variable These kind of expressions do not work:: sage: QQ['a,b','c'] Traceback (most recent call last): ... ValueError: variable name 'a,b' is not alphanumeric sage: QQ[['a,b','c']] Traceback (most recent call last): ... ValueError: variable name 'a,b' is not alphanumeric sage: QQ[[['x']]] Traceback (most recent call last): ... TypeError: expected R[...] or R[[...]], not R[[[...]]] Extension towers are built as follows and use distinct generator names:: sage: K = QQ[2^(1/3), 2^(1/2), 3^(1/3)] sage: K Number Field in a with defining polynomial x^3 - 2 over its base field sage: K.base_field() Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field sage: K.base_field().base_field() Number Field in b with defining polynomial x^3 - 3 Embeddings:: sage: QQ[I](I.pyobject()) I sage: a = 10^100; expr = (2*a + sqrt(2))/(2*a^2-1) sage: QQ[expr].coerce_embedding() is None False sage: QQ[sqrt(5)].gen() > 0 True sage: expr = sqrt(2) + I*(cos(pi/4, hold=True) - sqrt(2)/2) sage: QQ[expr].coerce_embedding() Generic morphism: From: Number Field in a with defining polynomial x^2 - 2 To: Real Lazy Field Defn: a -> 1.414213562373095? """ def normalize_arg(arg): if isinstance(arg, (tuple, list)): # Allowing arbitrary iterables would create confusion, but we # may want to support a few more. return tuple(arg) elif isinstance(arg, str): return tuple(arg.split(',')) else: return (arg,) # 1. If arg is a list, try to return a power series ring. if isinstance(arg, list): if arg == []: raise TypeError("power series rings must have at least one variable") elif len(arg) == 1: # R[["a,b"]], R[[(a,b)]]... if isinstance(arg[0], list): raise TypeError("expected R[...] or R[[...]], not R[[[...]]]") elts = normalize_arg(arg[0]) else: elts = normalize_arg(arg) from sage.rings.power_series_ring import PowerSeriesRing return PowerSeriesRing(self, elts) if isinstance(arg, tuple): from sage.categories.morphism import Morphism if len(arg) == 2 and isinstance(arg[1], Morphism): from sage.rings.polynomial.skew_polynomial_ring_constructor import SkewPolynomialRing return SkewPolynomialRing(self, arg[1], names=arg[0]) # 2. Otherwise, if all specified elements are algebraic, try to # return an algebraic extension elts = normalize_arg(arg) try: minpolys = [a.minpoly() for a in elts] except (AttributeError, NotImplementedError, ValueError, TypeError): minpolys = None if minpolys: # how to pass in names? names = tuple(_gen_names(elts)) if len(elts) == 1: from sage.rings.all import CIF, CLF, RIF, RLF elt = elts[0] try: iv = CIF(elt) except (TypeError, ValueError): emb = None else: # First try creating an ANRoot manually, because # extension(..., embedding=CLF(expr)) (or # ...QQbar(expr)) would normalize the expression in # QQbar, which currently is VERY slow in many cases. # This may fail when minpoly has close roots or elt is # a complicated symbolic expression. # TODO: Rewrite using #19362 and/or #17886 and/or # #15600 once those issues are solved. from sage.rings.qqbar import AlgebraicNumber, ANRoot try: elt = AlgebraicNumber(ANRoot(minpolys[0], iv)) except ValueError: pass # Force a real embedding when possible, to get the # right ordered ring structure. if (iv.imag().is_zero() or iv.imag().contains_zero() and elt.imag().is_zero()): emb = RLF(elt) else: emb = CLF(elt) return self.extension(minpolys[0], names[0], embedding=emb) try: # Doing the extension all at once is best, if possible... return self.extension(minpolys, names) except (TypeError, ValueError): # ...but we can also construct it iteratively return reduce(lambda R, ext: R.extension(*ext), zip(minpolys, names), self) # 2. Otherwise, try to return a polynomial ring from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing return PolynomialRing(self, elts)
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 dual(self): r""" Return the projective dual of the given subscheme of projective space. INPUT: - ``X`` -- A subscheme of projective space. At present, ``X`` is required to be an irreducible and reduced hypersurface defined over `\QQ` or a finite field. OUTPUT: - The dual of ``X`` as a subscheme of the dual projective space. EXAMPLES: The dual of a smooth conic in the plane is also a smooth conic:: sage: R.<x, y, z> = QQ[] sage: P.<x, y, z> = ProjectiveSpace(2, QQ) sage: I = R.ideal(x^2 + y^2 + z^2) sage: X = P.subscheme(I) sage: X.dual() Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: y0^2 + y1^2 + y2^2 The dual of the twisted cubic curve in projective 3-space is a singular quartic surface. In the following example, we compute the dual of this surface, which by double duality is equal to the twisted cubic itself. The output is the twisted cubic as an intersection of three quadrics:: sage: R.<x, y, z, w> = QQ[] sage: P.<x, y, z, w> = ProjectiveSpace(3, QQ) sage: I = R.ideal(y^2*z^2 - 4*x*z^3 - 4*y^3*w + 18*x*y*z*w - 27*x^2*w^2) sage: X = P.subscheme(I) sage: X.dual() Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: y2^2 - y1*y3, y1*y2 - y0*y3, y1^2 - y0*y2 The singular locus of the quartic surface in the last example is itself supported on a twisted cubic:: sage: X.Jacobian().radical() Ideal (z^2 - 3*y*w, y*z - 9*x*w, y^2 - 3*x*z) of Multivariate Polynomial Ring in x, y, z, w over Rational Field An example over a finite field:: sage: R = PolynomialRing(GF(61), 'a,b,c') sage: P.<a, b, c> = ProjectiveSpace(2, R.base_ring()) sage: X = P.subscheme(R.ideal(a*a+2*b*b+3*c*c)) sage: X.dual() Closed subscheme of Projective Space of dimension 2 over Finite Field of size 61 defined by: y0^2 - 30*y1^2 - 20*y2^2 TESTS:: sage: R = PolynomialRing(Qp(3), 'a,b,c') sage: P.<a, b, c> = ProjectiveSpace(2, R.base_ring()) sage: X = P.subscheme(R.ideal(a*a+2*b*b+3*c*c)) sage: X.dual() Traceback (most recent call last): ... NotImplementedError: base ring must be QQ or a finite field """ from sage.libs.singular.function_factory import ff K = self.base_ring() if not (is_RationalField(K) or is_FiniteField(K)): raise NotImplementedError("base ring must be QQ or a finite field") I = self.defining_ideal() m = I.ngens() n = I.ring().ngens() - 1 if (m != 1 or (n < 1) or I.is_zero() or I.is_trivial() or not I.is_prime()): raise NotImplementedError("At the present, the method is only" " implemented for irreducible and" " reduced hypersurfaces and the given" " list of generators for the ideal must" " have exactly one element.") R = PolynomialRing(K, 'x', n + 1) from sage.schemes.projective.projective_space import ProjectiveSpace Pd = ProjectiveSpace(n, K, 'y') Rd = Pd.coordinate_ring() x = R.variable_names() y = Rd.variable_names() S = PolynomialRing(K, x + y + ('t', )) if S.has_coerce_map_from(I.ring()): T = PolynomialRing(K, 'w', n + 1) I_S = (I.change_ring(T)).change_ring(S) else: I_S = I.change_ring(S) f_S = I_S.gens()[0] z = S.gens() J = I_S for i in range(n + 1): J = J + S.ideal(z[-1] * f_S.derivative(z[i]) - z[i + n + 1]) sat = ff.elim__lib.sat max_ideal = S.ideal(z[n + 1:2 * n + 2]) J_sat_gens = sat(J, max_ideal)[0] J_sat = S.ideal(J_sat_gens) L = J_sat.elimination_ideal(z[0:n + 1] + (z[-1], )) return Pd.subscheme(L.change_ring(Rd))
def expand(self, n, letter='x'): r""" Expand ``self`` written in the `\mathbf{w}` basis in `n^2` commuting variables which satisfy the relation `x_{ij} x_{ik} = 0` for all `i`, `j`, and `k`. The expansion of an element of the `\mathbf{w}` basis is given by equations (26) and (55) in [HNT06]_. INPUT: - ``n`` -- an integer - ``letter`` -- (default: ``'x'``) a string OUTPUT: - The symmetric function of ``self`` expressed in the ``n*n`` non-commuting variables described by ``letter``. REFERENCES: .. [HNT06] \F. Hivert, J.-C. Novelli, J.-Y. Thibon. *Commutative combinatorial Hopf algebras*. (2006). :arxiv:`0605262v1`. EXAMPLES:: sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w() sage: w[[1,3],[2]].expand(4) x02*x11*x20 + x03*x11*x30 + x03*x22*x30 + x13*x22*x31 One can use a different set of variable by using the optional argument ``letter``:: sage: w[[1,3],[2]].expand(3, letter='y') y02*y11*y20 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.combinat.permutation import Permutations m = self.parent() names = ['{}{}{}'.format(letter, i, j) for i in range(n) for j in range(n)] R = PolynomialRing(m.base_ring(), n*n, names) x = [[R.gens()[i*n+j] for j in range(n)] for i in range(n)] I = R.ideal([x[i][j]*x[i][k] for j in range(n) for k in range(n) for i in range(n)]) Q = R.quotient(I, names) x = [[Q.gens()[i*n+j] for j in range(n)] for i in range(n)] P = SetPartitions() def on_basis(A): k = A.size() ret = R.zero() if n < k: return ret for p in Permutations(k): if P(p.to_cycles()) == A: # -1 for indexing ret += R.sum(prod(x[I[i]][I[p[i]-1]] for i in range(k)) for I in Subsets(range(n), k)) return ret return m._apply_module_morphism(self, on_basis, codomain=R)
def __init__(self, F, m, B, a=None): r""" Initialization routine (constructor). INPUT: - ``F`` -- number field, the base field - ``m`` -- integer, the relative degree - ``B`` -- integer, the discriminant bound - ``a`` -- list (default: []), the coefficient list to begin with, corresponding to ``a[len(a)]*x^n + ... + a[0]x^(n-len(a))``. OUTPUT: the data initialized to begin enumeration of totally real fields with base field F, degree n, discriminant bounded by B, and starting with coefficients a. EXAMPLES:: sage: F.<t> = NumberField(x^2-2) sage: T = sage.rings.number_field.totallyreal_rel.tr_data_rel(F, 2, 2000) """ if a is None: # don't make the stupid noob mistake of putting a=[] a = [] # in the function signature above. # Initialize constants. self.m = m d = F.degree() self.d = d self.n = m*d self.B = B self.gamma = hermite_constant(self.n-self.d) self.F = F self.Z_F = F.maximal_order() self.Foo = F.real_embeddings() self.dF = abs(F.disc()) self.Fx = PolynomialRing(F, 'xF') self.beta = [[]]*m self.gnk = [[]]*m self.trace_elts = [] Z_Fbasis = self.Z_F.basis() # Initialize variables. if a == []: # No starting input, all polynomials will be found; initialize to zero. self.a = [0]*m + [1] self.amaxvals = [[]]*m anm1s = [[i] for i in range(0,m//2+1)] for i in range(1,self.d): for j in range(len(anm1s)): anm1s[j] = [ anm1s[j] + [i] for i in range(m)] anm1s = sum(anm1s, []) anm1s = [sum([Z_Fbasis[i]*a[i] for i in range(self.d)]) for a in anm1s] # Minimize trace in class. import numpy for i in range(len(anm1s)): Q = [ [ v(m*x) for v in self.Foo] + [0] for x in Z_Fbasis] + [[v(anm1s[i]) for v in self.Foo] + [10**6]] pari_string = '['+';'.join([','.join(["%s"%ii for ii in row]) for row in zip(*Q)])+']' adj = pari(pari_string).qflll()[self.d] anm1s[i] += sum([m*Z_Fbasis[ii]*int(adj[ii])//int(adj[self.d]) for ii in range(self.d)]) self.amaxvals[m-1] = anm1s self.a[m-1] = self.amaxvals[m-1].pop() self.k = m-2 bl = math.ceil(1.7719*self.n) br = max([1./m*(am1**2).trace() + \ self.gamma*(1./(m**d)*self.B/self.dF)**(1./(self.n-d)) for am1 in anm1s]) br = math.floor(br) T2s = self.F._positive_integral_elements_with_trace([bl,br]) self.trace_elts.append([bl,br,T2s]) elif len(a) <= m+1: # First few coefficients have been specified. # The value of k is the largest index of the coefficients of a which is # currently unknown; e.g., if k == -1, then we can iterate # over polynomials, and if k == n-1, then we have finished iterating. if a[len(a)-1] != 1: raise ValueError, "a[len(a)-1](=%s) must be 1 so polynomial is monic"%a[len(a)-1] raise NotImplementedError, "These have not been checked." k = m-len(a) self.k = k a = [0]*(k+1) + a self.amaxvals = [[]]*m for i in range(0,n+1): self.a[i] = a[i] # Bounds come from an application of Lagrange multipliers in degrees 2,3. self.b_lower = [-1./m*(v(self.a[m-1]) + (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo] self.b_upper = [-1./m*(v(self.a[m-1]) - (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo] if k < m-2: bminmax = [lagrange_degree_3(n,v(self.a[m-1]),v(self.a[m-2]),v(self.a[m-3])) for v in self.Foo] self.b_lower = bminmax[0] self.b_upper = bminmax[1] # Annoying, but must reverse coefficients for numpy. gnk = [binomial(j,k+2)*a[j] for j in range(k+2,n+1)] self.beta[k+1] = [[self.b_lower] + numpy.roots([v(gnk[i]) for i in range(len(gnk))].reverse()).tolist().sort() + [self.b_upper] for v in self.Foo] # Now to really initialize gnk. self.gnk[k+1] = [[0] + [binomial(j,k+1)*v(a[j]) for j in range (k+2,m+1)] for v in self.Foo] else: # Bad input! raise ValueError, "a has length %s > m+1"%len(a)
class PetersonPolynomials(SageObject): """ A class that computes the Peterson polynomials and their expression as Dickson polynomials. """ def __init__(self, p, n): """ TESTS:: sage: from yacop.modules.dickson import PetersonPolynomials sage: P=PetersonPolynomials(3,2) ; P Peterson element factory for prime 3, index 2 sage: for idx in range(20): ....: print("%-3d : %s" % (idx,P.omega(idx))) 0 : 1 1 : x1^2 + x2^2 2 : x1^4 + x1^2*x2^2 + x2^4 3 : x1^6 + x1^4*x2^2 + x1^2*x2^4 + x2^6 4 : x1^6*x2^2 + x1^4*x2^4 + x1^2*x2^6 5 : -x1^10 + x1^6*x2^4 + x1^4*x2^6 - x2^10 6 : x1^12 - x1^10*x2^2 + x1^6*x2^6 - x1^2*x2^10 + x2^12 7 : x1^12*x2^2 - x1^10*x2^4 - x1^4*x2^10 + x1^2*x2^12 8 : x1^12*x2^4 - x1^10*x2^6 - x1^6*x2^10 + x1^4*x2^12 9 : x1^18 + x1^12*x2^6 + x1^6*x2^12 + x2^18 10 : x1^18*x2^2 + x1^10*x2^10 + x1^2*x2^18 11 : x1^18*x2^4 - x1^12*x2^10 - x1^10*x2^12 + x1^4*x2^18 12 : x1^18*x2^6 + x1^12*x2^12 + x1^6*x2^18 13 : 0 14 : x1^28 - x1^18*x2^10 - x1^10*x2^18 + x2^28 15 : -x1^30 + x1^28*x2^2 + x1^18*x2^12 + x1^12*x2^18 + x1^2*x2^28 - x2^30 16 : -x1^30*x2^2 + x1^28*x2^4 + x1^4*x2^28 - x1^2*x2^30 17 : -x1^30*x2^4 + x1^28*x2^6 + x1^6*x2^28 - x1^4*x2^30 18 : x1^36 - x1^30*x2^6 + x1^18*x2^18 - x1^6*x2^30 + x2^36 19 : x1^36*x2^2 - x1^28*x2^10 - x1^10*x2^28 + x1^2*x2^36 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from yacop.modules.classifying_spaces import BZpGeneric from sage.categories.tensor import tensor self.p = p self.n = n self.B = BZpGeneric(p) factors = tuple([ self.B, ] * n) self.BT = tensor(factors) self.tc = self.BT.tensor_constructor(factors) deg = -1 fac = 2 # if p>2 else 1 self.b = self.B.monomial(fac * deg) self.binv = self.B.monomial(-fac * deg) self.bt = tensor([ self.b, ] * n) self.bti = tensor([ self.binv, ] * n) self.P = SteenrodAlgebra(p, generic=True).P self.Q = PolynomialRing( GF(p), ["x%d" % (i + 1) for i in range(n)] + [ "t", ], ) def _repr_(self): return "Peterson element factory for prime %d, index %d" % (self.p, self.n) @cached_method def dicksons(self): """ TESTS:: sage: from yacop.modules.dickson import PetersonPolynomials sage: P=PetersonPolynomials(2,3) sage: for p in P.dicksons(): ....: print(p) x1^4*x2^2*x3 + x1^2*x2^4*x3 + x1^4*x2*x3^2 + x1*x2^4*x3^2 + x1^2*x2*x3^4 + x1*x2^2*x3^4 x1^4*x2^2 + x1^2*x2^4 + x1^4*x2*x3 + x1*x2^4*x3 + x1^4*x3^2 + x1^2*x2^2*x3^2 + x2^4*x3^2 + x1^2*x3^4 + x1*x2*x3^4 + x2^2*x3^4 x1^4 + x1^2*x2^2 + x2^4 + x1^2*x2*x3 + x1*x2^2*x3 + x1^2*x3^2 + x1*x2*x3^2 + x2^2*x3^2 + x3^4 sage: P=PetersonPolynomials(5,2) sage: for p in P.dicksons(): ....: print(p) x1^20*x2^4 + x1^16*x2^8 + x1^12*x2^12 + x1^8*x2^16 + x1^4*x2^20 x1^20 + x1^16*x2^4 + x1^12*x2^8 + x1^8*x2^12 + x1^4*x2^16 + x2^20 """ xi = self.Q.gens()[:-1] t = self.Q.gens()[self.n] pol = self.Q.prod(t + self.Q.sum(a * x for (a, x) in zip(cf, xi)) for cf in GF(self.p)**self.n) return [ pol.coefficient(t**(self.p**i)) * (-1)**(self.n - i) for i in range(self.n) ] def is_invariant(self, qelem): """ TESTS:: sage: from yacop.modules.dickson import PetersonPolynomials sage: P=PetersonPolynomials(2,3) sage: [P.is_invariant(d) for d in P.dicksons()] [True, True, True] sage: [(n,P.is_invariant(P.omega(n))) for n in range(10)] [(0, True), (1, False), (2, False), (3, False), (4, True), (5, False), (6, True), (7, True), (8, True), (9, False)] """ if self.n == 1: return True Q = self.Q x1, x2 = Q.gens()[0:2] # we already know the element is symmetric in the variables # so we only check invariance under x1 -> x1+x2 return (qelem - qelem.subs({x1: x1 + x2})).is_zero() # def toQ(self, x): return self.Q.sum(cf * self.Q.prod(a**(e >> 1) for (a, e) in zip(self.Q.gens(), expo)) for (expo, cf) in x) def opelem(self, op): return self.toQ((op * self.bt) * self.bti) def opconjelem(self, op): return self.toQ((op % self.bt) * self.bti) @cached_method def omega(self, n): return self._omega_fast(n) def _omega_safe(self, n): return self.opelem(self.P(n).antipode()) def _omega_exponents(self, sum, len): if len == 1: cf = self.gamma(sum) if cf: yield ( cf, [ sum, ], ) return if len > 1: for smd in range(sum + 1): cf = self.gamma(smd) if cf: for (c, x) in self._omega_exponents(sum - smd, len - 1): yield ( cf * c, [ smd, ] + x, ) def _omega_fast(self, n): """ TESTS:: sage: from yacop.modules.dickson import PetersonPolynomials sage: P=PetersonPolynomials(5,3) sage: for n in range(25,31): ....: assert P._omega_safe(n) == P._omega_fast(n) sage: P=PetersonPolynomials(2,4) sage: for n in range(10,13): ....: assert P._omega_safe(n) == P._omega_fast(n) """ from sage.combinat.integer_vector_weighted import WeightedIntegerVectors from sage.misc.misc_c import prod pmo = self.p - 1 ans = [] for (cf, expos) in self._omega_exponents(n, self.n): if 0 == cf % self.p: continue ans.append(cf * self.Q.prod(a**(pmo * e) for (a, e) in zip(self.Q.gens(), expos))) return self.Q.sum(ans) @staticmethod def _milnor_basis(p, n): from sage.algebras.steenrod.steenrod_algebra_bases import milnor_basis if p == 2: for x in milnor_basis(n, 2): yield x else: for (x, y) in milnor_basis(n, p): if len(x) == 0: yield y def gamma(self, n): """ the gamma(n) in the definition of omega(n) """ return binom_modp(self.p, -(self.p - 1) * n, n) @staticmethod def decompose(p, n): """ Decompose a omega_n into a product of Dicksonians """ inv = p**(p - 2) tdeg = 2 * (p - 1) if p > 2 else 1 pmo = p - 1 # FIXME: why does this not depend on the generic/non-generic flag for p=2? for expos in PetersonPolynomials._milnor_basis(p, tdeg * n): sum = 0 cf = 1 for a in expos: sum += a cf *= binom_modp(p, sum, a) if 0 == cf: break if 0 == cf: continue cf *= binom_modp(p, -n * pmo, sum) if 0 != cf: yield [cf, expos]
def count(arg, ehrhart_polynomial=False, multivariate_generating_function=False, raw_output=False, verbose=False, **kwds): r""" Call to the program count from LattE integrale INPUT: - ``arg`` -- a cdd or LattE description string - ``ehrhart_polynomial``, ``multivariate_generating_function`` -- to compute Ehrhart polynomial or multivariate generating function instead of just counting points - ``raw_output`` -- if ``True`` then return directly the output string from LattE - For all other options of the count program, consult the LattE manual OUTPUT: Either a string (if ``raw_output`` if set to ``True``) or an integer (when counting points), or a polynomial (if ``ehrhart_polynomial`` is set to ``True``) or a multivariate THING (if ``multivariate_generating_function`` is set to ``True``) EXAMPLES:: sage: from sage.interfaces.latte import count # optional - latte_int sage: P = 2 * polytopes.cube() Counting integer points from either the H or V representation:: sage: count(P.cdd_Hrepresentation(), cdd=True) # optional - latte_int 125 sage: count(P.cdd_Vrepresentation(), cdd=True) # optional - latte_int 125 Ehrhart polynomial:: sage: count(P.cdd_Hrepresentation(), cdd=True, ehrhart_polynomial=True) # optional - latte_int 64*t^3 + 48*t^2 + 12*t + 1 Multivariate generating function currently only work with ``raw_output=True``:: sage: opts = {'cdd': True, ....: 'multivariate_generating_function': True, ....: 'raw_output': True} sage: cddin = P.cdd_Hrepresentation() sage: print(count(cddin, **opts)) # optional - latte_int x[0]^2*x[1]^(-2)*x[2]^(-2)/((1-x[1])*(1-x[2])*(1-x[0]^(-1))) + x[0]^(-2)*x[1]^(-2)*x[2]^(-2)/((1-x[1])*(1-x[2])*(1-x[0])) + x[0]^2*x[1]^(-2)*x[2]^2/((1-x[1])*(1-x[0]^(-1))*(1-x[2]^(-1))) + x[0]^(-2)*x[1]^(-2)*x[2]^2/((1-x[1])*(1-x[0])*(1-x[2]^(-1))) + x[0]^2*x[1]^2*x[2]^(-2)/((1-x[2])*(1-x[0]^(-1))*(1-x[1]^(-1))) + x[0]^(-2)*x[1]^2*x[2]^(-2)/((1-x[2])*(1-x[0])*(1-x[1]^(-1))) + x[0]^2*x[1]^2*x[2]^2/((1-x[0]^(-1))*(1-x[1]^(-1))*(1-x[2]^(-1))) + x[0]^(-2)*x[1]^2*x[2]^2/((1-x[0])*(1-x[1]^(-1))*(1-x[2]^(-1))) TESTS: Testing raw output:: sage: from sage.interfaces.latte import count # optional - latte_int sage: P = polytopes.cuboctahedron() sage: cddin = P.cdd_Vrepresentation() sage: count(cddin, cdd=True, raw_output=True) # optional - latte_int '19' sage: count(cddin, cdd=True, raw_output=True, ehrhart_polynomial=True) # optional - latte_int ' + 1 * t^0 + 10/3 * t^1 + 8 * t^2 + 20/3 * t^3' sage: count(cddin, cdd=True, raw_output=True, multivariate_generating_function=True) # optional - latte_int 'x[0]^(-1)*x[1]^(-1)/((1-x[0]*x[2])*(1-x[0]^(-1)*x[1])*...x[0]^(-1)*x[2]^(-1)))\n' Testing the ``verbose`` option:: sage: n = count(cddin, cdd=True, verbose=True, raw_output=True) # optional - latte_int This is LattE integrale ... ... Invocation: count '--redundancy-check=none' --cdd /dev/stdin ... Total Unimodular Cones: ... Maximum number of simplicial cones in memory at once: ... <BLANKLINE> **** The number of lattice points is: **** Total time: ... sec Trivial input for which LattE's preprocessor does all the work:: sage: P = Polyhedron(vertices=[[0,0,0]]) sage: cddin = P.cdd_Hrepresentation() sage: count(cddin, cdd=True, raw_output=False) # optional - latte_int 1 """ # Check that LattE is present Latte().require() args = ['count'] if ehrhart_polynomial and multivariate_generating_function: raise ValueError if ehrhart_polynomial: args.append('--ehrhart-polynomial') elif multivariate_generating_function: args.append('--multivariate-generating-function') if 'redundancy_check' not in kwds: args.append('--redundancy-check=none') for key, value in kwds.items(): if value is None or value is False: continue key = key.replace('_', '-') if value is True: args.append('--{}'.format(key)) else: args.append('--{}={}'.format(key, value)) if multivariate_generating_function: from sage.misc.temporary_file import tmp_filename filename = tmp_filename() with open(filename, 'w') as f: f.write(arg) args += [filename] else: args += ['/dev/stdin'] # The cwd argument is needed because latte # always produces diagnostic output files. latte_proc = Popen(args, stdin=PIPE, stdout=PIPE, stderr=(None if verbose else PIPE), cwd=str(SAGE_TMP)) ans, err = latte_proc.communicate(arg) ret_code = latte_proc.poll() if ret_code: if err is None: err = ", see error message above" else: err = ":\n" + err raise RuntimeError( "LattE integrale program failed (exit code {})".format(ret_code) + err.strip()) if ehrhart_polynomial: ans = ans.splitlines()[-2] if raw_output: return ans else: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ R = PolynomialRing(QQ, 't') return R(ans) elif multivariate_generating_function: with open(filename + '.rat') as f: ans = f.read() if raw_output: return ans else: raise NotImplementedError( "there is no Sage object to handle multivariate series from LattE, use raw_output=True" ) else: if ans: # Sometimes (when LattE's preproc does the work), no output appears on stdout. ans = ans.splitlines()[-1] if not ans: # opening a file is slow (30e-6s), so we read the file # numOfLatticePoints only in case of a IndexError above with open(SAGE_TMP + '/numOfLatticePoints', 'r') as f: ans = f.read() if raw_output: return ans else: return Integer(ans)
def gcd(self, other, algorithm=None): """ Return the gcd of this polynomial and ``other`` INPUT: - ``other`` -- a polynomial defined over the same ring as this polynomial. ALGORITHM: Two algorithms are provided: - ``generic``: Uses the generic implementation, which depends on the base ring being a UFD or a field. - ``dense``: The polynomials are converted to the dense representation, their gcd is computed and is converted back to the sparse representation. Default is ``dense`` for polynomials over ZZ and ``generic`` in the other cases. EXAMPLES:: sage: R.<x> = PolynomialRing(ZZ,sparse=True) sage: p = x^6 + 7*x^5 + 8*x^4 + 6*x^3 + 2*x^2 + x + 2 sage: q = 2*x^4 - x^3 - 2*x^2 - 4*x - 1 sage: gcd(p,q) x^2 + x + 1 sage: gcd(p, q, algorithm = "dense") x^2 + x + 1 sage: gcd(p, q, algorithm = "generic") x^2 + x + 1 sage: gcd(p, q, algorithm = "foobar") Traceback (most recent call last): ... ValueError: Unknown algorithm 'foobar' TESTS: Check that :trac:`19676` is fixed:: sage: S.<y> = R[] sage: x.gcd(y) 1 sage: (6*x).gcd(9) 3 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.arith.all import lcm if algorithm is None: if self.base_ring() == ZZ: algorithm = "dense" else: algorithm = "generic" if algorithm == "dense": S = self.parent() # FLINT is faster but a bug makes the conversion extremely slow, # so NTL is used in those cases where the conversion is too slow. Cf # <https://groups.google.com/d/msg/sage-devel/6qhW90dgd1k/Hoq3N7fWe4QJ> sd = self.degree() od = other.degree() if max(sd,od)<100 or \ min(len(self.__coeffs)/sd, len(other.__coeffs)/od)>.06: implementation = "FLINT" else: implementation = "NTL" D = PolynomialRing(S.base_ring(), 'x', implementation=implementation) g = D(self).gcd(D(other)) return S(g) elif algorithm == "generic": return Polynomial.gcd(self, other) else: raise ValueError("Unknown algorithm '%s'" % algorithm)
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 local_coordinates(self, pt, n): r""" Return local coordinates to precision n at the given point. Behaviour is flaky - some choices of `n` are worst that others. INPUT: - ``pt`` - an F-rational point on X which is not a point of ramification for the projection (x,y) - x. - ``n`` - the number of terms desired OUTPUT: x = x0 + t y = y0 + power series in t EXAMPLES:: sage: F = GF(5) sage: pt = (2,3) sage: R = PolynomialRing(F,2, names = ['x','y']) sage: x,y = R.gens() sage: f = y^2-x^9-x sage: C = Curve(f) sage: C.local_coordinates(pt, 9) [t + 2, -2*t^12 - 2*t^11 + 2*t^9 + t^8 - 2*t^7 - 2*t^6 - 2*t^4 + t^3 - 2*t^2 - 2] """ f = self.defining_polynomial() R = f.parent() F = self.base_ring() p = F.characteristic() x0 = F(pt[0]) y0 = F(pt[1]) astr = ["a" + str(i) for i in range(1, 2 * n)] x, y = R.gens() R0 = PolynomialRing(F, 2 * n + 2, names=[str(x), str(y), "t"] + astr) vars0 = R0.gens() t = vars0[2] yt = y0 * t**0 + add( [vars0[i] * t**(i - 2) for i in range(3, 2 * n + 2)]) xt = x0 + t ft = f(xt, yt) S = singular S.eval('ring s = ' + str(p) + ',' + str(R0.gens()) + ',lp;') S.eval('poly f = ' + str(ft) + ';') c = S('coeffs(%s, t)' % ft) N = int(c.size()) b = ["%s[%s,1]," % (c.name(), i) for i in range(2, N / 2 - 4)] b = ''.join(b) b = b[:len(b) - 1] # to cut off the trailing comma cmd = 'ideal I = ' + b S.eval(cmd) S.eval('short=0') # print using *'s and ^'s. c = S.eval('slimgb(I)') d = c.split("=") d = d[1:] d[len(d) - 1] += "\n" e = [x[:x.index("\n")] for x in d] vals = [] for x in e: for y in vars0: if str(y) in x: if len(x.replace(str(y), "")) != 0: i = x.find("-") if i > 0: vals.append( [eval(x[1:i]), x[:i], F(eval(x[i + 1:]))]) i = x.find("+") if i > 0: vals.append( [eval(x[1:i]), x[:i], -F(eval(x[i + 1:]))]) else: vals.append([eval(str(y)[1:]), str(y), F(0)]) vals.sort() k = len(vals) v = [x0 + t, y0 + add([vals[i][2] * t**(i + 1) for i in range(k)])] return v