Ticket #12561: 12561.patch
| File 12561.patch, 36.1 KB (added by bsinclai, 16 months ago) |
|---|
-
new file sage/rings/polynomial/padics/factor/__init__.py
# HG changeset patch # User Brian Sinclair <basincla@uncg.edu> # Date 1329985637 28800 # Node ID 896b0b29d7c546ccd9f37f0d92e79fad2e6d1a89 # Parent c9ec4d501534074ccf2ef0a6f3a203bad4f78f51 #12561:add padic polynomial factorization diff --git a/sage/rings/polynomial/padics/factor/__init__.py b/sage/rings/polynomial/padics/factor/__init__.py new file mode 100644
- + 1 # Initialization file for p-adic polynomial factoring -
new file sage/rings/polynomial/padics/factor/associatedfactor.py
diff --git a/sage/rings/polynomial/padics/factor/associatedfactor.py b/sage/rings/polynomial/padics/factor/associatedfactor.py new file mode 100644
- + 1 from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing 2 from sage.rings.finite_rings.constructor import GF 3 from sage.matrix.constructor import Matrix 4 from sage.rings.polynomial.padics.factor.frameelt import FrameElt 5 from sage.rings.infinity import infinity 6 7 class AssociatedFactor: 8 9 def __init__(self,segment,rho,rhoexp): 10 self.segment = segment 11 self.rho = rho 12 self.rhoexp = rhoexp 13 self.Fplus = self.rho.degree() 14 15 if self.segment.frame.is_first(): 16 # In the first frame, so FFbase is the residue class field of O 17 self.FFbase = self.segment.frame.R 18 else: 19 # Not the first frame 20 self.FFbase = self.segment.frame.prev.FF 21 22 if self.segment.frame.E * self.segment.frame.F * self.segment.Eplus * self.Fplus == self.segment.frame.Phi.degree(): 23 # Polynomial is irreducible 24 return 25 26 if self.Fplus == 1: 27 self.FF = self.FFbase 28 self.FFz = PolynomialRing(self.FF,'z'+str(self.segment.frame.depth)) 29 # rho is linear delta is the root of rho 30 self.delta = self.rho.roots()[0][0] 31 else: 32 self.FF = GF(self.FFbase.order()**self.Fplus,'a'+str(self.segment.frame.depth)) 33 self.FFz = PolynomialRing(self.FF,'z'+str(self.segment.frame.depth)) 34 self.FFbase_gamma = (self.FFz(self.FFbase.modulus())).roots()[0][0] 35 FFrho = self.FFz([self.FFbase_elt_to_FF(a) for a in list(rho)]) 36 self.gamma = FFrho.roots()[0][0] 37 basis = [(self.gamma**j*self.FFbase_gamma**i).polynomial() for j in range(0,self.Fplus) for i in range(0,self.FFbase.degree())] 38 self.basis_trans_mat = Matrix([self.FF(b)._vector_() for b in basis]) 39 40 def FF_elt_to_FFbase_vector(self,a): 41 if self.segment.frame.is_first() and self.Fplus == 1: 42 return a 43 elif self.Fplus == 1: 44 return self.segment.frame.prev.FF_elt_to_FFbase_vector(a) 45 else: 46 basedeg = self.FFbase.degree() 47 avec = self.FF(a)._vector_() 48 svector = self.basis_trans_mat.solve_left(Matrix(self.FF.prime_subfield(),avec)) 49 s_list = svector.list() 50 s_split = [ s_list[i*basedeg:(i+1)*basedeg] for i in range(0,self.Fplus)] 51 s = [sum([ss[i]*self.FFbase.gen()**i for i in range(0,len(ss))]) for ss in s_split] 52 return s 53 54 def FFbase_elt_to_FF(self,b): 55 if self.segment.frame.is_first(): 56 return b 57 elif self.Fplus == 1: 58 return self.segment.frame.prev.FFbase_elt_to_FF(b) 59 elif self.segment.frame.F == 1: 60 return b * self.FFbase_gamma 61 else: 62 bvec = b._vector_() 63 return sum([ bvec[i]*self.FFbase_gamma**i for i in range(len(bvec))]) 64 65 def __repr__(self): 66 return "AssociatedFactor of rho "+repr(self.rho) 67 68 def lift(self,delta): 69 # FrameElt representation of a lift of delta 70 if self.segment.frame.F == 1: 71 return FrameElt(self.segment.frame,self.segment.frame.Ox(delta)) 72 elif self.segment.frame.prev.Fplus == 1: 73 return FrameElt(self.segment.frame,self.segment.frame.prev.lift(delta),this_exp=0) 74 else: 75 dvec = self.segment.frame.prev.FF_elt_to_FFbase_vector(delta) 76 return sum([self.segment.frame.prev.gamma_frameelt**i*FrameElt(self.segment.frame,self.segment.frame.prev.lift(dvec[i]),this_exp=0) for i in range(len(dvec)) if dvec[i] != 0]) 77 78 def next_frame(self,length=infinity): 79 from frame import Frame 80 if self.Fplus == 1 and self.segment.Eplus == 1: 81 next = Frame(self.segment.frame.Phi,self.segment.frame.prev,self.segment.frame.iteration) 82 else: 83 next = Frame(self.segment.frame.Phi,self,self.segment.frame.iteration) 84 self.next = next 85 self.gamma_frameelt = FrameElt(next,self.segment.psi**-1,self.segment.Eplus) 86 if self.Fplus == 1 and self.segment.frame.F == 1: 87 next_phi = self.segment.frame.phi**self.segment.Eplus-(self.segment.psi.polynomial()*self.segment.frame.Ox(self.delta)) 88 self.reduce_elt = FrameElt(next,self.segment.psi*self.lift(self.delta),0) 89 next.seed(next_phi,length=length) 90 elif self.Fplus == 1 and self.segment.Eplus == 1: 91 delta_elt = self.lift(self.delta) 92 next_phi_tail = self.segment.psi*delta_elt.reduce() 93 next_phi = self.segment.frame.phi-next_phi_tail.polynomial() 94 self.reduce_elt = FrameElt(next,next_phi_tail,0) 95 next.seed(next_phi,length=length) 96 else: 97 lifted_rho_coeffs = [self.lift(r) for r in list(self.rho)] 98 lifted_rho_coeffs_with_psi = [FrameElt(next,(self.segment.psi**(self.Fplus-i)*lifted_rho_coeffs[i]).reduce(),0) for i in range(len(lifted_rho_coeffs))] 99 phi_elt = FrameElt(next,self.segment.frame.Ox(1),1) 100 next_phi_tail = sum([phi_elt**(self.segment.Eplus*i)*lifted_rho_coeffs_with_psi[i] for i in range(len(lifted_rho_coeffs_with_psi)-1)]) 101 next_phi = (phi_elt**(self.segment.Eplus*self.Fplus)+next_phi_tail).polynomial() 102 self.reduce_elt = FrameElt(next)+(-next_phi_tail) # that is -next_phi_tail 103 next.seed(next_phi,length=length) 104 return next -
new file sage/rings/polynomial/padics/factor/factoring.py
diff --git a/sage/rings/polynomial/padics/factor/factoring.py b/sage/rings/polynomial/padics/factor/factoring.py new file mode 100644
- + 1 from sage.rings.padics.factory import ZpFM 2 from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing 3 from sage.rings.polynomial.padics.factor.frame import Frame 4 5 def pfactortree(Phi): 6 r""" 7 Return a factorization of Phi 8 9 This is accomplished by constructing a tree of Frames of approximations of factors 10 11 INPUT:: 12 13 - ``Phi`` -- squarefree, monic padic polynomial with fixed precision coefficients 14 15 OUTPUT:: 16 17 - list -- polynomial factors of Phi 18 19 EXAMPLES:: 20 21 Factoring polynomials over Zp(2)[x]:: 22 23 sage: from sage.rings.polynomial.padics.factor.factoring import jorder4,pfactortree 24 sage: f = ZpFM(2,24,'terse')['x']( (x^32+16)*(x^32+16+2^16*x^2)+2^34 ) 25 sage: pfactortree(f) # long (3.8s) 26 [(1 + O(2^24))*x^64 + (65536 + O(2^24))*x^34 + (32 + O(2^24))*x^32 + (1048576 + O(2^24))*x^2 + (256 + O(2^24))] 27 28 See the irreducibility of x^32+16 in Zp(2)[x]:: 29 30 sage: pfactortree(ZpFM(2)['x'](x^32+16)) 31 [(1 + O(2^20))*x^32 + (2^4 + O(2^20))] 32 33 Test the irreducibility of test polynomial jorder4 for Zp(3):: 34 35 sage: len(pfactortree(jorder4(3))) == 1 36 True 37 38 Factor jorder4 for Zp(5) and Zp(7) and check that the products return the original:: 39 40 sage: ff = pfactortree(jorder4(5)) 41 sage: prod(ff) == jorder4(5) 42 True 43 sage: ff = pfactortree(jorder4(7)) 44 sage: prod(ff) == jorder4(7) 45 True 46 47 AUTHORS:: 48 49 - Brian Sinclair (2012-02-22): initial version 50 51 """ 52 from sage.misc.flatten import flatten 53 54 def followsegment(next,Phi): 55 """ Returns next if it corresponds to an irreducible factor of $\Phi$ and follows every branch if not """ 56 # Handle the unlikely event that our approximation is actually a factor 57 if next.phi_divides_Phi(): 58 return next 59 # With E potentially increased, Check to see if E*F == deg(Phi) (and thus Phi is irreducible) 60 if next.E * next.F * next.polygon[0].Eplus == Phi.degree(): 61 return next 62 # With F potentially increaded, Check to see if E*F == deg(Phi) (and thus Phi is irreducible) 63 if next.E * next.F * next.polygon[0].Eplus * next.polygon[0].factors[0].Fplus == Phi.degree(): 64 return next 65 # Check if we should begin Single Factor Lifting 66 if sum([seg.length for seg in next.polygon]) == 1: 67 return next 68 return [[followsegment(fact.next_frame(fact.rhoexp+1),Phi) for fact in seg.factors] for seg in next.polygon] 69 70 # Handle the situation that x is a factor of $\Phi(x)$ 71 if Phi.constant_coefficient() == 0: 72 x_divides = True 73 Phi = Phi >> 1 74 else: 75 x_divides = False 76 77 # Construct and initialize the first frame (phi = x) 78 next = Frame(Phi) 79 next.first() 80 81 # With E potentially increased, Check to see if E*F == deg(Phi) (and thus Phi is irreducible) 82 if next.E * next.F * next.polygon[0].Eplus == Phi.degree(): 83 return ([Phi.parent().gen()] if x_divides else []) + [Phi] 84 # With F potentially increaded, Check to see if E*F == deg(Phi) (and thus Phi is irreducible) 85 if next.E * next.F * next.polygon[0].Eplus * next.polygon[0].factors[0].Fplus == Phi.degree(): 86 return ([Phi.parent().gen()] if x_divides else []) + [Phi] 87 88 # Construct the next level of the tree by following every factor of the 89 # residual polynomials of every Newton polygon segment in our frame 90 tree = [[followsegment(fact.next_frame(fact.rhoexp+1),Phi) for fact in seg.factors] for seg in next.polygon] 91 92 # tree contains the leaves of the tree of frames and each leaf corresponds 93 # to an irreducible factor of Phi, so we flatten the list and start lifting 94 flat = flatten(tree) 95 96 # If we only have one leaf, Phi is irreducible, so we do not lift it. 97 if len(flat) == 1: 98 return ([Phi.parent().gen()] if x_divides else []) + [Phi] 99 # quo_rem is faster than Improve, so Phi = f*g are specially handled 100 if len(flat) == 2: 101 if flat[0].phi.degree() < flat[1].phi.degree(): 102 fact = Improve(flat[0]) 103 return ([Phi.parent().gen()] if x_divides else []) + [fact,Phi.quo_rem(fact)[0]] 104 else: 105 fact = Improve(flat[1]) 106 return ([Phi.parent().gen()] if x_divides else []) + [fact,Phi.quo_rem(fact)[0]] 107 # Phi has more than two factors, so we lift them all 108 return ([Phi.parent().gen()] if x_divides else []) + [Improve(frame) for frame in flatten(tree)] 109 110 def jorder4(p): 111 r""" 112 Produce a particularly complicated example of polynomials for factorization over Zp(p) 113 114 INPUT:: 115 116 - ``p`` a prime number 117 118 EXAMPLES:: 119 120 sage: from sage.rings.polynomial.padics.factor.factoring import jorder4 121 sage: jorder4(3) 122 (1 + O(3^20))*x^24 + (24 + O(3^20))*x^23 + (276 + O(3^20))*x^22 + (2048 + O(3^20))*x^21 + (11310 + O(3^20))*x^20 + (51180 + O(3^20))*x^19 + (201652 + O(3^20))*x^18 + (709092 + O(3^20))*x^17 + (2228787 + O(3^20))*x^16 + (6232484 + O(3^20))*x^15 + (15469950 + O(3^20))*x^14 + (34143276 + O(3^20))*x^13 + (67323664 + O(3^20))*x^12 + (119268300 + O(3^20))*x^11 + (190652502 + O(3^20))*x^10 + (275456480 + O(3^20))*x^9 + (359189415 + O(3^20))*x^8 + (420635664 + O(3^20))*x^7 + (438402286 + O(3^20))*x^6 + (400618284 + O(3^20))*x^5 + (313569267 + O(3^20))*x^4 + (203945072 + O(3^20))*x^3 + (105227142 + O(3^20))*x^2 + (38341248 + O(3^20))*x + (10912597 + O(3^20)) 123 124 Input must be prime:: 125 126 sage: jorder4(4) 127 Traceback (most recent call last): 128 ... 129 ValueError: p must be prime 130 131 """ 132 K = ZpFM(p,20,print_mode='terse') 133 Kx = PolynomialRing(K,names='x') 134 x = Kx.gen() 135 f1 = (x+1)**3+p; 136 f2 = f1**2+p**2*(x+1); 137 f3 = f2**2+4*p**3*f1*(x+1)**2; 138 f4 = f3**2+20*p**2*f3*f2*(x+1)**2+64*p**9*f1; 139 return f4; 140 141 def Improve(frame,prec=2**20): 142 r""" 143 Lift a frame to a factor 144 145 EXAMPLES:: 146 sage: from sage.rings.polynomial.padics.factor.factoring import Improve 147 sage: from sage.rings.polynomial.padics.factor.frame import Frame 148 sage: Kx.<x> = PolynomialRing(ZpFM(3,20,'terse')) 149 sage: f = (x**3+x-1)*(x**2+1) 150 sage: fr = Frame(f) 151 sage: fr.first() 152 sage: fr = fr.polygon[0].factors[0].next_frame() 153 sage: fact = Improve(fr) ; fact 154 (1 + O(3^20))*x + (904752403 + O(3^20)) 155 sage: f % fact 156 0 157 158 """ 159 def _reduce(poly,phi,d): 160 """ returns poly mod phi and simplifies the denominator of poly """ 161 poly = phi.parent()(poly) % phi 162 if d != 1: 163 g = min([d] + [p.valuation() for p in poly]) 164 if g > 0: 165 poly = poly.parent( [p >> g for p in poly] ) 166 d = d - g 167 return poly,d 168 if frame.phi_divides_Phi(): 169 return frame.phi 170 171 LiftRing = ZpFM(frame.O.uniformizer(),2*frame.O.precision_cap()) 172 Lifty = PolynomialRing(LiftRing,names='y') 173 Phi = Lifty(frame.Phi) 174 phi = Lifty(frame.phi) 175 a0,a1 = frame.elt_phi_expansion()[0:2] 176 177 Psi = frame.find_psi(-a1.valuation()) 178 A0 = Psi * a0 179 A1 = Psi * a1 180 181 Psi,Psiden = Psi.polynomial(True) 182 Psi = Lifty(Psi) 183 184 C1inv = frame.polygon[0].factors[0].lift(1/(A1.residue())) 185 C1inv,C1invden = C1inv.polynomial(True) 186 C1inv,C1invden = _reduce(C1inv,phi,C1invden) 187 188 A0,A0den = A0.polynomial(True) 189 A0,A0den = _reduce(Lifty(A0),phi,A0den) 190 191 C,Cden = _reduce(frame.Ox(A0*C1inv),phi,A0den+C1invden) 192 phi = (phi + C) 193 194 h = 2 195 oldphi = None 196 while h < prec and phi != oldphi: 197 oldphi = phi 198 C1, C0 = Phi.quo_rem(phi) 199 200 C0,C0den = _reduce((Psi*C0),phi,Psiden) 201 C1,C1den = _reduce((Psi*C1),phi,Psiden) 202 203 x1,x1den = _reduce((LiftRing(2)<<(C1den+C1invden))-C1*C1inv,phi,C1den+C1invden) 204 C1inv,C1invden = _reduce(C1inv*x1,phi,C1invden+x1den) 205 206 C,Cden = _reduce((C0*C1inv),phi,C0den+C1invden) 207 208 phi = (phi + C) 209 h = 2 * h 210 return frame.Ox(phi) -
new file sage/rings/polynomial/padics/factor/frame.py
diff --git a/sage/rings/polynomial/padics/factor/frame.py b/sage/rings/polynomial/padics/factor/frame.py new file mode 100644
- + 1 from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing 2 from sage.rings.polynomial.padics.factor.frameelt import FrameElt, FrameEltTerm 3 from sage.rings.polynomial.padics.factor.segment import Segment 4 from sage.rings.infinity import infinity 5 from sage.misc.functional import denominator 6 7 class Frame: 8 """Everything for one iteration of local field polynomial factorization""" 9 def __init__(self,Phi,pre=None,iteration_count=0): 10 self.prev = pre 11 self.Phi = Phi 12 self.O = Phi.base_ring() 13 self.Ox = Phi.parent() 14 self.x = self.Ox.gen() 15 self.R = self.O.residue_class_field() 16 self.Rz = PolynomialRing(self.R,names='z') 17 self.phi = None 18 self.iteration = iteration_count + 1 19 if self.is_first(): # that is self.prev == None 20 self.E = 1 21 self.F = 1 22 self.depth = 0 23 else: 24 self.E = self.prev_frame().E * self.prev.segment.Eplus 25 self.F = self.prev_frame().F * self.prev.Fplus 26 self.depth = self.prev_frame().depth + 1 27 28 def first(self): 29 """ 30 Computes all of the frame data based on being the root of the tree of frames 31 """ 32 self._phidividesPhi = False 33 self.phi = self.x 34 self._expansion_of_Phi() 35 self.polygon = self._newton_polygon([e.valuation() for e in self._phiexpelt]) # list of segments 36 37 def is_first(self): 38 return self.prev == None 39 40 def seed(self,phi,length=infinity): 41 """ 42 Computes all of the frame data with the new phi 43 """ 44 self.phi = phi 45 self._phidividesPhi = False 46 self._expansion_of_Phi(length=length) 47 # If phi divides Phi, we return to the main factorization loop, where 48 # this property should be checked for 49 if self._phiexppoly[0] == 0: 50 return 51 else: 52 self.polygon = self._newton_polygon([e.valuation() for e in self._phiexpelt]) # list of segments 53 54 def find_psi(self,val): 55 psielt = FrameElt(self) 56 if self.prev == None: 57 psielt.rep = [FrameEltTerm(psielt,self.O(1),val)] 58 else: 59 vphi = self.prev.segment.slope 60 d = self.prev_frame().E 61 vprime = val*d 62 e = vphi * d 63 psimod = denominator(e) 64 s = 0 65 if not psimod == 1: 66 s = vprime / e 67 if denominator(s) == 1: 68 s = s % psimod 69 else: 70 s = int(s % psimod) 71 val = val - s * vphi 72 psielt.rep = [FrameEltTerm(psielt,self.prev_frame().find_psi(val),s)] 73 return psielt 74 75 def _expansion_of_Phi(self,length=infinity): 76 self._phiexppoly = [] 77 if self.phi.degree() > self.Phi.degree(): 78 self._phiexppoly = [self.Phi] 79 q, r = self.Phi.quo_rem(self.phi) 80 self._phiexppoly.append(r) 81 while q != 0 and length > len(self._phiexppoly): 82 q, r = q.quo_rem(self.phi) 83 self._phiexppoly.append(r) 84 self._phiexpelt = [FrameElt(self,a) for a in self._phiexppoly] 85 86 def _newton_polygon(self,a,xoffset=0): 87 if len(a) == 0: 88 raise ValueError, "Cannot compute Newton polygon from empty list" 89 slope = (a[0]-a[len(a)-1]) / (len(a)-1) 90 verts = [(xoffset,a[0])] 91 length = 0 92 for i in range(1,len(a)): 93 y = a[0] - i*slope 94 if a[i] == y: 95 verts.append((xoffset+i,y)) 96 length = i 97 elif a[i] < y: 98 verts = [(xoffset,a[0]),(xoffset+i,a[i])] 99 slope = (a[0]-a[i]) / i 100 length = i 101 elif y < 0: 102 if len(a[verts[len(verts)-1][0]-xoffset:]) == 0: 103 return [Segment(self,slope,verts,length)] 104 else: 105 return [Segment(self,slope,verts,length)]+self._newton_polygon(a[verts[len(verts)-1][0]-xoffset:],verts[len(verts)-1][0]) 106 return [Segment(self,slope,verts,length)] 107 108 # Data Access Methods 109 110 def prev_frame(self): 111 if self.prev == None: 112 return None 113 else: 114 return self.prev.segment.frame 115 116 def elt_phi_expansion(self): 117 return self._phiexpelt 118 119 def phi_divides_Phi(self): 120 """ 121 Returns whether or not phi divides Phi 122 123 Checks to see if the constant term of the phi-expansion of Phi is 0 124 """ 125 return self._phiexppoly[0] == 0 126 127 def __repr__(self): 128 if self.phi: 129 return 'Frame with phi '+repr(self.phi) 130 else: 131 return 'Unseeded Frame regarding '+repr(self.Phi) -
new file sage/rings/polynomial/padics/factor/frameelt.py
diff --git a/sage/rings/polynomial/padics/factor/frameelt.py b/sage/rings/polynomial/padics/factor/frameelt.py new file mode 100644
- + 1 class FrameElt: 2 """Polynomials recursively represented by powers of the approximations $\phi_t(x)$ to a factor of $\Phi(x)$.""" 3 4 def __init__(self,frame,a=None,this_exp=None): 5 # deg(a) < deg(frame.phi)*frame.Eplus*frame.Fplus 6 self.frame = frame 7 if this_exp != None: 8 # initializes a FrameElt of phi_t ^ this_exp * a 9 self.rep = [FrameEltTerm(self,a,this_exp)] 10 elif a == None: 11 self.rep = [] 12 elif frame.is_first(): 13 self.rep = [FrameEltTerm(self,a,0)] 14 else: 15 b = _phi_expansion(a,self.frame.prev_frame().phi) 16 self.rep = [FrameEltTerm(self,b[i],i) for i in range(len(b)) if b[i].is_zero() == False] 17 18 def is_single_term(self): 19 if len(self.rep) == 1: 20 if self.frame.prev == None: 21 return True 22 else: 23 return self.rep[0]._coefficient.is_single_term() 24 return False 25 26 def valuation(self,purge=True): 27 if not purge: 28 return min([a.valuation() for a in self.rep]) 29 else: 30 v = min([a.valuation() for a in self.rep]) 31 self.rep = [a for a in self.rep if a.valuation() == v] 32 return v 33 34 def residue(self): 35 if not self.is_reduced(): 36 self = self.reduce() 37 38 if self.frame.is_first(): 39 if self.rep[0]._exponent == 0: 40 # unable to coerce in Zq 41 return self.frame.R(self.rep[0]._unit) 42 else: 43 return self.frame.R(0) 44 45 Eplus = int(self.frame.prev.segment.Eplus) 46 if self.frame.prev.Fplus > 1: 47 psi = self.frame.prev.segment.psi 48 gamma = self.frame.prev.gamma 49 residuelist = [gamma**(a._exponent/Eplus)*self.frame.prev.FFbase_elt_to_FF((psi**(a._exponent/Eplus)*a.value()).residue()) for a in self.rep if int(a._exponent) % Eplus == 0] 50 else: 51 residuelist = [a.value().residue() for a in self.rep if int(a._exponent) == 0] 52 if len(residuelist) > 0: 53 return sum(residuelist) 54 else: 55 return self.frame.R(0) 56 57 def reduce(self): 58 if self.frame.is_first(): 59 return self 60 Eplus = self.frame.prev.segment.Eplus 61 Fplus = self.frame.prev.Fplus 62 reduced_elt = FrameElt(self.frame) # zero FrameElt 63 for a in self.rep: 64 if a._exponent >= Eplus * Fplus: 65 b = FrameElt(self.frame) 66 b.rep = [FrameEltTerm(b,a.value(),a._exponent - Eplus * Fplus)] 67 b *= self.frame.prev.reduce_elt 68 reduced_elt += b.reduce() 69 elif a._exponent < 0: 70 b = FrameElt(self.frame) 71 b.rep = [FrameEltTerm(b,a.value(),a._exponent + Eplus * Fplus)] 72 b *= (self.frame.prev.reduce_elt)**(-1) 73 reduced_elt += b.reduce() 74 else: 75 summand = FrameElt(self.frame) 76 summand.rep = [FrameEltTerm(reduced_elt,a.value().reduce(),a._exponent)] 77 reduced_elt += summand 78 return reduced_elt 79 80 def sumcollapse(self): 81 sumt = FrameElt(self.frame) 82 sumc = FrameElt(self.frame) 83 for i in range(len(self.rep)): 84 sumc.rep = [self.rep[i]] 85 sumt += sumc 86 return sumt 87 88 def is_reduced(self): 89 return all([a.is_reduced() for a in self.rep]) 90 91 def find_denominator(self): 92 """ 93 Find the lowest power (possibly negative) of the uniformizer in a FrameElt 94 """ 95 if self.frame.is_first(): 96 return self.rep[0]._exponent 97 else: 98 return min([fet._coefficient.find_denominator() for fet in self.rep]) 99 100 def polynomial(self,denominator=False): 101 if denominator: 102 piexp = self.find_denominator() 103 if piexp < 0: 104 return (self * FrameElt(self.frame,self.frame.Ox(self.frame.O.uniformizer()**(-piexp)))).polynomial(),-piexp 105 else: 106 return self.polynomial(),0 107 else: 108 if self.frame.is_first(): 109 return self.frame.O.uniformizer()**int(self.rep[0]._exponent)*self.rep[0]._unit 110 else: 111 return sum([self.frame.prev_frame().phi**int(a._exponent)*a._coefficient.polynomial() for a in self.rep]) 112 113 def __neg__(self): 114 if self.frame.is_first(): 115 return FrameElt(self.frame,-self.polynomial()) 116 else: 117 neg = FrameElt(self.frame) 118 neg.rep = [-r for r in self.rep] 119 return neg 120 121 def __radd__(self,l): 122 return self.__add__(l) 123 124 def __add__(self,r): 125 if isinstance(r,int) and r == 0: 126 return self 127 if self.frame.phi != r.frame.phi: 128 raise ValueError, "Cannot add FrameElts with different values of phi" 129 if len(self.rep) == 0: 130 return r 131 sum = FrameElt(self.frame) 132 if self.frame.prev == None: 133 v = min(self.rep[0]._exponent,r.rep[0]._exponent) 134 pi = self.frame.O.uniformizer() 135 usum = self.rep[0]._unit * pi ** (self.rep[0]._exponent - v) 136 usum = usum + r.rep[0]._unit * pi ** (r.rep[0]._exponent - v) 137 sum.rep = [FrameEltTerm(sum,usum,v)] 138 else: 139 if self.rep == []: 140 for k in range(len(r.rep)): 141 sum.rep.append(FrameEltTerm(sum,r.rep[k].value(),r.rep[k]._exponent)) 142 elif r.rep == []: 143 for k in range(len(self.rep)): 144 sum.rep.append(FrameEltTerm(sum,self.rep[k].value(),self.rep[k]._exponent)) 145 else: 146 i = 0 ; j = 0 147 while i < len(self.rep) and j < len(r.rep): 148 if self.rep[i]._exponent < r.rep[j]._exponent: 149 sum.rep.append(FrameEltTerm(sum,self.rep[i].value(),self.rep[i]._exponent)) 150 i = i + 1 151 elif self.rep[i]._exponent > r.rep[j]._exponent: 152 sum.rep.append(FrameEltTerm(sum,r.rep[j].value(),r.rep[j]._exponent)) 153 j = j + 1 154 elif self.rep[i]._exponent == r.rep[j]._exponent: 155 sum.rep.append(FrameEltTerm(sum,self.rep[i].value()+r.rep[j].value(),self.rep[i]._exponent)) 156 i = i + 1; j = j + 1 157 if j < len(r.rep): 158 for k in range(j,len(r.rep)): 159 sum.rep.append(FrameEltTerm(sum,r.rep[k].value(),r.rep[k]._exponent)) 160 elif i < len(self.rep): 161 for k in range(i,len(self.rep)): 162 sum.rep.append(FrameEltTerm(sum,self.rep[k].value(),self.rep[k]._exponent)) 163 return sum 164 165 def __rmul__(self,l): 166 return self.__mul__(l) 167 168 def __mul__(self,r): 169 if isinstance(r,int) and r == 0: 170 return self 171 if self.frame.depth != r.frame.depth: 172 raise ValueError, "Cannot multiply FrameElts with different frame depths" 173 product = FrameElt(self.frame) 174 if self.frame.prev == None: 175 v = self.rep[0]._exponent + r.rep[0]._exponent 176 uprod = self.rep[0]._unit 177 uprod = uprod * r.rep[0]._unit 178 product.rep = [FrameEltTerm(product,uprod,v)] 179 else: 180 for i in range(len(self.rep)): 181 summand = FrameElt(self.frame) 182 for j in range(len(r.rep)): 183 summand.rep.append(FrameEltTerm(product,self.rep[i].value()*r.rep[j].value(),self.rep[i]._exponent+r.rep[j]._exponent)) 184 product = product + summand 185 return product 186 187 def __pow__(self,n): 188 if not self.is_single_term(): 189 raise NotImplementedError, "Cannot take a power of a non-single term FrameElt" 190 else: 191 product = FrameElt(self.frame) 192 product.rep = [self.rep[0]**n] 193 return product 194 195 def __div__(self,right): 196 if not right.is_single_term(): 197 raise NotImplementedError, "Cannot divide by a non-single term FrameElt" 198 else: 199 quotient = FrameElt(self.frame) 200 quotient.rep = [a / right.rep[0] for a in self.rep] 201 return quotient 202 203 def __repr__(self): 204 return repr(self.rep) 205 206 def _phi_expansion(P,phi): 207 """ Compute the phi-expansion of P """ 208 if phi.degree() > P.degree(): 209 return [P] 210 expansion = [] 211 q, r = P.quo_rem(phi) 212 expansion.append(r) 213 while q != 0: 214 q, r = q.quo_rem(phi) 215 expansion.append(r) 216 return expansion 217 218 class FrameEltTerm: 219 220 def __init__(self,frelt,a,e): 221 self.frameelt = frelt 222 self._scalar_flag = (self.frameelt.frame.prev == None) 223 self._exponent = e 224 self._cached_valuation = None 225 self._zero_flag = False 226 227 if a in self.frameelt.frame.Ox or a in self.frameelt.frame.O: 228 self._zero_flag = a.is_zero() 229 if self._scalar_flag: 230 a = self.frameelt.frame.O(a) 231 if self._zero_flag: 232 self._unit = a 233 else: 234 self._unit = a.unit_part() 235 if a.valuation() > 0 and a.valuation(): 236 self._exponent += a.valuation() 237 else: 238 self._coefficient = FrameElt(self.frameelt.frame.prev_frame(),a) 239 else: 240 self._coefficient = a 241 a._zero_flag = False 242 243 def valuation(self): 244 if self._cached_valuation == None: 245 if self.frameelt.frame.prev == None: 246 self._cached_valuation = self._exponent 247 else: 248 self._cached_valuation = self.frameelt.frame.prev.segment.slope * self._exponent + self._coefficient.valuation() 249 return self._cached_valuation 250 251 def reduce(self): 252 if self.frameelt.frame.prev == None: 253 return 254 Eplus = self.frameelt.frame.prev.segment.Eplus 255 Fplus = self.frameelt.frame.prev.Fplus 256 257 if self._exponent >= Eplus * Fplus: 258 q,r = int(self._exponent).quo_rem(int(Eplus)) 259 self._exponent = r 260 self._coefficient *= (self.frameelt.frame.prev.segment.psi ** (q*Fplus)) 261 self._coefficient.reduce() 262 return 263 264 def is_reduced(self): 265 if self.frameelt.frame.prev == None: 266 return True 267 if self._exponent < self.frameelt.frame.prev.segment.Eplus: 268 return self._coefficient.is_reduced() 269 return False 270 271 def is_scalar(self): 272 return self._scalar_flag 273 def is_zero(self): 274 return self._zero_flag 275 def is_single_term(self): 276 if self._scalar_flag: 277 return True 278 else: 279 return self._coefficient.is_single_term() 280 281 def value(self): 282 if self._scalar_flag: 283 return self._unit 284 else: 285 return self._coefficient 286 287 #def __add__(self,right): 288 #def __mul__(self,right): 289 # We don't add or multiply on FrameEltTerms directly -- the parent FrameElt does this 290 291 def __pow__(self,n): 292 if not self.is_single_term(): 293 raise NotImplementedError, "Cannot take a power of a non-single term FrameEltTerm" 294 else: 295 n = int(n) 296 if self._scalar_flag: 297 return FrameEltTerm(self.frameelt, self._unit**n, self._exponent*n) 298 else: 299 return FrameEltTerm(self.frameelt, self._coefficient**n, self._exponent*n) 300 301 def __div__(self,right): 302 if not right.is_single_term(): 303 raise NotImplementedError, "Cannot divide by a non-single term FrameEltTerm" 304 else: 305 if self._scalar_flag: 306 return FrameEltTerm(self.frameelt, self._unit/right._unit, self._exponent-right._exponent) 307 else: 308 return FrameEltTerm(self.frameelt, self._coefficient/right._coefficient, self._exponent-right._exponent) 309 310 def __neg__(self): 311 if self.frameelt.frame.is_first(): 312 return FrameEltTerm(self.frameelt,-self._unit,self._exponent) 313 else: 314 return FrameEltTerm(self.frameelt,-self._coefficient,self._exponent) 315 316 def __repr__(self): 317 if self._zero_flag: 318 return 'FET<0>' 319 if self._scalar_flag: 320 return 'FET<pi^'+repr(self._exponent)+'*'+repr(self._unit)+'>' 321 else: 322 return 'FET<'+repr(self._exponent)+','+repr(self._coefficient)+'>' -
new file sage/rings/polynomial/padics/factor/segment.py
diff --git a/sage/rings/polynomial/padics/factor/segment.py b/sage/rings/polynomial/padics/factor/segment.py new file mode 100644
- + 1 from sage.rings.polynomial.padics.factor.associatedfactor import AssociatedFactor 2 from sage.rings.arith import gcd 3 4 class Segment: 5 6 def __init__(self,frame,slope,vert,length): 7 self.frame = frame 8 self.vertex = vert 9 self.slope = slope 10 self.length = length 11 self.Eplus = self.e() / gcd(self.e(),int(self.frame.E)) 12 if self.frame.E * self.frame.F * self.Eplus < self.frame.Phi.degree(): 13 self.psi = self.frame.find_psi(self.slope*self.Eplus) 14 self._associate_polynomial = self.associate_polynomial(cached=False) 15 self.factors = [AssociatedFactor(self,afact[0],afact[1]) for afact in list(self._associate_polynomial.factor())] 16 else: 17 # Polynomial is irreducible 18 return 19 20 def h(self): 21 if isinstance(self.slope,int): 22 return self.slope.numerator 23 else: 24 return self.slope.numerator() 25 def e(self): 26 if isinstance(self.slope,int): 27 return self.slope.denominator 28 else: 29 return self.slope.denominator() 30 31 def vphi(self): 32 return self.slope 33 34 def associate_polynomial(self,cached=True): 35 if cached: 36 return self._associate_polynomial() 37 else: 38 a = self.frame.elt_phi_expansion() 39 vertx = [v[0] for v in self.vertex] 40 chiex = [int((v-vertx[0]) // self.Eplus) for v in vertx] 41 chi = [a[vertx[i]] * self.psi**chiex[i] for i in range(len(vertx))] 42 psitilde = self.frame.find_psi(chi[0].valuation()) 43 Ahat = [(c/psitilde).reduce() for c in chi] 44 if self.frame.prev == None: 45 Az = sum([(Ahat[i].residue()) * self.frame.Rz.gen() ** chiex[i] for i in range(len(Ahat))]) 46 else: 47 Az = sum([(Ahat[i].residue()) * self.frame.prev.FFz.gen() ** chiex[i] for i in range(len(Ahat))]) 48 return Az 49 50 def __repr__(self): 51 return 'Segment of length '+repr(self.length)+' and slope '+repr(self.slope) -
sage/rings/polynomial/padics/polynomial_padic_flat.py
diff --git a/sage/rings/polynomial/padics/polynomial_padic_flat.py b/sage/rings/polynomial/padics/polynomial_padic_flat.py
a b 96 96 return "0" 97 97 return s[1:] 98 98 99 def quo_rem(self,right): 100 """ 101 Returns the quotient and remainder of division by right 102 103 EXAMPLES: 104 sage: Kx.<x> = PolynomialRing(Zp(7)) 105 sage: (x^3+7*x+1).quo_rem(x-7) 106 ((1 + O(7^20))*x^2 + (7 + O(7^21))*x + (7 + 7^2 + O(7^21)), (O(7^20))*x^3 + (O(7^21))*x^2 + (O(7^21))*x + (1 + 7^2 + 7^3 + O(7^20))) 107 """ 108 return self._quo_rem_naive(right) 109 110 def _quo_rem_naive(self, right): 111 """ 112 Naive quotient with remainder operating on padic polynomials as their coefficient lists 113 """ 114 if right == 0: 115 raise ZeroDivisionError, "cannot divide by a polynomial indistinguishable from 0" 116 P = self.parent() 117 F = list(self); G = list(right); 118 fdeg = self.degree() 119 gdeg = right.degree() 120 Q = [0 for i in range(fdeg-gdeg+1)] 121 j=1 122 while fdeg >= gdeg: 123 a = F[-j] 124 if a!=0: 125 for i in range(fdeg-gdeg,fdeg+1): 126 F[i] -= a * G[i-(fdeg-gdeg)] 127 Q[fdeg-gdeg] += a 128 j+=1; fdeg-=1; 129 return (P(Q), P(F)) 130 99 131 def factor(self, absprec = None): 100 132 r""" 101 133 Returns the factorization of this Polynomial_padic_flat. -
setup.py
diff --git a/setup.py b/setup.py
a b 975 975 'sage.rings.padics', 976 976 'sage.rings.polynomial', 977 977 'sage.rings.polynomial.padics', 978 'sage.rings.polynomial.padics.factor', 978 979 'sage.rings.semirings', 979 980 980 981 'sage.tests',
