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;