123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182(******************************************************************************)(* ocplib-simplex *)(* *)(* Copyright (C) --- OCamlPro --- See README.md for information and licensing *)(******************************************************************************)moduletypeS=sigmoduleCore:CoreSig.Svalget:(Core.P.t*bool)option->Core.t->Core.resultendmoduleMake(Core:CoreSig.S):SwithmoduleCore=Core=structmoduleCore=CoreopenCoreletexplain_polynon_basicpexis_lower=letinvert_sign=ifis_lowerthen1else-1inP.fold(funxcoefex->letc=invert_sign*R.signcoefinassert(c<>0);letxi,_=tryMX.findxnon_basicwithNot_found->assertfalseinletex,optimum=ifc>0thenEx.unionex(Core.expl_of_max_boundxi),xi.maxielseEx.unionex(Core.expl_of_min_boundxi),xi.miniinassert(equals_optimumxi.valueoptimum);ex)pexletget_unsat_coresenv=tryletsi,p=MX.findsenv.basicinifnot(consistent_boundssi)thenEx.union(Core.expl_of_min_boundsi)(Core.expl_of_max_boundsi)elsematchsi.vstatuswith|ValueOK->assertfalse|LowerKO->explain_polyenv.non_basicp(Core.expl_of_min_boundsi)true|UpperKO->explain_polyenv.non_basicp(Core.expl_of_max_boundsi)falsewithNot_found->letsi,_=MX.findsenv.non_basicinassert(not(consistent_boundssi));Ex.union(Core.expl_of_min_boundsi)(Core.expl_of_max_boundsi)letget_int_solutionenv=letis_int_sol=reftrueinletsol=MX.fold(funx(xi,_)sol->letv=xi.valueinassert(R2.is_pure_rationalv);is_int_sol:=!is_int_sol&&R.is_intv.R2.v;(x,v.R2.v)::sol)env.non_basic[]inletsol=MX.fold(funx(xi,_)sol->letv=xi.valueinassert(R2.is_pure_rationalv);is_int_sol:=!is_int_sol&&R.is_intv.R2.v;(x,v.R2.v)::sol)env.basicsolinletslake=env.slakeinletsol_slk,sol=List.partition(fun(x,_)->MX.memxslake)solin{main_vars=sol;slake_vars=sol_slk;int_sol=!is_int_sol;epsilon=R.zero}leteval_eps(eps:R.t)(inf:R2.t)(sup:R2.t)=let{R2.v=inf_r;offset=inf_d}:R2.t=infinlet{R2.v=sup_r;offset=sup_d}:R2.t=supinletc=R.compareinf_rsup_rinassert(c<=0);ifc=0||R.compareinf_dsup_d<=0thenepselseR.mineps(R.div(R.subsup_rinf_r)(R.subinf_dsup_d))leteps_for_mini(i:Core.var_info)(min:R2.t)(eps:R.t):R.t=assert(R2.is_pure_rationalmin||R.equalmin.R2.offsetR.one);leteps=eval_epsepsmini.valueinepsleteps_for_maxi(i:Core.var_info)(max:R2.t)(eps:R.t):R.t=assert(R2.is_pure_rationalmax||R.equalmax.R2.offsetR.m_one);leteps=eval_epsepsi.valuemaxinepsletget_rat_solution=letcompute_epsilonmpeps=MX.fold(fun_(i,_)eps->leteps'=matchi.mini,i.maxiwith|None,None->eps|Somemin,None->eps_for_miniimin.bvalueeps|None,Somemax->eps_for_maxiimax.bvalueeps|Somemin,Somemax->eps|>eps_for_miniimin.bvalue|>eps_for_maxiimax.bvalueinassert(R.compareeps'R.zero>0);eps')mpepsinletcompute_solutionslakempepsacc=MX.fold(funx(info,_)(m,s)->let{R2.v=q1;offset=q2}=info.valueinletq=R.addq1(R.multq2eps)inletq2=R2.of_rqinassert(not(violates_min_boundq2info.mini));assert(not(violates_max_boundq2info.maxi));ifMX.memxslakethenm,(x,q)::selse(x,q)::m,s)mpaccinfunenv->leteps=compute_epsilonenv.basicR.oneinleteps=compute_epsilonenv.non_basicepsinletacc=compute_solutionenv.slakeenv.basiceps([],[])inletm,s=compute_solutionenv.slakeenv.non_basicepsaccin{main_vars=m;slake_vars=s;int_sol=false;epsilon=eps}letget_solutionenv=ifenv.is_intthenget_int_solutionenvelseget_rat_solutionenvletget_max_info{non_basic;_}p=letmax_v:Core.bound=Core.P.fold(funxc(max_v:Core.bound)->letxi,_=tryMX.findxnon_basicwithNot_found->assertfalseinletbnd=ifR.signc>0thenxi.maxielsexi.miniinletex=matchbndwith|None->Core.Ex.empty|Some{explanation;_}->explanationinletvalue=xi.valueinassert(equals_optimumvaluebnd);{bvalue=R2.addmax_v.bvalue(R2.mult_by_constcvalue);explanation=Ex.unionmax_v.explanationex})p{bvalue=R2.zero;explanation=Ex.empty}in{max_v;is_le=R.is_zeromax_v.bvalue.R2.offset}letgetoptenv=matchenv.statuswith|UNK->Unknown|UNSATs->Unsat(lazy(get_unsat_coresenv))|SAT->matchoptwith|None->Sat(lazy(get_solutionenv))|Some(_,false)->Unbounded(lazy(get_solutionenv))|Some(p,true)->Max(lazy(get_max_infoenvp),lazy(get_solutionenv))end