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;