def sage_ideal(vars, eqns): polynomialRing = PolynomialRing(RationalField(), vars, order='lex') return Ideal(polynomialRing, [sage_eqn(eqn) for eqn in eqns])
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 __init_extra__(self): """ Sets up the coercions between the different bases EXAMPLES:: sage: Sym = SymmetricFunctions(QQ) # indirect doctest sage: s = Sym.s(); p = Sym.p() sage: f = s.coerce_map_from(p); f Generic morphism: From: Symmetric Functions over Rational Field in the powersum basis To: Symmetric Functions over Rational Field in the Schur basis sage: p.an_element() 2*p[] + 2*p[1] + 3*p[2] sage: f(p.an_element()) 2*s[] + 2*s[1] - 3*s[1, 1] + 3*s[2] sage: f(p.an_element()) == p.an_element() True """ #powersum = self.powersum () #complete = self.complete () #elementary = self.elementary() #schur = self.schur () #monomial = self.monomial () iso = self.register_isomorphism from sage.combinat.sf.classical import conversion_functions for (basis1_name, basis2_name) in conversion_functions: basis1 = getattr(self, basis1_name)() basis2 = getattr(self, basis2_name)() on_basis = SymmetricaConversionOnBasis( t=conversion_functions[basis1_name, basis2_name], domain=basis1, codomain=basis2) from sage.rings.rational_field import RationalField if basis2_name != "powersum" or self._base.has_coerce_map_from( RationalField()): iso(basis1._module_morphism(on_basis, codomain=basis2)) else: # Don't register conversions to powersums as coercions, # unless the base ring is a `\QQ`-algebra # (otherwise the coercion graph loses commutativity). iso(basis1._module_morphism(on_basis, codomain=basis2), only_conversion=True)
def antipode_by_coercion(self, element): r""" The antipode of ``element`` via coercion to and from the power-sum basis or the Schur basis (depending on whether the power sums really form a basis over the given ground ring). INPUT: - ``element`` -- element in a basis of the ring of symmetric functions EXAMPLES:: sage: Sym = SymmetricFunctions(QQ) sage: m = Sym.monomial() sage: m[3,2].antipode() m[3, 2] + 2*m[5] sage: m.antipode_by_coercion(m[3,2]) m[3, 2] + 2*m[5] sage: Sym = SymmetricFunctions(ZZ) sage: m = Sym.monomial() sage: m[3,2].antipode() m[3, 2] + 2*m[5] sage: m.antipode_by_coercion(m[3,2]) m[3, 2] + 2*m[5] .. TODO:: Is there a not too difficult way to get the power-sum computations to work over any ring, not just one with coercion from `\QQ`? """ from sage.rings.rational_field import RationalField if self.has_coerce_map_from(RationalField()): p = self.realization_of().powersum() return self(p.antipode(p(element))) s = self.realization_of().schur() return self(s.antipode(s(element)))
def experiment(): rank = 5 level = 4 num_points = 11 client = cbc.CBClient() liealg = cbd.TypeALieAlgebra(rank, store_fusion=True, exact=True) rays = [] wts = [] ranks = [] for wt in liealg.get_weights(level): if wt == tuple([0 for x in range(0, rank)]): continue cbb = cbd.SymmetricConformalBlocksBundle(client, liealg, wt, num_points, level) if cbb.get_rank() == 0: continue divisor = cbb.get_symmetrized_divisor() if divisor == [ sage.Rational(0) for x in range(0, num_points // 2 - 1) ]: continue rays = rays + [divisor] wts = wts + [wt] ranks = ranks + [cbb.get_rank()] #print(wt, cbb.get_rank(), divisor) p = Polyhedron(rays=rays, base_ring=RationalField(), backend="cdd") extremal_rays = [list(v.vector()) for v in p.Vrepresentation()] c = Cone(p) print("Extremal rays:") for i in range(0, len(rays)): ray = rays[i] wt = wts[i] rk = ranks[i] if ray in extremal_rays: print(rk, wt, ray)
import sage.combinat.skew_partition import sage.libs.symmetrica.all as symmetrica # used in eval() from sage.rings.integer_ring import IntegerRing from sage.rings.rational_field import RationalField import hall_littlewood import sfa import llt import macdonald import jack import orthotriang import kschur ZZ = IntegerRing() QQ = RationalField() translate = { 'monomial': 'MONOMIAL', 'homogeneous': 'HOMSYM', 'powersum': 'POWSYM', 'elementary': 'ELMSYM', 'Schur': 'SCHUR' } conversion_functions = {} def init(): """ Set up the conversion functions between the classical bases.
def _precompute(self, n): """ Compute the transition matrices between ``self`` and its dual basis for the homogeneous component of size `n`. The result is not returned, but stored in the cache. INPUT: - ``n`` -- nonnegative integer EXAMPLES:: sage: e = SymmetricFunctions(QQ['t']).elementary() sage: f = e.dual_basis() sage: f._precompute(0) sage: f._precompute(1) sage: f._precompute(2) sage: l = lambda c: [ (i[0],[j for j in sorted(i[1].items())]) for i in sorted(c.items())] sage: l(f._to_self_cache) # note: this may depend on possible previous computations! [([], [([], 1)]), ([1], [([1], 1)]), ([1, 1], [([1, 1], 2), ([2], 1)]), ([2], [([1, 1], 1), ([2], 1)])] sage: l(f._from_self_cache) [([], [([], 1)]), ([1], [([1], 1)]), ([1, 1], [([1, 1], 1), ([2], -1)]), ([2], [([1, 1], -1), ([2], 2)])] sage: f._transition_matrices[2] [1 1] [1 2] sage: f._inverse_transition_matrices[2] [ 2 -1] [-1 1] """ base_ring = self.base_ring() zero = base_ring.zero() # Handle the n == 0 and n == 1 cases separately if n == 0 or n == 1: part = sage.combinat.partition.Partition([1]*n) self._to_self_cache[ part ] = { part: base_ring.one() } self._from_self_cache[ part ] = { part: base_ring.one() } self._transition_matrices[n] = matrix(base_ring, [[1]]) self._inverse_transition_matrices[n] = matrix(base_ring, [[1]]) return partitions_n = sage.combinat.partition.Partitions_n(n).list() # We now get separated into two cases, depending on whether we can # use the power-sum basis to compute the matrix, or we have to use # the Schur basis. from sage.rings.rational_field import RationalField if (not base_ring.has_coerce_map_from(RationalField())) and self._scalar == sage.combinat.sf.sfa.zee: # This is the case when (due to the base ring not being a # \mathbb{Q}-algebra) we cannot use the power-sum basis, # but (due to zee being the standard zee function) we can # use the Schur basis. schur = self._sym.schur() # Get all the basis elements of the n^th homogeneous component # of the dual basis and express them in the Schur basis d = {} for part in partitions_n: d[part] = schur(self._dual_basis(part))._monomial_coefficients # This contains the data for the transition matrix from the # dual basis to self. transition_matrix_n = matrix(base_ring, len(partitions_n), len(partitions_n)) # This first section calculates how the basis elements of the # dual basis are expressed in terms of self's basis. # For every partition p of size n, compute self(p) in # terms of the dual basis using the scalar product. i = 0 for s_part in partitions_n: # s_part corresponds to self(dual_basis(part)) # s_mcs corresponds to self(dual_basis(part))._monomial_coefficients s_mcs = {} # We need to compute the scalar product of d[s_part] and # all of the d[p_part]'s j = 0 for p_part in partitions_n: # Compute the scalar product of d[s_part] and d[p_part] sp = zero for ds_part in d[s_part]: if ds_part in d[p_part]: sp += d[s_part][ds_part]*d[p_part][ds_part] if sp != zero: s_mcs[p_part] = sp transition_matrix_n[i,j] = sp j += 1 self._to_self_cache[ s_part ] = s_mcs i += 1 else: # Now the other case. Note that just being in this case doesn't # guarantee that we can use the power-sum basis, but we can at # least try. # Get all the basis elements of the n^th homogeneous component # of the dual basis and express them in the power-sum basis d = {} for part in partitions_n: d[part] = self._p(self._dual_basis(part))._monomial_coefficients # This contains the data for the transition matrix from the # dual basis to self. transition_matrix_n = matrix(base_ring, len(partitions_n), len(partitions_n)) # This first section calculates how the basis elements of the # dual basis are expressed in terms of self's basis. # For every partition p of size n, compute self(p) in # terms of the dual basis using the scalar product. i = 0 for s_part in partitions_n: # s_part corresponds to self(dual_basis(part)) # s_mcs corresponds to self(dual_basis(part))._monomial_coefficients s_mcs = {} # We need to compute the scalar product of d[s_part] and # all of the d[p_part]'s j = 0 for p_part in partitions_n: # Compute the scalar product of d[s_part] and d[p_part] sp = zero for ds_part in d[s_part]: if ds_part in d[p_part]: sp += d[s_part][ds_part]*d[p_part][ds_part]*self._scalar(ds_part) if sp != zero: s_mcs[p_part] = sp transition_matrix_n[i,j] = sp j += 1 self._to_self_cache[ s_part ] = s_mcs i += 1 # Save the transition matrix self._transition_matrices[n] = transition_matrix_n # This second section calculates how the basis elements of # self expand in terms of the dual basis. We do this by # computing the inverse of the matrix obtained above. inverse_transition = ~transition_matrix_n for i in range(len(partitions_n)): d_mcs = {} for j in range(len(partitions_n)): if inverse_transition[i,j] != zero: d_mcs[ partitions_n[j] ] = inverse_transition[i,j] self._from_self_cache[ partitions_n[i] ] = d_mcs self._inverse_transition_matrices[n] = inverse_transition
def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=None, simplify=True, simplify_all=False): r""" Compute the splitting field of a given polynomial, defined over a number field. INPUT: - ``poly`` -- a monic polynomial over a number field - ``name`` -- a variable name for the number field - ``map`` -- (default: ``False``) also return an embedding of ``poly`` into the resulting field. Note that computing this embedding might be expensive. - ``degree_multiple`` -- a multiple of the absolute degree of the splitting field. If ``degree_multiple`` equals the actual degree, this can enormously speed up the computation. - ``abort_degree`` -- abort by raising a :class:`SplittingFieldAbort` if it can be determined that the absolute degree of the splitting field is strictly larger than ``abort_degree``. - ``simplify`` -- (default: ``True``) during the algorithm, try to find a simpler defining polynomial for the intermediate number fields using PARI's ``polred()``. This usually speeds up the computation but can also considerably slow it down. Try and see what works best in the given situation. - ``simplify_all`` -- (default: ``False``) If ``True``, simplify intermediate fields and also the resulting number field. OUTPUT: If ``map`` is ``False``, the splitting field as an absolute number field. If ``map`` is ``True``, a tuple ``(K, phi)`` where ``phi`` is an embedding of the base field in ``K``. EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = (x^3 + 2).splitting_field(); K Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1 sage: K.<a> = (x^3 - 3*x + 1).splitting_field(); K Number Field in a with defining polynomial x^3 - 3*x + 1 The ``simplify`` and ``simplify_all`` flags usually yield fields defined by polynomials with smaller coefficients. By default, ``simplify`` is True and ``simplify_all`` is False. :: sage: (x^4 - x + 1).splitting_field('a', simplify=False) Number Field in a with defining polynomial x^24 - 2780*x^22 + 2*x^21 + 3527512*x^20 - 2876*x^19 - 2701391985*x^18 + 945948*x^17 + 1390511639677*x^16 + 736757420*x^15 - 506816498313560*x^14 - 822702898220*x^13 + 134120588299548463*x^12 + 362240696528256*x^11 - 25964582366880639486*x^10 - 91743672243419990*x^9 + 3649429473447308439427*x^8 + 14310332927134072336*x^7 - 363192569823568746892571*x^6 - 1353403793640477725898*x^5 + 24293393281774560140427565*x^4 + 70673814899934142357628*x^3 - 980621447508959243128437933*x^2 - 1539841440617805445432660*x + 18065914012013502602456565991 sage: (x^4 - x + 1).splitting_field('a', simplify=True) Number Field in a with defining polynomial x^24 + 8*x^23 - 32*x^22 - 310*x^21 + 540*x^20 + 4688*x^19 - 6813*x^18 - 32380*x^17 + 49525*x^16 + 102460*x^15 - 129944*x^14 - 287884*x^13 + 372727*x^12 + 150624*x^11 - 110530*x^10 - 566926*x^9 + 1062759*x^8 - 779940*x^7 + 863493*x^6 - 1623578*x^5 + 1759513*x^4 - 955624*x^3 + 459975*x^2 - 141948*x + 53919 sage: (x^4 - x + 1).splitting_field('a', simplify_all=True) Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 Reducible polynomials also work:: sage: pol = (x^4 - 1)*(x^2 + 1/2)*(x^2 + 1/3) sage: pol.splitting_field('a', simplify_all=True) Number Field in a with defining polynomial x^8 - x^4 + 1 Relative situation:: sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^3 + 2) sage: S.<t> = PolynomialRing(K) sage: L.<b> = (t^2 - a).splitting_field() sage: L Number Field in b with defining polynomial t^6 + 2 With ``map=True``, we also get the embedding of the base field into the splitting field:: sage: L.<b>, phi = (t^2 - a).splitting_field(map=True) sage: phi Ring morphism: From: Number Field in a with defining polynomial x^3 + 2 To: Number Field in b with defining polynomial t^6 + 2 Defn: a |--> b^2 sage: (x^4 - x + 1).splitting_field('a', simplify_all=True, map=True)[1] Ring morphism: From: Rational Field To: Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 Defn: 1 |--> 1 We can enable verbose messages:: sage: from sage.misc.verbose import set_verbose sage: set_verbose(2) sage: K.<a> = (x^3 - x + 1).splitting_field() verbose 1 (...: splitting_field.py, splitting_field) Starting field: y verbose 1 (...: splitting_field.py, splitting_field) SplittingData to factor: [(3, 0)] verbose 2 (...: splitting_field.py, splitting_field) Done factoring (time = ...) verbose 1 (...: splitting_field.py, splitting_field) SplittingData to handle: [(2, 2), (3, 3)] verbose 1 (...: splitting_field.py, splitting_field) Bounds for absolute degree: [6, 6] verbose 2 (...: splitting_field.py, splitting_field) Handling polynomial x^2 + 23 verbose 1 (...: splitting_field.py, splitting_field) New field before simplifying: x^2 + 23 (time = ...) verbose 1 (...: splitting_field.py, splitting_field) New field: y^2 - y + 6 (time = ...) verbose 2 (...: splitting_field.py, splitting_field) Converted polynomials to new field (time = ...) verbose 1 (...: splitting_field.py, splitting_field) SplittingData to factor: [] verbose 2 (...: splitting_field.py, splitting_field) Done factoring (time = ...) verbose 1 (...: splitting_field.py, splitting_field) SplittingData to handle: [(3, 3)] verbose 1 (...: splitting_field.py, splitting_field) Bounds for absolute degree: [6, 6] verbose 2 (...: splitting_field.py, splitting_field) Handling polynomial x^3 - x + 1 verbose 1 (...: splitting_field.py, splitting_field) New field: y^6 + 3*y^5 + 19*y^4 + 35*y^3 + 127*y^2 + 73*y + 271 (time = ...) sage: set_verbose(0) Try all Galois groups in degree 4. We use a quadratic base field such that ``polgalois()`` cannot be used:: sage: R.<x> = PolynomialRing(QuadraticField(-11)) sage: C2C2pol = x^4 - 10*x^2 + 1 sage: C2C2pol.splitting_field('x') Number Field in x with defining polynomial x^8 + 24*x^6 + 608*x^4 + 9792*x^2 + 53824 sage: C4pol = x^4 + x^3 + x^2 + x + 1 sage: C4pol.splitting_field('x') Number Field in x with defining polynomial x^8 - x^7 - 2*x^6 + 5*x^5 + x^4 + 15*x^3 - 18*x^2 - 27*x + 81 sage: D8pol = x^4 - 2 sage: D8pol.splitting_field('x') Number Field in x with defining polynomial x^16 + 8*x^15 + 68*x^14 + 336*x^13 + 1514*x^12 + 5080*x^11 + 14912*x^10 + 35048*x^9 + 64959*x^8 + 93416*x^7 + 88216*x^6 + 41608*x^5 - 25586*x^4 - 60048*x^3 - 16628*x^2 + 12008*x + 34961 sage: A4pol = x^4 - 4*x^3 + 14*x^2 - 28*x + 21 sage: A4pol.splitting_field('x') Number Field in x with defining polynomial x^24 - 20*x^23 + 290*x^22 - 3048*x^21 + 26147*x^20 - 186132*x^19 + 1130626*x^18 - 5913784*x^17 + 26899345*x^16 - 106792132*x^15 + 371066538*x^14 - 1127792656*x^13 + 2991524876*x^12 - 6888328132*x^11 + 13655960064*x^10 - 23000783036*x^9 + 32244796382*x^8 - 36347834476*x^7 + 30850889884*x^6 - 16707053128*x^5 + 1896946429*x^4 + 4832907884*x^3 - 3038258802*x^2 - 200383596*x + 593179173 sage: S4pol = x^4 + x + 1 sage: S4pol.splitting_field('x') Number Field in x with defining polynomial x^48 ... Some bigger examples:: sage: R.<x> = PolynomialRing(QQ) sage: pol15 = chebyshev_T(31, x) - 1 # 2^30*(x-1)*minpoly(cos(2*pi/31))^2 sage: pol15.splitting_field('a') Number Field in a with defining polynomial x^15 - x^14 - 14*x^13 + 13*x^12 + 78*x^11 - 66*x^10 - 220*x^9 + 165*x^8 + 330*x^7 - 210*x^6 - 252*x^5 + 126*x^4 + 84*x^3 - 28*x^2 - 8*x + 1 sage: pol48 = x^6 - 4*x^4 + 12*x^2 - 12 sage: pol48.splitting_field('a') Number Field in a with defining polynomial x^48 ... If you somehow know the degree of the field in advance, you should add a ``degree_multiple`` argument. This can speed up the computation, in particular for polynomials of degree >= 12 or for relative extensions:: sage: pol15.splitting_field('a', degree_multiple=15) Number Field in a with defining polynomial x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 - 220*x^9 - 165*x^8 + 330*x^7 + 210*x^6 - 252*x^5 - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 1 A value for ``degree_multiple`` which isn't actually a multiple of the absolute degree of the splitting field can either result in a wrong answer or the following exception:: sage: pol48.splitting_field('a', degree_multiple=20) Traceback (most recent call last): ... ValueError: inconsistent degree_multiple in splitting_field() Compute the Galois closure as the splitting field of the defining polynomial:: sage: R.<x> = PolynomialRing(QQ) sage: pol48 = x^6 - 4*x^4 + 12*x^2 - 12 sage: K.<a> = NumberField(pol48) sage: L.<b> = pol48.change_ring(K).splitting_field() sage: L Number Field in b with defining polynomial x^48 ... Try all Galois groups over `\QQ` in degree 5 except for `S_5` (the latter is infeasible with the current implementation):: sage: C5pol = x^5 + x^4 - 4*x^3 - 3*x^2 + 3*x + 1 sage: C5pol.splitting_field('x') Number Field in x with defining polynomial x^5 + x^4 - 4*x^3 - 3*x^2 + 3*x + 1 sage: D10pol = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1 sage: D10pol.splitting_field('x') Number Field in x with defining polynomial x^10 - 28*x^8 + 216*x^6 - 681*x^4 + 902*x^2 - 401 sage: AGL_1_5pol = x^5 - 2 sage: AGL_1_5pol.splitting_field('x') Number Field in x with defining polynomial x^20 + 10*x^19 + 55*x^18 + 210*x^17 + 595*x^16 + 1300*x^15 + 2250*x^14 + 3130*x^13 + 3585*x^12 + 3500*x^11 + 2965*x^10 + 2250*x^9 + 1625*x^8 + 1150*x^7 + 750*x^6 + 400*x^5 + 275*x^4 + 100*x^3 + 75*x^2 + 25 sage: A5pol = x^5 - x^4 + 2*x^2 - 2*x + 2 sage: A5pol.splitting_field('x') Number Field in x with defining polynomial x^60 ... We can use the ``abort_degree`` option if we don't want to compute fields of too large degree (this can be used to check whether the splitting field has small degree):: sage: (x^5+x+3).splitting_field('b', abort_degree=119) Traceback (most recent call last): ... SplittingFieldAbort: degree of splitting field equals 120 sage: (x^10+x+3).splitting_field('b', abort_degree=60) # long time (10s on sage.math, 2014) Traceback (most recent call last): ... SplittingFieldAbort: degree of splitting field is a multiple of 180 Use the ``degree_divisor`` attribute to recover the divisor of the degree of the splitting field or ``degree_multiple`` to recover a multiple:: sage: from sage.rings.number_field.splitting_field import SplittingFieldAbort sage: try: # long time (4s on sage.math, 2014) ....: (x^8+x+1).splitting_field('b', abort_degree=60, simplify=False) ....: except SplittingFieldAbort as e: ....: print(e.degree_divisor) ....: print(e.degree_multiple) 120 1440 TESTS:: sage: from sage.rings.number_field.splitting_field import splitting_field sage: splitting_field(polygen(QQ), name='x', map=True, simplify_all=True) (Number Field in x with defining polynomial x, Ring morphism: From: Rational Field To: Number Field in x with defining polynomial x Defn: 1 |--> 1) """ from sage.misc.all import cputime from sage.misc.verbose import verbose degree_multiple = Integer(degree_multiple or 0) abort_degree = Integer(abort_degree or 0) # Kpol = PARI polynomial in y defining the extension found so far F = poly.base_ring() if is_RationalField(F): Kpol = pari("'y") else: Kpol = F.pari_polynomial("y") # Fgen = the generator of F as element of Q[y]/Kpol # (only needed if map=True) if map: Fgen = F.gen().__pari__() verbose("Starting field: %s" % Kpol) # L and Lred are lists of SplittingData. # L contains polynomials which are irreducible over K, # Lred contains polynomials which need to be factored. L = [] Lred = [SplittingData(poly._pari_with_name(), degree_multiple)] # Main loop, handle polynomials one by one while True: # Absolute degree of current field K absolute_degree = Integer(Kpol.poldegree()) # Compute minimum relative degree of splitting field rel_degree_divisor = Integer(1) for splitting in L: rel_degree_divisor = rel_degree_divisor.lcm(splitting.poldegree()) # Check for early aborts abort_rel_degree = abort_degree // absolute_degree if abort_rel_degree and rel_degree_divisor > abort_rel_degree: raise SplittingFieldAbort(absolute_degree * rel_degree_divisor, degree_multiple) # First, factor polynomials in Lred and store the result in L verbose("SplittingData to factor: %s" % [s._repr_tuple() for s in Lred]) t = cputime() for splitting in Lred: m = splitting.dm.gcd(degree_multiple).gcd( factorial(splitting.poldegree())) if m == 1: continue factors = Kpol.nffactor(splitting.pol)[0] for q in factors: d = q.poldegree() fac = factorial(d) # Multiple of the degree of the splitting field of q, # note that the degree equals fac iff the Galois group is S_n. mq = m.gcd(fac) if mq == 1: continue # Multiple of the degree of the splitting field of q # over the field defined by adding square root of the # discriminant. # If the Galois group is contained in A_n, then mq_alt is # also the degree multiple over the current field K. # Here, we have equality if the Galois group is A_n. mq_alt = mq.gcd(fac // 2) # If we are over Q, then use PARI's polgalois() to compute # these degrees exactly. if absolute_degree == 1: try: G = q.polgalois() except PariError: pass else: mq = Integer(G[0]) mq_alt = mq // 2 if (G[1] == -1) else mq # In degree 4, use the cubic resolvent to refine the # degree bounds. if d == 4 and mq >= 12: # mq equals 12 or 24 # Compute cubic resolvent a0, a1, a2, a3, a4 = (q / q.pollead()).Vecrev() assert a4 == 1 cubicpol = pari([ 4 * a0 * a2 - a1 * a1 - a0 * a3 * a3, a1 * a3 - 4 * a0, -a2, 1 ]).Polrev() cubicfactors = Kpol.nffactor(cubicpol)[0] if len(cubicfactors) == 1: # A4 or S4 # After adding a root of the cubic resolvent, # the degree of the extension defined by q # is a factor 3 smaller. L.append(SplittingData(cubicpol, 3)) rel_degree_divisor = rel_degree_divisor.lcm(3) mq = mq // 3 # 4 or 8 mq_alt = 4 elif len(cubicfactors) == 2: # C4 or D8 # The irreducible degree 2 factor is # equivalent to x^2 - q.poldisc(). discpol = cubicfactors[1] L.append(SplittingData(discpol, 2)) mq = mq_alt = 4 else: # C2 x C2 mq = mq_alt = 4 if mq > mq_alt >= 3: # Add quadratic resolvent x^2 - D to decrease # the degree multiple by a factor 2. discpol = pari([-q.poldisc(), 0, 1]).Polrev() discfactors = Kpol.nffactor(discpol)[0] if len(discfactors) == 1: # Discriminant is not a square L.append(SplittingData(discpol, 2)) rel_degree_divisor = rel_degree_divisor.lcm(2) mq = mq_alt L.append(SplittingData(q, mq)) rel_degree_divisor = rel_degree_divisor.lcm(q.poldegree()) if abort_rel_degree and rel_degree_divisor > abort_rel_degree: raise SplittingFieldAbort( absolute_degree * rel_degree_divisor, degree_multiple) verbose("Done factoring", t, level=2) if len(L) == 0: # Nothing left to do break # Recompute absolute degree multiple new_degree_multiple = absolute_degree for splitting in L: new_degree_multiple *= splitting.dm degree_multiple = new_degree_multiple.gcd(degree_multiple) # Absolute degree divisor degree_divisor = rel_degree_divisor * absolute_degree # Sort according to degree to handle low degrees first L.sort(key=lambda x: x.key()) verbose("SplittingData to handle: %s" % [s._repr_tuple() for s in L]) verbose("Bounds for absolute degree: [%s, %s]" % (degree_divisor, degree_multiple)) # Check consistency if degree_multiple % degree_divisor != 0: raise ValueError( "inconsistent degree_multiple in splitting_field()") for splitting in L: # The degree of the splitting field must be a multiple of # the degree of the polynomial. Only do this check for # SplittingData with minimal dm, because the higher dm are # defined as relative degree over the splitting field of # the polynomials with lesser dm. if splitting.dm > L[0].dm: break if splitting.dm % splitting.poldegree() != 0: raise ValueError( "inconsistent degree_multiple in splitting_field()") # Add a root of f = L[0] to construct the field N = K[x]/f(x) splitting = L[0] f = splitting.pol verbose("Handling polynomial %s" % (f.lift()), level=2) t = cputime() Npol, KtoN, k = Kpol.rnfequation(f, flag=1) # Make Npol monic integral primitive, store in Mpol # (after this, we don't need Npol anymore, only Mpol) Mdiv = pari(1) Mpol = Npol while True: denom = Integer(Mpol.pollead()) if denom == 1: break denom = pari(denom.factor().radical_value()) Mpol = (Mpol * (denom**Mpol.poldegree())).subst( "x", pari([0, 1 / denom]).Polrev("x")) Mpol /= Mpol.content() Mdiv *= denom # We are finished for sure if we hit the degree bound finished = (Mpol.poldegree() >= degree_multiple) if simplify_all or (simplify and not finished): # Find a simpler defining polynomial Lpol for Mpol verbose("New field before simplifying: %s" % Mpol, t) t = cputime() M = Mpol.polred(flag=3) n = len(M[0]) - 1 Lpol = M[1][n].change_variable_name("y") LtoM = M[0][n].change_variable_name("y").Mod( Mpol.change_variable_name("y")) MtoL = LtoM.modreverse() else: # Lpol = Mpol Lpol = Mpol.change_variable_name("y") MtoL = pari("'y") NtoL = MtoL / Mdiv KtoL = KtoN.lift().subst("x", NtoL).Mod(Lpol) Kpol = Lpol # New Kpol (for next iteration) verbose("New field: %s" % Kpol, t) if map: t = cputime() Fgen = Fgen.lift().subst("y", KtoL) verbose("Computed generator of F in K", t, level=2) if finished: break t = cputime() # Convert f and elements of L from K to L and store in L # (if the polynomial is certain to remain irreducible) or Lred. Lold = L[1:] L = [] Lred = [] # First add f divided by the linear factor we obtained, # mg is the new degree multiple. mg = splitting.dm // f.poldegree() if mg > 1: g = [c.subst("y", KtoL).Mod(Lpol) for c in f.Vecrev().lift()] g = pari(g).Polrev() g /= pari([k * KtoL - NtoL, 1]).Polrev() # divide linear factor Lred.append(SplittingData(g, mg)) for splitting in Lold: g = [c.subst("y", KtoL) for c in splitting.pol.Vecrev().lift()] g = pari(g).Polrev() mg = splitting.dm if Integer(g.poldegree()).gcd( f.poldegree()) == 1: # linearly disjoint fields L.append(SplittingData(g, mg)) else: Lred.append(SplittingData(g, mg)) verbose("Converted polynomials to new field", t, level=2) # Convert Kpol to Sage and construct the absolute number field Kpol = PolynomialRing(RationalField(), name=poly.variable_name())(Kpol / Kpol.pollead()) K = NumberField(Kpol, name) if map: return K, F.hom(Fgen, K) else: return K
def _solve_two_equations(eqn1, eqn2, x_val, y_val): """ Given two polynomial equations with rational coefficients in 'x' and 'y' and real intervals for x and y to isolate a solution to the system of equations, return the number field generated by x and the value of y in that number field. If y is not contained in the number field generated by x, return None. """ # Ring we work in Q[x][y] Rx = PolynomialRing(RationalField(), 'x') R = PolynomialRing(Rx, 'y') Reqn1 = R(eqn1) # Compute the resultant in Q[x] resultant = Reqn1.resultant(R(eqn2)) # Factorize the resultant. Find the unique factor that has the given value # for x as a root. def eval_factor_res(p): """ Evaluation method for the factors of the resultant. Apply polynomial to the given interval for x. """ return p(x_val) resultant_factor = _find_unique_good_factor(resultant, eval_factor_res) resultant_factor = Rx(resultant_factor) # The number field generated by x. # # (The embedding passed to the NumberField is a real number, so sage # will raise an exception if the resultant_factor has no real roots. # However, such a factor should not make it through # _find_unique_good_factor) result_number_field = NumberField(resultant_factor, 'x', embedding=x_val.center()) # Get one of the equations and think of it as an element in NumberField[y] yEqn = Reqn1.change_ring(result_number_field) # Factorize that equation over the NumberField. Find the unique factor # such that the given value y is a root when setting x to the given value # for x. def eval_factor_yEqn(p): """ Evaluation method for the factors of the equation factored over the number field. We take the factor and turn it into a polynomial in Q[x][y]. We then put in the given intervals for x and y. """ lift = p.map_coefficients(lambda c: c.lift('x'), Rx) return lift.substitute(x=x_val, y=y_val) yEqn_factor = _find_unique_good_factor(yEqn, eval_factor_yEqn) # If the equation for y in x is not of degree 1, then y is in a field # extension of the number field generated by x. # Bail if this happens. if not yEqn_factor.degree() == 1: return None # The equation of y is of the form # linear_term * y + constant_term = 0 constant_term, linear_term = yEqn_factor.coefficients(sparse=False) # Thus, y is given by - constant_term / linear_term return result_number_field, -constant_term / linear_term
from lxml.etree import tostring import qmt import sage.all hack = c.Converter() hack.register_to_python_name("http://python.org/", "Python", "list", lambda *args: list(args)) hack.register_to_python_class(om.OMString, lambda s: s.string) hack.register_to_python_class(om.OMInteger, lambda i: i.integer) from sage.rings.rational_field import RationalField hack.register_to_python_name("http://python.org/", "sage.rings.rational_field", "RationalField", RationalField()) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing hack.register_to_python_name( "http://python.org/", "sage.rings.polynomial.polynomial_ring_constructor", "PolynomialRing", PolynomialRing) def run(query, host="127.0.0.1", port=26134): """ Evaluates a query on a MitM server """ xml = encoder.encode_xml(query.getQuery()) client = None result = None try: client = SCSCPCLI(host, port=port)
def find_monomials(polynomial, poly_degree, r, s, form="list", sort_type="zero", early_finish=True, rolling_output=True, out_file=None): """This function finds all monomials that, in relation to the given monomial, fit the criteria of the problem. ***ATTENTION: DESPITE THE VARIABLE DECLARATIONS AT THE BEGINNING OF THE FUNCTION, THIS FUNCTION WILL NOT WORK CORRECTLY IF ALL VARIABLES IN THE INPUT POLYNOMIAL HAVE NOT ALREADY BEEN DECLARED.*** Args: polynomial(symb exp): The polynomial to which monomials will be matched. poly_degree(int): The degree of the input polynomial. r(int): The r value for the input polynomial. s(int): The s value for the input polynomial. form(str): If form is "list", the function will return a list of monomials. If form is "tup", the function will return a list of tuples with the form: (monomial, coefficient). sort_type(str): If sort_type is "zero", monomials are sorted by distance of the coefficient from zero. If sort type is "value", monomials are sorted by the coefficient's value. Returns: monomials(list): Returns either a list of monomials or a list of tuples depending on the value of form. Sorted by value or distance from zero of coefficients depending on the value of sort_type. If there are no working monomials, the function returns an empty list. """ if out_file != None: try: file = open(out_file, "w+") except: out_file = None print "File failed to open, printing to stdout..." print #Double check that variables are declared to prevent errors when forming monomials. for num in xrange(1, r + 1): var("x" + str(num)) for num in xrange(1, s + 1): var("y" + str(num)) # Declare ring as R ringlists = ring_lists(r, s) R, ringlists[1] = PolynomialRing(RationalField(), r + s, ringlists[0]).objgens() #Monomials must be checked against the expanded monomial # polynomial_expanded = polynomial.expand() #--- This was the old way polynomial_expanded = type_change(polynomial, ring=R) """This variable will be used to create a monomial "template" with all the essential variables and variables in place of exponent values. """ test_monomial = create_template_monomial(r, s) """This block creates a list of placeholders for x and y variable exponents in the order they appear. """ list_of_both_powers = create_power_list(r, s) """This block finds all possible exponent combinations for x and y variables in a list form, then finds all possible permutations of that list. """ list_of_power_values = create_power_values(r, s, poly_degree) """Now, every list of exponent possibilites is subbed into the monomial template, then checked against the expanded polynomial. If it is present in the expanded form, it is added to the final list. """ workable_monomials = [] for power_values in list_of_power_values: for power_set in multiset_permutations(power_values): temp_test_monomial = test_monomial power_set = list(power_set) if r > 0 and s > 0: testing_list = check_monomial_rs(r, s, power_set, temp_test_monomial, list_of_both_powers, polynomial_expanded, R) elif r > 0 and s == 0: testing_list = check_monomial_r(r, s, power_set, temp_test_monomial, list_of_both_powers, polynomial_expanded, R) elif r == 0 and s > 0: testing_list = check_monomial_s(r, s, power_set, temp_test_monomial, list_of_both_powers, polynomial_expanded, R) else: raise ValueError( "Invalid r and s inputs. r and s may not be bellow zero and may not both be zero" ) if testing_list[0] == 1: workable_monomials.append( (testing_list[2] * testing_list[1], int(testing_list[2]))) if rolling_output == True: if out_file != None: file.write(str(testing_list[2] * testing_list[1])) file.write("\n") else: print testing_list[2] * testing_list[1] #The following block tests to see if the function can finish early if early_finish == True: fin = 1 for fac in list(factor(int(testing_list[2]))): if r + s > 9: prime_range = xrange(-5, 6) else: prime_range = xrange(-3, 4) if fac[0] not in prime_range: fin = 0 if fin == 1: if form == "list": for i in xrange(0, len(workable_monomials)): workable_monomials[i] = workable_monomials[i][ 0] return workable_monomials #Changes output depending on preferences set at the outset. if len(workable_monomials) > 0: if sort_type == "zero": workable_monomials = sorted(workable_monomials, key=lambda tup: abs(tup[1])) else: workable_monomials = sorted(workable_monomials, key=lambda tup: tup[1]) if form == "list": for i in xrange(0, len(workable_monomials)): workable_monomials[i] = workable_monomials[i][0] return workable_monomials