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
    - +  
     1from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing 
     2from sage.rings.finite_rings.constructor import GF 
     3from sage.matrix.constructor import Matrix 
     4from sage.rings.polynomial.padics.factor.frameelt import FrameElt 
     5from sage.rings.infinity import infinity 
     6 
     7class 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
    - +  
     1from sage.rings.padics.factory import ZpFM 
     2from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing 
     3from sage.rings.polynomial.padics.factor.frame import Frame 
     4 
     5def 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 
     110def 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 
     141def 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
    - +  
     1from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing 
     2from sage.rings.polynomial.padics.factor.frameelt import FrameElt, FrameEltTerm 
     3from sage.rings.polynomial.padics.factor.segment import Segment 
     4from sage.rings.infinity import infinity 
     5from sage.misc.functional import denominator 
     6 
     7class 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
    - +  
     1class 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 
     206def _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 
     218class 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
    - +  
     1from sage.rings.polynomial.padics.factor.associatedfactor import AssociatedFactor 
     2from sage.rings.arith import gcd 
     3 
     4class 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  
    9696            return "0" 
    9797        return s[1:] 
    9898 
     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 
    99131    def factor(self, absprec = None): 
    100132        r""" 
    101133        Returns the factorization of this Polynomial_padic_flat. 
  • setup.py

    diff --git a/setup.py b/setup.py
    a b  
    975975                     'sage.rings.padics', 
    976976                     'sage.rings.polynomial', 
    977977                     'sage.rings.polynomial.padics', 
     978                     'sage.rings.polynomial.padics.factor', 
    978979                     'sage.rings.semirings', 
    979980                      
    980981                     'sage.tests',