123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279(************************************************************************)(* * 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) *)(************************************************************************)openNumCompatopenQ.NotationsopenMutils(** [t] is the type of vectors.
A vector [(x1,v1) ; ... ; (xn,vn)] is such that:
- variables indexes are ordered (x1 < ... < xn
- values are all non-zero
*)typevar=inttypemono={var:var;coe:Q.t}typet=monolisttypevector=t(** [equal v1 v2 = true] if the vectors are syntactically equal. *)letrecequalv1v2=match(v1,v2)with|[],[]->true|[],_->false|_::_,[]->false|{var=i1;coe=n1}::v1,{var=i2;coe=n2}::v2->Int.equali1i2&&n1=/n2&&equalv1v2lethashv=letrechashi=function|[]->i|{var=vr;coe=vl}::l->hash(i+Hashtbl.hash(vr,Q.to_floatvl))linHashtbl.hash(hash0v)letnull=[]letis_nullv=matchvwith|[]->true|[{var=0;coe=x}]whenQ.zero=/x->true|_->falseletpp_var_numpp_varo{var=v;coe=n}=ifInt.equalv0thenifQ.zero=/nthen()elsePrintf.fprintfo"%s"(Q.to_stringn)elseifQ.one=/nthenpp_varovelseifQ.minus_one=/nthenPrintf.fprintfo"-%a"pp_varvelseifQ.zero=/nthen()elsePrintf.fprintfo"%s*%a"(Q.to_stringn)pp_varvletpp_var_num_smtpp_varo{var=v;coe=n}=letpp_numoq=letnn=Q.numninletdn=Q.denninifZ.equaldnZ.onethenoutput_stringo(Z.to_stringnn)elsePrintf.fprintfo"(/ %s %s)"(Z.to_stringnn)(Z.to_stringdn)inifInt.equalv0thenifQ.zero=/nthen()elsepp_numonelseifQ.one=/nthenpp_varovelseifQ.minus_one=/nthenPrintf.fprintfo"(- %a)"pp_varvelseifQ.zero=/nthen()elsePrintf.fprintfo"(* %a %a)"pp_numnpp_varvletrecpp_genpp_varov=matchvwith|[]->output_stringo"0"|[e]->pp_var_numpp_varoe|e::l->Printf.fprintfo"%a + %a"(pp_var_numpp_var)e(pp_genpp_var)lletpp_varov=Printf.fprintfo"x%i"vletppov=pp_genpp_varovletpp_smtov=letlistov=List.iter(fune->Printf.fprintfo"%a "(pp_var_num_smtpp_var)e)vinPrintf.fprintfo"(+ %a)"listvletfrom_list(l:Q.tlist)=letrecxfrom_listil=matchlwith|[]->[]|e::l->ife<>/Q.zerothen{var=i;coe=e}::xfrom_list(i+1)lelsexfrom_list(i+1)linxfrom_list0lletconsivrst=ifv=/Q.zerothenrstelse{var=i;coe=v}::rstletrecupdateift=matchtwith|[]->consi(fQ.zero)[]|x::l->(matchInt.compareix.varwith|0->consx.var(fx.coe)l|-1->consi(fQ.zero)t|1->x::updateifl|_->failwith"compare_num")letrecsetint=matchtwith|[]->consin[]|x::l->(matchInt.compareix.varwith|0->consx.varnl|-1->consint|1->x::setinl|_->failwith"compare_num")letcstn=ifn=/Q.zerothen[]else[{var=0;coe=n}]letmulzt=ifz=/Q.zerothen[]elseifz=/Q.onethentelseList.map(fun{var=i;coe=n}->{var=i;coe=z*/n})tletdivzt=ifz<>/Q.onethenList.map(fun{var=x;coe=nx}->{var=x;coe=nx//z})telsetletuminust=List.map(fun{var=i;coe=n}->{var=i;coe=Q.negn})tletrecadd(ve1:t)(ve2:t)=match(ve1,ve2)with|[],v|v,[]->v|{var=v1;coe=c1}::l1,{var=v2;coe=c2}::l2->letcmp=Int.comparev1v2inifcmp==0thenlets=c1+/c2inifQ.zero=/sthenaddl1l2else{var=v1;coe=s}::addl1l2elseifcmp<0then{var=v1;coe=c1}::addl1ve2else{var=v2;coe=c2}::addl2ve1letrecxmul_add(n1:Q.t)(ve1:t)(n2:Q.t)(ve2:t)=match(ve1,ve2)with|[],_->muln2ve2|_,[]->muln1ve1|{var=v1;coe=c1}::l1,{var=v2;coe=c2}::l2->letcmp=Int.comparev1v2inifcmp==0thenlets=(n1*/c1)+/(n2*/c2)inifQ.zero=/sthenxmul_addn1l1n2l2else{var=v1;coe=s}::xmul_addn1l1n2l2elseifcmp<0then{var=v1;coe=n1*/c1}::xmul_addn1l1n2ve2else{var=v2;coe=n2*/c2}::xmul_addn1ve1n2l2letmul_addn1ve1n2ve2=ifn1=/Q.one&&n2=/Q.onethenaddve1ve2elsexmul_addn1ve1n2ve2letcompare:t->t->int=Mutils.Cmp.compare_list(funxy->Mutils.Cmp.compare_lexical[(fun()->Int.comparex.vary.var);(fun()->Q.comparex.coey.coe)])(** [tail v vect] returns
- [None] if [v] is not a variable of the vector [vect]
- [Some(vl,rst)] where [vl] is the value of [v] in vector [vect]
and [rst] is the remaining of the vector
We exploit that vectors are ordered lists
*)letrectail(v:var)(vect:t)=matchvectwith|[]->None|{var=v';coe=vl}::vect'->(matchInt.comparev'vwith|0->Some(vl,vect)(* Ok, found *)|-1->tailvvect'(* Might be in the tail *)|_->None)(* Hopeless *)letgetvvect=matchtailvvectwithNone->Q.zero|Some(vl,_)->vlletis_constantv=matchvwith[]|[{var=0}]->true|_->falseletget_cstvect=matchvectwith{var=0;coe=v}::_->v|_->Q.zeroletchoosev=matchvwith[]->None|{var=vr;coe=vl}::rst->Some(vr,vl,rst)letrecfreshv=matchvwith[]->1|[{var=v}]->v+1|_::v->freshvletvariablesv=List.fold_left(funacc{var=x}->ISet.addxacc)ISet.emptyvletdecomp_cstv=matchvwith{var=0;coe=vl}::v->(vl,v)|_->(Q.zero,v)letdecomp_fstv=matchvwith[]->((0,Q.zero),[])|x::v->((x.var,x.coe),v)letrecsubst(vr:int)(e:t)(v:t)=matchvwith|[]->[]|{var=x;coe=n}::v'->(matchInt.comparevrxwith|0->mul_addneQ.onev'|-1->v|1->add[{var=x;coe=n}](substvrev')|_->assertfalse)letfoldfaccv=List.fold_left(funaccx->faccx.varx.coe)accvletrecfindpv=matchvwith|[]->None|{var=v;coe=n}::v'->(matchpvnwithNone->findpv'|Somer->Somer)letfor_allpl=List.for_all(fun{var=v;coe=n}->pvn)lletdecr_variv=List.map(funx->{xwithvar=x.var-i})vletincr_variv=List.map(funx->{xwithvar=x.var+i})vletgcdv=letres=fold(func_n->assert(Int.equal(Z.compare(Q.denn)Z.one)0);Z.gcdc(Q.numn))Z.zerovinifInt.equal(Z.compareresZ.zero)0thenZ.oneelseresletnormalisev=letppcm=fold(func_n->Z.ppcmc(Q.denn))Z.onevinletgcd=letgcd=fold(func_n->Z.gcdc(Q.numn))Z.zerovinifInt.equal(Z.comparegcdZ.zero)0thenZ.oneelsegcdinList.map(fun{var=x;coe=v}->{var=x;coe=v*/Q.of_bigintppcm//Q.of_bigintgcd})vletrecexists2pvect1vect2=match(vect1,vect2)with|_,[]|[],_->None|{var=v1;coe=n1}::vect1',{var=v2;coe=n2}::vect2'->ifInt.equalv1v2thenifpn1n2thenSome(v1,n1,n2)elseexists2pvect1'vect2'elseifv1<v2thenexists2pvect1'vect2elseexists2pvect1vect2'letdotproductv1v2=letrecdotaccv1v2=match(v1,v2)with|[],_|_,[]->acc|{var=x1;coe=n1}::v1',{var=x2;coe=n2}::v2'->ifInt.equalx1x2thendot(acc+/(n1*/n2))v1'v2'elseifx1<x2thendotaccv1'v2elsedotaccv1v2'indotQ.zerov1v2moduleBound=structtypet={cst:Q.t;var:var;coeff:Q.t}letof_vect(v:vector)=matchvwith|[{var=x;coe=v}]->ifInt.equalx0thenNoneelseSome{cst=Q.zero;var=x;coeff=v}|[{var=0;coe=v};{var=x;coe=v'}]->Some{cst=v;var=x;coeff=v'}|_->Noneletto_vect{cst=k;var=v;coeff=c}=let()=assert(not(c=/Q.zero))inifk=/Q.zerothen[{var=v;coe=c}]else[{var=0;coe=k};{var=v;coe=c}]end