123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755(************************************************************************)(* * 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) *)(************************************************************************)(* Nullstellensatz with Groebner basis computation
We use a sparse representation for polynomials:
a monomial is an array of exponents (one for each variable)
with its degree in head
a polynomial is a sorted list of (coefficient, monomial)
*)openUtileexceptionNotInIdeal(***********************************************************************
Global options
*)letlexico=reffalse(* division of tail monomials *)letreduire_les_queues=false(* divide first with new polynomials *)letnouveaux_pol_en_tete=falsetypemetadata={name_var:stringlist;}moduleMonomial:sigtypetvalrepr:t->intarrayvalmake:intarray->tvaldeg:t->intvalnvar:t->intvalvar_mon:int->int->tvalmult_mon:t->t->tvalcompare_mon:t->t->intvaldiv_mon:t->t->tvaldiv_mon_test:t->t->boolvalppcm_mon:t->t->tvalconst_mon:int->tend=structtypet=intarraytypemon=tletreprm=mletmakem=mletnvar(m:mon)=Array.lengthm-1letdeg(m:mon)=m.(0)letmult_mon(m:mon)(m':mon)=letd=nvarminletm''=Array.make(d+1)0infori=0toddom''.(i)<-(m.(i)+m'.(i));done;m''letcompare_mon(m:mon)(m':mon)=letd=nvarminif!lexicothen((* Comparaison de monomes avec ordre du degre lexicographique = on commence par regarder la 1ere variable*)letres=ref0inleti=ref1in(* 1 si lexico pur 0 si degre*)while(!res=0)&&(!i<=d)dores:=(Int.comparem.(!i)m'.(!i));i:=!i+1;done;!res)else((* degre lexicographique inverse *)matchInt.comparem.(0)m'.(0)with|0->(* meme degre total *)letres=ref0inleti=refdinwhile(!res=0)&&(!i>=1)dores:=-(Int.comparem.(!i)m'.(!i));i:=!i-1;done;!res|x->x)letdiv_monmm'=letd=nvarminletm''=Array.make(d+1)0infori=0toddom''.(i)<-(m.(i)-m'.(i));done;m''(* m' divides m *)letdiv_mon_testmm'=letd=nvarminletres=reftrueinleti=ref0in(*il faut que le degre total soit bien mis sinon, i=ref 1*)while(!res)&&(!i<=d)dores:=(m.(!i)>=m'.(!i));i:=succ!i;done;!resletset_degm=letd=nvarminm.(0)<-0;fori=1toddom.(0)<-m.(i)+m.(0);done;m(* lcm *)letppcm_monmm'=letd=nvarminletm''=Array.make(d+1)0infori=1toddom''.(i)<-(maxm.(i)m'.(i));done;set_degm''(* returns a constant polynom ial with d variables *)letconst_mond=letm=Array.make(d+1)0inletm=set_degminmletvar_mondi=letm=Array.make(d+1)0inm.(i)<-1;letm=set_degminmend(***********************************************************************
Functor
*)moduleMake(P:Polynom.S)=structtypecoef=P.tletcoef0=P.of_numQ.zeroletcoef1=P.of_numQ.oneletstring_of_coefc="["^(P.to_stringc)^"]"(***********************************************************************
Monomials
array of integers, first is the degree
*)openMonomialtypemon=Monomial.ttypedeg=inttypepoly=(coef*mon)listtypepolynom={pol:poly;num:int;}(**********************************************************************
Polynomials
list of (coefficient, monomial) decreasing order
*)letreprp=pletequal=Util.List.for_all2eq(fun(c1,m1)(c2,m2)->P.equalc1c2&&m1=m2)lethashp=letc=List.mapfstpinletm=List.mapsndpinList.fold_left(funhp->h*17+P.hashp)(Hashtbl.hashm)cmoduleHashpol=Hashtbl.Make(structtypet=polyletequal=equallethash=hashend)(* A pretty printer for polynomials, with Maple-like syntax. *)letgetvarlvi=try(List.nthlvi)withFailure_->(List.fold_left(funrx->r^" "^x)"lv= "lv)^" i="^(string_of_inti)letstring_of_polzeroPhdPtlPcoeftermmontermstring_of_coefdimmonstring_of_explvarp=letrecstring_of_monmcoefone=lets=ref[]infori=1to(dimmonm)do(match(string_of_expmi)with"0"->()|"1"->s:=(!s)@[(getvarlvar(i-1))]|e->s:=(!s)@[((getvarlvar(i-1))^"^"^e)]);done;(match!swith[]->ifcoefonethen"1"else""|l->ifcoefonethen(String.concat"*"l)else("*"^(String.concat"*"l)))andstring_of_termtstart=leta=coeftermtandm=montermtinmatch(string_of_coefa)with"0"->""|"1"->(matchstartwithtrue->string_of_monmtrue|false->("+ "^(string_of_monmtrue)))|"-1"->("-"^" "^(string_of_monmtrue))|c->if(String.getc0)='-'then("- "^(String.subc1((String.lengthc)-1))^(string_of_monmfalse))else(matchstartwithtrue->(c^(string_of_monmfalse))|false->("+ "^c^(string_of_monmfalse)))andstringPpstart=if(zeroPp)then(ifstartthen("0")else"")else((string_of_term(hdPp)start)^" "^(stringP(tlPp)false))in(stringPptrue)letstringPmetadata(p:poly)=string_of_pol(funp->matchpwith[]->true|_->false)(funp->matchpwith(t::p)->t|_->failwith"print_pol dans dansideal")(funp->matchpwith(t::p)->p|_->failwith"print_pol dans dansideal")(fun(a,m)->a)(fun(a,m)->m)string_of_coef(funm->(Array.length(Monomial.reprm))-1)(funmi->(string_of_int((Monomial.reprm).(i))))metadata.name_varpletnsP2=10letstringPcutmetadata(p:poly)=(*Polynomesrec.nsP1:=20;*)letres=if(List.lengthp)>nsP2then(stringPmetadata[List.hdp])^" + "^(string_of_int(List.lengthp))^" terms"elsestringPmetadatapin(*Polynomesrec.nsP1:= max_int;*)res(* Operations *)letzeroP=[](* returns a constant polynom ial with d variables *)letpolconstdc=letm=const_mondin[(c,m)]letplusPpq=letrecplusPpqaccu=matchp,qwith|[],[]->List.revaccu|[],_->List.rev_appendaccuq|_,[]->List.rev_appendaccup|t::p',t'::q'->letc=compare_mon(sndt)(sndt')inifc>0thenplusPp'q(t::accu)elseifc<0thenplusPpq'(t'::accu)elseletc=P.plusP(fstt)(fstt')inifP.equalccoef0thenplusPp'q'accuelseplusPp'q'((c,(sndt))::accu)inplusPpq[](* multiplication by (a,monomial) *)letmult_t_polamp=letmap(b,m')=(P.multPab,mult_monmm')inCList.mapmappletcoef_of_intx=P.of_num(Q.of_intx)(* variable i *)letgendi=letm=var_mondiin[((coef_of_int1),m)]letoppPp=letrecoppPp=matchpwith[]->[]|(b,m')::p->((P.oppPb),m')::(oppPp)inoppPp(* multiplication by a coefficient *)letemultPap=letrecemultPp=matchpwith[]->[]|(b,m')::p->((P.multPab),m')::(emultPp)inemultPpletmultPpq=letrecauxpaccu=matchpwith[]->accu|(a,m)::p'->auxp'(plusP(mult_t_polamq)accu)inauxp[]letpuisPpn=matchpwith[]->[]|_->ifn=0thenletd=nvar(snd(List.hdp))in[coef1,const_mond]elseletrecpuisPpn=ifn=1thenpelseletq=puisPp(n/2)inletq=multPqqinifnmod2=0thenqelsemultPpqinpuisPpn(***********************************************************************
Division of polynomials
*)typetable={hmon:(mon,poly)Hashtbl.toption;(* coefficients of polynomials when written with initial polynomials *)coefpoldep:((int*int),poly)Hashtbl.t;mutablenallpol:int;mutableallpol:polynomarray;(* list of initial polynomials *)}letpgcdposab=P.pgcdPabletpolynom0={pol=[];num=0}letppolp=p.polletlmp=snd(List.hd(ppolp))letnew_allpoltablep=table.nallpol<-table.nallpol+1;iftable.nallpol>=Array.lengthtable.allpolthentable.allpol<-Array.appendtable.allpol(Array.maketable.nallpolpolynom0);letp={pol=p;num=table.nallpol}intable.allpol.(table.nallpol)<-p;p(* returns a polynomial of l whose head monomial divides m, else [] *)letrecselectdivml=matchlwith[]->polynom0|q::r->letm'=snd(List.hd(ppolq))inmatch(div_mon_testmm')withtrue->q|false->selectdivmrletdiv_polpqabm=plusP(emultPap)(mult_t_polbmq)letfind_hmontablem=matchtable.hmonwith|None->raiseNot_found|Somehmon->Hashtbl.findhmonmletadd_hmontablemq=matchtable.hmonwith|None->()|Somehmon->Hashtbl.addhmonmqletselectdivtableml=tryfind_hmontablemwithNot_found->letq=selectdivmlinletq=ppolqinmatchqwith|[]->q|_::_->let()=add_hmontablemqinqletdiv_coefab=P.divPab(* remainder r of the division of p by polynomials of l, returns (c,r) where c is the coefficient for pseudo-division : c p = sum_i q_i p_i + r *)letreduce2tablepl=letl=ifnouveaux_pol_en_tetethenList.revlelselinletrecreducep=matchpwith[]->(coef1,[])|t::p'->let(a,m)=tinletq=selectdivtablemlinmatchqwith[]->ifreduire_les_queuesthenlet(c,r)=(reducep')in(c,((P.multPac,m)::r))else(coef1,p)|(b,m')::q'->letc=(pgcdposab)inleta'=(div_coefbc)inletb'=(P.oppP(div_coefac))inlet(e,r)=reduce(div_polp'q'a'b'(div_monmm'))in(P.multPa'e,r)inlet(c,r)=reducepin(c,r)(* coef of q in p = sum_i c_i*q_i *)letcoefpoldep_findtablepq=try(Hashtbl.findtable.coefpoldep(p.num,q.num))withNot_found->[]letcoefpoldep_settablepqc=Hashtbl.addtable.coefpoldep(p.num,q.num)c(* keeps trace in coefpoldep
divides without pseudodivisions *)letreduce2_tracetablepllcp=letlp=linletl=ifnouveaux_pol_en_tetethenList.revlelselin(* rend (lq,r), ou r = p + sum(lq) *)letrecreducep=matchpwith[]->([],[])|t::p'->let(a,m)=tinletq=selectdivtablemlinmatchqwith[]->ifreduire_les_queuesthenlet(lq,r)=(reducep')in(lq,((a,m)::r))else([],p)|(b,m')::q'->letb'=(P.oppP(div_coefab))inletm''=div_monmm'inletp1=plusPp'(mult_t_polb'm''q')inlet(lq,r)=reducep1in((b',m'',q)::lq,r)inlet(lq,r)=reducepin(List.map2(func0q->letc=List.fold_left(funx(a,m,s)->ifequals(ppolq)thenplusPx(mult_t_polam(polconst(nvarm)(coef_of_int1)))elsex)c0lqinc)lcplp,r)(***********************************************************************
Completion
*)letspol0psqs=letp=ppolpsinletq=ppolqsinletm=snd(List.hdp)inletm'=snd(List.hdq)inleta=fst(List.hdp)inletb=fst(List.hdq)inletp'=List.tlpinletq'=List.tlqinletc=(pgcdposab)inletm''=(ppcm_monmm')inletm1=div_monm''minletm2=div_monm''m'inletfspp'q'=plusP(mult_t_pol(div_coefbc)m1p')(mult_t_pol(P.oppP(div_coefac))m2q')inletsp=fspp'q'inletp0=fsp(polconst(nvarm)(coef_of_int1))[]inletq0=fsp[](polconst(nvarm)(coef_of_int1))in(sp,p0,q0)letetrangerspp'=letm=snd(List.hdp)inletm'=snd(List.hdp')inletd=nvarminletres=reftrueinleti=ref1inwhile(!res)&&(!i<=d)dores:=((Monomial.reprm).(!i)=0)||((Monomial.reprm').(!i)=0);i:=!i+1;done;!resletaddSxl=l@[x](* oblige de mettre en queue sinon le certificat deconne *)(***********************************************************************
critical pairs/s-polynomials
*)moduleCPair=structtypet=(int*int)*Monomial.tletcompare((i1,j1),m1)((i2,j2),m2)=compare_monm2m1endmoduleHeap:sigtypeelt=(int*int)*Monomial.ttypetvallength:t->intvalempty:tvaladd:elt->t->tvalpop:t->(elt*t)optionend=structincludeHeap.Functional(CPair)letlengthh=fold(fun_accu->accu+1)h0letpoph=trySome(maximumh,removeh)withHeap.EmptyHeap->Noneendletordij=ifi<jthen(i,j)else(j,i)letcpairpqaccu=ifetrangers(ppolp)(ppolq)thenaccuelseHeap.add(ordp.numq.num,ppcm_mon(lmp)(lmq))acculetcpairs1plqaccu=List.fold_left(funrq->cpairpqr)acculqletreccpairslaccu=matchlwith|[]|[_]->accu|p::l->cpairsl(cpairs1placcu)letcritere3table((i,j),m)lplcp=List.exists(funh->h.num<>i&&h.num<>j&&(div_mon_testm(lmh))&&(h.num<j||not(m=ppcm_mon(lm(table.allpol.(i)))(lmh)))&&(h.num<i||not(m=ppcm_mon(lm(table.allpol.(j)))(lmh))))lpletinfobuchpq=(info(fun()->Printf.sprintf"[%i,%i]"(List.lengthp)(Heap.lengthq)))(* in lp new polynomials are at the end *)typecertificate={coef:coef;power:int;gb_comb:polylistlist;last_comb:polylist}typecurrent_problem={cur_poly:poly;cur_coef:coef;}exceptionNotInIdealUpdateofcurrent_problemlettest_dans_idealcur_pbtablemetadataplplen0=(* Invariant: [lp] is [List.tl (Array.to_list table.allpol)] *)let(c,r)=reduce2tablecur_pb.cur_polylpininfo(fun()->"remainder: "^(stringPcutmetadatar));letcur_pb={cur_coef=P.multPcur_pb.cur_coefc;cur_poly=r;}inmatchrwith|[]->sinfo"polynomial reduced to 0";letlcp=List.map(funq->[])lpinletc=cur_pb.cur_coefinlet(lcq,r)=reduce2_tracetable(emultPcp)lplcpinsinfo"r ok";info(fun()->"r: "^(stringPmetadatar));info(fun()->letfoldrescqq=plusPres(multPcq(ppolq))inletres=List.fold_left2fold(emultPcp)lcqlpin"verif sum: "^(stringPmetadatares));info(fun()->"coefficient: "^(stringPmetadata(polconst1c)));letcoefficient_multiplicateur=cinletliste_des_coefficients_intermediaires=letrecauxacculp=matchlpwith|[]->accu|p::lp->letelt=List.map(funq->coefpoldep_findtablepq)lpinaux(elt::accu)lpinletlci=aux[](List.revlp)inCList.skipnlen0lciinletliste_des_coefficients=List.rev_map(funcq->emultP(coef_of_int(-1))cq)lcqin{coef=coefficient_multiplicateur;power=1;gb_comb=liste_des_coefficients_intermediaires;last_comb=liste_des_coefficients}|_->raise(NotInIdealUpdatecur_pb)letdeg_homp=matchpwith|[]->-1|(a,m)::_->Monomial.degmletpbuchftablemetadatacur_pbhomogeneous(lp,lpc)p=(* Invariant: [lp] is [List.tl (Array.to_list table.allpol)] *)sinfo"computation of the Groebner basis";let()=matchtable.hmonwith|None->()|Somehmon->Hashtbl.clearhmoninletlen0=List.lengthlpinletrecpbuchfcur_pb(lp,lpc)=infobuchlplpc;matchHeap.poplpcwith|None->test_dans_idealcur_pbtablemetadataplplen0|Some(((i,j),m),lpc2)->ifcritere3table((i,j),m)lplpc2then(sinfo"c";pbuchfcur_pb(lp,lpc2))elselet(a0,p0,q0)=spol0table.allpol.(i)table.allpol.(j)inifhomogeneous&&a0<>[]&°_homa0>deg_homcur_pb.cur_polythen(sinfo"h";pbuchfcur_pb(lp,lpc2))else(* let sa = a.sugar in*)matchreduce2tablea0lpwith_,[]->sinfo"0";pbuchfcur_pb(lp,lpc2)|ca,_::_->(* info "pair reduced\n";*)letmapq=letr=ifq.num==ithenp0elseifq.num==jthenq0else[]inemultPcarinletlcp=List.mapmaplpinlet(lca,a0)=reduce2_tracetable(emultPcaa0)lplcpin(* info "paire re-reduced";*)leta=new_allpoltablea0inList.iter2(funcq->coefpoldep_settableaqc)lcalp;leta0=aininfo(fun()->"new polynomial: "^(stringPcutmetadata(ppola0)));letnlp=addSa0lpintrytest_dans_idealcur_pbtablemetadatapnlplen0withNotInIdealUpdatecur_pb->letnewlpc=cpairs1a0lplpc2inpbuchfcur_pb(nlp,newlpc)inpbuchfcur_pb(lp,lpc)letis_homogeneousp=matchpwith|[]->true|(a,m)::p1->letd=degminList.for_all(fun(b,m')->degm'=d)p1(* returns
c
lp = [pn;...;p1]
p
lci = [[a(n+1,n);...;a(n+1,1)];
[a(n+2,n+1);...;a(n+2,1)];
...
[a(n+m,n+m-1);...;a(n+m,1)]]
lc = [qn+m; ... q1]
such that
c*p = sum qi*pi
where pn+k = a(n+k,n+k-1)*pn+k-1 + ... + a(n+k,1)* p1
*)letin_idealmetadatadlpp=lettable={hmon=None;coefpoldep=Hashtbl.create51;nallpol=0;allpol=Array.make1000polynom0;}inlethomogeneous=List.for_allis_homogeneous(p::lp)inifhomogeneousthensinfo"homogeneous polynomials";info(fun()->"p: "^(stringPcutmetadatap));info(fun()->"lp:\n"^(List.fold_left(funrp->r^(stringPcutmetadatap)^"\n")""lp));letlp=List.map(func->new_allpoltablec)lpinList.iter(funp->coefpoldep_settablepp(polconstd(coef_of_int1)))lp;letcur_pb={cur_poly=p;cur_coef=coef1;}inletcert=trypbuchftablemetadatacur_pbhomogeneous(lp,Heap.empty)pwithNotInIdealUpdatecur_pb->trypbuchftablemetadatacur_pbhomogeneous(lp,cpairslpHeap.empty)pwithNotInIdealUpdate_->raiseNotInIdealinsinfo"computed";certend