123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672(************************************************************************)(* * The Coq Proof Assistant / The Coq Development Team *)(* v * Copyright INRIA, CNRS and contributors *)(* <O___,, * (see version control and CREDITS file for authors & dates) *)(* \VV/ **************************************************************)(* // * This file is distributed under the terms of the *)(* * GNU Lesser General Public License Version 2.1 *)(* * (see LICENSE file for the text of the license) *)(************************************************************************)(* Recursive polynomials: R[x1]...[xn]. *)openUtilopenUtile(* 1. Coefficients: R *)moduletypeCoef=sigtypetvalequal:t->t->boolvallt:t->t->boolvalle:t->t->boolvalabs:t->tvalplus:t->t->tvalmult:t->t->tvalsub:t->t->tvalopp:t->tvaldiv:t->t->tvalmodulo:t->t->tvalpuis:t->int->tvalpgcd:t->t->tvalhash:t->intvalof_num:Q.t->tvalto_string:t->stringendmoduletypeS=sigtypecoeftypevariable=inttypet=Pintofcoef|Precofvariable*tarrayvalof_num:Q.t->tvalx:variable->tvalmonome:variable->int->tvalis_constantP:t->boolvalis_zero:t->boolvalmax_var_pol:t->variablevalmax_var_pol2:t->variablevalmax_var:tarray->variablevalequal:t->t->boolvalnorm:t->tvaldeg:variable->t->intvaldeg_total:t->intvalcopyP:t->tvalcoef:variable->int->t->tvalplusP:t->t->tvalcontent:t->coefvaldiv_int:t->coef->tvalvire_contenu:t->tvalvars:t->variablelistvalint_of_Pint:t->coefvalmultx:int->variable->t->tvalmultP:t->t->tvalderiv:variable->t->tvaloppP:t->tvalmoinsP:t->t->tvalpuisP:t->int->tval(@@):t->t->tval(--):t->t->tval(^^):t->int->tvalcoefDom:variable->t->tvalcoefConst:variable->t->tvalremP:variable->t->tvalcoef_int_tete:t->coefvalnormc:t->tvalcoef_constant:t->coefvaluniv:boolrefvalstring_of_var:int->stringvalnsP:intrefvalto_string:t->stringvalprintP:t->unitvalprint_tpoly:tarray->unitvalprint_lpoly:tlist->unitvalquo_rem_pol:t->t->variable->t*tvaldiv_pol:t->t->variable->tvaldivP:t->t->tvaldiv_pol_rat:t->t->boolvalpseudo_div:t->t->variable->t*t*int*tvalpgcdP:t->t->tvalpgcd_pol:t->t->variable->tvalcontent_pol:t->variable->tvalpgcd_coef_pol:t->t->variable->tvalpgcd_pol_rec:t->t->variable->tvalgcd_sub_res:t->t->variable->tvalgcd_sub_res_rec:t->t->t->t->int->variable->tvallazard_power:t->t->int->variable->tvalhash:t->intmoduleHashpol:Hashtbl.Swithtypekey=tend(***********************************************************************
2. Type of polynomials, operations.
*)moduleMake(C:Coef)=structtypecoef=C.tletcoef_of_inti=C.of_num(Q.of_inti)letcoef0=coef_of_int0letcoef1=coef_of_int1typevariable=inttypet=Pintofcoef(* constant polynomial *)|Precofvariable*(tarray)(* coefficients, increasing degree *)(* by default, operations work with normalized polynomials:
- variables are positive integers
- coefficients of a polynomial in x only use variables < x
- no zero coefficient at beginning
- no Prec(x,a) where a is constant in x
*)(* constant polynomials *)letof_numx=Pint(C.of_numx)letcf0=of_numQ.zeroletcf1=of_numQ.one(* nth variable *)letxn=Prec(n,[|cf0;cf1|])(* create v^n *)letmonomevn=matchnwith0->Pintcoef1;|_->lettmp=Array.make(n+1)(Pintcoef0)intmp.(n)<-(Pintcoef1);Prec(v,tmp)letis_constantP=functionPint_->true|Prec_->falseletint_of_Pint=functionPintx->x|_->failwith"non"letis_zerop=matchpwithPintn->ifC.equalncoef0thentrueelsefalse|_->falseletmax_var_polp=matchpwithPint_->0|Prec(x,_)->x(* p not normalized *)letrecmax_var_pol2p=matchpwithPint_->0|Prec(v,c)->Array.fold_right(funqm->max(max_var_pol2q)m)cvletmax_varl=Array.fold_right(funpm->max(max_var_pol2p)m)l0(* equality between polynomials *)letrecequalpq=match(p,q)with(Pinta,Pintb)->C.equalab|(Prec(x,p1),Prec(y,q1))->(Int.equalxy)&&Array.for_all2equalp1q1|(_,_)->false(* normalize polynomial: remove head zeros, coefficients are normalized
if constant, returns the coefficient
*)letnormp=matchpwithPint_->p|Prec(x,a)->letd=(Array.lengtha-1)inletn=refdinwhile!n>0&&(equala.(!n)(Pintcoef0))don:=!n-1;done;if!n<0thenPintcoef0elseifInt.equal!n0thena.(0)elseifInt.equal!ndthenpelse(letb=Array.make(!n+1)(Pintcoef0)infori=0to!ndob.(i)<-a.(i);done;Prec(x,b))(* degree in v, v >= max var of p *)letdegvp=matchpwithPrec(x,p1)whenInt.equalxv->Array.lengthp1-1|_->0(* total degree *)letrecdeg_totalp=matchpwithPrec(x,p1)->letd=ref0inArray.iteri(funiq->d:=(max!d(i+(deg_totalq))))p1;!d|_->0letreccopyPp=matchpwithPinti->Pinti|Prec(x,q)->Prec(x,Array.mapcopyPq)(* coefficient of degree i in v, v >= max var of p *)letcoefvip=matchpwithPrec(x,p1)whenInt.equalxv->ifi<(Array.lengthp1)thenp1.(i)elsePintcoef0|_->ifInt.equali0thenpelsePintcoef0(* addition *)letrecplusPpq=letres=(match(p,q)with(Pinta,Pintb)->Pint(C.plusab)|(Pinta,Prec(y,q1))->letq2=Array.mapcopyPq1inq2.(0)<-plusPpq1.(0);Prec(y,q2)|(Prec(x,p1),Pintb)->letp2=Array.mapcopyPp1inp2.(0)<-plusPp1.(0)q;Prec(x,p2)|(Prec(x,p1),Prec(y,q1))->ifx<ythen(letq2=Array.mapcopyPq1inq2.(0)<-plusPpq1.(0);Prec(y,q2))elseifx>ythen(letp2=Array.mapcopyPp1inp2.(0)<-plusPp1.(0)q;Prec(x,p2))else(letn=max(degxp)(degxq)inletr=Array.make(n+1)(Pintcoef0)infori=0tondor.(i)<-plusP(coefxip)(coefxiq);done;Prec(x,r)))innormres(* content, positive integer *)letreccontentp=matchpwithPinta->C.absa|Prec(x,p1)->Array.fold_leftC.pgcdcoef0(Array.mapcontentp1)letrecdiv_intpa=matchpwithPintb->Pint(C.divba)|Prec(x,p1)->Prec(x,Array.map(funx->div_intxa)p1)letvire_contenup=letc=contentpinifC.equalccoef0thenpelsediv_intpc(* sorted list of variables of a polynomial *)letrecvars=functionPint_->[]|Prec(x,l)->(List.flatten([x]::(List.mapvars(Array.to_listl))))(* multiply p by v^n, v >= max_var p *)letmultxnvp=matchpwithPrec(x,p1)whenInt.equalxv->letp2=Array.make((Array.lengthp1)+n)(Pintcoef0)infori=0to(Array.lengthp1)-1dop2.(i+n)<-p1.(i);done;Prec(x,p2)|_->ifequalp(Pintcoef0)then(Pintcoef0)else(letp2=Array.make(n+1)(Pintcoef0)inp2.(n)<-p;Prec(v,p2))(* product *)letrecmultPpq=match(p,q)with(Pinta,Pintb)->Pint(C.multab)|(Pinta,Prec(y,q1))->ifC.equalacoef0thenPintcoef0elseletq2=Array.map(funz->multPpz)q1inPrec(y,q2)|(Prec(x,p1),Pintb)->ifC.equalbcoef0thenPintcoef0elseletp2=Array.map(funz->multPzq)p1inPrec(x,p2)|(Prec(x,p1),Prec(y,q1))->ifx<ythen(letq2=Array.map(funz->multPpz)q1inPrec(y,q2))elseifx>ythen(letp2=Array.map(funz->multPzq)p1inPrec(x,p2))elseArray.fold_leftplusP(Pintcoef0)(Array.mapi(funiz->(multxix(multPzq)))p1)(* derive p with variable v, v >= max_var p *)letderivvp=matchpwithPinta->Pintcoef0|Prec(x,p1)whenInt.equalxv->letd=Array.lengthp1-1inifInt.equald1thenp1.(1)else(letp2=Array.maked(Pintcoef0)infori=0tod-1dop2.(i)<-multP(Pint(coef_of_int(i+1)))p1.(i+1);done;Prec(x,p2))|Prec(x,p1)->Pintcoef0(* opposite *)letrecoppPp=matchpwithPinta->Pint(C.oppa)|Prec(x,p1)->Prec(x,Array.mapoppPp1)letmoinsPpq=plusPp(oppPq)letrecpuisPpn=matchnwith0->cf1|_->(multPp(puisPp(n-1)))(* infix notations *)(*let (++) a b = plusP a b
*)let(@@)ab=multPablet(--)ab=moinsPablet(^^)ab=puisPab(* leading coefficient in v, v>= max_var p *)letcoefDomvp=coefv(degvp)pletcoefConstvp=coefv0p(* tail of a polynomial *)letremPvp=moinsPp(multP(coefDomvp)(puisP(xv)(degvp)))(* first integer coefficient of p *)letreccoef_int_tetep=letv=max_var_polpinifv>0thencoef_int_tete(coefDomvp)else(matchpwith|Pinta->a|_->assertfalse)(* divide by the content and make the head int coef positive *)letnormcp=letp=vire_contenupinleta=coef_int_tetepinifC.lecoef0athenpelseoppPp(* constant coef of normalized polynomial *)letreccoef_constantp=matchpwithPinta->a|Prec(_,q)->coef_constantq.(0)(***********************************************************************
3. Printing polynomials.
*)(* if univ = false, we use x,y,z,a,b,c,d... as variables, else x1,x2,...
*)letuniv=reftrueletstring_of_varx=if!univthen"u"^(string_of_intx)elseifx<=3thenString.make1(Char.chr(x+(Char.code'w')))elseString.make1(Char.chr(x-4+(Char.code'a')))letnsP=ref0letrecstring_of_Pcutp=if(!nsP)<=0then"..."elsematchpwith|Pinta->nsP:=(!nsP)-1;ifC.lecoef0athenC.to_stringaelse"("^(C.to_stringa)^")"|Prec(x,t)->letv=string_of_varxands=ref""andsp=ref""inletst0=string_of_Pcutt.(0)inifnot(String.equalst0"0")thens:=st0;letfin=reffalseinfori=(Array.lengtht)-1downto1doif(!nsP)<0then(sp:="...";ifnot(!fin)thens:=(!s)^"+"^(!sp);fin:=true)else(letsi=string_of_Pcutt.(i)insp:="";ifInt.equali1then(ifnot(String.equalsi"0")then(nsP:=(!nsP)-1;ifString.equalsi"1"thensp:=velse(if(String.containssi'+')thensp:="("^si^")*"^velsesp:=si^"*"^v)))else(ifnot(String.equalsi"0")then(nsP:=(!nsP)-1;ifString.equalsi"1"thensp:=v^"^"^(string_of_inti)else(if(String.containssi'+')thensp:="("^si^")*"^v^"^"^(string_of_inti)elsesp:=si^"*"^v^"^"^(string_of_inti))));ifnot(String.is_empty!sp)&¬(!fin)then(nsP:=(!nsP)-1;ifString.is_empty!sthens:=!spelses:=(!s)^"+"^(!sp)));done;ifString.is_empty!sthen(nsP:=(!nsP)-1;(s:="0"));!sletto_stringp=nsP:=20;string_of_PcutpletprintPp=Format.printf"@[%s@]"(to_stringp)letprint_tpolylp=lets=ref"\n{ "inArray.iter(funp->s:=(!s)^(to_stringp)^"\n")lp;prt0((!s)^"}")letprint_lpolylp=print_tpoly(Array.of_listlp)(***********************************************************************
4. Exact division of polynomials.
*)(* return (s,r) s.t. p = s*q+r *)letrecquo_rem_polpqx=ifInt.equalx0then(match(p,q)with|(Pinta,Pintb)->ifC.equal(C.moduloab)coef0then(Pint(C.divab),cf0)elsefailwith"div_pol1"|_->assertfalse)elseletm=degxqinletb=coefDomxqinletq1=remPxqin(* q = b*x^m+q1 *)letr=refpinlets=refcf0inletcontinue=reftrueinwhile(!continue)&&(not(equal!rcf0))doletn=degx!rinifn<mthencontinue:=falseelse(leta=coefDomx!rinletp1=remPx!rin(* r = a*x^n+p1 *)letc=div_polab(x-1)in(* a = c*b *)lets1=c@@((monomex(n-m)))ins:=plusP(!s)s1;r:=p1--(s1@@q1);)done;(!s,!r)(* returns quotient p/q if q divides p, else fails *)anddiv_polpqx=let(s,r)=quo_rem_polpqxinifequalrcf0thenselsefailwith("div_pol:\n"^"p:"^(to_stringp)^"\n"^"q:"^(to_stringq)^"\n"^"r:"^(to_stringr)^"\n"^"x:"^(string_of_intx)^"\n")letdivPpq=letx=max(max_var_polp)(max_var_polq)indiv_polpqxletdiv_pol_ratpq=letx=max(max_var_polp)(max_var_polq)intryletr=puisP(Pint(coef_int_teteq))(1+(degxp)-(degxq))inlet_=div_pol(multPpr)qxintruewithFailure_->false(***********************************************************************
5. Pseudo-division and gcd with subresultants.
*)(* pseudo division :
q = c*x^m+q1
returns (r,c,d,s) s.t. c^d*p = s*q + r.
*)letpseudo_divpqx=matchqwithPint_->(cf0,q,1,p)|Prec(v,q1)whennot(Int.equalxv)->(cf0,q,1,p)|Prec(v,q1)->((* pr "pseudo_division: c^d*p = s*q + r";*)letdelta=ref0inletr=refpinletc=coefDomxqinletq1=remPxqinletd'=degxqinlets=refcf0inwhile(degx!r)>=(degxq)doletd=degx!rinleta=coefDomx!rinletr1=remPx!rinletu=a@@((monomex(d-d')))inr:=(c@@r1)--(u@@q1);s:=plusP(c@@(!s))u;delta:=(!delta)+1;done;(*
pr ("deg d: "^(string_of_int (!delta))^", deg c: "^(string_of_int (deg_total c)));
pr ("deg r:"^(string_of_int (deg_total !r)));
*)(!r,c,!delta,!s))(* gcd with subresultants *)letrecpgcdPpq=letx=max(max_var_polp)(max_var_polq)inpgcd_polpqxandpgcd_polpqx=pgcd_pol_recpqxandcontent_polpx=matchpwithPrec(v,p1)whenInt.equalvx->Array.fold_left(funab->pgcd_pol_recab(x-1))cf0p1|_->pandpgcd_coef_polcpx=matchpwithPrec(v,p1)whenInt.equalxv->Array.fold_left(funab->pgcd_pol_recab(x-1))cp1|_->pgcd_pol_reccp(x-1)andpgcd_pol_recpqx=match(p,q)with(Pinta,Pintb)->Pint(C.pgcd(C.absa)(C.absb))|_->ifequalpcf0thenqelseifequalqcf0thenpelseifInt.equal(degxq)0thenpgcd_coef_polqpxelseifInt.equal(degxp)0thenpgcd_coef_polpqxelse(leta=content_polpxinletb=content_polqxinletc=pgcd_pol_recab(x-1)inpr(string_of_intx);letp1=div_polpcxinletq1=div_polqcxinletr=gcd_sub_resp1q1xinletcr=content_polrxinletres=c@@(div_polrcrx)inres)(* Sub-résultants:
ai*Ai = Qi*Ai+1 + bi*Ai+2
deg Ai+2 < deg Ai+1
Ai = ci*X^ni + ...
di = ni - ni+1
ai = (- ci+1)^(di + 1)
b1 = 1
bi = ci*si^di si i>1
s1 = 1
si+1 = ((ci+1)^di*si)/si^di
*)andgcd_sub_respqx=ifequalqcf0thenpelseletd=degxpinletd'=degxqinifd<d'thengcd_sub_resqpxelseletdelta=d-d'inletc'=coefDomxqinletr=snd(quo_rem_pol(((oppPc')^^(delta+1))@@p)(oppPq)x)ingcd_sub_res_recqr(c'^^delta)c'd'xandgcd_sub_res_recpqscdx=ifequalqcf0thenpelse(letd'=degxqinletc'=coefDomxqinletdelta=d-d'inletr=snd(quo_rem_pol(((oppPc')^^(delta+1))@@p)(oppPq)x)inlets'=lazard_powerc'sdeltaxingcd_sub_res_recq(div_polr(c@@(s^^delta))x)s'c'd'x)andlazard_powercsdx=letres=refcinfor_i=1tod-1dores:=div_pol((!res)@@c)sx;done;!res(* memoizations *)letrechash=functionPinta->(C.hasha)|Prec(v,p)->Array.fold_right(funqh->h+hashq)p0moduleHashpol=Hashtbl.Make(structtypepoly=ttypet=polyletequal=equallethash=hashend)end