polys.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 
--
-- This module is distributed freely in the sence of 
-- GPL(GNU General Public License).
--
-- Class of 1 variable polynomial.
-- Coefficients admit Integer,Rationall,Complex and Float.
--
-- Class of single variable polynomial of ring "R" coefficient.
-- K.Kodama 2000-07-01. Port from ruby polynomial class.
-- refinement checkDivZe,checkZp and setPoly
--     by toyofuku@jiuce.or.jp 2000-03-10 
-- Ruby. [] []= by Masaki Suketa 2000-01-22
--
--  Thaks to Hideto ISHIBASHI and Masaki Suketa for their suggestion.
--
--  K.Kodama(kodama@kobe-kosen.ac.jp) 2000-01-09 
--    first version(Ruby)
--



class POLYS_INTI <$IS_LT{POLYS_INTI},$STR

class POLYS_INTI <$IS_LT{POLYS_INTI},$STR is include COMPARABLE; include POLYS{INTI} is_SqrFree->, squareFreeDecomposition->, integral->; -- include PID_GCD; include POLYS_COMPARE{POLYS_INTI}; compare(other:SAME):INT is return compare_lt(other); end; init is r_0:=0.inti; r_1:=1.inti; divmodForce0:=false; POLYS_RAT::init; end; create(c:INT,d:CARD): SAME is -- c*x^(d) res:SAME:=allocate(d); res.clear; res.arr[d]:=c.inti; return res; end; create(c:INT): SAME is -- c*x^0 return #(c.inti,0); end; create(c:CARD): SAME is -- c*x^0 return #(c.inti,0); end; polys_fp:POLYS_FP is g:POLYS_FP:=#; loop i::=arr.ind!; g[i]:=#(arr[i]); end; return g; end; gcd_coeff:INTI is -- gcd of coefficients g:INTI:=0.inti; -- gcd loop c::=arr.elt!; if c.is_zero.not then g:=g.gcd(c); if g=1.inti then return g; end; end; end; return g; end; lcm_coeff:INTI is -- lcm of of coefficients l:INTI:=1.inti; -- lcm loop c::=arr.elt!; if c.is_zero.not then l:=l.lcm(c); end; end; return l; end; remove_gcd is -- self/gcd_coeff g::=gcd_coeff; if g>1.inti then loop i::=arr.ind!; arr[i]:=arr[i]/g; end; end; end; remove_gcd:SAME is -- self/gcd_coeff f::=self.copy; f.remove_gcd; return f; end; mod(n:INTI):SAME is -- mod each coefficient. r::=copy; loop i::=r.arr.ind!; r.arr[i]:=r.arr[i]%n; end; r.normalize; return r; end; mod_lt(other:ARRAY{SAME}):SAME is -- mod for leading term r:SAME:=self.copy; lcR::=r.lc.abs; i:CARD:=0; loop while!(i<other.size); b:SAME:=other[i]; if (b.degree<=r.degree)and(b.lc.abs<=lcR)and(b.is_zero.not) then lcQ::=r.lc/b.lc; if lcQ.is_zero then i:=i+1; else r:=r-(b*lcQ).shift_deg(r.degree-b.degree); lcR:=r.lc.abs; i:=0; end; else i:=i+1; end; end; return r; end; mod_n(n:INTI):SAME is -- mod( -n/2< coeff <= n/2 ) for each coeff. c:INTI; r::=copy; n2::=(n+1.inti)/2.inti; loop i::=r.arr.ind!; c:=r.arr[i]%n; if c>n2 then c:=c-n; end; r.arr[i]:=c; end; r.normalize; return r; end; divmod_Zp(p:INTI, divisor:SAME, out q:SAME, out r:SAME) is -- as Zp coefficient polynomial. q:=#; r:=mod(p); -- Quotient/ Residue degR:CARD:=r.degree.card; d_poly::=divisor.mod(p); degD:CARD:=d_poly.degree.card; if degR>=degD then pd::=INTI_EXT::inv(p,d_poly.lc); loop dq::=(degR-degD).downto!(0); if (r.arr[dq+degD]/=r_0) then ;-- q.arr[dq]:=r_0 q1::=(r[dq+degD]*pd)%p; q[dq]:=q1; loop i::=0.upto!(degD); j::=dq.up!; r.arr[j] := (r.arr[j]-q1*d_poly.arr[i])%p; end; end; end; end; q.normalize; r.normalize; end; gcd_Zp(prime:INTI, o:SAME):SAME is -- Euclidean algorithm. a::=copy; b::=o.copy; q:SAME; loop if b.is_zero then return a; end; a.divmod_Zp(prime, b,out q, out a); if a.is_zero then return b; end; b.divmod_Zp(prime, a,out q, out b); end; end; extended_gcd_Zp(prime:INTI,o:SAME, out f1:SAME, out f2:SAME):SAME is a::=copy; b::=o.copy; x::=one; y::=zero; u::=zero; v::=one; q:SAME; loop if b.is_zero then f1:=x; f2:=y; return a; end; a.divmod_Zp(prime,b, out q, out a); x:=(x-q*u)%prime; y:=(y-q*v)%prime; if a.is_zero then f1:=u; f2:=v; return b; end; b.divmod_Zp(prime,a,out q, out b); u:=(u-q*x)%prime; v:=(v-q*y)%prime; end; end; polys_rat:POLYS_RAT is g:POLYS_RAT:=#; loop i::=arr.ind!; g[i]:=#RAT(arr[i]); end; return g; end; is_SqrFree(prime:INTI):BOOL is return self.gcd_Zp(prime, self.derivative).degree.is_zero; end; is_SqrFree:BOOL is return polys_rat.is_SqrFree; end; squareFreeDecomposition:ARRAY{SAME} is f_rat::=polys_rat; sqf_rat::=f_rat.squareFreeDecomposition; sqf:ARRAY{SAME}:=#(sqf_rat.size); loop i::=sqf_rat.ind!; sqf[i]:=sqf_rat[i].polys_inti; end; return sqf; end; constructionHensel(g,h:SAME, n,prime,pn:INTI, out g1,out h1:SAME) is -- Hensel's construction. -- Input: self,g,h,n,prime,pn s.t. self==g*h (mod pn), pn=prime^n -- Output: g,h s.t. f=g*h (mod prime^(n+1)) d0:SAME:=self-g*h; d:SAME:=(d0/#SAME(pn))%prime; a,b,a0,b0,a1,b1,q:SAME; gcd_gh:SAME:=g.extended_gcd_Zp(prime,h,out a0,out b0); a1:=(a0*d*INTI_EXT::inv(prime,gcd_gh[0])); b1:=(b0*d*INTI_EXT::inv(prime,gcd_gh[0])); -- Must be a1.degree<h.degree, b1.degree<=g.degree. a1.divmod_Zp(prime, h,out q, out a); b:=(b1+q*g)%prime; g1:=(g+b*pn).mod_n(pn*prime); h1:=(h+a*pn).mod_n(pn*prime); -- Now, a*g1+b*h1==d mod prime and self==g*h mod prime^(n+1) end; factorize:ARRAY{SAME} is return FACTORIZATION_ALG::factorize(self); end; countSolution(a,b: INTI, countRedundancy:BOOL):CARD is return countSolution(a,b, false,false, countRedundancy); end; countSolution(a,b:INTI, infty_n,infty:BOOL , countRedundancy:BOOL):CARD is return polys_rat.countSolution(#RAT(a),#RAT(b),infty_n,infty,countRedundancy); end; S_poly_PID(g:SAME):SAME is ldF::=degree; lcF::=lc; ldG::=g.degree; lcG::=g.lc; --lcmP::=lpF.lcm(lpG); lcmC::=lcF.abs.lcm(lcG.abs); -- lcm=fc*gc/gcd --s::=#SAME(lcmP/lpF)*self*(lcmC/lcF)-#SAME(lcmP/lpG)*g*(lcmC/lcG); lcmD::=ldF.max(ldG); lcmC::=lcF.abs.lcm(lcG.abs); -- lcm=fc*gc/gcd s:SAME:=(self*(lcmC/lcF)).shift_deg(lcmD-ldF) -(g*(lcmC/lcG)).shift_deg(lcmD-ldG); return s; end; S_poly_PID_L2(g:SAME):SAME is -- S in Z<x>. Erase lowest term. fc::=arr[0]; gc::=g.arr[0]; gcd::=fc.abs.gcd(gc.abs); -- lcm=fc*gc/gcd return (self*(gc/gcd)-g*(fc/gcd)).shift_deg(-1); end; S_poly_PID_L3(g:SAME):SAME is -- S in Z<x> fc::=self.lc; gc::=g.arr[0]; gcd::=fc.abs.gcd(gc.abs); -- lcm=fc*gc/gcd -- f*(gc/gcd)-(g*(fc/gcd)).shift_deg(f.degree) return (self*(gc/gcd)).S_poly_PID_L2(g); end; end;

class POLYS_GAUSS_INTI < $IS_LT{POLYS_GAUSS_INTI},$STR

class POLYS_GAUSS_INTI < $IS_LT{POLYS_GAUSS_INTI},$STR is include COMPARABLE; include POLYS{GAUSS_INTI} is_SqrFree->, squareFreeDecomposition->, integral->; -- include PID_GCD; -- Note that POLYS_GAUSS_INTI is not PID include POLYS_COMPARE{GAUSS_INTI}; compare(other:SAME):INT is return compare_deg(other); end; init is r_0:=GAUSS_INTI::zero; r_1:=GAUSS_INTI::one; divmodForce0:=false; end; mod(n:GAUSS_INTI):SAME is -- mod each coefficient. r::=copy; loop i::=r.arr.ind!; r.arr[i]:=r.arr[i]%n; end; r.normalize; return r; end; end;

class POLYS_RAT < $STR,$IS_LT{POLYS_RAT}

class POLYS_RAT < $STR,$IS_LT{POLYS_RAT} is -- POLYS_RAT is PID. include COMPARABLE; include POLYS{RAT}; include PID_GCD; include STRUM{RAT}; include POLYS_COMPARE{RAT}; compare(other:SAME):INT is return compare_deg(other); end; init is r_0:=#RAT(0); r_1:=#RAT(1); divmodForce0:=false; end; gcd_coeff_num:INTI is -- gcd of numerator of coefficients as Rational g:INTI:=0.inti; -- gcd loop c::=arr.elt!; if c.is_zero.not then g:=g.gcd(c.num); end; end; return g; end; lcm_coeff_den:INTI is -- lcm of of denominator of coefficients as Rarional l:INTI:=1.inti; -- lcm loop c::=arr.elt!; if c.is_zero.not then l:=l.lcm(c.denom); end; end; return l; end; polys_inti:POLYS_INTI is f::=self*#RAT(lcm_coeff_den); -- make coefficients integer. g:POLYS_INTI:=#; loop i::=(f.arr.size-1).downto!(0); g[i]:=f[i].inti; end; g.remove_gcd; return g; end; is_SqrFree:BOOL is return self.gcd(self.derivative).degree.is_zero; end; end;

class POLYS_FLTD < $STR,$IS_LT{POLYS_FLTD}

class POLYS_FLTD < $STR,$IS_LT{POLYS_FLTD} is -- POLYS_FLTD is PID. include COMPARABLE; include POLYS{FLTD}; include PID_GCD; include POLYS_COMPARE{FLTD}; compare(other:SAME):INT is return compare_deg(other); end; init is r_0:=0.0d; r_1:=1.0d; divmodForce0:=true; end; abs:SAME is if lc.is_neg then return -self; else return self; end; end; end;

class POLYS_FP < $STR,$IS_LT{POLYS_FP}

class POLYS_FP < $STR,$IS_LT{POLYS_FP} is -- Finite field F(p) coefficient -- POLYS_FP is PID. include COMPARABLE; include POLYS{FINITE_FIELD}; include PID_GCD; include POLYS_COMPARE{FINITE_FIELD}; compare(other:SAME):INT is return compare_deg(other); end; init(prime_number:INT) is FINITE_FIELD::set_base(prime_number); r_0:=FINITE_FIELD::zero; r_1:=FINITE_FIELD::one; divmodForce0:=true; end; abs:SAME is return self; end; polys_inti:POLYS_INTI is g:POLYS_INTI:=#; loop i::=arr.ind!; g[i]:=arr[i].inti; end; return g; end; end;

partial class POLYS_COMPARE{R}

partial class POLYS_COMPARE{R} is stub degree:INT; stub arr:ARRAY{R}; compare_deg(other:SAME):INT is -- <=>: -1 if "<", 0 if "=", 1 if ">" . d0::=degree; d1::=other.degree; return (d0-d1).sgn; end; compare_lt(other:SAME):INT is -- <=>: -1 if "<", 0 if "=", 1 if ">" . d0::=degree; d1::=other.degree; if d0=d1 then loop i::=d0.card.downto!(0); if arr[i]/=other.arr[i] then return (arr[i]-other.arr[i]).sgn.int; end; end; return 0.int; else return (d0-d1).sgn.int; end; end; end;

partial class POLYS{R}

partial class POLYS{R} is attr arr: ARRAY{R}; shared r_0:R; shared r_1:R; clear is loop arr.set!(r_0); end; end; allocate(d:CARD):SAME is -- degree "d" res:SAME:=new; res.arr:=#(d+1); return res; end; create(c:R,d:CARD): SAME is -- c*x^(d) res:SAME:=allocate(d); res.clear; res.arr[d]:=c; return res; end; create(c:R): SAME is -- same as create(c,0) res:SAME:=new; res.arr:= #(1); res.arr[0] := c; return res; end; create: SAME is -- same as create(r_0,c) res:SAME:=new; res.arr:= #(1); res.arr[0] := r_0; return res; end; create(a:ARRAY{R}):SAME is res:SAME:=new; res.arr:=a.copy; return res; end; zero:SAME is return #SAME(r_0,0); end; one:SAME is return #SAME(r_1,0); end; x:SAME is return #SAME(r_1,1); end; gen_func(a:ARRAY{R}):SAME is -- generating function. return #(a); end; exp_gen_func(a:ARRAY{R}):SAME is -- exponential generating function res:SAME:=allocate(a.size-1); factorial:R:= r_1; loop i::=1.upto!(a.size-1); factorial:=factorial*#R(i); res.arr[i]:=res.arr[i]/factorial; end; return res; end; array:ARRAY{R} is return normalize.arr; end; aget(i:CARD): R is if arr.has_ind(i) then return arr[i]; else return r_0; end; end; aget(i:INT): R is if i.is_neg then return r_0; end; return aget(i.card); end; aset(i:CARD, v:R) is if (i>=arr.size) then s::=arr.size; arr:=arr.resize(i+1); loop arr.set!(s, r_0); end; end; arr[i]:=v; end; aset(i:INT, v:R) pre i.is_non_neg is aset(i.card,v); end; copy:SAME is p:SAME:=#; p.arr:=arr.copy; return p; end; degree:INT is if arr.size=0 then return 0; end; d:CARD:=arr.size-1; loop while!((d>0)and(arr[d]=r_0)); d:=d-1; end; return d.int; end; low_deg:INT is -- (lowest degree of non-zero term) or 0. i:CARD:=0; loop while!( (arr.has_ind(i))and(arr[i]=r_0) ); i:=i+1; end; if arr.has_ind(i) then return i.int; else return 0.int; end; end; low_coeff:R is -- (lowest coefficient of non-zero term) or zero. i:CARD:=0; loop while!( (arr.has_ind(i))and(arr[i]=r_0) ); i:=i+1; end; if arr.has_ind(i) then return arr[i]; else return r_0; end; end; shift0:SAME is return self.shift_deg(-low_deg); end; reverseDeg:SAME is h:SAME:=self.normalize; h.arr:=h.arr.reverse; return h.normalize; end; normalize is -- destructive. ### Note that arr[0]==0 for polynomial "0". arr:=arr.resize(degree.card+1); end; normalize:SAME is p:SAME:=copy; p.normalize; return p; end; str:STR is return str("text","x",true); end; str(lib : LIBCHARS) : STR is return str; end; str(format:STR, v:STR, r:BOOL): STR is -- needed "is_lt" in R. -- format: "text","tex", "texm", "prog" -- v: variable, -- r: switch of order. true:decreasing order. false:increasing order timeC,timeV,power1,power2,ms,me:STR; POLY_WRITE::str_parts (format,out timeC,out timeV,out power1,out power2,out ms,out me); s:STR:=""; addS:STR:=""; deg::=degree.card; d:CARD; -- degree c:R; -- coefficient loop i::=0.upto!(deg); if r then d:=deg-i; else d:=i; end; c:=arr[d]; if c/=r_0 then if c<r_0 then s:=s+"-"; c:=-c; else; s:=s+addS; end; addS:="+"; --if c.kind_of?(Rational)&&(c.denominator != 1); -- den="/"+c.denominator.to_s; c=c.numerator -- else -- end if (c /= r_1)or(d=0) then s:=s+c.str; end; if (c /= r_1)and(d/=0) then s:=s+timeC; end; if d /= 0 then s:=s+v; if d /= 1 then s:=s+power1+(d.str)+power2; end; end; end; end; if s="" then s:="0"; end; s:=ms+s+me; -- math start and math end return s; end; lc: R is -- lc: leading coefficient return arr[degree.card]; end; lp:SAME is -- leading power product return #SAME(r_1,degree.card); end; lt:SAME is -- leading term d:CARD:=degree.card; return #SAME(arr[d],d); end; is_zero: BOOL is return ((degree.is_zero)and(arr[0]=r_0)); end; is_one:BOOL is return ((degree.is_zero)and(arr[0]=r_1)); end; negate:SAME is p:SAME:=allocate(arr.size-1); loop i::=arr.ind!; p.arr[i]:=-arr[i]; end; return p; end; plus(other:R):SAME is p:SAME:=copy; p.arr[0]:=p.arr[0]+other; return p.normalize; end; plus(other:INT):SAME is p:SAME:=copy; p.arr[0]:=p.arr[0]+#R(other); return p.normalize; end; plus(other:CARD):SAME is p:SAME:=copy; p.arr[0]:=p.arr[0]+#R(other); return p.normalize; end; plus(other:SAME):SAME is s0::=(arr.size).min(other.arr.size); s1::=(arr.size).max(other.arr.size); p:SAME:=allocate(s1-1); loop i::=0.upto!(s0-1); p.arr[i]:=arr[i]+other.arr[i]; end; if (arr.size)>(other.arr.size) then loop i::=s0.upto!(s1-1); p.arr[i]:=arr[i]; end; elsif (arr.size)<(other.arr.size) then loop i::=s0.upto!(s1-1); p.arr[i]:=other.arr[i]; end; end; return p.normalize; end; minus(other:R):SAME is p:SAME:=copy; p.arr[0]:=p.arr[0]-other; return p.normalize; end; minus(other:INT):SAME is p:SAME:=copy; p.arr[0]:=p.arr[0]-#R(other); return p.normalize; end; minus(other:CARD):SAME is p:SAME:=copy; p.arr[0]:=p.arr[0]-#R(other); return p.normalize; end; minus(other:SAME):SAME is s0::=(arr.size).min(other.arr.size); s1::=(arr.size).max(other.arr.size); p:SAME:=allocate(s1-1); loop i::=0.upto!(s0-1); p.arr[i]:=arr[i]-other.arr[i]; end; if (arr.size)>(other.arr.size) then loop i::=s0.upto!(s1-1); p.arr[i]:=arr[i]; end; elsif (arr.size)<(other.arr.size) then loop i::=s0.upto!(s1-1); p.arr[i]:=-other.arr[i]; end; end; -- #OUT+"minus: self="+arr.str+" o="+other.arr.str+" p="+p.arr.str+"\n"; return p.normalize; end; times(other:R):SAME is p:SAME:=copy.normalize; loop i::=p.arr.ind!; p.arr[i]:=p.arr[i]*other; end; return p; end; times(other:INT):SAME is return times(#R(other)); end; times(other:CARD):SAME is return times(#R(other)); end; times(other:SAME): SAME is d0:CARD:=degree.card; d1:CARD:=other.degree.card; d2:CARD:=d0+d1; p:SAME:=allocate(d2); p.clear; loop i::=0.upto!(d0); loop j::=0.upto!(d1); p.arr[i+j]:=p.arr[i+j]+arr[i]*other.arr[j]; end; end; return p; end; shift_deg(d:INT):SAME is -- self * (x^d) d0:INT:=degree; if d.is_zero then return copy.normalize; elsif d.is_pos then if is_zero then return zero; end; res:SAME:=allocate((d0+d).card); res.clear; loop i::=0.upto!(d0.card); j::=d.up!.card; res.arr[j]:=arr[i]; end; return res; elsif (d+d0).is_non_neg then -- d<0 res:SAME:=allocate((d0+d).card); loop i::=((-d).card).upto!(d0.card); j::=0.up!; res.arr[j]:=arr[i]; end; return res; else -- d<0, d+d0<0 return zero; end; end; shared divmodForce0:BOOL; divmod(divisor:SAME, out q:SAME, out r:SAME) is divmod(divmodForce0, divisor, out q, out r); end; divmod(force0:BOOL, divisor:SAME, out q:SAME, out r:SAME) is -- R be field or PID -- "force0" be true to force "0" at head of remainder. -- true: continuous field e.g.FLT,FLTD, CPX,CPXD... -- false: PID or discrete field or RAT e.g. INT,INTI,RAT,finite field q:=#; r:=copy; -- Quotient, Residue degR:CARD:=r.degree.card; degD:CARD:=divisor.degree.card; if degR>=degD then loop dq::=(degR-degD).downto!(0); if (r.arr[dq+degD]/=r_0) then ; --q.arr[dq]:=r_0 q1::=r.arr[dq+degD].div(divisor.arr[degD]); q[dq]:=q1; loop i::=0.upto!(degD); j::=dq.up!; r.arr[j] := r.arr[j]-q1*divisor.arr[i]; end; if force0 then r[dq+degD]:=r_0; end; end; end; end; q.normalize; r.normalize; end; div(other:SAME): SAME is q,r:SAME; divmod(other,out q,out r); return q; end; mod(other:SAME): SAME is q,r:SAME; divmod(other,out q,out r); return r; end; mod(other:ARRAY{SAME}):SAME is -- mod for multi division r:SAME:=self.copy; q:SAME; i::=0; loop while!(i<other.size); b::=other[i]; if (b.degree<=r.degree)and(b.is_zero.not) then r.divmod(b,out q, out r); if q.is_zero then i:=i+1; else i:=0; end; else i:=i+1; end; end; return r; end; pow(power:CARD): SAME is return pow(power.inti); end; pow(power:INT): SAME is return pow(power.inti); end; pow(power:INTI): SAME pre power.is_non_neg is s:SAME:=one; if (power.is_pos) then p:SAME:=copy; -- with binary notation of "power". loop while!(power.is_pos); if power.is_odd then s:=s*p; end; p:=p*p; power:=power/2.inti; end; end; return s; end; derivative:SAME is return derivative(1); end; derivative(n:CARD):SAME is -- n-th derivative p:SAME:=copy; d:CARD:=p.degree.card; loop n.times!; loop i::=1.upto!(d); p[i-1] := p[i]*#R(i); end; p[d]:=r_0; if d>0 then d:=d-1; end; end; return p.normalize; end; integral:SAME is return integral(1); end; integral(n:CARD):SAME is -- integral n-times p:SAME:=copy; d:CARD:=p.degree.card; if n>1 then p.arr:=p.arr.resize(d+n+1); end; loop n.times!; loop i::=d.downto!(0); p.arr[i+1]:=p.arr[i]/#R(i+1); end; p.arr[0]:=r_0; d:=d+1; end; return p.normalize; end; substitute(x:R):R is d:CARD:=degree.card; s:R:=arr[d]; if d>0 then loop i::=(d-1).downto!(0); s:= (x*s)+arr[i]; end; end; return s; end; substitute(x:SAME):SAME is d:CARD:=degree.card; s:SAME:=#(arr[d]); if d>0 then loop i::=(d-1).downto!(0); s:= (x*s)+arr[i]; end; end; return s; end; is_eq(other:SAME): BOOL is d:CARD:=degree.card; if ( d/= other.degree.card) then return false; end; loop i::=0.upto!(d); if (arr[i] /= other.arr[i]) then return false; end; end; return true; end; is_lt(other:SAME): BOOL is return compare(other).is_neg; end; squareFreeDecomposition:ARRAY{SAME} is g:ARRAY{SAME}:=|self.copy|; gm:SAME; loop s:CARD:=g.size; while!( g[s-1].degree.is_pos ); gm:=g[s-1].copy; gm:=gm.gcd(gm.derivative); g:=g.append(|gm|); end; s::=g.size; h:ARRAY{SAME}:=#(s+1); h[0]:=one; loop i::=1.upto!(s-1); h[i]:=g[i-1]/g[i]; end; h[s]:=one; fd:ARRAY{SAME}:=#(s); fd[0]:=one; loop i::=1.upto!(s-1); fd[i]:=h[i]/h[i+1]; end; return fd; end; is_SqrFree:BOOL is return self.gcd(self.derivative).degree.is_zero; end; monic is -- make monic i.e. f(x/lc)*(lc^(degree-1)) d::=degree.card; c::=lc; c1::=c; arr[d]:=r_1; if d>=2 then loop i::=(d-2).downto!(0); arr[i]:=arr[i]*c1; c1:=c1*c; end; end; end; pseudo_monic(c:R) is -- f(x/c)*(c^degree) d::=degree.card; if d.is_pos then c1::=c; loop i::=(d-1).downto!(0); arr[i]:=arr[i]*c1; c1:=c1*c; end; end; end; -- coeff_to_real -- coeff_to_Z -- coeff_truncate # truncate each coefficient to Integer -- coeff_to_f # converts each element to Float -- Polynomial.factor2s(f,s="") -- cnv_prog_format(str) end; -- POLYS

partial class STRUM{R}

partial class STRUM{R} is -- Assume that coefficient R is field (rational or real). getSturm(out gcd_s:SAME,out sturm:ARRAY{SAME}) is s:CARD; sturm0:ARRAY{SAME}:=|self.copy, self.derivative|; loop s:=sturm0.size; while!(sturm0[s-1].is_zero.not); sturm0:=sturm0.append(| -(sturm0[s-2]%sturm0[s-1]) |); end; gcd_s:=sturm0[ s-2 ]; sturm:=#((s-1)); loop i::=sturm.ind!; sturm[i]:=sturm0[i]/gcd_s; end end; countSturmChange(a:R,infty_n,infty:BOOL, sturm:ARRAY{SAME}):CARD is sturmA:ARRAY{R}:=#(0); loop p::=sturm.elt!; if infty then sturmA:=sturmA.append(|p.lc|); elsif infty_n then if p.degree.is_odd then sturmA:=sturmA.append(|-p.lc|); else sturmA:=sturmA.append(|p.lc|); end; else pa:R:=p.substitute(a); if pa.is_zero.not then sturmA:=sturmA.append(|pa|); end; end end; v:CARD:=0; -- #of sign change loop i::=0.up!;while!(sturmA.has_ind(i+1)); if (sturmA[i]*sturmA[i+1]).is_neg then v:=v+1; end; end; return v; end; countSolution(a,b: R, countRedundancy:BOOL):CARD is return countSolution(a,b, false,false, countRedundancy); end; countSolution(a,b: R, infty_n,infty:BOOL , countRedundancy:BOOL):CARD is -- count # of solution between a and b using Sturm's algorithm. -- infty_n : a is -infinity, infty : b is infinity -- R Rational,Float if infty_n.not and substitute(a).is_zero then return (self/(x-a)).countSolution(a,b,infty_n,infty,countRedundancy); end; if infty.not and substitute(b).is_zero then return (self/(x-b)).countSolution(a,b,infty_n,infty,countRedundancy); end; gcd_s:SAME; sturm:ARRAY{SAME}; getSturm(out gcd_s, out sturm); n1:CARD:=0; -- for Redundancy if (countRedundancy)and(gcd_s.degree.is_pos)then n1:=gcd_s.countSolution(a,b,infty_n,infty,countRedundancy); end; return countSturmChange(a,infty_n,false,sturm)-countSturmChange(b,false,infty,sturm)+n1; end; end;

class TEST_POLYS

class TEST_POLYS is include TEST; testSI is class_name("POLYS_INTI"); -------------test factorization --------------- x::=POLYS_INTI::x; p1:POLYS_INTI; fa:ARRAY{POLYS_INTI}; s:STR; p1:=(x+2.inti)*(x+3.inti); s:="{x+2,x+3}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x+1.inti)*x^3; s:="{x,x,x,x+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x+1.inti)^2*x^3; s:="{x,x,x,x+1,x+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x+1.inti)^4; s:="{x+1,x+1,x+1,x+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=x^3+1.inti; s:="{x+1,x^(2)-x+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3-1.inti)*(x^3+1.inti); s:="{x-1,x+1,x^(2)-x+1,x^(2)+x+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3*27.inti-(8.inti))*(x^3*27.inti+(8.inti)); s:="{3x-2,3x+2,9x^(2)-6x+4,9x^(2)+6x+4}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3-27.inti)^3; s:="{x-3,x-3,x-3,x^(2)+3x+9,x^(2)+3x+9,x^(2)+3x+9}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3+27.inti)^3; s:="{x+3,x+3,x+3,x^(2)-3x+9,x^(2)-3x+9,x^(2)-3x+9}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3*27.inti-1.inti)^3; s:="{3x-1,3x-1,3x-1,9x^(2)+3x+1,9x^(2)+3x+1,9x^(2)+3x+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3*27.inti+1.inti)^3; s:="{3x+1,3x+1,3x+1,9x^(2)-3x+1,9x^(2)-3x+1,9x^(2)-3x+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3*8.inti-27.inti)^3; s:="{2x-3,2x-3,2x-3,4x^(2)+6x+9,4x^(2)+6x+9,4x^(2)+6x+9}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3*8.inti+27.inti)^3; s:="{2x+3,2x+3,2x+3,4x^(2)-6x+9,4x^(2)-6x+9,4x^(2)-6x+9}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3*27.inti-8.inti)^3; s:="{3x-2,3x-2,3x-2,9x^(2)+6x+4,9x^(2)+6x+4,9x^(2)+6x+4}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3*27.inti+8.inti)^3; s:="{3x+2,3x+2,3x+2,9x^(2)-6x+4,9x^(2)-6x+4,9x^(2)-6x+4}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^4+x^3+x^2+x+1.inti)^3; s:="{x^(4)+x^(3)+x^(2)+x+1,x^(4)+x^(3)+x^(2)+x+1,x^(4)+x^(3)+x^(2)+x+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^4-x^3+x^2-x+1.inti)^3; s:="{x^(4)-x^(3)+x^(2)-x+1,x^(4)-x^(3)+x^(2)-x+1,x^(4)-x^(3)+x^(2)-x+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^2+x+1.inti)*(x^2+x+8.inti)*(x^2+x+15.inti); s:="{x^(2)+x+1,x^(2)+x+8,x^(2)+x+15}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3*27.inti-1.inti)*(x^3*8.inti+1.inti); s:="{2x+1,3x-1,4x^(2)-2x+1,9x^(2)+3x+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3*27.inti-8.inti)*(x^3*8.inti+27.inti); s:="{2x+3,3x-2,4x^(2)-6x+9,9x^(2)+6x+4}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^(4)+1.inti)*(x^(4)+2.inti); s:="{x^(4)+1,x^(4)+2}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=x*(x+1.inti)*(x+2.inti)*(x^2+1.inti)*(x^4+2.inti)*(x^4+1.inti); s:="{x,x+1,x+2,x^(2)+1,x^(4)+1,x^(4)+2}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^2-x*3+9)*(x^4+1)*(x^4+2); s:="{x^(2)-3x+9,x^(4)+1,x^(4)+2}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^2+1)*(x^4+2)*(x^4+1); s:="{x^(2)+1,x^(4)+1,x^(4)+2}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^5+2)*(x^5+3); s:="{x^(5)+2,x^(5)+3}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x*2-1)*(x*3-7)*(x*2+7); s:="{2x-1,2x+7,3x-7}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^2*2+1)*(x^2-7)*(x^2*3+1); s:="{x^(2)-7,2x^(2)+1,3x^(2)+1}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^3*7+x*2+5)*(x^3*6+x*5+7); s:="{6x^(3)+5x+7,7x^(3)+2x+5}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^4*5+2)*(x^4*7+3); s:="{5x^(4)+2,7x^(4)+3}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^4*7+2)*(x^5*2+3); s:="{7x^(4)+2,2x^(5)+3}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^5*3+2)*(x^5*2+3); s:="{2x^(5)+3,3x^(5)+2}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^(4)*3+1)*(x^(4)*5+2)*(x^(4)+1); s:="{x^(4)+1,3x^(4)+1,5x^(4)+2}"; fa:=p1.factorize; test("factor", fa.str, s); p1:=(x^5*3+2)*(x^5*2+3)*(x^5+1); s:="{x+1,x^(4)-x^(3)+x^(2)-x+1,2x^(5)+3,3x^(5)+2}"; fa:=p1.factorize; test("factor", fa.str, s); finish; end; t1 is #OUT+"polys_inti_test\n"; class_name("POLYS_INTI"); -------------test factorization --------------- x::=POLYS_INTI::x; p1:POLYS_INTI; fa:ARRAY{POLYS_INTI}; s:STR; --p1:=(x^5*3+2)*(x^5*2+3)*(x^5+1); p1:=(x^6+1); s:="{x^{2}+1,x^{4}-x^{2}+1}"; fa:=p1.factorize; test("factor", fa.str, s); ----test matrix --- mat:MAT_POLYS_INTI:=#(3,3); mat[0][0]:=x+1; mat[0][1]:=x; mat[0][2]:=x; mat[1][0]:=x; mat[1][1]:=x+1; mat[1][2]:=x; mat[2][0]:=x; mat[2][1]:=x; mat[2][2]:=x+1; d::=mat.det; ds::=(x+1)^3+x^3*2-(x+1)*x^2*3; test("determinant",d.str,ds.str); finish; end; testCountSoluyion is class_name("POLYS_INTI"); x::=POLYS_INTI::x; p1:POLYS_INTI:=(x-1)^3*(x+2)^2; test("testCount",p1.countSolution(0.inti,10.inti,true).str,3.str); test("testCount",p1.countSolution(0.inti,10.inti,false).str,1.str); test("testCount",p1.countSolution((-3).inti,10.inti,true).str,5.str); test("testCount",p1.countSolution((-3).inti,10.inti,false).str,2.str); test("testCount",p1.countSolution((-3).inti,10.inti,false,true,true).str,5.str); test("testCount",p1.countSolution(0.inti,10.inti,false,true,true).str,3.str); test("testCount",p1.countSolution((-3).inti,10.inti,true,false,true).str,5.str); test("testCount",p1.countSolution(0.inti,0.inti,true,false,true).str,2.str); p1:=(x-1)^3*(x+2)^2*x^4; test("testCount",p1.countSolution(0.inti,10.inti,false,false,true).str,3.str); test("testCount",p1.countSolution(-(10.inti),0.inti,false,false,true).str,2.str); test("testCount",p1.countSolution(0.inti,0.inti,false,true,true).str,3.str); test("testCount",p1.countSolution(0.inti,0.inti,true,false,true).str,2.str); finish; end; main is POLYS_INTI::init; POLYS_RAT::init; --testSI; --t1; testCountSoluyion; end; end;