polym.sa
Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
-- POLYM{R} : polynomial class of multi variable
-- MONOMIAL{R} : monomial class of multi variable
-- VARNAME : list of var names
-- R be ring class with +,-,* or field.
class POLYM_INTI < $IS_LT{POLYM_INTI},$STR
class POLYM_INTI < $IS_LT{POLYM_INTI},$STR is
include COMPARABLE;
include POLYM{INTI};
init is
r_0:=0.inti; r_1:=1.inti; divmodForce:=false;
MONOMIAL{INTI}::r_0:=r_0; MONOMIAL{INTI}::r_1:=r_1;
end;
gcd_coeff_num:INTI is
-- gcd of numerator of coefficients as Rational
g:INTI:=0.inti; -- gcd
loop g:=g.gcd(monomials.elt!.coeff); end;
return g;
end;
polym_rat:POLYM_RAT is
g:POLYM_RAT:=#; gm:MONOMIAL{RAT};
loop fm::=monomials.elt!;
gm:=#;
gm.coeff:=#RAT(fm.coeff);
gm.power:=fm.power.copy;
g:=g+#POLYM_RAT(gm);
end;
return g;
end;
mod(n:INTI):SAME is
p::=copy;
loop i::=p.monomials.ind!;
p.monomials[i].coeff:=p.monomials[i].coeff%n;
end;
return p;
end;
divmod_Zp(prime:INTI,divisors:ARRAY{SAME},out q:ARRAY{SAME},out r:SAME) is
-- Do mod(prime) before use this.
-- Multiple division.
h::=self.normalize;
-- sort as heigher be top
-- divisors.sort!{|f1,f2| f2.lt<=>f1.lt};
ltD:ARRAY{MONOMIAL{INTI}}:=#(divisors.size);--leading terms of divisors
lc_nz_D:ARRAY{BOOL}:=#(divisors.size);
lc_inv_D:ARRAY{INTI}:=#(divisors.size);
q:=#(divisors.size); -- quotients
loop i::=divisors.ind!;
ltD[i]:=divisors[i].lt.copy;
ltD[i].coeff:=1.inti;
lc_nz_D[i]:=(divisors[i].lc%prime).is_zero.not;
lc_inv_D[i]:=INTI_EXT::inv(prime,divisors[i].lc);
q[i]:=#;
end;
r:=#;
pw:SAME:=#;
loop while!(0<h.monomials.size);
i::=0;
ltH::=h.lt;
loop while!(i<ltD.size);
if lc_nz_D[i] and ltH.is_divisible(ltD[i],false,false) then
qt::=ltH/ltD[i];
qt.coeff:=(ltH.coeff*lc_inv_D[i])%prime;
q[i].monomials:=q[i].monomials.append(|qt|);
pw.monomials:= |qt|;
h:=h-(pw*divisors[i]);
h:=(h%prime).normalize;
if h.monomials.size=0 then break!; end;
ltH:=h.lt;
i:=0;
else
i:=i+1;
end;
end;
if h.monomials.size>0 then
r.monomials:=r.monomials.append(|ltH|);
if h.monomials.size>1 then
h.monomials:=h.monomials.slice(1,h.monomials.size-1);
else
h.monomials:=#;
end;
end;
end;
r:=r.normalize;
loop i::=q.ind!; q[i]:=q[i].normalize; end;
end;
divmod_Zp_lt(prime:INTI,divisors:ARRAY{SAME},out q:ARRAY{SAME},out r:SAME) is
-- Do mod(prime) before use this.
-- Multiple division.
h::=self.normalize;
-- sort as heigher be top
-- divisors.sort!{|f1,f2| f2.lt<=>f1.lt};
ltD:ARRAY{MONOMIAL{INTI}}:=#(divisors.size);--leading terms of divisors
lc_nz_D:ARRAY{BOOL}:=#(divisors.size);
lc_inv_D:ARRAY{INTI}:=#(divisors.size);
q:=#(divisors.size); -- quotients
loop i::=divisors.ind!;
ltD[i]:=divisors[i].lt.copy;
ltD[i].coeff:=1.inti;
lc_nz_D[i]:=(divisors[i].lc%prime).is_zero.not;
lc_inv_D[i]:=INTI_EXT::inv(prime,divisors[i].lc);
q[i]:=#;
end;
r:=#;
pw:SAME:=#;
--loop while!(0<h.monomials.size);
i::=0;
ltH::=h.lt;
loop while!(i<ltD.size);
if lc_nz_D[i] and ltH.is_divisible(ltD[i],false,false) then
qt::=ltH/ltD[i];
qt.coeff:=(ltH.coeff*lc_inv_D[i])%prime;
q[i].monomials:=q[i].monomials.append(|qt|);
pw.monomials:= |qt|;
h:=h-(pw*divisors[i]);
h:=(h%prime).normalize;
if h.monomials.size=0 then break!; end;
ltH:=h.lt;
i:=0;
else
i:=i+1;
end;
end;
r:=h;
r:=r.normalize;
loop i:=q.ind!; q[i]:=q[i].normalize; end;
end;
S_poly_Zp(prime:INTI, g:SAME):SAME is
lpF::=lp; lcFinv::=INTI_EXT::inv(prime, lc);
lpG::=g.lp; lcGinv::=INTI_EXT::inv(prime, g.lc);
lcm::=lpF.lcm(lpG);
s::=#SAME(lcm/lpF)*self*lcFinv-#SAME(lcm/lpG)*g*lcGinv;
return s;
end;
S_poly_PID(g:SAME):SAME is
lpF::=lp; lcF::=lc;
lpG::=g.lp; 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);
return s;
end;
end;
class POLYM_RAT < $IS_LT{POLYM_RAT},$STR
class POLYM_RAT < $IS_LT{POLYM_RAT},$STR is
include COMPARABLE;
include POLYM{RAT};
init is
r_0:=#RAT(0); r_1:=#RAT(1); divmodForce:=false;
MONOMIAL{RAT}::r_0:=r_0; MONOMIAL{RAT}::r_1:=r_1;
end;
gcd_coeff_num:INTI is
-- gcd of numerator of coefficients as Rational
g:INTI:=0.inti; -- gcd
loop g:=g.gcd(monomials.elt!.coeff.num); end;
return g;
end;
lcm_coeff_den:INTI is
-- lcm of of denominator of coefficients as Rarional
l:INTI:=1.inti; -- lcm
loop l:=l.lcm(monomials.elt!.coeff.denom); end;
return l;
end;
polym_inti:POLYM_INTI is
-- make coefficients inti.
f::=self*#RAT(lcm_coeff_den);
g:POLYM_INTI:=#; gm:MONOMIAL{INTI};
loop fm::=f.monomials.elt!;
gm:=#;
gm.coeff:=fm.coeff.floor.inti;
gm.power:=fm.power.copy;
g:=g+#POLYM_INTI(gm);
end;
return g;
end;
end;
class POLYM_FLTD < $IS_LT{POLYM_FLTD},$STR
class POLYM_FLTD < $IS_LT{POLYM_FLTD},$STR is
include COMPARABLE;
include POLYM{FLTD};
init is
r_0:=#FLTD(0); r_1:=#FLTD(1); divmodForce:=true;
MONOMIAL{FLTD}::r_0:=r_0; MONOMIAL{FLTD}::r_1:=r_1;
end;
end;
class VARNAME
class VARNAME is
shared varOrder0:ARRAY{STR}:=|"x","y","z","u","v","w","p","q","r","s","t","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o"|;
shared VarOrder:ARRAY{STR}; -- order --> var_name
-- top is heavy
shared varmap:MAP{STR,CARD}; -- map var_name to var_id
shared varmapr:MAP{CARD,STR}; -- map var_id to var_name
shared idOrder:ARRAY{CARD}; -- order--> var_id
-- shared idOrderR:ARRAY{CARD}; -- var_id-->order
shared weight:ARRAY{FLT}; -- var_id --> weight
init is
if void(VarOrder) then VarOrder:=varOrder0.copy; end;
if void(idOrder) then idOrder:=#; end;
if void(varmap) then varmap:=#; varmapr:=#; end;
if void(weight) then weight:=#; end;
end;
private setIdOrder is
init;
loop name::=varOrder0.elt!;
if VarOrder.has(name).not then
VarOrder:=VarOrder.resize(VarOrder.size+1);
VarOrder[VarOrder.size-1]:=name;
end;
end;
-- set varmap
n:CARD:=varmap.size;
idOrder:=#(VarOrder.size);
-- idOrderR:=#(VarOrder.size);
loop i::=VarOrder.ind!;
name::=VarOrder[i];
if (varmap.has_ind(name).not) then
varmap[name]:=n; varmapr[n]:=name;
weight:=weight.resize(n+1); weight[n]:=#FLT(1);
n:=n+1;
end;
idOrder[i]:=varmap[name];
-- if void(idOrderR[varmap[name]]) then idOrderR[varmap[name]]:=i; end;
end;
end;
getVarOrder:ARRAY{STR} is
if VarOrder.is_empty then setVarOrder; end;
return VarOrder;
end;
setVarOrder is
-- make default.
VarOrder:=varOrder0.copy; setIdOrder;
end;
setVarOrder(order:ARRAY{STR}) is
-- setVarOrder(|"x","y"|) means x>y
VarOrder:=#;
loop name::=order.elt!;
if VarOrder.has(name).not then
VarOrder:=VarOrder.append(|name|);
end;
end;
setIdOrder;
end;
getWeight:MAP{STR,FLT} is
w:MAP{STR,FLT};
loop id::=weight.ind!;
w[ varmapr[id] ]:=weight[id];
end;
end;
setWeight(wmap:MAP{STR,FLT}) is
-- No change, if name is not occur.
loop name:STR:=wmap.ind!;
if varOrder0.has(name).not then appendVarName(name); end;
weight[varmap[name]]:=wmap[name];
end;
end;
setWeight(name:STR, w:FLT) is
if varOrder0.has(name).not then appendVarName(name); end;
weight[varmap[name]]:=w;
end;
setWeight is
-- make default.
weight.to_val(#FLT(1));
end;
appendVarName(v:STR) is
-- Assume that v be String
if varOrder0.has(v).not then
varOrder0:=varOrder0.resize(varOrder0.size+1);
varOrder0[varOrder0.size-1]:=v;
end;
setIdOrder;
end;
is_lt(v1,v2:STR):BOOL is
-- compare var name "v1" with "v2".
vorder::=getVarOrder;
return (vorder.index_of(v1)>(vorder.index_of(v2)));
end;
is_lt(id1,id2:CARD):BOOL is
vorder::=getVarOrder;
return (idOrder.index_of(id1)>(idOrder.index_of(id2)));
end;
end; -- class VARNAME
class MONOMIAL{R} < $STR
class MONOMIAL{R} < $STR is
attr coeff: R;
attr power: MAP{CARD,INT}; -- map var_id to power
shared r_0:R;
shared r_1:R;
shared TermOrder: STR:="degrevlex"; -- "lex", "degrex", "degrevrex"
create:SAME is
-- initialize(c=0,p={})
res:SAME:=new;
res.power:=#;
res.coeff:=r_0;
return res;
end;
create(c:R): SAME is
-- initialize(c,p={})
res:SAME:=new;
res.power:=#;
res.coeff:=c;
return res;
end;
copy:SAME is
res:SAME:=new;
res.power:=power.copy;
res.coeff:=coeff; -- copy
return res;
end;
zero: SAME is return #SAME; end;
one: SAME is return #SAME(r_1); end;
is_zero:BOOL is
return coeff=r_0;
end;
normalize:SAME is
m:SAME:=#; m.coeff:=coeff;
loop pair::=power.pair!;
if (pair.t2.is_non_zero) then m.power[pair.t1]:=pair.t2; end;
end;
return m;
end;
str:STR is return str("text"); end;
str(lib : LIBCHARS) : STR is return str; end;
str(format:STR):STR is
timeC,timeV,power1,power2,ms,me,sign:STR;
POLY_WRITE::str_parts
(format,out timeC,out timeV,out power1,out power2,out ms,out me);
c:R:=coeff;
if c<r_0 then sign:="-"; c:=-c; else; sign:=""; end;
--if c.kind_of?(Rational)&&(c.denominator != 1);
-- den="/"+c.denominator.to_s; c=c.numerator
--else
-- den=""
--end
vs::="";
ts::="";
------ for check ----------
--vs:=vs+"[";
--loop id::=power.ind!;
-- vs:=vs+"("+id.str+","+VARNAME::varmapr[id]+","+power[id]+")";
--end;
--vs:=vs+"]";
loop v::=VARNAME::VarOrder.elt!; vid::=VARNAME::varmap[v];
if power.has_ind(vid) then d::=power[vid];
if d /= 0.int then
vs:=vs+ts+v; ts:=timeV;
if d/=1.int then vs:=vs+power1+d.str+power2; end;
end;
end;
end;
s:STR:=sign;
if (c /= r_1)or(vs="") then s:=s+c.str;
if (vs /= "") then s:=s+timeC; end;
end;
s:=s+vs;
return s;
end;
inspect:STR is
-- coeff(var:var_id,degree)...
s:STR:="["+coeff.str;
loop v::=VARNAME::VarOrder.elt!; vid::=VARNAME::varmap[v];
if power.has_ind(vid) then d::=power[vid];
s:=s+"("+v+":"+vid.str+","+d.str+")";
end;
end;
return s+"]";
end;
powerProduct:SAME is
m:SAME:=copy; m.coeff:=r_1; return m;
end;
powerProduct_neg:SAME is
-- power product of negative part
m0::=normalize;
m:SAME:=#; m.coeff:=r_1;
loop v::=m0.power.elt!;
if v.t2.is_neg then m.power[v.t1]:=v.t2; end;
end;
return m;
end;
powerProduct_pos:SAME is
-- power product of positive part
m0::=normalize;
m:SAME:=#; m.coeff:=r_1;
loop v::=m0.power.elt!;
if v.t2.is_pos then m.power[v.t1]:=v.t2; end;
end;
return m;
end;
lcm(other:SAME):SAME is
-- lcm of power product
m::=self.copy; m.coeff:=r_1;
loop v::=other.power.elt!;
if m.power.has_ind(v.t1) then
m.power[v.t1]:=m.power[v.t1].max(v.t2);
else m.power[v.t1]:=v.t2;
end;
end;
return m;
end;
gcd(other:SAME):SAME is
-- gcd of power product
m::=copy; m.coeff:=r_1;
loop v::=m.power.elt!;
if other.power.has_ind(v.t1) then
m.power[v.t1]:=v.t2.min(other.power[v.t1]);
else m.power.delete(v.t1);
end;
end;
return m;
end;
aget(id:CARD):INT is
if power.has_ind(id) then return power[id]; else return 0; end;
end;
aget(s:STR):INT pre VARNAME::varmap.has_ind(s) is
id::=VARNAME::varmap[s];
if power.has_ind(id) then return power[id]; else return 0; end;
end;
aset(id:CARD,e:INT) is power[id]:=e; end;
aset(s:STR, e:INT) is
VARNAME::appendVarName(s); id::=VARNAME::varmap[s]; power[id]:=e;
end;
negate: SAME is
p:SAME:= self.copy; p.coeff:=-coeff; return p;
end;
plus(other:SAME): SAME is
-- expr1 + expr2 expr1.plus(expr2)
-- Assume that power is the same for "plus" and "minus".
p::=copy;
p.coeff:=coeff+other.coeff;
return p;
end;
plus(other:R): SAME is
p:SAME:=copy;
p.coeff:=coeff+other;
return p;
end;
minus(other:SAME): SAME is
-- expr1 - expr2 expr1.minus(expr2)
p:SAME:=copy;
p.coeff:=coeff-other.coeff;
return p;
end;
minus(other:R): SAME is
p:SAME:=copy;
p.coeff:=coeff-other;
return p;
end;
times(other:SAME): SAME is
-- expr1 * expr2 expr1.times(expr2)
p:SAME:=copy;
p.coeff:=coeff*other.coeff;
-- map_key!: K , map_pair!: TUP{K,E}
loop pair::=other.power.pair!;
key::=pair.t1;
if p.power.has_ind(key) then
p.power[key]:=power[key]+pair.t2;
else
p.power[key]:=pair.t2;
end;
end;
return p;
end;
times(other:R): SAME is
-- expr1 * expr2 expr1.times(expr2)
p:SAME:=copy;
p.coeff:=p.coeff*other;
return p;
end;
is_divisible(divisor:SAME):BOOL is
-- self/divisor /= 0
return is_divisible(divisor,true,false);
end;
is_divisible(divisor:SAME,check_coeff:BOOL,Laurent:BOOL):BOOL is
if check_coeff and ((coeff=r_0)or(divisor.coeff=r_0)
or((coeff/divisor.coeff)=r_0)) then return false;
end;
if Laurent then
-- Laurent polynomial
return true;
else -- polynomial
loop pair::=divisor.power.pair!;
key::=pair.t1;
if power.has_ind(key) then
if (power[key]<pair.t2) then return false; end;
else
return false;
end;
end;
return true
end;
end;
div(m:SAME):SAME is
-- if ~is_divisible(m,false,false) then
-- #ERR+"Not divisible.\n"; return copy;
-- end;
p:SAME:=copy;
p.coeff:=p.coeff/m.coeff;
loop pair::=m.power.pair!;
v::=pair.t1;
p.power[v]:=p.power[v]-pair.t2; -- determine exponents
end;
return p;
end;
div(m:R):SAME is
p:SAME:=copy;
p.coeff:=p.coeff/m;
return p;
end;
-- divisibleI?(divisor)
-- divmodI(m)
-- divZp(m,prime)
-- coerce(x)
totalDegree:INT is
deg:INT:=0.int; loop deg:=deg+power.target!; end; return deg;
end;
totalWeightedDegree:FLT is
deg:FLT:=0.0;
loop id::=power.ind!;
deg:=deg+#FLT(power[id])*VARNAME::weight[id];
end;
return deg;
end;
getTermOrders:ARRAY{STR} is
-- acceptable order names
return |"lex", "deglex", "degrevlex", "wdeglex", "wdegrevlex"|;
end;
setTermOrder is TermOrder:="degrevlex"; end;
setTermOrder(t:STR) is
if getTermOrders.has(t) then TermOrder:=t;
else TermOrder:="degrevlex";
end;
end;
getTermOrder:STR is return TermOrder; end;
lex(m:SAME):INT is
-- lexical order 1: self>m, 0:self=m, -1:self<m
loop id::=VARNAME::idOrder.elt!;
if power.has_ind(id) and m.power.has_ind(id) then
if power[id] /= m.power[id] then
return (power[id]-m.power[id]).sgn;
end;
elsif power.has_ind(id) then return power[id].sgn;
elsif m.power.has_ind(id) then return -m.power[id].sgn;
end;
end;
return 0.int;
end;
revlex(m:SAME):INT is
-- reversed lexical order 1: self>m, 0:self=m, -1:self<m
loop i::=(VARNAME::idOrder.size.int-1).downto!(0.int);
id::=VARNAME::idOrder[i];
if power.has_ind(id) and m.power.has_ind(id) then
if power[id] /= m.power[id] then
return (m.power[id]-power[id]).sgn;
end;
elsif power.has_ind(id) then return -power[id].sgn;
elsif m.power.has_ind(id) then return m.power[id].sgn;
end;
end;
return 0.int;
end;
deglex(m:SAME):INT is
t1::=totalDegree; t2::=m.totalDegree;
if t1 /= t2 then return (t1-t2).sgn; end;
return lex(m)
end;
wdeglex(m:SAME):INT is
-- weighted deg-lex
t1::=totalWeightedDegree; t2::=m.totalWeightedDegree;
if t1 /= t2 then return (t1-t2).sgn.int; end;
return lex(m)
end;
degrevlex(m:SAME):INT is
t1::=totalDegree; t2::=m.totalDegree;
if t1 /= t2 then return (t1-t2).sgn; end;
return revlex(m)
end;
wdegrevlex(m:SAME):INT is
-- weighted deg-rev-lex
t1::=totalWeightedDegree; t2::=m.totalWeightedDegree;
if t1 /= t2 then return (t1-t2).sgn.int; end;
return revlex(m)
end;
compare(m:SAME):INT is
-- <=>: -1 if "<", 0 if "=", 1 if ">" .
case TermOrder
when "lex" then return lex(m);
when "deglex" then return deglex(m);
when "degrevlex" then return degrevlex(m);
when "wdeglex" then return wdeglex(m);
when "wdegrevlex" then return wdegrevlex(m);
end;
end;
is_lt(m:SAME):BOOL is
return compare(m).is_neg;
end;
is_eq(m:SAME):BOOL is
return lex(m).is_zero;
end;
end; --class MONOMIAL
partial class POLYM{R}
partial class POLYM{R} is
attr monomials:ARRAY{MONOMIAL{R}};
-- Polynomial is sequence of Monomials.
shared r_0:R;
shared r_1:R;
create: SAME is
-- 0
res::=new; res.monomials:=#; return res;
end;
create(m:MONOMIAL{R}):SAME is
res:SAME:=new; res.monomials:=|m|; return res;
end;
create(a:ARRAY{MONOMIAL{R}}):SAME is
res:SAME:=new; res.monomials:=a.copy; return res;
end;
create(c:R,x:STR,d:INT):SAME is
-- c*x^d
m:MONOMIAL{R}:=#; m.coeff:=c; m[x]:=d;
return #SAME(m);
end;
create(x:STR):SAME is
-- 1x^1. assume "x" is var_name
return create(r_1,x,1.int);
end;
create(c:R): SAME is
-- c as polynomial.
res:SAME:=new; m::=#MONOMIAL{R}(c);
return #SAME(m);
end;
create(p:SAME):SAME is return copy; end;
zero: SAME is return #SAME; end;
one: SAME is return #SAME(r_1); end;
copy:SAME is
p:SAME:=new; p.monomials:=#(monomials.size);
loop p.monomials.set!(monomials.elt!.copy); end;
return p;
end;
str:STR is return self.str("text"); end;
str(lib : LIBCHARS) : STR is return str; end;
str(format:STR):STR is
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:="";
loop m::=monomials.elt!;
if (m.coeff>r_0) then s:=s+addS; end;
s:=s+m.str(format); addS:="+";
end;
if (s="")then s:="0"; end;
s:=ms+s+me; -- math start and math end
return s;
end;
inspect:STR is
-- [term][term]...
s:STR:="";
loop m::=monomials.elt!;
s:=s+m.inspect;
end;
return s;
end;
monomial_sort_func(m1,m2:MONOMIAL{R}):BOOL is return m2.is_lt(m1); end;
sort is
-- sort decerasing order ">". i.e. higher term is top.
--sf::=bind(monomial_sort_func(_,_)); monomials.insertion_sort_by(sf);
ARRAY_SORT{MONOMIAL{R}}::quick_sort(inout monomials);
monomials:=monomials.reverse;
end;
normalize:SAME is
-- remove 0 coefficient and normalize each term
p:SAME:=#; p.monomials:=#(monomials.size);
loop m::=monomials.elt!; p.monomials.set!(m.normalize); end;
p.sort;
-- sum up terms of same power product
i0::=0;
loop i::=p.monomials.ind!;
if (i0<i)and(p.monomials[i0].is_eq(p.monomials[i])) then
p.monomials[i0]:=p.monomials[i0]+p.monomials[i];
p.monomials[i].coeff:=r_0;
else
i0:=i;
end;
end;
p1:SAME:=#;
loop m::=p.monomials.elt!;
if m.coeff /= r_0 then p1.monomials:=p1.monomials.append(|m|); end;
end;
return p1;
end;
lt:MONOMIAL{R} is
-- leading term
if self.is_zero then return #MONOMIAL{R}(r_0);
else self.sort; m::=monomials[0]; return m;
end;
end;
lc:R is
-- leading coefficient
return lt.coeff;
end;
lp:MONOMIAL{R} is
-- leading power product
return lt.powerProduct;
end;
gcd_term:MONOMIAL{R} is
-- gcd of power product of terms
if monomials.size=0 then m::=#MONOMIAL{R}(r_1); return m;
else
m::=monomials[0];
loop m1::=monomials.elt!; m:=m.gcd(m1); end;
m.coeff:=r_1;
return m;
end;
end;
lcm_term:MONOMIAL{R} is
-- lcm of power product of terms
if monomials.size=0 then m::=#MONOMIAL{R}(r_1); return m;
else
m::=monomials[0];
loop m1::=monomials.elt!; m:=m.lcm(m1); end;
m.coeff:=r_1;
return m;
end;
end;
is_eq(o:SAME):BOOL is
return (self-o).is_zero;
end;
is_lt(o:SAME):BOOL is
return lp.is_lt(o.lp);
end;
is_zero:BOOL is return monomials.is_empty; end;
is_one:BOOL is
return (self-one).is_zero;
end;
is_unit:BOOL is
if lp.totalDegree.is_pos then return false; end;
c::=lc;
typecase c
when INT then return (c.abs=r_1);
when INTI then return (c.abs=r_1);
when FLT then return true;
when FLTD then return true;
when CPX then return true;
when CPXD then return true;
when RAT then return true;
else return ((r_1/c)*c)=r_1;
end;
end;
coeff(varId:CARD, deg:INT):SAME is
-- coefficient of degree "deg" as a "var" variable polynomial.
p:SAME:=#;
m1:MONOMIAL{R};
loop m::=monomials.elt!;
m1:=m.copy;
if (m1[varId]=deg) then
if (m1.power.has_ind(varId)) then m1.power.delete(varId); end;
p.monomials:=p.monomials.append(|m1|);
end;
end;
return p.normalize;
end;
coeff(varName:STR, deg:INT):SAME is
-- coefficient of degree "deg" as a "var" variable polynomial.
varId:CARD:=VARNAME::varmap[varName];
return (coeff(varId,deg));
end;
vars:ARRAY{STR} is
-- return var names in the polynomial.
idTbl:MAP{CARD,INT}:=#; varTbl:ARRAY{STR}:=#;
loop m::=monomials.elt!;
loop idTbl[m.power.ind!]:=1.int; end;
end;
loop
varTbl:=varTbl.append(|VARNAME::varmapr[idTbl.ind!]|);
end;
lt_proc:ROUT{STR,STR}:BOOL:=bind(VARNAME::is_lt(_,_));
varTbl.insertion_sort_by(lt_proc);
varTbl:=varTbl.reverse;
return varTbl;
end;
maxdeg(varId:CARD):INT is
if monomials.size>0 then
deg:INT:=monomials[0][varId];
loop m::=monomials.elt!;
deg:=deg.max(m[varId]);
end;
return deg;
else return 0;
end;
end;
mindeg(varId:CARD):INT is
if monomials.size>0 then
deg:INT:=monomials[0][varId];
loop m::=monomials.elt!;
deg:=deg.min(m[varId]);
end;
return deg;
else return 0;
end;
end;
maxdeg(name:STR):INT is
return maxdeg(VARNAME::varmap[name]);
end;
mindeg(name:STR):INT is
return mindeg(VARNAME::varmap[name]);
end;
-- <=>(other)
-- ==(other)
-- coerce(x)
negate:SAME is
p:SAME:=#;
p.monomials:=monomials.copy;
loop i::=p.monomials.ind!;
p.monomials[i]:=-p.monomials[i];
end;
return p;
end;
private plus_merge(other:SAME):SAME is
-- plus
-- Assume self and other are sorted by ">".
if monomials.size=0 then return other.copy; end;
if other.monomials.size=0 then return self.copy; end;
r:SAME:=#; r.monomials:=#(monomials.size+other.monomials.size);
i,j,k:CARD; w:MONOMIAL{R};
k:=0;
loop
while!((i<monomials.size)or(j<other.monomials.size));
if i=monomials.size then w:=other.monomials[j].copy; j:=j+1;
r.monomials[k]:=w; k:=k+1;
elsif j=other.monomials.size then w:=monomials[i].copy; i:=i+1;
r.monomials[k]:=w; k:=k+1;
else
case monomials[i].compare(other.monomials[j])
when 1.int then w:=monomials[i].copy; i:=i+1;
r.monomials[k]:=w; k:=k+1;
when -1 then w:=other.monomials[j].copy; j:=j+1;
r.monomials[k]:=w; k:=k+1;
when 0.int then w:=monomials[i]+other.monomials[j]; i:=i+1; j:=j+1;
if w.coeff/=r_0 then r.monomials[k]:=w; k:=k+1; end;
end;
end;
end;
r.monomials:=r.monomials.resize(k);
return r;
end;
plus(other:SAME):SAME is
return self.normalize.plus_merge(other.normalize);
--p:SAME:=#; p.monomials:=monomials.append(other.monomials);
--return p.normalize;
end;
minus(other:SAME):SAME is return self+(-other); end;
plus(other:R):SAME is
m:MONOMIAL{R}:=#; m.coeff:=other;
p:SAME:=#; p.monomials:=monomials.append(|m|);
return p.normalize;
end;
plus(n:INT):SAME is return self+#R(n); end;
plus(n:CARD):SAME is return self+#R(n); end;
minus(other:R):SAME is return self+(-other); end;
minus(n:INT):SAME is return self+(-n); end;
minus(n:CARD):SAME is return self+(-n.int); end;
times(other:SAME):SAME is
p:SAME:=#;
p.monomials:=#(monomials.size*other.monomials.size);
i::=0;
loop m1::=monomials.elt!;
loop p.monomials[i]:=(m1*other.monomials.elt!);i:=i+1 end;
end;
return p.normalize;
end;
times(other:R):SAME is
p:SAME:=#; p.monomials:=#(monomials.size);
loop p.monomials.set!(monomials.elt!*other); end;
return p.normalize;
end;
times(n:INT):SAME is return times( #R(n) ); end;
times(n:CARD):SAME is return times( #R(n) ); end;
pow(power:INTI):SAME is
-- calculate expr1^expr2 following to binary notation of "power".
s:SAME:=#(r_1);
if power.is_zero or (monomials.size=0) then return s; end;
p:SAME:=copy;
if (power.is_neg) then -- for Laurent polynomial
if (p.monomials.size=1) then
m::=p.monomials[0]; m.coeff:=r_1/m.coeff;
loop v::=m.power.ind!; m.power[v]:=-m.power[v]; end;
power:=-power;
else return s;
end;
end;
if (power.is_pos) then
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;
pow(power:INT):SAME is return pow(#INTI(power)); end;
pow(power:CARD):SAME is return pow(#INTI(power)); end;
shared divmodForce:BOOL;
divmod(divisors:ARRAY{SAME}, out q:ARRAY{SAME}, out r:SAME) is
-- Multiple division.
h::=self.normalize;
-- sort as heigher be top
-- divisors.sort; divisors:=divisors.reverse;
ltD:ARRAY{MONOMIAL{R}}:=#(divisors.size); -- leading terms of divisors
lc_nz_D:ARRAY{BOOL}:=#(divisors.size);
q:=#(divisors.size); -- quotients
loop i::=divisors.ind!;
ltD[i]:=divisors[i].lt;
lc_nz_D[i]:=divisors[i].lc.is_zero.not;
q[i]:=#;
end;
r:=#;
pw:SAME:=#;
loop while!(0/=h.monomials.size);
i::=0;
ltH::=h.lt;
loop while!(i<ltD.size);
if lc_nz_D[i] and ltH.is_divisible(ltD[i]) then
qt::=ltH/ltD[i];
q[i].monomials:=q[i].monomials.append(|qt|);
pw.monomials:= |qt|;
h:=h-(pw*divisors[i]);
h:=h.normalize;
if h.monomials.size=0 then break!; end;
ltH:=h.lt;
i:=0;
else
i:=i+1;
end;
end;
if h.monomials.size>0 then
r.monomials:=r.monomials.append(|ltH|);
if h.monomials.size>1 then
h.monomials:=h.monomials.slice(1,h.monomials.size-1);
else
h.monomials:=#;
end;
end;
end;
r:=r.normalize;
loop i::=q.ind!; q[i]:=q[i].normalize; end;
--a:SAME:=r.copy; loop i::=q.ind!; a:=a+q[i]*divisors[i]; end;
--assert self=a;
end;
divmod_lt(divisors:ARRAY{SAME}, out q:ARRAY{SAME}, out r:SAME) is
-- Multiple division for leading term.
h::=self.normalize;
-- sort as heigher be top
-- divisors.sort; divisors:=divisors.reverse;
ltD:ARRAY{MONOMIAL{R}}:=#(divisors.size); -- leading terms of divisors
lc_nz_D:ARRAY{BOOL}:=#(divisors.size);
q:=#(divisors.size); -- quotients
loop i::=divisors.ind!;
ltD[i]:=divisors[i].lt;
lc_nz_D[i]:=divisors[i].lc.is_zero.not;
q[i]:=#;
end;
r:=#;
pw:SAME:=#;
--
i::=0;
ltH::=h.lt;
loop while!(i<ltD.size);
if lc_nz_D[i] and ltH.is_divisible(ltD[i]) then
qt::=ltH/ltD[i];
q[i].monomials:=q[i].monomials.append(|qt|);
pw.monomials:= |qt|;
h:=h-(pw*divisors[i]);
h:=h.normalize;
if h.monomials.size=0 then break!; end;
ltH:=h.lt;
i:=0;
else
i:=i+1;
end;
end;
--
r:=h;
r:=r.normalize;
loop i:=q.ind!; q[i]:=q[i].normalize; end;
--- check ---
--a:SAME:=r.copy; loop i::=q.ind!; a:=a+q[i]*divisors[i]; end;
--assert self=a;
end;
div(other:ARRAY{SAME}):ARRAY{SAME} is
q:ARRAY{SAME};
r:SAME;
divmod(other,out q, out r); return q;
end;
mod(other:ARRAY{SAME}):SAME is
q:ARRAY{SAME};
r:SAME;
divmod(other,out q, out r); return r;
end;
divmod(divisor:SAME, out q:SAME, out r:SAME) is
q1:ARRAY{SAME};
divmod( |divisor|, out q1, out r);
q:=q1[0];
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;
divmod(divisor:R, out q:SAME, out r:SAME) is
q:=div(divisor); r:=self-q*divisor;
end;
div(other:R):SAME is
q::=copy; loop q.monomials.set!(q.monomials.elt!/other); end;
return q;
end;
-- divmodZp(divisors,p) -- when R is Zp.
-- divmodI(divisors) -- when R is INTL.
private nameMap_to_idMap(nlist:MAP{STR,SAME}):MAP{CARD,SAME} is
list:MAP{CARD,SAME}:=#;
loop v::=nlist.pair!;
if VARNAME::varmap.has_ind(v.t1) then
list[VARNAME::varmap[v.t1]]:=v.t2;
end;
end;
return list;
end;
private nameArr_to_idArr(narr: ARRAY{STR}):ARRAY{CARD} is
iarr:ARRAY{CARD}:=#(narr.size);
loop iarr.set!(VARNAME::varmap[narr.elt!]); end;
return iarr;
end;
substitute(list:MAP{CARD,SAME}):SAME is
-- list is Hash of "var id" => val
f:SAME:=#; fw1:SAME;
loop m::=monomials.elt!;
fw:SAME:=#; fw:=fw+m.coeff;
loop pair::=m.power.pair!; var::=pair.t1; deg::=pair.t2;
if list.has_ind(var) then fw1:=list[var].copy^deg;
else m1:MONOMIAL{R}:=#; m1.coeff:=r_1; m1.power[var]:=deg;
fw1:=#(m1);
end;
fw:=fw*fw1;
end;
f:=f+fw;
end;
return f.normalize;
end;
substitute(nlist:MAP{STR,SAME}):SAME is
-- list is Hash of "var name" => val
return substitute(nameMap_to_idMap(nlist));
end;
derivative(vars:ARRAY{CARD}):SAME is
-- vars is Array of var id
f::=self.copy;
loop m::=f.monomials.elt!;
loop var::=vars.elt!;
if m.power.has_ind(var) then
p::=m.power[var];
m.coeff:=m.coeff*#R(p);
if p=1.int then m.power:=m.power.delete_ind(var);
else m.power[var]:=p-1;
end;
else m.coeff:=r_0; break!;
end;
end;
end;
return f.normalize;
end;
derivative(nlist:ARRAY{STR}):SAME is
-- nlist is array of "var name"
return derivative(nameArr_to_idArr(nlist));
end;
integral(vars:ARRAY{CARD}):SAME is
-- vars is Array of var id
f::=self.copy;
loop m::=f.monomials.elt!;
loop var::=vars.elt!;
if m.power.has_ind(var) then
p::=m.power[var]+1.int;
m.power[var]:=p;
m.coeff:=m.coeff/(r_1*#R(p));
else m.power[var]:=1.int;
end;
end;
end;
return f.normalize;
end;
integral(nlist:ARRAY{STR}):SAME is
-- nlist is array of "var name".
return integral(nameArr_to_idArr(nlist));
end;
S_poly(g:SAME):SAME is
-- coefficient is field
lpF::=lp; ltF::=lt;
lpG::=g.lp; ltG::=g.lt;
lcm::=lpF.lcm(lpG);
return #SAME(lcm/ltF)*self-#SAME(lcm/ltG)*g;
end;
coeff_to_one:SAME is
f::=self.copy;
loop f.monomials[f.monomials.ind!].coeff:=r_1; end;
return f;
end;
-- coeff_truncate # truncate each coefficient to Integer
-- coeff_to_f # converts each element to Float
-- coeff_to_Zp(p)
-- inspect
end; --class POLYM
class TEST_POLYM
class TEST_POLYM is
include TEST;
testM is
class_name("MONOMIAL");
m:MONOMIAL{INTI};
m:=#;
test("gen",m.str,"0");
m:=#(5.inti);
test("gen",m.str,"5");
m:=#; m.coeff:=3.inti; m["x"]:=2.int;
test("gen",m.str,"3*x^{2}");
m:=#; m.coeff:=4.inti; m["y"]:=5.int; m["z"]:=6.int;
test("gen",m.str,"4*y^{5}*z^{6}");
finish;
end;
testP is
class_name("POLYM_INTI");
poly,p1,p2,p3,p4:POLYM_INTI;
poly:=#;
test("generate",poly.str,"0");
poly:=#(5.inti);
test("generate",poly.str,"5");
poly:=#(5.inti,"x",3.int);
test("generate",poly.str,"5*x^{3}");
poly:=#((-5).inti,"x",3.int);
test("generate",poly.str,"-5*x^{3}");
poly:=#(5.inti,"x",-3);
test("generate",poly.str,"5*x^{-3}");
poly:=#(5.inti,"x1",3.int);
test("generate",poly.str,"5*x1^{3}");
p1:=#(2.inti,"x",3.int);
p2:=#(3.inti,"x",3.int);
test("plus", (p1+p2).str, "5*x^{3}");
p1:=#(2.inti,"x",3.int);
p2:=#(3.inti,"x",4.int);
test("plus", (p1+p2).str, "3*x^{4}+2*x^{3}");
-- if true then finish; return; end;
p1:=#(2.inti,"x",3.int);
test("plus", (p1+7.inti).str, "2*x^{3}+7");
poly:=#(5.inti,"x",3.int);
test("negate",(-poly).str,"-5*x^{3}");
p1:=#(7.inti,"x",3.int);
p2:=#(3.inti,"x",3.int);
test("minus", (p1-p2).str, "4*x^{3}");
p1:=#(2.inti,"x",3.int);
p2:=#(3.inti,"x",4.int);
test("minus", (p1-p2).str, "-3*x^{4}+2*x^{3}");
p1:=#(2.inti,"x",3.int);
p2:=#(3.inti,"x",4.int);
test("minus", (p2-p1).str, "3*x^{4}-2*x^{3}");
p1:=#(2.inti,"x",5.int);
p1:=p1+3.inti;
p2:=p1.copy;
test("times", (p1*p2).str, "4*x^{10}+12*x^{5}+9");
test("times", (p1*4.inti).str, "8*x^{5}+12");
p1:=#(2.inti,"x",1.int);
p1:=p1+3.inti;
p2:=#(2.inti,"y",2.int);
p2:=p2+1.inti;
test("times", (p1*p2).str, "4*x*y^{2}+6*y^{2}+2*x+3");
p1:=#(2.inti,"x",1.int); p1:=p1+3.inti;
p2:=#(1.inti); p2:=p2+p1*p1-1.inti;
p2.divmod(p1,out p3,out p4);
test("divmod", p3.str,"2*x+3");
test("divmod", p4.str,"0");
x::=#POLYM_INTI(1.inti,"x",1.int);
y::=#POLYM_INTI(1.inti,"y",1.int);
z::=#POLYM_INTI(1.inti,"z",1.int);
p1:=x*2.inti+y*3.inti+3.inti;--"2x+3y+3"
test("poly set",p1.str,"2*x+3*y+3");
p1:=x*2.inti+y*3.inti+3.inti;--"2x+3y+3"
p2:=x+y*5.inti+2.inti; --"x+5y+2"
p3:=p1.S_poly_PID(p2);
test("S",p3.str,"-7*y-1");
p1:=x+y+z+x*y+y*z+z*x+x*x+y*y+z*z+ z*z*z;
VARNAME::setVarOrder(|"x","y","z"|);
MONOMIAL{INTI}::setTermOrder("lex");
p1:=p1.normalize;
test("lex(x,y,z))", p1,"x^{2}+x*y+x*z+x+y^{2}+y*z+y+z^{3}+z^{2}+z");
VARNAME::setVarOrder(|"x","z","y"|);
MONOMIAL{INTI}::setTermOrder("lex");
p1:=p1.normalize;
test("lex(x,z,y)", p1,"x^{2}+x*z+x*y+x+z^{3}+z^{2}+z*y+z+y^{2}+y");
VARNAME::setVarOrder(|"x","y","z"|);
MONOMIAL{INTI}::setTermOrder("deglex");
p1:=p1.normalize;
test("deglex", p1,"z^{3}+x^{2}+x*y+x*z+y^{2}+y*z+z^{2}+x+y+z");
VARNAME::setVarOrder(|"x","y","z"|);
MONOMIAL{INTI}::setTermOrder("degrevlex");
p1:=p1.normalize;
test("degrevlex", p1,"z^{3}+x^{2}+x*y+y^{2}+x*z+y*z+z^{2}+x+y+z");
p1:=x^3+x^2*z^2+y^4;
VARNAME::setVarOrder(|"x","y","z"|);
MONOMIAL{INTI}::setTermOrder("lex");
p1:=p1.normalize;
test("lex", p1,"x^{3}+x^{2}*z^{2}+y^{4}");
MONOMIAL{INTI}::setTermOrder("deglex");
p1:=p1.normalize;
test("deglex", p1,"x^{2}*z^{2}+y^{4}+x^{3}");
MONOMIAL{INTI}::setTermOrder("degrevlex");
p1:=p1.normalize;
test("degrevlex", p1,"y^{4}+x^{2}*z^{2}+x^{3}");
-- ar:ARRAY{INT}:=|2,3,1|; ar.sort; test("sort", ar.str,"{1,2,3}");
finish;
end;
main is
POLYM_INTI::init;
testM;
testP;
end;
end;