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->POLYS_is_SqrFree,
squareFreeDecomposition->POLYS_squareFreeDecomposition;
include PID_GCD;
init is
r_0:=0.inti; r_1:=1.inti; divmodForce0:=false;
POLYS_RAT::init;
end;
create(c:INT,d:INT): SAME pre (d>=0) is
-- c*x^(d)
res:SAME:=allocate(d); res.clear; res.arr[d]:=c.inti; return res;
end;
create(c:INT): SAME is
-- same as create(c,0)
res:SAME:=new; res.arr:= #(1); res.arr[0] := c.inti;
return res;
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 for each coeff.
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:INT:=0;
loop
while!(i<other.size);
b::=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.
r:=mod(p); degR:INT:=r.degree;
d_poly::=divisor.mod(p); degD:INT:=d_poly.degree;
pd::=INTI_EXT::inv(p,d_poly.lc);
q:=#; -- Quotient
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;
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=0;
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):INT is
return countSolution(a,b, false,false, countRedundancy);
end;
countSolution(a,b:INTI, infty_n,infty:BOOL , countRedundancy:BOOL):INT 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};
init is
r_0:=GAUSS_INTI::zero; r_1:=GAUSS_INTI::one; divmodForce0:=false;
end;
mod(n:GAUSS_INTI):SAME is
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} compare->compare_o;
include POLYS_FIELD;
include PID_GCD;
include STRUM{RAT};
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.u); 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.v); 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].floor; end;
g.remove_gcd;
return g;
end;
is_SqrFree:BOOL is
return self.gcd(self.derivative).degree=0;
end;
end;
class POLYS_FLTD < $STR,$IS_LT{POLYS_FP}
class POLYS_FLTD < $STR,$IS_LT{POLYS_FP} is
-- POLYS_FLTD is PID.
include COMPARABLE;
include POLYS{FLTD} compare->compare_o;
include POLYS_FIELD;
include PID_GCD;
init is
r_0:=0.0d; r_1:=1.0d; divmodForce0:=true;
end;
abs:SAME is
if lc>=0.0 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} compare->compare_o;
include POLYS_FIELD;
include PID_GCD;
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_FIELD
partial class POLYS_FIELD is
compare(other:SAME):INT is
-- <=>: -1 if "<", 0 if "=", 1 if ">" .
d0::=degree; d1::=other.degree; return (d0-d1).sign;
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:INT):SAME pre (d>=0) is
-- degree "d"
res:SAME:=new; res.arr:=#(d+1); return res;
end;
create(c:R,d:INT): SAME pre (d>=0) 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:INT): R is
if arr.has_ind(i) then return arr[i]; else return r_0; end;
end;
aset(i:INT, v:R) pre i>=0 is
if (i>=arr.size) then
s:INT:=arr.size;
arr:=arr.resize(i+1); loop arr.set!(s, r_0); end;
end;
arr[i]:=v;
end;
copy:SAME is
p:SAME:=#; p.arr:=arr.copy; return p;
end;
degree:INT is
d:INT:=arr.size-1; loop while!((d>0)and(arr[d]=r_0)); d:=d-1; end; return d;
end;
mindeg:INT is
--minimum degree of non-zero term
i::=0; d::=degree; loop while!( (i<degree)and(arr[i]=r_0)); i:=i+1; end; return i;
end;
shift0:SAME is return self.shift_deg(-mindeg); 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+1);
end;
normalize:SAME is p:SAME:=copy; p.normalize; return p; end;
str:STR is return str("text","x",true); 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; d:INT; -- 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];
end;
lp:SAME is
-- leading power product
d:INT:=degree; return #SAME(r_1,d);
end;
lt:SAME is
-- leading term
d:INT:=degree; return #SAME(arr[d],d);
end;
low_deg:INT is
-- (lowest degree of non-zero term) or 0.
i:INT:=0;
loop while!( (arr.has_ind(i))and(arr[i]=r_0) ); i:=i+1; end;
if arr.has_ind(i) then return i; else return 0; end;
end;
is_zero: BOOL is
return ((degree=0)and(arr[0]=r_0));
end;
is_one:BOOL is
return ((degree=0)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: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: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
oR::=#R(other);
p:SAME:=copy.normalize;
loop i::=p.arr.ind!; p.arr[i]:=p.arr[i]*oR; end;
return p;
end;
times(other:SAME): SAME is
d0:INT:=degree; d1:INT:=other.degree;
d2:INT:=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::=degree;
if d=0 then return copy.normalize;
elsif d>0 then
if is_zero then return zero; end;
res:SAME:=allocate(d0+d); res.clear;
loop i::=0.upto!(d0); j::=d.up!;
res.arr[j]:=arr[i];
end;
return res;
elsif d+d0>=0 then -- d<0
res:SAME:=allocate(d0+d);
loop i::=(-d).upto!(d0); 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
r:=copy; degR:INT:=r.degree;
degD:INT:=divisor.degree;
q:=#; -- Quotient
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;
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:INT:=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:INT): SAME pre power>=0 is
s:SAME:=one;
if (power>0) then
p:SAME:=copy;
loop while!(power>0); -- with binary notation of "power".
if power.is_odd then s:=s*p; end;
p:=p*p; power:=power/2;
end;
end;
return s;
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:INT):SAME pre n>=0 is
-- n-th derivative
p:SAME:=copy;
d:INT:=p.degree;
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:INT):SAME pre n>=0 is
-- integral n-times
p:SAME:=copy;
d:INT:=p.degree;
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:INT:=degree; s:R:=arr[d];
loop i::=(d-1).downto!(0); s:= (x*s)+arr[i]; end;
return s;
end;
substitute(x:SAME):SAME is
d:INT:=degree; s:SAME:=#(arr[d]);
loop i::=(d-1).downto!(0); s:= (x*s)+arr[i]; end;
return s;
end;
is_eq(other:SAME): BOOL is
d:INT:=degree;
if ( d/= other.degree) then return false; end;
loop i::=0.upto!(d);
if (arr[i] /= other.arr[i]) then return false; end;
end;
return true;
end;
compare(other:SAME):INT is
-- <=>: -1 if "<", 0 if "=", 1 if ">" .
d0::=degree; d1::=other.degree;
if d0=d1 then
loop i::=d0.downto!(0);
if arr[i]/=other.arr[i] then
return (arr[i]-other.arr[i]).sign;
end;
end;
return 0;
else return (d0-d1).sign;
end;
end;
is_lt(other:SAME): BOOL is
-- expr1 < expr2 expr1.is_lt(expr2)
-- return degree<other.degree;
return compare(other)<0;
end;
squareFreeDecomposition:ARRAY{SAME} is
g:ARRAY{SAME}:=|self.copy|;
gm:SAME;
loop s:INT:=g.size; while!( g[s-1].degree>0 );
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=0;
end;
monic is
-- make monic i.e. f(x/lc)*(lc^(degree-1))
d::=degree; c::=lc; c1::=c;
arr[d]:=r_1;
loop i::=(d-2).downto!(0); arr[i]:=arr[i]*c1; c1:=c1*c; end;
end;
pseudo_monic(c:R) is
-- f(x/c)*(c^degree)
d::=degree; c1::=c;
loop i::=(d-1).downto!(0); arr[i]:=arr[i]*c1; c1:=c1*c; 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:INT;
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}):INT 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:INT:=0; -- #of sign change
loop i::=0.upto!(sturmA.size-2);
if (sturmA[i]*sturmA[i+1]).is_neg then v:=v+1; end;
end;
return v;
end;
countSolution(a,b: R, countRedundancy:BOOL):INT is
return countSolution(a,b, false,false, countRedundancy);
end;
countSolution(a,b: R, infty_n,infty:BOOL , countRedundancy:BOOL):INT 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:INT:=0; -- for Redundancy
if (countRedundancy)and(gcd_s.degree>0)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;