123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329(************************************************************************)(* * 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) *)(************************************************************************)(* *)(* Micromega: A reflexive tactic using the Positivstellensatz *)(* *)(* Frédéric Besson (Irisa/Inria) 2006-20018 *)(* *)(************************************************************************)openNumCompatopenQ.NotationsopenMutilsmoduleMc=Micromegaletmax_nb_cstr=refmax_inttypevar=intletdebug=falselet(<+>)=(+/)let(<*>)=(*/)moduleMonomial:sigtypetvalconst:tvalis_const:t->boolvalvar:var->tvalis_var:t->boolvalget_var:t->varoptionvalprod:t->t->tvalfactor:t->var->toptionvalcompare:t->t->intvalpp:out_channel->t->unitvalfold:(var->int->'a->'a)->t->'a->'avalsqrt:t->toptionvalvariables:t->ISet.tvaldegree:t->intvalsubset:t->t->boolvaloutput:out_channel->t->unitend=structtypet=intarray(* Compact representation [| d; e₀; v₀; ...; eₙ; vₙ |] where
d = Σi v_i is the multi-degree
e_i gives the variable number as a diff, i.e. the variable at position i
is Σi e_i, and e_i ≠ 0 for all i > 0
v_i is the degree of e_i, must be ≠ 0
*)letconst=[|0|]letsubsetm1m2=m1.(0)<=m2.(0)&&letlen1=Array.lengthm1inletlen2=Array.lengthm2inletget_varmcv=v+m.(c),m.(c+1)inletrecxsubsetcur1v1e1cur2v2e2=matchInt.comparev1v2with|0->e1<=e2&&(ifcur1+2=len1thentrueelseifcur2+2=len2thenfalseelselet(v1,e1)=get_varm1(cur1+2)v1inlet(v2,e2)=get_varm2(cur2+2)v2inxsubset(cur1+2)v1e1(cur2+2)v2e2)|-1->false|_->ifcur2+2=len2thenfalseelselet(v2,e2)=get_varm2(cur2+2)v2inxsubsetcur1v1e1(cur2+2)v2e2iniflen1<=1thentrueelseiflen2<=1thenfalseelsexsubset1m1.(1)m1.(2)1m2.(1)m2.(2)letis_const(m:t)=matchmwith[|_|]->true|_->falseletvarx=[|1;x;1|]letis_var(m:t)=Int.equalm.(0)1letget_var(m:t)=matchmwith|[|1;x;_|]->Somex|_->Noneletprod(m1:t)(m2:t)=letlen1=Array.lengthm1inletlen2=Array.lengthm2in(* Compute the number of variables in the monomial *)letrecnvarsaccucur1cur2i1i2=ifInt.equali1len1&&Int.equali2len2thenaccuelseifInt.equali1len1thenaccu+(len2-i2)elseifInt.equali2len2thenaccu+(len1-i1)elseletncur1=cur1+m1.(i1)inletncur2=cur2+m2.(i2)inifncur1<ncur2thennvars(accu+2)ncur1cur2(i1+2)i2elseifncur1>ncur2thennvars(accu+2)cur1ncur2i1(i2+2)elsenvars(accu+2)ncur1ncur2(i1+2)(i2+2)inletn=nvars10011inletm=Array.maken0inlet()=m.(0)<-m1.(0)+m2.(0)in(* Set the variable exponents *)letrecsetcurcur1cur2ii1i2=ifInt.equali1len1&&Int.equali2len2then()elseifInt.equali1len1thenletncur2=cur2+m2.(i2)inlet()=m.(i)<-ncur2-curinlet()=m.(i+1)<-m2.(i2+1)insetncur2cur1ncur2(i+2)i1(i2+2)elseifInt.equali2len2thenletncur1=cur1+m1.(i1)inlet()=m.(i)<-ncur1-curinlet()=m.(i+1)<-m1.(i1+1)insetncur1ncur1cur2(i+2)(i1+2)i2elseletncur1=cur1+m1.(i1)inletncur2=cur2+m2.(i2)inifncur1<ncur2thenlet()=m.(i)<-ncur1-curinlet()=m.(i+1)<-m1.(i1+1)insetncur1ncur1cur2(i+2)(i1+2)i2elseifncur1>ncur2thenlet()=m.(i)<-ncur2-curinlet()=m.(i+1)<-m2.(i2+1)insetncur2cur1ncur2(i+2)i1(i2+2)elselet()=m.(i)<-ncur1-curinlet()=m.(i+1)<-m1.(i1+1)+m2.(i2+1)insetncur1ncur1ncur2(i+2)(i1+2)(i2+2)inlet()=set000111inm(* [factor m x] returns [None] if [x] does not appear in [m], and decreases
its exponent by one otherwise *)letfactor(m:t)(x:var)=letlen=Array.lengthminletrecfactorcuri=ifInt.equalilenthenNoneelseletncur=cur+m.(i)inletk=m.(i+1)inifncur<xthenfactorncur(i+2)elseifx<ncurthenNoneelseifInt.equalk1then(* Need to squeeze out the binding for x *)letans=Array.make(len-2)0inlet()=ans.(0)<-m.(0)-1inlet()=Array.blitm1ans1(i-1)inlet()=Array.blitm(i+2)ansi(len-i-2)in(* Correct the diff *)let()=ifnot(Int.equallen(i+2))thenans.(i)<-ans.(i)+m.(i)inSomeanselseletans=Array.copyminlet()=ans.(0)<-ans.(0)-1inlet()=ans.(i+1)<-ans.(i+1)-1inSomeansinfactor01letcompare(m1:t)(m2:t)=CArray.compareInt.comparem1m2letsqrt(m:t)=matchmwith|[|_|]->Someconst|_->letm=Array.copyminletlen=Array.lengthminlet()=m.(0)<-m.(0)/2inletrecseti=ifInt.equalilenthen()elseletv=m.(i+1)inlet()=ifvmod2=0thenm.(i+1)<-v/2elseraise_notraceExitinset(i+2)intrylet()=set1inSomemwithExit->Noneletdegree(m:t)=m.(0)letfoldf(m:t)accu=letlen=Array.lengthminletrecfoldaccucuri=ifInt.equalilenthenaccuelseletcur=cur+m.(i)inletaccu=fcurm.(i+1)accuinfoldaccucur(i+2)infoldaccu01letoutputom=fold(funvi()->Printf.fprintfo"x%i^%i"vi)m()letvariables(m:t)=fold(funx_accu->ISet.addxaccu)mISet.emptyletppom=letpp_elto(k,v)=ifv=1thenPrintf.fprintfo"x%i"kelsePrintf.fprintfo"x%i^%i"kvinletrecpp_listol=matchlwith|[]->()|[e]->pp_eltoe|e::l->Printf.fprintfo"%a*%a"pp_eltepp_listlinpp_listo(List.rev@@fold(funxvaccu->(x,v)::accu)m[])endmoduleMonMap=structincludeMap.Make(Monomial)letunionf=merge(funxv1v2->match(v1,v2)with|None,None->None|Somev,None|None,Somev->Somev|Somev1,Somev2->fxv1v2)endletpp_mono(m,i)=ifMonomial.is_constmthenifQ.zero=/ithen()elsePrintf.fprintfo"%s"(Q.to_stringi)elseifQ.one=/ithenMonomial.ppomelseifQ.minus_one=/ithenPrintf.fprintfo"-%a"Monomial.ppmelseifQ.zero=/ithen()elsePrintf.fprintfo"%s*%a"(Q.to_stringi)Monomial.ppmmodulePoly:(* A polynomial is a map of monomials *)(*
This is probably a naive implementation
(expected to be fast enough - Coq is probably the bottleneck)
*The new ring contribution is using a sparse Horner representation.
*)sigtypetvalpp:out_channel->t->unitvalget:Monomial.t->t->Q.tvalvariable:var->tvaladd:Monomial.t->Q.t->t->tvalconstant:Q.t->tvalproduct:t->t->tvaladdition:t->t->tvaluminus:t->tvalfold:(Monomial.t->Q.t->'a->'a)->t->'a->'avalfactorise:var->t->t*tend=struct(*normalisation bug : 0*x ... *)moduleP=Map.Make(Monomial)openPtypet=Q.tP.tletppop=P.iter(funmni->Printf.fprintfo"%a + "pp_mon(mn,i))p(* Get the coefficient of monomial mn *)letget:Monomial.t->t->Q.t=funmnp->tryfindmnpwithNot_found->Q.zero(* The polynomial 1.x *)letvariable:var->t=funx->add(Monomial.varx)Q.oneempty(*The constant polynomial *)letconstant:Q.t->t=func->addMonomial.constcempty(* The addition of a monomial *)letadd:Monomial.t->Q.t->t->t=funmnvp->ifQ.signv=0thenpelseletvl=getmnp<+>vinifQ.signvl=0thenremovemnpelseaddmnvlp(** Design choice: empty is not a polynomial
I do not remember why ....
**)(* The product by a monomial *)letmult:Monomial.t->Q.t->t->t=funmnvp->ifQ.signv=0thenconstantQ.zeroelsefold(funmn'v'res->P.add(Monomial.prodmnmn')(v<*>v')res)pemptyletaddition:t->t->t=funp1p2->fold(funmnvp->addmnvp)p1p2letproduct:t->t->t=funp1p2->fold(funmnvres->addition(multmnvp2)res)p1emptyletuminus:t->t=funp->map(funv->Q.negv)pletfold=P.foldletfactorisexp=P.fold(funmv(px,cx)->matchMonomial.factormxwith|None->(px,addmvcx)|Somemx->(addmxvpx,cx))p(constantQ.zero,constantQ.zero)endtypevector=Vect.ttypecstr={coeffs:vector;op:op;cst:Q.t}andop=Eq|Ge|GtexceptionStrictletis_strictc=c.op=Gtleteval_op=functionEq->(=/)|Ge->(>=/)|Gt->(>/)letstring_of_op=functionEq->"="|Ge->">="|Gt->">"letcompare_opo1o2=match(o1,o2)with|Eq,Eq->0|Eq,_->-1|_,Eq->1|Ge,Ge->0|Ge,_->-1|_,Ge->1|Gt,Gt->0letoutput_cstro{coeffs;op;cst}=Printf.fprintfo"%a %s %s"Vect.ppcoeffs(string_of_opop)(Q.to_stringcst)letopMulto1o2=match(o1,o2)withEq,_|_,Eq->Eq|Ge,_|_,Ge->Ge|Gt,Gt->GtletopAddo1o2=match(o1,o2)withEq,x|x,Eq->x|Gt,x|x,Gt->Gt|Ge,Ge->GemoduleLinPoly=struct(** A linear polynomial a0 + a1.x1 + ... + an.xn
By convention, the constant a0 is the coefficient of the variable 0.
*)typet=Vect.tmoduleMonT=structmoduleMonoMap=Map.Make(Monomial)moduleIntMap=Map.Make(Int)(** A hash table might be preferable but requires a hash function. *)let(index_of_monomial:intMonoMap.tref)=refMonoMap.emptylet(monomial_of_index:Monomial.tIntMap.tref)=refIntMap.emptyletfresh=ref0letreservevr=if!fresh>vrthenfailwith(Printf.sprintf"Cannot reserve %i"vr)elsefresh:=vr+1letsafe_reservevr=if!fresh>vrthen()elsefresh:=vr+1letget_fresh()=letvr=!freshinincrfresh;vrletregisterm=tryMonoMap.findm!index_of_monomialwithNot_found->letres=!freshinindex_of_monomial:=MonoMap.addmres!index_of_monomial;monomial_of_index:=IntMap.addresm!monomial_of_index;incrfresh;resletretrievei=IntMap.findi!monomial_of_indexletclear()=index_of_monomial:=MonoMap.empty;monomial_of_index:=IntMap.empty;fresh:=0;ignore(registerMonomial.const)let_=registerMonomial.constendletvarv=Vect.set(MonT.register(Monomial.varv))Q.oneVect.nullletof_monomialm=letv=MonT.registerminVect.setvQ.oneVect.nullletlinpol_of_polp=Poly.fold(funmonnumvct->letvr=MonT.registermoninVect.setvrnumvct)pVect.nullletpol_of_linpolv=Vect.fold(funpvrn->Poly.add(MonT.retrievevr)np)(Poly.constantQ.zero)vletcoq_poly_of_linpolcstp=letpol_of_monm=Monomial.fold(funxvp->Mc.PEmul(Mc.PEpow(Mc.PEX(CamlToCoq.positivex),CamlToCoq.nv),p))m(Mc.PEc(cstQ.one))inVect.fold(funaccxv->letmn=MonT.retrievexinMc.PEadd(Mc.PEmul(Mc.PEc(cstv),pol_of_monmn),acc))(Mc.PEc(cstQ.zero))pletpp_varovr=tryMonomial.ppo(MonT.retrievevr)(* this is a non-linear variable *)withNot_found->Printf.fprintfo"v%i"vrletppop=Vect.pp_genpp_varopletconstantc=ifQ.signc=0thenVect.nullelseVect.set0cVect.nullletis_linearp=Vect.for_all(funv_->letmn=MonT.retrievevinMonomial.is_varmn||Monomial.is_constmn)pletis_variablep=let(x,v),r=Vect.decomp_fstpinifVect.is_nullr&&v>/Q.zerothenMonomial.get_var(MonT.retrievex)elseNoneletfactorisexp=letpx,cx=Poly.factorisex(pol_of_linpolp)in(linpol_of_polpx,linpol_of_polcx)letis_linear_forxp=leta,b=factorisexpinVect.is_constantaletsearch_all_linearpl=Vect.fold(funaccxv->ifpvthenletx'=MonT.retrievexinmatchMonomial.get_varx'with|None->acc|Somex->ifis_linear_forxlthenx::accelseaccelseacc)[]lletmin_list(l:intlist)=matchlwith[]->None|e::l->Some(List.fold_leftminel)letsearch_linearpl=min_list(search_all_linearpl)letmul_cstcp=Vect.mulcpletproductp1p2=linpol_of_pol(Poly.product(pol_of_linpolp1)(pol_of_linpolp2))letadditionp1p2=Vect.addp1p2letof_vectv=Vect.fold(funaccvvl->addition(product(varv)(constantvl))acc)Vect.nullvletvariablesp=Vect.fold(funaccv_->ISet.union(Monomial.variables(MonT.retrievev))acc)ISet.emptypletmonomialsp=Vect.fold(funaccv_->ISet.addvacc)ISet.emptypletpp_goaltypol=letvars=List.fold_left(funaccp->ISet.unionacc(variables(fstp)))ISet.emptylinletpp_varsoi=ISet.iter(funv->Printf.fprintfo"(x%i : %s) "vtyp)varsinPrintf.fprintfo"forall %a\n"pp_varsvars;List.iteri(funi(p,op)->Printf.fprintfo"(H%i : %a %s 0)\n"ippp(string_of_opop))l;Printf.fprintfo", False\n"letcollect_squarep=Vect.fold(funaccv_->letm=MonT.retrievevinmatchMonomial.sqrtmwithNone->acc|Somes->MonMap.addsmacc)MonMap.emptypendmoduleProofFormat=structtypeprf_rule=|Annotofstring*prf_rule|Hypofint|Defofint|Refofint|CstofQ.t|Zero|SquareofVect.t|MulCofVect.t*prf_rule|GcdofZ.t*prf_rule|MulPrfofprf_rule*prf_rule|AddPrfofprf_rule*prf_rule|CutPrfofprf_rule|LetPrfofprf_rule*prf_ruletypeproof=|Done|Stepofint*prf_rule*proof|Splitofint*Vect.t*proof*proof|Enumofint*prf_rule*Vect.t*prf_rule*prooflist|ExProofofint*int*int*var*var*var*proof(* x = z - t, z >= 0, t >= 0 *)letrecoutput_prf_ruleo=function|Annot(s,p)->Printf.fprintfo"(%a)@%s"output_prf_ruleps|Hypi->Printf.fprintfo"Hyp %i"i|Defi->Printf.fprintfo"Def %i"i|Refi->Printf.fprintfo"Ref %i"i|LetPrf(p1,p2)->Printf.fprintfo"Let (%a) in %a"output_prf_rulep1output_prf_rulep2|Cstc->Printf.fprintfo"Cst %s"(Q.to_stringc)|Zero->Printf.fprintfo"Zero"|Squares->Printf.fprintfo"(%a)^2"Poly.pp(LinPoly.pol_of_linpols)|MulC(p,pr)->Printf.fprintfo"(%a) * (%a)"Poly.pp(LinPoly.pol_of_linpolp)output_prf_rulepr|MulPrf(p1,p2)->Printf.fprintfo"(%a) * (%a)"output_prf_rulep1output_prf_rulep2|AddPrf(p1,p2)->Printf.fprintfo"%a + %a"output_prf_rulep1output_prf_rulep2|CutPrfp->Printf.fprintfo"[%a]"output_prf_rulep|Gcd(c,p)->Printf.fprintfo"(%a)/%s"output_prf_rulep(Z.to_stringc)letrecoutput_proofo=function|Done->Printf.fprintfo"."|Step(i,p,pf)->Printf.fprintfo"%i:= %a\n ; %a"ioutput_prf_rulepoutput_proofpf|Split(i,v,p1,p2)->Printf.fprintfo"%i:=%a ; { %a } { %a }"iVect.ppvoutput_proofp1output_proofp2|Enum(i,p1,v,p2,pl)->Printf.fprintfo"%i{%a<=%a<=%a}%a"ioutput_prf_rulep1Vect.ppvoutput_prf_rulep2(pp_list";"output_proof)pl|ExProof(i,j,k,x,z,t,pr)->Printf.fprintfo"%i := %i = %i - %i ; %i := %i >= 0 ; %i := %i >= 0 ; %a"ixztjzktoutput_proofprmoduleOrdPrfRule=structtypet=prf_ruleletid_of_constr=function|Annot_->0|Hyp_->1|Def_->2|Ref_->3|Cst_->4|Zero->5|Square_->6|MulC_->7|Gcd_->8|MulPrf_->9|AddPrf_->10|CutPrf_->11|LetPrf_->12letcmp_pairc1c2(x1,x2)(y1,y2)=matchc1x1y1with0->c2x2y2|i->iletreccomparep1p2=match(p1,p2)with|Annot(s1,p1),Annot(s2,p2)->ifs1=s2thencomparep1p2elseString.compares1s2|Hypi,Hypj->Int.compareij|Defi,Defj->Int.compareij|Refi,Refj->Int.compareij|Cstn,Cstm->Q.comparenm|Zero,Zero->0|Squarev1,Squarev2->Vect.comparev1v2|MulC(v1,p1),MulC(v2,p2)->cmp_pairVect.comparecompare(v1,p1)(v2,p2)|Gcd(b1,p1),Gcd(b2,p2)->cmp_pairZ.comparecompare(b1,p1)(b2,p2)|MulPrf(p1,q1),MulPrf(p2,q2)->cmp_paircomparecompare(p1,q1)(p2,q2)|AddPrf(p1,q1),AddPrf(p2,q2)->cmp_paircomparecompare(p1,q1)(p2,q2)|CutPrfp,CutPrfp'->comparepp'|LetPrf(p1,q1),LetPrf(p2,q2)->cmp_paircomparecompare(p1,q1)(p2,q2)|_,_->Int.compare(id_of_constrp1)(id_of_constrp2)endmodulePrfRuleMap=Map.Make(OrdPrfRule)letrecpr_size=function|Annot(_,p)->pr_sizep|Zero|Square_->Q.zero|Hyp_->Q.one|Def_->Q.one|Ref_->Q.one|Cstn->n|Gcd(i,p)->pr_sizep//Q.of_biginti|MulPrf(p1,p2)|AddPrf(p1,p2)|LetPrf(p1,p2)->pr_sizep1+/pr_sizep2|CutPrfp->pr_sizep|MulC(v,p)->pr_sizepletrecpr_unit=function|Annot(_,p)->pr_unitp|Zero|Square_->true|Hyp_->true|Def_->true|Cstn->true|_->falseletrecpr_rule_max_hyp=function|Annot(_,p)->pr_rule_max_hypp|Hypi->i|Defi->-1|Refi->-1|Cst_|Zero|Square_->-1|MulC(_,p)|CutPrfp|Gcd(_,p)->pr_rule_max_hypp|MulPrf(p1,p2)|AddPrf(p1,p2)|LetPrf(p1,p2)->max(pr_rule_max_hypp1)(pr_rule_max_hypp2)letrecpr_rule_max_def=function|Annot(_,p)->pr_rule_max_hypp|Hypi->-1|Defi->i|Ref_->-1|Cst_|Zero|Square_->-1|MulC(_,p)|CutPrfp|Gcd(_,p)->pr_rule_max_defp|MulPrf(p1,p2)|AddPrf(p1,p2)|LetPrf(p1,p2)->max(pr_rule_max_defp1)(pr_rule_max_defp2)letrecproof_max_def=function|Done->-1|Step(i,pr,prf)->maxi(max(pr_rule_max_defpr)(proof_max_defprf))|Split(i,_,p1,p2)->maxi(max(proof_max_defp1)(proof_max_defp2))|Enum(i,p1,_,p2,l)->letm=max(pr_rule_max_defp1)(pr_rule_max_defp2)inList.fold_left(funiprf->maxi(proof_max_defprf))(maxim)l|ExProof(i,j,k,_,_,_,prf)->max(max(maxij)k)(proof_max_defprf)(** [pr_rule_def_cut id pr] gives an explicit [id] to cut rules.
This is because the Coq proof format only accept they as a proof-step *)letpr_rule_def_cutmidp=letrecpr_rule_def_cutmid=function|Annot(_,p)->pr_rule_def_cutmidp|MulC(p,prf)->letbds,m,id',prf'=pr_rule_def_cutmidprfin(bds,m,id',MulC(p,prf'))|MulPrf(p1,p2)->letbds1,m,id,p1=pr_rule_def_cutmidp1inletbds2,m,id,p2=pr_rule_def_cutmidp2in(bds2@bds1,m,id,MulPrf(p1,p2))|AddPrf(p1,p2)->letbds1,m,id,p1=pr_rule_def_cutmidp1inletbds2,m,id,p2=pr_rule_def_cutmidp2in(bds2@bds1,m,id,AddPrf(p1,p2))|LetPrf(p1,p2)->letbds1,m,id,p1=pr_rule_def_cutmidp1inletbds2,m,id,p2=pr_rule_def_cutmidp2in(bds2@bds1,m,id,LetPrf(p1,p2))|CutPrfp|Gcd(_,p)->(letbds,m,id,p=pr_rule_def_cutmidpintryletid'=PrfRuleMap.findpmin(bds,m,id,Defid')withNot_found->letm=PrfRuleMap.addpidmin((id,p)::bds,m,id+1,Defid))|(Square_|Cst_|Def_|Hyp_|Ref_|Zero)asx->([],m,id,x)inpr_rule_def_cutmidp(* Do not define top-level cuts *)letpr_rule_def_cutmid=function|CutPrfp->letbds,m,ids,p'=pr_rule_def_cutmidpin(bds,m,ids,CutPrfp')|p->pr_rule_def_cutmidpletrecimplicit_cutp=matchpwithCutPrfp->implicit_cutp|_->pletrecpr_rule_collect_defspr=matchprwith|Annot(_,pr)->pr_rule_collect_defspr|Defi->ISet.addiISet.empty|Hypi->ISet.empty|Refi->ISet.empty|Cst_|Zero|Square_->ISet.empty|MulC(_,pr)|Gcd(_,pr)|CutPrfpr->pr_rule_collect_defspr|MulPrf(p1,p2)|AddPrf(p1,p2)|LetPrf(p1,p2)->ISet.union(pr_rule_collect_defsp1)(pr_rule_collect_defsp2)letadd_proofxy=match(x,y)withZero,p|p,Zero->p|_->AddPrf(x,y)letrecmul_cst_proofcp=matchpwith|Annot(s,p)->Annot(s,mul_cst_proofcp)|MulC(v,p')->MulC(Vect.mulcv,p')|_->(matchQ.signcwith|0->Zero(* This is likely to be a bug *)|-1->MulC(LinPoly.constantc,p)(* [p] should represent an equality *)|1->ifQ.one=/cthenpelseMulPrf(Cstc,p)|_->assertfalse)letsMulCvp=letc,v'=Vect.decomp_cstvinifVect.is_nullv'thenmul_cst_proofcpelseMulC(v,p)letmul_proofp1p2=match(p1,p2)with|Zero,_|_,Zero->Zero|Cstc,p|p,Cstc->mul_cst_proofcp|_,_->MulPrf(p1,p2)letprf_rule_of_mapm=PrfRuleMap.fold(funkvacc->add_proof(sMulCvk)acc)mZeroletrecdev_prf_rulep=matchpwith|Annot(s,p)->dev_prf_rulep|Hyp_|Def_|Ref_|Cst_|Zero|Square_->PrfRuleMap.singletonp(LinPoly.constantQ.one)|MulC(v,p)->PrfRuleMap.map(funv1->LinPoly.productvv1)(dev_prf_rulep)|AddPrf(p1,p2)->PrfRuleMap.merge(funko1o2->match(o1,o2)with|None,None->None|None,Somev|Somev,None->Somev|Somev1,Somev2->Some(LinPoly.additionv1v2))(dev_prf_rulep1)(dev_prf_rulep2)|MulPrf(p1,p2)->(letp1'=dev_prf_rulep1inletp2'=dev_prf_rulep2inletp1''=prf_rule_of_mapp1'inletp2''=prf_rule_of_mapp2'inmatchp1''with|Cstc->PrfRuleMap.map(funv1->Vect.mulcv1)p2'|_->PrfRuleMap.singleton(MulPrf(p1'',p2''))(LinPoly.constantQ.one))|Gcd(c,p)->PrfRuleMap.singleton(Gcd(c,prf_rule_of_map(dev_prf_rulep)))(LinPoly.constantQ.one)|CutPrfp->PrfRuleMap.singleton(CutPrf(prf_rule_of_map(dev_prf_rulep)))(LinPoly.constantQ.one)|LetPrf(p1,p2)->letp1'=dev_prf_rulep1inletp2'=dev_prf_rulep2inletp1''=prf_rule_of_mapp1'inletp2''=prf_rule_of_mapp2'inPrfRuleMap.singleton(LetPrf(p1'',p2''))(LinPoly.constantQ.one)letsimplify_prf_rulep=prf_rule_of_map(dev_prf_rulep)(** [simplify_proof p] removes proof steps that are never re-used. *)letrecsimplify_proofp=matchpwith|Done->(Done,ISet.empty)|Step(i,pr,Done)->(p,ISet.addi(pr_rule_collect_defspr))|Step(i,pr,prf)->letprf',hyps=simplify_proofprfinifnot(ISet.memihyps)then(prf',hyps)else(Step(i,pr,prf'),ISet.addi(ISet.union(pr_rule_collect_defspr)hyps))|Split(i,v,p1,p2)->letp1,h1=simplify_proofp1inletp2,h2=simplify_proofp2inifnot(ISet.memih1)then(p1,h1)(* Should not have computed p2 *)elseifnot(ISet.memih2)then(p2,h2)else(Split(i,v,p1,p2),ISet.addi(ISet.unionh1h2))|Enum(i,p1,v,p2,pl)->letpl,hl=List.split(List.mapsimplify_proofpl)inlethyps=List.fold_leftISet.unionISet.emptyhlin(Enum(i,p1,v,p2,pl),ISet.addi(ISet.union(ISet.union(pr_rule_collect_defsp1)(pr_rule_collect_defsp2))hyps))|ExProof(i,j,k,x,z,t,prf)->letprf',hyps=simplify_proofprfinif(not(ISet.memihyps))&&(not(ISet.memjhyps))&¬(ISet.memkhyps)then(prf',hyps)else(ExProof(i,j,k,x,z,t,prf'),ISet.addi(ISet.addj(ISet.addkhyps)))letrecnormalise_proofidprf=matchprfwith|Done->(id,Done)|Step(i,Gcd(c,p),Done)->normalise_proofid(Step(i,p,Done))|Step(i,p,prf)->letbds,m,id,p'=pr_rule_def_cutPrfRuleMap.emptyid(simplify_prf_rulep)inletid,prf=normalise_proofidprfinletprf=List.fold_left(funacc(i,p)->Step(i,CutPrfp,acc))(Step(i,p',prf))bdsin(id,prf)|Split(i,v,p1,p2)->letid,p1=normalise_proofidp1inletid,p2=normalise_proofidp2in(id,Split(i,v,p1,p2))|ExProof(i,j,k,x,z,t,prf)->letid,prf=normalise_proofidprfin(id,ExProof(i,j,k,x,z,t,prf))|Enum(i,p1,v,p2,pl)->(* Why do I have top-level cuts ? *)(* let p1 = implicit_cut p1 in
let p2 = implicit_cut p2 in
let (ids,prfs) = List.split (List.map (normalise_proof id) pl) in
(List.fold_left max 0 ids ,
Enum(i,p1,v,p2,prfs))
*)letbds1,m,id,p1'=pr_rule_def_cutPrfRuleMap.emptyid(implicit_cutp1)inletbds2,m,id,p2'=pr_rule_def_cutmid(implicit_cutp2)inletids,prfs=List.split(List.map(normalise_proofid)pl)in(List.fold_leftmax0ids,List.fold_left(funacc(i,p)->Step(i,CutPrfp,acc))(Enum(i,p1',v,p2',prfs))(bds2@bds1))letnormalise_proofidprf=letprf=fst(simplify_proofprf)inletres=normalise_proofidprfinifdebugthenPrintf.printf"normalise_proof %a -> %a"output_proofprfoutput_proof(sndres);res(*
let mul_proof p1 p2 =
let res = mul_proof p1 p2 in
Printf.printf "mul_proof %a %a = %a\n"
output_prf_rule p1 output_prf_rule p2 output_prf_rule res; res
let add_proof p1 p2 =
let res = add_proof p1 p2 in
Printf.printf "add_proof %a %a = %a\n"
output_prf_rule p1 output_prf_rule p2 output_prf_rule res; res
let sMulC v p =
let res = sMulC v p in
Printf.printf "sMulC %a %a = %a\n" Vect.pp v output_prf_rule p output_prf_rule res ;
res
let mul_cst_proof c p =
let res = mul_cst_proof c p in
Printf.printf "mul_cst_proof %s %a = %a\n" (Num.string_of_num c) output_prf_rule p output_prf_rule res ;
res
*)letproof_of_farkasenvvect=Vect.fold(funprfxn->add_proof(mul_cst_proofn(IMap.findxenv))prf)ZerovectmoduleEnv:sigtypetvalmake:int->tvalid_of_def:int->t->intvalid_of_hyp:int->t->intvalpush_ref:t->tvalpush_def:int->t->tend=struct(* Environments are of the form refs @ defs @ hyps *)typet={lref:int;ndefs:int;(* Size of ldefs *)ldefs:intInt.Map.t;nhyps:int;}letpush_ref{nhyps;ndefs;lref;ldefs}={nhyps;ndefs;lref=lref+1;ldefs}letpush_defi{nhyps;ndefs;lref;ldefs}=let()=iflref<>0thenfailwith"Cannot push def"in{nhyps;ndefs=ndefs+1;lref;ldefs=Int.Map.addindefsldefs}letmaken={nhyps=n;ndefs=0;lref=0;ldefs=Int.Map.empty}letid_of_defdef{nhyps;ndefs;lref;ldefs}=tryletpos=Int.Map.finddefldefsinlref+(ndefs-pos-1)withNot_found->failwith"Cannot find def"letid_of_hyph{nhyps;ndefs;lref;ldefs}=if0<=h&&h<nhypsthenlref+ndefs+helsefailwith"Cannot find hyp"endletcmpl_prf_rulenorm(cst:Q.t->'a)envprf=letreccmplenv=function|Annot(s,p)->cmplenvp|Refi->Mc.PsatzIn(CamlToCoq.nati)|Hyph->Mc.PsatzIn(CamlToCoq.nat(Env.id_of_hyphenv))|Defd->Mc.PsatzIn(CamlToCoq.nat(Env.id_of_defdenv))|Csti->Mc.PsatzC(csti)|Zero->Mc.PsatzZ|MulPrf(p1,p2)->Mc.PsatzMulE(cmplenvp1,cmplenvp2)|AddPrf(p1,p2)->Mc.PsatzAdd(cmplenvp1,cmplenvp2)|LetPrf(p1,p2)->Mc.PsatzLet(cmplenvp1,cmpl(Env.push_refenv)p2)|MulC(lp,p)->letlp=norm(LinPoly.coq_poly_of_linpolcstlp)inMc.PsatzMulC(lp,cmplenvp)|Squarelp->Mc.PsatzSquare(norm(LinPoly.coq_poly_of_linpolcstlp))|_->failwith"Cuts should already be compiled"incmplenvprfletcmpl_prf_rule_zenvr=cmpl_prf_ruleMc.normZ(funx->CamlToCoq.bigint(Q.numx))envrletcmpl_pol_zlp=tryletcstx=CamlToCoq.bigint(Q.numx)inMc.normZ(LinPoly.coq_poly_of_linpolcstlp)withx->Printf.printf"cmpl_pol_z %s %a\n"(Printexc.to_stringx)LinPoly.pplp;raisexletreccmpl_proofenvprf=matchprfwith|Done->Mc.DoneProof|Step(i,p,prf)->(matchpwith|CutPrfp'->Mc.CutProof(cmpl_prf_rule_zenvp',cmpl_proof(Env.push_defienv)prf)|_->Mc.RatProof(cmpl_prf_rule_zenvp,cmpl_proof(Env.push_defienv)prf))|Split(i,v,p1,p2)->Mc.SplitProof(cmpl_pol_zv,cmpl_proof(Env.push_defienv)p1,cmpl_proof(Env.push_defienv)p2)|Enum(i,p1,_,p2,l)->Mc.EnumProof(cmpl_prf_rule_zenvp1,cmpl_prf_rule_zenvp2,List.map(cmpl_proof(Env.push_defienv))l)|ExProof(i,j,k,x,_,_,prf)->Mc.ExProof(CamlToCoq.positivex,cmpl_proof(Env.push_defi(Env.push_defj(Env.push_defkenv)))prf)letcompile_proofenvprf=letid=1+proof_max_defprfinlet_,prf=normalise_proofidprfincmpl_proofenvprfendmoduleWithProof=structtypet=(LinPoly.t*op)*ProofFormat.prf_ruleletreprp=pletproofp=sndpletpolynomial((p,_),_)=p(* The comparison ignores proofs on purpose *)letcompare:t->t->int=fun((lp1,o1),_)((lp2,o2),_)->letc=Vect.comparelp1lp2inifc=0thencompare_opo1o2elsecletannots(p,prf)=(p,ProofFormat.Annot(s,prf))letoutputo((lp,op),prf)=Printf.fprintfo"%a %s 0 by %a\n"LinPoly.pplp(string_of_opop)ProofFormat.output_prf_ruleprfletoutput_sysol=List.iter(Printf.fprintfo"%a\n"output)lexceptionInvalidProofletzero=((Vect.null,Eq),ProofFormat.Zero)letconstn=((LinPoly.constantn,Ge),ProofFormat.Cstn)letof_cstr(c,prf)=((Vect.set0(Q.negc.cst)c.coeffs,c.op),prf)letproduct:t->t->t=fun((p1,o1),prf1)((p2,o2),prf2)->((LinPoly.productp1p2,opMulto1o2),ProofFormat.mul_proofprf1prf2)letaddition:t->t->t=fun((p1,o1),prf1)((p2,o2),prf2)->((Vect.addp1p2,opAddo1o2),ProofFormat.add_proofprf1prf2)letneg:t->t=fun((p1,o1),prf1)->matcho1with|Eq->((Vect.mulQ.minus_onep1,o1),ProofFormat.mul_cst_proofQ.minus_oneprf1)|_->failwith"neg: invalid proof"letmul_cstc((p1,o1),prf1)=let()=matcho1with|Eq->()|Gt|Ge->assert(c>/Q.zero)inletp=LinPoly.mul_cstcp1inletprf=ProofFormat.mul_cst_proofcprf1in((p,o1),prf)letmultp((p1,o1),prf1)=matcho1with|Eq->((LinPoly.productpp1,o1),ProofFormat.sMulCpprf1)|Gt|Ge->letn,r=Vect.decomp_cstpinifVect.is_nullr&&n>/Q.zerothen((LinPoly.productpp1,o1),ProofFormat.mul_cst_proofnprf1)else(ifdebugthenPrintf.printf"mult_error %a [*] %a\n"LinPoly.pppoutput((p1,o1),prf1);raiseInvalidProof)letdefpopi=((p,op),ProofFormat.Defi)letmkhyppopi=((p,op),ProofFormat.Hypi)letsquarepq=((p,Ge),ProofFormat.Squareq)letcutting_plane((p,o),prf)=letc,p'=Vect.decomp_cstpinletg=Vect.gcdp'inifZ.equalZ.oneg||c=/Q.zero||not(Z.equal(Q.denc)Z.one)thenNone(* Nothing to do *)elseletc1=c//Q.of_bigintginletc1'=Q.floorc1inifc1=/c1'thenNoneelsematchowith|Eq->Some((Vect.set0Q.minus_oneVect.null,Eq),ProofFormat.CutPrfprf)|Gt->failwith"cutting_plane ignore strict constraints"|Ge->(* This is a non-trivial common divisor *)Some((Vect.set0c1'(Vect.div(Q.of_bigintg)p),o),ProofFormat.CutPrfprf)letconstruct_signp=letc,p'=Vect.decomp_cstpinifVect.is_nullp'thenSome(matchQ.signcwith|0->(true,Eq,ProofFormat.Zero)|1->(true,Gt,ProofFormat.Cstc)|_(*-1*)->(false,Gt,ProofFormat.Cst(Q.negc)))elseNoneletget_signlp=matchconstruct_signpwith|None->(trylet(p',o),prf=List.find(fun((p',o),prf)->Vect.equalpp')linSome(true,o,prf)withNot_found->(letp=Vect.uminuspintrylet(p',o),prf=List.find(fun((p',o),prf)->Vect.equalpp')linSome(false,o,prf)withNot_found->None))|Somes->Somesletmult_sign:bool->t->t=funb((p,o),prf)->ifbthen((p,o),prf)else((Vect.uminusp,o),prf)letreclinear_pivotsys((lp1,op1),prf1)x((lp2,op2),prf2)=(* lp1 = a1.x + b1 *)leta1,b1=LinPoly.factorisexlp1in(* lp2 = a2.x + b2 *)leta2,b2=LinPoly.factorisexlp2inifVect.is_nulla2then(* We are done *)Some((lp2,op2),prf2)elsematch(op1,op2)with|Eq,(Ge|Gt)->(matchget_signsysa1with|None->None(* Impossible to pivot without sign information *)|Some(b,o,prf)->letsa1=mult_signb((a1,o),prf)inletsa2=ifbthenVect.uminusa2elsea2inlet(lp2,op2),prf2=addition(productsa1((lp2,op2),prf2))(multsa2((lp1,op1),prf1))inlinear_pivotsys((lp1,op1),prf1)x((lp2,op2),prf2))|Eq,Eq->let(lp2,op2),prf2=addition(multa1((lp2,op2),prf2))(mult(Vect.uminusa2)((lp1,op1),prf1))inlinear_pivotsys((lp1,op1),prf1)x((lp2,op2),prf2)|(Ge|Gt),(Ge|Gt)->(match(get_signsysa1,get_signsysa2)with|Some(b1,o1,p1),Some(b2,o2,p2)->ifb1<>b2thenlet(lp2,op2),prf2=addition(product(mult_signb1((a1,o1),p1))((lp2,op2),prf2))(product(mult_signb2((a2,o2),p2))((lp1,op1),prf1))inlinear_pivotsys((lp1,op1),prf1)x((lp2,op2),prf2)elseNone|_->None)|(Ge|Gt),Eq->failwith"pivot: equality as second argument"letlinear_pivotsys((lp1,op1),prf1)x((lp2,op2),prf2)=matchlinear_pivotsys((lp1,op1),prf1)x((lp2,op2),prf2)with|None->None|Some(c,p)->Some(c,ProofFormat.simplify_prf_rulep)letis_substitutionstrict((p,o),prf)=letpredv=ifstrictthenv=/Q.one||v=/Q.minus_oneelsetrueinmatchowithEq->LinPoly.search_linearpredp|_->Noneletsort(sys:tlist)=letsize((p,o),prf)=let_,p'=Vect.decomp_cstpinlet(x,q),p'=Vect.decomp_fstp'inVect.fold(fun(l,(q,x))x'q'->letq'=Q.absq'in(l+1,ifq</qthen(q,x)else(q',x')))(1,(Q.absq,x))pinletcmp((l1,(q1,_)),((_,o),_))((l2,(q2,_)),((_,o'),_))=ifl1<l2then-1elseifl1=l2thenQ.compareq1q2else1inList.sortcmp(List.rev_map(funwp->(sizewp,wp))sys)letiterate_pivotpsys0=letelimsys=letoeq,sys'=extractpsysinmatchoeqwith|None->None|Some(v,pc)->simplify(linear_pivotsys0pcv)sys'initerate_until_stableelim(List.mapsnd(sortsys0))letsubst_constantis_intsys=letis_integerq=Q.(q=/floorq)inletis_constant((c,o),p)=matchowith|Ge|Gt->None|Eq->(Vect.Bound.(matchof_vectcwith|None->None|Someb->if(notis_int)||is_integer(b.cst//b.coeff)thenMonomial.get_var(LinPoly.MonT.retrieveb.var)elseNone))initerate_pivotis_constantsysletsubstsys0=iterate_pivot(is_substitutiontrue)sys0letsaturate_substbsys0=letselect=is_substitutionbinletgen(v,pc)((c,op),prf)=ifISet.memv(LinPoly.variablesc)thenlinear_pivotsys0pcv((c,op),prf)elseNoneinsaturateselectgensys0letsimple_pivot(q1,x)((v1,o1),prf1)((v2,o2),prf2)=letq2=Vect.getxv2inifq2=/Q.zerothenNoneelseletcv1,cv2=ifQ.signq1<>Q.signq2then(Q.absq2,Q.absq1)elsematch(o1,o2)with|Eq,_->(q2,Q.absq1)|_,Eq->(Q.absq2,q2)|_,_->(Q.zero,Q.zero)inifcv2=/Q.zerothenNoneelseSome((Vect.mul_addcv1v1cv2v2,opAddo1o2),ProofFormat.add_proof(ProofFormat.mul_cst_proofcv1prf1)(ProofFormat.mul_cst_proofcv2prf2))endmoduleBoundWithProof=structtypet=Vect.Bound.t*op*ProofFormat.prf_ruleletmake((p,o),prf)=matchVect.Bound.of_vectpwith|None->None|Someb->Some(b,o,prf)letpadd(o1,prf1)(o2,prf2)=(opAddo1o2,ProofFormat.add_proofprf1prf2)letpmul(o1,prf1)(o2,prf2)=(opMulto1o2,ProofFormat.mul_proofprf1prf2)letplet(o1,p1)(o2,p2)f=matchProofFormat.pr_unitp1,ProofFormat.pr_unitp2with|true,true->f(o1,p1)(o2,p2)|false,false->let(o,prf)=f(o1,ProofFormat.Ref1)(o2,ProofFormat.Ref0)in(o,ProofFormat.LetPrf(p1,ProofFormat.LetPrf(p2,prf)))|true,false->let(o,prf)=f(o1,p1)(o2,ProofFormat.Ref0)in(o,ProofFormat.LetPrf(p2,prf))|false,true->let(o,prf)=f(o1,ProofFormat.Ref0)(o2,p2)in(o,ProofFormat.LetPrf(p1,prf))letpextc(o,prf)=ifc=/Q.zerothen(Eq,ProofFormat.Zero)else(o,ProofFormat.mul_cst_proofcprf)letmul_bound(b1,o1,prf1)(b2,o2,prf2)=letopenVect.Boundinmatch(b1,b2)with|{cst=c1;var=v1;coeff=c1'},{cst=c2;var=v2;coeff=c2'}->letgood_coeffbo=matchowith|Eq->Some(Q.negb)|_->ifb<=/Q.zerothenSome(Q.negb)elseNoneinmatch(good_coeffc1o2,good_coeffc2o1)with|None,_|_,None->None|Somec1,Somec2->letw1=(o1,prf1)inletw2=(o2,prf2)inlet(o,prf)=pletw1w2(funw1w2->padd(padd(pmulw1w2)(pextc1w2))(pextc2w1))inletb={cst=Q.neg(c1*/c2);var=LinPoly.MonT.register(Monomial.prod(LinPoly.MonT.retrievev1)(LinPoly.MonT.retrievev2));coeff=c1'*/c2';}inSome(b,o,prf)letbound(b,_,_)=bletproof(b,o,w)=letp=Vect.Bound.to_vectbin((p,o),w)end(* Local Variables: *)(* coding: utf-8 *)(* End: *)