123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447(************************************************************************)(* * The Rocq Prover / The Rocq 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 *)(* *)(* ** Utility functions ** *)(* *)(* - Modules CoqToCaml, CamlToCoq *)(* - Modules Cmp, Tag, TagSet *)(* *)(* Frédéric Besson (Irisa/Inria) 2006-2008 *)(* *)(************************************************************************)openNumCompatmoduleZ_=NumCompat.ZmoduleISet=structincludeInt.Setletppos=iter(funi->Printf.fprintfo"%i "i)sendmoduleIMap=structincludeInt.Mapletfromkm=let_,_,r=split(k-1)minrendletrecpp_listsfol=matchlwith|[]->()|[e]->foe|e::l->foe;output_stringos;pp_listsfolletfinallyfrst=tryletres=f()inrst();reswithreraise->(tryrst()withany->raisereraise);raisereraiseletall_pairsfl=letpair_withaccel=List.fold_left(funaccx->fex::acc)acclinletrecxpairsaccl=matchlwith[]->acc|e::lx->xpairs(pair_withaccel)lxinxpairs[]lletrecis_sublistfl1l2=match(l1,l2)with|[],_->true|e::l1',[]->false|e::l1',e'::l2'->iffee'thenis_sublistfl1'l2'elseis_sublistfl1l2'letextractpredl=List.fold_left(fun(fd,sys)e->matchfdwith|None->(matchpredewithNone->(fd,e::sys)|Somev->(Some(v,e),sys))|_->(fd,e::sys))(None,[])lletextract_allpredl=List.fold_left(fun(s1,s2)e->matchpredewithNone->(s1,e::s2)|Somev->(v::s1,s2))([],[])lletsimplifyfsys=letsys',b=List.fold_left(fun(sys',b)c->matchfcwithNone->(c::sys',b)|Somec'->(c'::sys',true))([],false)sysinifbthenSomesys'elseNoneletgenerate_accfaccsys=List.fold_left(funsys'c->matchfcwithNone->sys'|Somec'->c'::sys')accsysletgeneratefsys=generate_accf[]sysletsaturatepfsys=letrecsataccl=matchextractplwith|None,_->acc|Somer,l'->letn=generate(fr)(l'@acc)insat(n@acc)l'intrysat[]syswithx->Printexc.print_backtracestdout;raisexletiterate_until_stablefx=letreciterx=matchfxwithNone->x|Somex'->iterx'initerxletrecapp_funslx=matchlwith|[]->None|f::fl->(matchfxwithNone->app_funsflx|Somex'->Somex')(**
* MODULE: Rocq to Caml data-structure mappings
*)moduleCoqToCaml=structopenMicromegaletrecnat=functionO->0|Sn->natn+1letrecpositivep=matchpwith|XH->1|XIp->1+(2*positivep)|XOp->2*positivepletnnt=matchntwithN0->0|Nposp->positivepletrecindexi=(* Swap left-right ? *)matchiwithXH->1|XIi->1+(2*indexi)|XOi->2*indexiletrecpositive_big_intp=matchpwith|XH->Z_.one|XIp->Z_.addZ_.one(Z_.mulZ_.two(positive_big_intp))|XOp->Z_.mulZ_.two(positive_big_intp)letz_big_intx=matchxwith|Z0->Z_.zero|Zposp->positive_big_intp|Znegp->Z_.neg(positive_big_intp)letzx=matchxwithZ0->0|Zposp->indexp|Znegp->-indexpletq_to_num{qnum=x;qden=y}=letopenQ.NotationsinQ.of_bigint(z_big_intx)//Q.of_bigint(z_big_int(Zposy))end(**
* MODULE: Caml to Rocq data-structure mappings
*)moduleCamlToCoq=structopenMicromegaletrecnat=function0->O|n->S(nat(n-1))letrecpositiven=ifInt.equaln1thenXHelseifInt.equal(nland1)1thenXI(positive(nlsr1))elseXO(positive(nlsr1))letnnt=ifnt<0thenassertfalseelseifInt.equalnt0thenN0elseNpos(positivent)letrecindexn=ifInt.equaln1thenXHelseifInt.equal(nland1)1thenXI(index(nlsr1))elseXO(index(nlsr1))letzx=matchcomparex0with|0->Z0|1->Zpos(positivex)|_->(* this should be -1 *)Zneg(positive(-x))letpositive_big_intn=letrec_posn=ifZ_.equalnZ_.onethenXHelseletq,m=Z_.quomodnZ_.twoinifZ_.equalZ_.onemthenXI(_posq)elseXO(_posq)in_posnletbigintx=matchZ_.signxwith|0->Z0|1->Zpos(positive_big_intx)|_->Zneg(positive_big_int(Z_.negx))letqn={Micromega.qnum=bigint(Q.numn);Micromega.qden=positive_big_int(Q.denn)}end(**
* MODULE: Comparisons on lists: by evaluating the elements in a single list,
* between two lists given an ordering, and using a hash computation
*)moduleCmp=structletreccompare_lexicall=matchlwith|[]->0(* Equal *)|f::l->letcmp=f()inifInt.equalcmp0thencompare_lexicallelsecmpletreccompare_listcmpl1l2=match(l1,l2)with|[],[]->0|[],_->-1|_,[]->1|e1::l1,e2::l2->letc=cmpe1e2inifInt.equalc0thencompare_listcmpl1l2elsecend(**
* MODULE: Labels for atoms in propositional formulas.
* Tags are used to identify unused atoms in CNFs, and propagate them back to
* the original formula. The translation back to Rocq then ignores these
* superfluous items, which speeds the translation up a bit.
*)moduletypeTag=sigtypet=intvalfrom:int->tvalnext:t->tvalpp:out_channel->t->unitvalcompare:t->t->intvalmax:t->t->tvalto_int:t->intendmoduleTag:Tag=structtypet=intletfromi=iletnexti=i+1letmax:int->int->int=maxletppoi=output_stringo(string_of_inti)letcompare:int->int->int=Int.compareletto_intx=xend(**
* MODULE: Ordered sets of tags.
*)moduleTagSet=structincludeSet.Make(Tag)endmoduleMcPrinter=structmoduleMc=Micromegaletpp_naton=Printf.fprintfo"%i"(CoqToCaml.natn)letpp_positiveox=Printf.fprintfo"%i"(CoqToCaml.positivex)letpp_zox=Printf.fprintfo"%s"(NumCompat.Z.to_string(CoqToCaml.z_big_intx))letpp_polpp_coe=letrecpp_poloe=matchewith|Mc.Pcn->Printf.fprintfo"Pc %a"pp_cn|Mc.Pinj(p,pol)->Printf.fprintfo"Pinj(%a,%a)"pp_positiveppp_polpol|Mc.PX(pol1,p,pol2)->Printf.fprintfo"PX(%a,%a,%a)"pp_polpol1pp_positiveppp_polpol2inpp_poloeletpp_psatzpp_zoe=letrecpp_coneoe=matchewith|Mc.PsatzLet(e1,e2)->Printf.fprintfo"(Let %a %a)%%nat"pp_conee1pp_conee2|Mc.PsatzInn->Printf.fprintfo"(In %a)%%nat"pp_natn|Mc.PsatzMulC(e,c)->Printf.fprintfo"( %a [*] %a)"(pp_polpp_z)epp_conec|Mc.PsatzSquaree->Printf.fprintfo"(%a^2)"(pp_polpp_z)e|Mc.PsatzAdd(e1,e2)->Printf.fprintfo"(%a [+] %a)"pp_conee1pp_conee2|Mc.PsatzMulE(e1,e2)->Printf.fprintfo"(%a [*] %a)"pp_conee1pp_conee2|Mc.PsatzCp->Printf.fprintfo"(%a)%%positive"pp_zp|Mc.PsatzZ->Printf.fprintfo"0"inpp_coneoeletrecpp_proof_termo=function|Micromega.DoneProof->Printf.fprintfo"D"|Micromega.RatProof(cone,rst)->Printf.fprintfo"R[%a,%a]"(pp_psatzpp_z)conepp_proof_termrst|Micromega.CutProof(cone,rst)->Printf.fprintfo"C[%a,%a]"(pp_psatzpp_z)conepp_proof_termrst|Micromega.SplitProof(p,p1,p2)->Printf.fprintfo"S[%a,%a,%a]"(pp_polpp_z)ppp_proof_termp1pp_proof_termp2|Micromega.EnumProof(c1,c2,rst)->Printf.fprintfo"EP[%a,%a,%a]"(pp_psatzpp_z)c1(pp_psatzpp_z)c2(pp_list","pp_proof_term)rst|Micromega.ExProof(p,prf)->Printf.fprintfo"Ex[%a,%a]"pp_positiveppp_proof_termprfend(** As for Unix.close_process, our Unix.waipid will ignore all EINTR *)letrecwaitpid_non_intrpid=trysnd(Unix.waitpid[]pid)withUnix.Unix_error(Unix.EINTR,_,_)->waitpid_non_intrpid(**
* Forking routine, plumbing the appropriate pipes where needed.
*)letcommandexe_pathargsvl=(* creating pipes for stdin, stdout, stderr *)letstdin_read,stdin_write=Unix.pipe()andstdout_read,stdout_write=Unix.pipe()andstderr_read,stderr_write=Unix.pipe()in(* Create the process *)letpid=Unix.create_processexe_pathargsstdin_readstdout_writestderr_writein(* Write the data on the stdin of the created process *)letoutch=Unix.out_channel_of_descrstdin_writeinoutput_valueoutchvl;flushoutch;(* Wait for its completion *)letstatus=waitpid_non_intrpidinfinally(* Recover the result *)(fun()->matchstatuswith|Unix.WEXITED0->(letinch=Unix.in_channel_of_descrstdout_readintryMarshal.from_channelinchwith(End_of_file|Failure_)asexn->failwith(Printf.sprintf"command \"%s\" exited with code 0 but result could not be read back: %s"exe_path(Printexc.to_stringexn)))|Unix.WEXITEDi->failwith(Printf.sprintf"command \"%s\" exited %i"exe_pathi)|Unix.WSIGNALEDi->failwith(Printf.sprintf"command \"%s\" killed %i"exe_pathi)|Unix.WSTOPPEDi->failwith(Printf.sprintf"command \"%s\" stopped %i"exe_pathi))(* Cleanup *)(fun()->List.iter(funx->tryUnix.closexwithUnix.Unix_error_->())[stdin_read;stdin_write;stdout_read;stdout_write;stderr_read;stderr_write])(** Hashing utilities *)moduleHash=structmoduleMc=MicromegaopenHashset.Combineletint_of_eq_op1=Mc.(functionEqual->0|NonEqual->1|Strict->2|NonStrict->3)letint_of_eq_op2=Mc.(function|OpEq->0|OpNEq->1|OpLe->2|OpGe->3|OpLt->4|OpGt->5)leteq_op1o1o2=Int.equal(int_of_eq_op1o1)(int_of_eq_op1o2)leteq_op2o1o2=Int.equal(int_of_eq_op2o1)(int_of_eq_op2o2)lethash_op1ho=combineh(int_of_eq_op1o)letreceq_positivep1p2=match(p1,p2)with|Mc.XH,Mc.XH->true|Mc.XIp1,Mc.XIp2->eq_positivep1p2|Mc.XOp1,Mc.XOp2->eq_positivep1p2|_,_->falseleteq_zz1z2=match(z1,z2)with|Mc.Z0,Mc.Z0->true|Mc.Zposp1,Mc.Zposp2|Mc.Znegp1,Mc.Znegp2->eq_positivep1p2|_,_->falseleteq_q{Mc.qnum=qn1;Mc.qden=qd1}{Mc.qnum=qn2;Mc.qden=qd2}=eq_zqn1qn2&&eq_positiveqd1qd2letreceq_poleqp1p2=match(p1,p2)with|Mc.Pcc1,Mc.Pcc2->eqc1c2|Mc.Pinj(i1,p1),Mc.Pinj(i2,p2)->eq_positivei1i2&&eq_poleqp1p2|Mc.PX(p1,i1,p1'),Mc.PX(p2,i2,p2')->eq_poleqp1p2&&eq_positivei1i2&&eq_poleqp1'p2'|_,_->falseleteq_paireq1eq2(x1,y1)(x2,y2)=eq1x1x2&&eq2y1y2lethash_polhelt=letrechashacc=function|Mc.Pcc->helt(combineacc1)c|Mc.Pinj(p,c)->hash(combine(combineacc1)(CoqToCaml.indexp))c|Mc.PX(p1,i,p2)->hash(hash(combine(combineacc2)(CoqToCaml.indexi))p1)p2inhashlethash_pairh1h2h(e1,e2)=h2(h1he1)e2lethash_eltfhe=combineh(fe)lethash_stringh(e:string)=hash_eltHashtbl.hashhelethash_z=hash_eltCoqToCaml.zlethash_q=hash_elt(funq->Hashtbl.hash(CoqToCaml.q_to_numq))end(* Local Variables: *)(* coding: utf-8 *)(* End: *)