1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306(************************************************************************)(* * 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)letproductp1p2=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_rule(* 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"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)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: *)