1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525(* This file is free software, part of Zipperposition. See file "license" for more details. *)(** {1 Cancellative Inferences} *)openLogtkopenLibzipperpositionmoduleT=TermmoduleLit=LiteralmoduleLits=LiteralsmoduleS=SubstmoduleM=MonomemoduleMF=Monome.FocusmoduleAL=Rat_litmoduleALF=AL.FocusmoduleStmt=StatementmoduleUS=Unif_substletstat_rat_sup=Util.mk_stat"rat.superposition"letstat_rat_cancellation=Util.mk_stat"rat.rat_cancellation"letstat_rat_eq_factoring=Util.mk_stat"rat.eq_factoring"letstat_rat_ineq_chaining=Util.mk_stat"rat.ineq_chaining"letstat_rat_semantic_tautology=Util.mk_stat"rat.semantic_tauto"letstat_rat_ineq_factoring=Util.mk_stat"rat.ineq_factoring"letstat_rat_demod=Util.mk_stat"rat.demod"letstat_rat_backward_demod=Util.mk_stat"rat.backward_demod"letstat_rat_trivial_ineq=Util.mk_stat"rat.redundant_by_ineq.calls"letstat_rat_trivial_ineq_steps=Util.mk_stat"rat.redundant_by_ineq.steps"letstat_rat_demod_ineq=Util.mk_stat"rat.demod_ineq.calls"letstat_rat_demod_ineq_steps=Util.mk_stat"rat.demod_ineq.steps"(*
let stat_rat_reflexivity_resolution = Util.mk_stat "rat.reflexivity_resolution"
*)letprof_rat_sup=Util.mk_profiler"rat.superposition"letprof_rat_cancellation=Util.mk_profiler"rat.rat_cancellation"letprof_rat_eq_factoring=Util.mk_profiler"rat.eq_factoring"letprof_rat_ineq_chaining=Util.mk_profiler"rat.ineq_chaining"letprof_rat_demod=Util.mk_profiler"rat.demod"letprof_rat_backward_demod=Util.mk_profiler"rat.backward_demod"letprof_rat_semantic_tautology=Util.mk_profiler"rat.semantic_tauto"letprof_rat_ineq_factoring=Util.mk_profiler"rat.ineq_factoring"letprof_rat_trivial_ineq=Util.mk_profiler"rat.redundant_by_ineq"letprof_rat_demod_ineq=Util.mk_profiler"rat.demod_ineq"(*
let prof_rat_reflexivity_resolution = Util.mk_profiler "rat.reflexivity_resolution"
*)letsection=Util.Section.make~parent:Const.section"rat-arith"letenable_rat_=reftrueletenable_ac_=reffalseletenable_semantic_tauto_=reftrueletdot_unit_=refNoneletflag_tauto=SClause.new_flag()letflag_computed_tauto=SClause.new_flag()moduletypeS=sigmoduleEnv:Env.SmoduleC:moduletypeofEnv.CmodulePS:moduletypeofEnv.ProofState(** {2 Contributions to Env} *)valregister:unit->unitendletenable_trivial_ineq_=reftrueletenable_demod_ineq_=reftruemoduleMake(E:Env.S):SwithmoduleEnv=E=structmoduleEnv=EmoduleCtx=Env.CtxmoduleC=Env.CmodulePS=Env.ProofStatelet_idx_eq=ref(PS.TermIndex.empty())let_idx_ineq_left=ref(PS.TermIndex.empty())let_idx_ineq_right=ref(PS.TermIndex.empty())let_idx_all=ref(PS.TermIndex.empty())(* unit clauses *)let_idx_unit_eq=ref(PS.TermIndex.empty())let_idx_unit_ineq=ref(PS.TermIndex.empty())(* apply [f] to some subterms of [c] *)letupdatefc=letord=Ctx.ord()in_idx_eq:=Lits.fold_terms~vars:false~ty_args:false~which:`Max~ord~subterms:false~eligible:C.Eligible.(filterLit.is_rat_eq**maxc)(C.litsc)|>Iter.fold(funacc(t,pos)->letwith_pos=C.WithPos.({term=t;pos;clause=c})infacctwith_pos)!_idx_eq;letleft,right=Lits.fold_terms~vars:false~ty_args:false~which:`Max~ord~subterms:false~eligible:C.Eligible.(filterLit.is_rat_less**maxc)(C.litsc)|>Iter.fold(fun(left,right)(t,pos)->letwith_pos=C.WithPos.({term=t;pos;clause=c})inmatchposwith|Position.Arg(_,Position.Left_)->flefttwith_pos,right|Position.Arg(_,Position.Right_)->left,frighttwith_pos|_->assertfalse)(!_idx_ineq_left,!_idx_ineq_right)in_idx_ineq_left:=left;_idx_ineq_right:=right;_idx_all:=Lits.fold_terms~vars:false~ty_args:false~which:`Max~ord~subterms:false~eligible:C.Eligible.(filterLit.is_rat**maxc)(C.litsc)|>Iter.fold(funacc(t,pos)->letwith_pos=C.WithPos.({term=t;pos;clause=c})infacctwith_pos)!_idx_all;()(* simplification set *)letupdate_simplfc=letord=Ctx.ord()inbeginmatchC.litscwith|[|Lit.Rat({AL.op=AL.Equal;_}asalit)|]->letpos=Position.(arg0stop)in_idx_unit_eq:=AL.fold_terms~subterms:false~vars:false~pos~which:`Max~ordalit|>Iter.fold(funacc(t,pos)->assert(not(T.is_vart));letwith_pos=C.WithPos.({term=t;pos;clause=c;})infacctwith_pos)!_idx_unit_eq|[|Lit.Rat({AL.op=AL.Less;_}asalit)|]->letpos=Position.(arg0stop)in_idx_unit_ineq:=if!enable_trivial_ineq_||!enable_demod_ineq_thenAL.fold_terms~subterms:false~vars:false~pos~which:`Max~ordalit|>Iter.fold(funacc(t,pos)->assert(not(T.is_vart));letwith_pos=C.WithPos.({term=t;pos;clause=c;})infacctwith_pos)!_idx_unit_ineqelse!_idx_unit_ineq|_->()end;()let()=Signal.onPS.ActiveSet.on_add_clause(func->if!enable_rat_thenupdatePS.TermIndex.addc;Signal.ContinueListening);Signal.onPS.SimplSet.on_add_clause(func->if!enable_rat_thenupdate_simplPS.TermIndex.addc;Signal.ContinueListening);Signal.onPS.ActiveSet.on_remove_clause(func->if!enable_rat_thenupdatePS.TermIndex.removec;Signal.ContinueListening);Signal.onPS.SimplSet.on_remove_clause(func->if!enable_rat_thenupdate_simplPS.TermIndex.removec;Signal.ContinueListening);()(** {2 Utils} *)(* data required for superposition *)moduleSupInfo=structtypet={active:C.t;active_pos:Position.t;active_lit:AL.Focus.t;active_scope:int;passive:C.t;passive_pos:Position.t;passive_lit:AL.Focus.t;passive_scope:int;subst:Unif_subst.t;}endletrule_canc=Proof.Rule.mk"canc_sup"(* do cancellative superposition *)let_do_cancinfoacc=letopenSupInfoinletord=Ctx.ord()inletrenaming=Subst.Renaming.create()inletus=info.substinletidx_a,_=Lits.Pos.cutinfo.active_posinletidx_p,_=Lits.Pos.cutinfo.passive_posinlets_a=info.active_scopeands_p=info.passive_scopeinletsubst=Unif_subst.substusinletlit_a=ALF.apply_substrenamingsubst(info.active_lit,s_a)inletlit_p=ALF.apply_substrenamingsubst(info.passive_lit,s_p)inUtil.debugf~section5"@[<2>arith superposition@ between @[%a[%d]@]@ and @[%a[%d]@]@ (subst @[%a@])...@]"(funk->kC.ppinfo.actives_aC.ppinfo.passives_pSubst.ppsubst);(* check ordering conditions *)ifC.is_maxlit(info.active,s_a)subst~idx:idx_a&&C.is_maxlit(info.passive,s_p)subst~idx:idx_p&&ALF.is_max~ordlit_a(* && ALF.is_max ~ord lit_p *)then((* the active literals *)letlit_a,lit_p=ALF.scalelit_alit_pin(* other literals *)letlits_a=CCArray.except_idx(C.litsinfo.active)idx_ainletlits_a=Lit.apply_subst_listrenamingsubst(lits_a,s_a)inletlits_p=CCArray.except_idx(C.litsinfo.passive)idx_pinletlits_p=Lit.apply_subst_listrenamingsubst(lits_p,s_p)in(* new literal: lit_a=[t+m1=m2], lit_p=[t'+m1' R m2'] for some
relation R. Now let's replace t' by [m2-m1] in lit', ie,
build m = [m1'-m2'+(m2-m1) R 0]. *)letmf_a,m_a=matchlit_awith|ALF.Left(AL.Equal,mf,m)|ALF.Right(AL.Equal,m,mf)->mf,m|_->assertfalseinletnew_lit=matchlit_pwith|ALF.Left(op,mf_p,m_p)->Lit.mk_rat_opop(M.sum(MF.restmf_p)m_a)(M.summ_p(MF.restmf_a))|ALF.Right(op,m_p,mf_p)->Lit.mk_rat_opop(M.summ_p(MF.restmf_a))(M.sum(MF.restmf_p)m_a)inletc_guard=Literal.of_unif_substrenamingusinletall_lits=new_lit::c_guard@lits_a@lits_pin(* build clause *)letproof=Proof.Step.inference~tags:[Proof.Tag.T_lra]~rule:rule_canc[C.proof_parent_substrenaming(info.active,s_a)subst;C.proof_parent_substrenaming(info.passive,s_p)subst]inlettrail=C.trail_l[info.active;info.passive]inletpenalty=max(C.penaltyinfo.active)(C.penaltyinfo.passive)inletnew_c=C.create~penalty~trailall_litsproofinUtil.debugf~section5"@[<2>... gives@ @[%a@]@]"(funk->kC.ppnew_c);Util.incr_statstat_rat_sup;new_c::acc)else(Util.debug~section5"... has bad ordering conditions";acc)letcanc_sup_activec=Util.enter_profprof_rat_sup;letord=Ctx.ord()inleteligible=C.Eligible.(pos**maxc**filterLit.is_rat_eq)inletsc_a=0andsc_p=1inletres=Lits.fold_rat_terms~eligible~which:`Max~ord(C.litsc)|>Iter.fold(funacc(t,active_lit,active_pos)->assert(ALF.opactive_lit=AL.Equal);Util.debugf~section5"@[<2>active canc. sup.@ with @[%a@]@ in @[%a@]@]"(funk->kALF.ppactive_litC.ppc);PS.TermIndex.retrieve_unifiables(!_idx_all,sc_p)(t,sc_a)|>Iter.fold(funacc(t',with_pos,subst)->letpassive=with_pos.C.WithPos.clauseinletpassive_pos=with_pos.C.WithPos.posinletpassive_lit=Lits.View.get_rat_exn(C.litspassive)passive_posinUtil.debugf~section5"@[<4> possible match:@ @[%a@]@ in @[%a@]@]"(funk->kALF.pppassive_litC.pppassive);(* now to unify active_lit and passive_lit further *)ifT.is_vart||T.is_vart'thenaccelseALF.unify~subst(active_lit,sc_a)(passive_lit,sc_p)|>Iter.fold(funacc(active_lit,passive_lit,subst)->letinfo=SupInfo.({active=c;active_pos;active_lit;active_scope=sc_a;passive;passive_pos;passive_lit;passive_scope=sc_p;subst;})in_do_cancinfoacc)acc)acc)[]inUtil.exit_profprof_rat_sup;resletcanc_sup_passivec=Util.enter_profprof_rat_sup;letord=Ctx.ord()inleteligible=C.Eligible.(maxc**arith)inletsc_a=0andsc_p=1inletres=Lits.fold_rat_terms~eligible~which:`All~ord(C.litsc)|>Iter.fold(funacc(t,passive_lit,passive_pos)->Util.debugf~section5"@[<2>passive canc. sup.@ with @[%a@]@ in @[%a@]@]"(funk->kALF.pppassive_litC.ppc);PS.TermIndex.retrieve_unifiables(!_idx_eq,sc_a)(t,sc_p)|>Iter.fold(funacc(t',with_pos,subst)->letactive=with_pos.C.WithPos.clauseinletactive_pos=with_pos.C.WithPos.posinletactive_lit=Lits.View.get_rat_exn(C.litsactive)active_posin(* must have an equation as active lit *)matchALF.opactive_litwith|AL.Equalwhennot(T.is_vart)&¬(T.is_vart')->Util.debugf~section5"@[<4> possible match:@ @[%a@]@ in @[%a@]@]"(funk->kALF.pppassive_litC.ppc);(* unify literals further *)ALF.unify~subst(active_lit,sc_a)(passive_lit,sc_p)|>Iter.fold(funacc(active_lit,passive_lit,subst)->letinfo=SupInfo.({active;active_pos;active_lit;active_scope=sc_a;passive=c;passive_pos;passive_lit;passive_scope=sc_p;subst;})in_do_cancinfoacc)acc|_->acc)acc)[]inUtil.exit_profprof_rat_sup;resexceptionSimplifyIntoofAL.t*C.t*S.t(* how to simplify the passive lit with the active lit, in one step *)let_try_demod_step~substpassive_lit_s_pcposactive_lits_ac'_pos'=letord=Ctx.ord()inleti=Lits.Pos.idxposinletrenaming=S.Renaming.create()inletactive_lit'=ALF.apply_substrenamingsubst(active_lit,s_a)in(* restrictions:
- the rewriting term must be bigger than other terms
(in other words, the inference is strictly decreasing)
- all variables of active clause must be bound by subst
- must not rewrite itself (c != c')
- trail(active) must subsume trail(passive) *)ifALF.is_strictly_max~ordactive_lit'&&(C.Seq.varsc'|>Iter.for_all(funv->S.memsubst((v:Type.tHVar.t:>InnerTerm.tHVar.t),s_a)))&&((C.litsc|>Array.length)>1||not(Lit.equal(C.litsc).(i)(C.litsc').(0))||not(ALF.is_max~ordpassive_lit&&C.is_maxlit(c,0)S.empty~idx:i))&&(C.trail_subsumesc'c)then((* we know all variables of [active_lit] are bound, no need
for a renaming *)letactive_lit=ALF.apply_substSubst.Renaming.nonesubst(active_lit,s_a)inletactive_lit,passive_lit=ALF.scaleactive_litpassive_litinmatchactive_lit,passive_litwith|ALF.Left(AL.Equal,mf1,m1),_|ALF.Right(AL.Equal,m1,mf1),_->letnew_lit=ALF.replacepassive_lit(M.differencem1(MF.restmf1))inraise(SimplifyInto(new_lit,c',subst))|_->())else()(* reduce an arithmetic literal to its current normal form *)letrec_demod_lit_nf~add_lit~add_premise~ica_lit=letord=Ctx.ord()inlets_a=1ands_p=0in(* scopes *)begintryAL.fold_terms~pos:Position.stop~vars:false~which:`Max~ord~subterms:falsea_lit|>Iter.iter(fun(t,lit_pos)->assert(not(T.is_vart));letpassive_lit=ALF.get_exna_litlit_posin(* search for generalizations of [t] *)PS.TermIndex.retrieve_generalizations(!_idx_unit_eq,s_a)(t,s_p)|>Iter.iter(fun(_t',with_pos,subst)->letc'=with_pos.C.WithPos.clauseinletpos'=with_pos.C.WithPos.posinassert(C.is_unit_clausec');assert(Lits.Pos.idxpos'=0);letactive_lit=Lits.View.get_rat_exn(C.litsc')pos'inletpos=Position.(argilit_pos)in_try_demod_step~substpassive_lits_pcposactive_lits_ac'pos'));(* could not simplify, keep the literal *)add_lit(Lit.mk_rata_lit)withSimplifyInto(a_lit',c',subst)->(* lit ----> lit' *)add_premisec'subst;(* recurse until the literal isn't reducible *)Util.debugf~section4"(@[<hv2>rewrite_rat_arith@ :lit `%a`@ :into `%a`@ \
:using @[%a@]@ :subst @[%a@]@])"(funk->kAL.ppa_litAL.ppa_lit'C.ppc'S.ppsubst);_demod_lit_nf~add_premise~add_lit~ica_lit'endleteq_c_subst(c1,s1)(c2,s2)=C.equalc1c2&&Subst.equals1s2(* demodulation (simplification) *)let_demodulationc=Util.enter_profprof_rat_demod;letdid_simplify=reffalseinletlits=ref[]in(* simplified literals *)letadd_litl=lits:=l::!litsinletclauses=ref[]in(* simplifying clauses *)(* add a rewriting clause *)letadd_premisec'subst=did_simplify:=true;clauses:=(c',subst)::!clausesin(* simplify each and every literal *)Lits.fold_lits~eligible:C.Eligible.always(C.litsc)|>Iter.iter(fun(lit,i)->matchlitwith|Lit.Rata_lit->_demod_lit_nf~add_lit~add_premise~ica_lit|_->add_litlit(* keep non-arith literals *));(* build result clause (if it was simplified) *)letres=if!did_simplifythen(clauses:=CCList.uniq~eq:eq_c_subst!clauses;letproof=Proof.Step.inference~tags:[Proof.Tag.T_lra]~rule:(Proof.Rule.mk"canc_demod")(C.proof_parentc::List.rev_map(fun(c,subst)->C.proof_parent_substSubst.Renaming.none(c,1)subst)!clauses)inlettrail=C.trailcinletnew_c=C.create~penalty:(C.penaltyc)~trail(List.rev!lits)proofinUtil.incr_statstat_rat_demod;Util.debugf~section5"@[<2>arith demodulation@ of @[%a@]@ with [@[%a@]]@ gives @[%a@]@]"(funk->letpp_c_sout(c,s)=Format.fprintfout"(@[%a@ :subst %a@])"C.ppcSubst.ppsinkC.ppc(Util.pp_listpp_c_s)!clausesC.ppnew_c);SimplM.return_newnew_c)elseSimplM.return_samecinUtil.exit_profprof_rat_demod;resletcanc_demodulationc=_demodulationc(* find clauses in which some literal could be rewritten by [c], iff
[c] is a positive unit arith clause *)letcanc_backward_demodulationc=Util.enter_profprof_rat_backward_demod;letord=Ctx.ord()inletres=C.ClauseSet.emptyinletres=matchC.litscwith|[|Lit.Rat({AL.op=AL.Equal;_}asalit)|]->AL.fold_terms~vars:false~which:`Max~subterms:false~ordalit|>Iter.fold(funacc(t,pos)->PS.TermIndex.retrieve_specializations(!_idx_all,0)(t,1)|>Iter.fold(funacc(_t',with_pos,subst)->letc'=with_pos.C.WithPos.clausein(* check whether the term [t] is indeed maximal in
its literal (and clause) after substitution *)letalit'=ALF.get_exnalitposinletalit'=ALF.apply_substSubst.Renaming.nonesubst(alit',1)inifC.trail_subsumesc'c&&ALF.is_max~ordalit'then(Util.incr_statstat_rat_backward_demod;C.ClauseSet.addc'acc)elseacc)acc)C.ClauseSet.empty|_->res(* no demod *)inUtil.exit_profprof_rat_backward_demod;resletcancellationc=Util.enter_profprof_rat_cancellation;letord=Ctx.ord()inleteligible=C.Eligible.(maxc**arith)inletres=Lits.fold_rat~eligible(C.litsc)|>Iter.fold(funacc(a_lit,pos)->letidx=Lits.Pos.idxposin(* cancellation depends on what the literal looks like *)let{AL.left=m1;right=m2;op}=a_litinUtil.debugf~section5"@[<2>try cancellation@ in @[%a@]@]"(funk->kAL.ppa_lit);(* try to unify terms in [m1] and [m2] *)MF.unify_mm(m1,0)(m2,0)|>Iter.fold(funacc(mf1,mf2,us)->letrenaming=Subst.Renaming.create()inletsubst=US.substusinletmf1'=MF.apply_substrenamingsubst(mf1,0)inletmf2'=MF.apply_substrenamingsubst(mf2,0)inletis_max_lit=C.is_maxlit(c,0)subst~idxinUtil.debugf~section5"@[<4>... candidate:@ @[%a@] (max lit ? %B)@]"(funk->kS.ppsubstis_max_lit);ifis_max_lit&&MF.is_max~ordmf1'&&MF.is_max~ordmf2'then((* do the inference *)letlits'=CCArray.except_idx(C.litsc)idxinletlits'=Lit.apply_subst_listrenamingsubst(lits',0)inletnew_lit=Lit.mk_rat_opop(MF.restmf1')(MF.restmf2')inletc_guard=Literal.of_unif_substrenamingusinletall_lits=new_lit::c_guard@lits'inletproof=Proof.Step.inference~tags:[Proof.Tag.T_lra]~rule:(Proof.Rule.mk"cancellation")[C.proof_parent_substrenaming(c,0)subst]inlettrail=C.trailcinletpenalty=C.penaltycinletnew_c=C.create~trail~penaltyall_litsproofinUtil.debugf~section3"@[<2>cancellation@ of @[%a@]@ (with %a)@ into @[%a@]@]"(funk->kC.ppcSubst.ppsubstC.ppnew_c);Util.incr_statstat_rat_cancellation;new_c::acc)elseacc)acc)[]inUtil.exit_profprof_rat_cancellation;resletrule_canc_eq_fact=Proof.Rule.mk"rat_eq_factoring"letcanc_equality_factoringc=Util.enter_profprof_rat_eq_factoring;letord=Ctx.ord()inleteligible=C.Eligible.(maxc**filterLit.is_rat_eq)inletres=Lits.fold_rat_terms~which:`Max~eligible~ord(C.litsc)|>Iter.fold(funacc(t1,lit1,pos1)->assert(ALF.oplit1=AL.Equal);letidx1=Lits.Pos.idxpos1in(* lit1 is the factored literal *)Lits.fold_rat_terms~which:`Max~ord~eligible:C.Eligible.(filterLit.is_rat_eq)(C.litsc)|>Iter.fold(funacc(t2,lit2,pos2)->assert(ALF.oplit2=AL.Equal);letidx2=Lits.Pos.idxpos2inletmf1=ALF.focused_monomelit1andmf2=ALF.focused_monomelit2intryifidx1=idx2thenraiseUnif.Fail;(* exit *)letsubst=Unif.FO.unify_full(t1,0)(t2,0)inUtil.debugf~section5"@[<2>arith canc. eq. factoring:@ possible match in @[%a@]@ (at %d, %d)@]"(funk->kC.ppcidx1idx2);MF.unify_ff~subst(mf1,0)(mf2,0)|>Iter.fold(funacc(_,_,us)->letrenaming=Subst.Renaming.create()inletsubst=US.substusinletlit1'=ALF.apply_substrenamingsubst(lit1,0)inletlit2'=ALF.apply_substrenamingsubst(lit2,0)inifC.is_maxlit(c,0)subst~idx:idx1&&ALF.is_max~ordlit1'&&ALF.is_max~ordlit2'then((* lit1 is a.t + l1 = l2,
lit2 is a'.t + l1' = l2',
so we scale them, and replace lit1 with
a'.l1 + a.l2' != a'.l2 + a.l1' *)letlit1',lit2'=ALF.scalelit1'lit2'inletm1=ALF.opposite_monomelit1'andmf1=ALF.focused_monomelit1'andm2=ALF.opposite_monomelit2'andmf2=ALF.focused_monomelit2'in(* m1 != m2, translated as two ineqs *)letnew_lits=letx=M.summ1(MF.restmf2)inlety=M.summ2(MF.restmf1)in[Lit.mk_rat_lessxy;Lit.mk_rat_lessyx]inletother_lits=CCArray.except_idx(C.litsc)idx1inletother_lits=Lit.apply_subst_listrenamingsubst(other_lits,0)inletc_guard=Literal.of_unif_substrenamingusin(* apply subst and build clause *)letall_lits=c_guard@new_lits@other_litsinletproof=Proof.Step.inference~tags:[Proof.Tag.T_lra]~rule:rule_canc_eq_fact[C.proof_parent_substrenaming(c,0)subst]inletpenalty=C.penaltycandtrail=C.trailcinletnew_c=C.create~trail~penaltyall_litsproofinUtil.debugf~section5"@[<2>arith_eq_factoring:@ @[%a@]@ gives @[%a@]@]"(funk->kC.ppcC.ppnew_c);Util.incr_statstat_rat_eq_factoring;new_c::acc)elseacc)accwithUnif.Fail->acc)acc)[]inUtil.exit_profprof_rat_eq_factoring;res(** Data necessary to fully describe a chaining inference.
[left] is basically the clause/literal in which the chained
term is on the left of <,
[right] is the other one. *)moduleChainingInfo=structtypet={left:C.t;left_scope:int;left_pos:Position.t;left_lit:AL.Focus.t;right:C.t;right_scope:int;right_pos:Position.t;right_lit:AL.Focus.t;subst:US.t;}end(* range from low to low+len *)(* cancellative chaining *)let_do_chaininginfoacc=letopenChainingInfoinletord=Ctx.ord()inletrenaming=S.Renaming.create()inletus=info.substinletidx_l,_=Lits.Pos.cutinfo.left_posinletidx_r,_=Lits.Pos.cutinfo.right_posinlets_l=info.left_scopeands_r=info.right_scopeinletsubst=Unif_subst.substusinletlit_l=ALF.apply_substrenamingsubst(info.left_lit,s_l)inletlit_r=ALF.apply_substrenamingsubst(info.right_lit,s_r)inUtil.debugf~section5"@[<2>arith chaining@ between @[%a[%d]@]@ and @[%a[%d]@]@ (subst @[%a@])...@]"(funk->kC.ppinfo.lefts_lC.ppinfo.rights_rSubst.ppsubst);(* check ordering conditions *)ifC.is_maxlit(info.left,s_l)subst~idx:idx_l&&C.is_maxlit(info.right,s_r)subst~idx:idx_r&&ALF.is_max~ordlit_l&&ALF.is_max~ordlit_rthen((* scale literals *)letlit_l,lit_r=ALF.scalelit_llit_rinmatchlit_l,lit_rwith|ALF.Left(AL.Less,mf_1,m1),ALF.Right(AL.Less,m2,mf_2)->(* m2 ≤ mf_2 and mf_1 ≤ m1, with mf_1 and mf_2 sharing the same
focused term. We deduce m2 + mf_1 ≤ m1 + mf_2 and cancel the
term out (after scaling) *)assert(Q.equal(MF.coeffmf_1)(MF.coeffmf_2));letnew_lit=Lit.mk_rat_less(M.summ2(MF.restmf_1))(M.summ1(MF.restmf_2))inletlits_l=CCArray.except_idx(C.litsinfo.left)idx_linletlits_l=Lit.apply_subst_listrenamingsubst(lits_l,s_l)inletlits_r=CCArray.except_idx(C.litsinfo.right)idx_rinletlits_r=Lit.apply_subst_listrenamingsubst(lits_r,s_r)inletc_guard=Literal.of_unif_substrenamingusinletall_lits=new_lit::c_guard@lits_l@lits_rinletproof=Proof.Step.inference~tags:[Proof.Tag.T_lra]~rule:(Proof.Rule.mk"canc_ineq_chaining")[C.proof_parent_substrenaming(info.left,s_l)subst;C.proof_parent_substrenaming(info.right,s_r)subst]inlettrail=C.trail_l[info.left;info.right]in(* penalty for some chaining *)letpenalty=max(C.penaltyinfo.left)(C.penaltyinfo.right)+3(* nested chainings are dangerous *)+(ifMF.termmf_1|>T.is_varthen10else0)+(ifMF.termmf_2|>T.is_varthen10else0)inletnew_c=C.create~penalty~trailall_litsproofinUtil.debugf~section5"@[<2>ineq chaining@ of @[%a@]@ and @[%a@]@ gives @[%a@]@]"(funk->kC.ppinfo.leftC.ppinfo.rightC.ppnew_c);Util.incr_statstat_rat_ineq_chaining;new_c::acc|_->assertfalse)elseaccletcanc_ineq_chainingc=Util.enter_profprof_rat_ineq_chaining;letord=Ctx.ord()inleteligible=C.Eligible.(maxc**filterLit.is_rat_less)inletsc_l=0andsc_r=1inletres=Lits.fold_rat_terms~eligible~ord~which:`Max(C.litsc)|>Iter.fold(funacc(t,lit,pos)->matchlitwith|_whenT.is_vart->acc(* ignore variables *)|ALF.Left(AL.Less,mf_l,_)->(* find a right-chaining literal in some other clause *)PS.TermIndex.retrieve_unifiables(!_idx_ineq_right,sc_r)(t,sc_l)|>Iter.fold(funacc(_t',with_pos,subst)->letright=with_pos.C.WithPos.clauseinletright_pos=with_pos.C.WithPos.posinletlit_r=Lits.View.get_rat_exn(C.litsright)right_posinmatchlit_rwith|ALF.Right(AL.Less,_,mf_r)->MF.unify_ff~subst(mf_l,sc_l)(mf_r,sc_r)|>Iter.fold(funacc(_,_,subst)->letinfo=ChainingInfo.({left=c;left_scope=sc_l;left_lit=lit;left_pos=pos;right;right_scope=sc_r;right_lit=lit_r;right_pos;subst;})in_do_chaininginfoacc)acc|_->acc)acc|ALF.Right(AL.Less,_,mf_r)->(* find a right-chaining literal in some other clause *)PS.TermIndex.retrieve_unifiables(!_idx_ineq_left,sc_l)(t,sc_r)|>Iter.fold(funacc(_t',with_pos,subst)->letleft=with_pos.C.WithPos.clauseinletleft_pos=with_pos.C.WithPos.posinletlit_l=Lits.View.get_rat_exn(C.litsleft)left_posinmatchlit_lwith|ALF.Left(AL.Less,mf_l,_)->MF.unify_ff~subst(mf_l,sc_l)(mf_r,sc_r)|>Iter.fold(funacc(_,_,subst)->letinfo=ChainingInfo.({left;left_scope=sc_l;left_lit=lit_l;left_pos;subst;right=c;right_scope=sc_r;right_lit=lit;right_pos=pos;})in_do_chaininginfoacc)acc|_->acc)acc|_->assertfalse)[]inUtil.exit_profprof_rat_ineq_chaining;res(* TODO: update with equality case, check that signs correct *)letcanc_ineq_factoringc=Util.enter_profprof_rat_ineq_factoring;letord=Ctx.ord()inletacc=ref[]in(* do the factoring if ordering conditions are ok *)let_do_factoring~subst:uslit1lit2ij=letrenaming=S.Renaming.create()inletsubst=US.substusinletlit1=ALF.apply_substrenamingsubst(lit1,0)inletlit2=ALF.apply_substrenamingsubst(lit2,0)in(* same coefficient for the focused term *)letlit1,lit2=ALF.scalelit1lit2inmatchlit1,lit2with|ALF.Left(AL.Less,mf1,m1),ALF.Left(AL.Less,mf2,m2)|ALF.Right(AL.Less,m1,mf1),ALF.Right(AL.Less,m2,mf2)->(* mf1 ≤ m1 or mf2 ≤ m2 (symmetry with > if needed)
so we deduce that if m1-mf1.rest ≤ m2 - mf2.rest
then the first literal implies the second, so we only
keep the second one *)if(C.is_maxlit(c,0)subst~idx:i||C.is_maxlit(c,0)subst~idx:j)&&(ALF.is_max~ordlit1||ALF.is_max~ordlit2)then(letleft=matchlit1withALF.Left_->true|_->falsein(* remove lit1, add the guard *)letother_lits=CCArray.except_idx(C.litsc)iinletother_lits=Lit.apply_subst_listrenamingsubst(other_lits,0)in(* build new literal *)letnew_lit=ifleftthenLit.mk_rat_less(M.differencem1(MF.restmf1))(M.differencem2(MF.restmf2))elseLit.mk_rat_less(M.differencem2(MF.restmf2))(M.differencem1(MF.restmf1))in(* negate the literal to obtain a guard *)letnew_lit=Lit.negatenew_litinletc_guard=Literal.of_unif_substrenamingusinletlits=new_lit::c_guard@other_litsin(* build clauses *)letproof=Proof.Step.inference~tags:[Proof.Tag.T_lra]~rule:(Proof.Rule.mk"canc_ineq_factoring")[C.proof_parent_substrenaming(c,0)subst]inlettrail=C.trailcandpenalty=C.penaltycinletnew_c=C.create~trail~penaltylitsproofinUtil.debugf~section5"@[<2>ineq factoring@ of @[%a@]@ gives @[%a@]@"(funk->kC.ppcC.ppnew_c);Util.incr_statstat_rat_ineq_factoring;acc:=new_c::!acc)|_->()in(* traverse the clause to find matching pairs *)leteligible=C.Eligible.(maxc**filterLit.is_rat_less)inLits.fold_rat~eligible(C.litsc)|>Iter.iter(fun(lit1,pos1)->leti=Lits.Pos.idxpos1inleteligible'=C.Eligible.(filterLit.is_rat_less)inLits.fold_rat~eligible:eligible'(C.litsc)|>Iter.iter(fun(lit2,pos2)->letj=Lits.Pos.idxpos2inmatchlit1,lit2with|_wheni=j->()(* need distinct lits *)|{AL.op=AL.Less;left=l1;right=r1},{AL.op=AL.Less;left=l2;right=r2}->(* see whether we have l1 < a.x + mf1 and l2 < a.x + mf2 *)MF.unify_mm(r1,0)(r2,0)(fun(mf1,mf2,subst)->letlit1=ALF.mk_rightAL.Lessl1mf1inletlit2=ALF.mk_rightAL.Lessl2mf2in_do_factoring~substlit1lit2ij);(* see whether we have a.x + mf1 < r1 and a.x + mf2 < r2 *)MF.unify_mm(l1,0)(l2,0)(fun(mf1,mf2,subst)->letlit1=ALF.mk_leftAL.Lessmf1r1inletlit2=ALF.mk_leftAL.Lessmf2r2in_do_factoring~substlit1lit2ij);()|_->assertfalse));Util.exit_profprof_rat_ineq_factoring;!acc(** One-shot literal/clause removal.
We use unit clauses to try to prove a literal absurd/tautological, possibly
using {b several} instances of unit clauses.
For instance, 0 ≤ f(x) makes 0 ≤ f(a) + f(b) redundant, but subsumption
is not able to detect it. *)(* allow traces of depth at most 3 *)letmax_ineq_trivial_steps=3(* rewrite a literal [l] into a smaller literal [l'], such that [l'] and
the current set of unit clauses imply [l]; then compute the
transitive closure of this relation. If we obtain a trivial
literal, then [l] is redundant (we keep a trace of literals used).
We use continuations to deal with the multiple choices. *)letrec_ineq_find_sufficient~ord~traceclitk=matchlitwith|_whenAL.is_triviallit->k(trace,lit)|_whenList.lengthtrace>=max_ineq_trivial_steps->()(* need another step, but it would exceed the limit *)|{AL.op=AL.Less;_}whenIter.existsT.is_var(AL.Seq.termslit)->()(* no way we rewrite this into a tautology *)|{AL.op=AL.Less;_}->Util.incr_statstat_rat_trivial_ineq;Util.debugf~section5"(@[try_ineq_find_sufficient@ :lit `%a`@ :trace (@[%a@])@])"(funk->kAL.pplit(Util.pp_listC.pp)trace);AL.fold_terms~vars:false~which:`Max~ord~subterms:falselit|>Iter.iter(fun(t,pos)->letplit=ALF.get_exnlitposinletis_left=matchposwith|Position.Left_->true|Position.Right_->false|_->assertfalsein(* try to eliminate [t] in passive lit [plit]*)PS.TermIndex.retrieve_generalizations(!_idx_unit_ineq,1)(t,0)|>Iter.iter(fun(_t',with_pos,subst)->letactive_clause=with_pos.C.WithPos.clauseinletactive_pos=with_pos.C.WithPos.posinmatchLits.View.get_rat(C.litsactive_clause)active_poswith|None->assertfalse|Some(ALF.Left(AL.Less,_,_)asalit')whenis_left->letalit'=ALF.apply_substSubst.Renaming.nonesubst(alit',1)inifC.trail_subsumesactive_clausec&&ALF.is_strictly_max~ordalit'then((* scale *)letplit,_alit'=ALF.scaleplitalit'inletmf1',m2'=matchLits.View.get_rat(C.litsactive_clause)active_poswith|Some(ALF.Left(_,mf1',m2'))->mf1',m2'|_->assertfalseinletmf1'=MF.apply_substSubst.Renaming.nonesubst(mf1',1)inletm2'=M.apply_substSubst.Renaming.nonesubst(m2',1)in(* from t+mf1 ≤ m2 and t+mf1' ≤ m2', we deduce
that if m2'-mf1' ≤ m2-mf1 then [lit] is redundant.
That is, the sufficient literal is
mf1 + m2' ≤ m2 + mf1' (we replace [t] with [m2'-mf1']) *)letnew_plit=ALF.replaceplit(M.differencem2'(MF.restmf1'))in(* transitive closure *)lettrace=active_clause::tracein_ineq_find_sufficient~ord~tracecnew_plitk)|Some(ALF.Right(AL.Less,_,_)asalit')whennotis_left->(* symmetric case *)letalit'=ALF.apply_substSubst.Renaming.nonesubst(alit',1)inifC.trail_subsumesactive_clausec&&ALF.is_strictly_max~ordalit'then((* scale *)letplit,_alit'=ALF.scaleplitalit'inletm1',mf2'=matchLits.View.get_rat(C.litsactive_clause)active_poswith|Some(ALF.Right(_,m1',mf2'))->m1',mf2'|_->assertfalseinletmf2'=MF.apply_substSubst.Renaming.nonesubst(mf2',1)inletm1'=M.apply_substSubst.Renaming.nonesubst(m1',1)inletnew_plit=ALF.replaceplit(M.differencem1'(MF.restmf2'))in(* transitive closure *)lettrace=active_clause::tracein_ineq_find_sufficient~ord~tracecnew_plitk)|Some_->()(* cannot make a sufficient literal *)))|_->()(* is a literal redundant w.r.t the current set of unit clauses *)let_ineq_is_redundant_by_unitclit=matchlitwith|_whenLit.is_triviallit||Lit.is_absurdlit->None(* something more efficient will take care of it *)|Lit.Rat({AL.op=AL.Less;_}asalit)->letord=Ctx.ord()inlettraces=_ineq_find_sufficient~ord~trace:[]calit|>Iter.head(* one is enough *)inbeginmatchtraceswith|Some(trace,_lit')->assert(AL.is_trivial_lit');lettrace=CCList.uniq~eq:C.equaltraceinSometrace|None->Noneend|_->Noneletis_redundant_by_ineqc=Util.enter_profprof_rat_trivial_ineq;letres=CCArray.exists(funlit->match_ineq_is_redundant_by_unitclitwith|None->false|Sometrace->Util.debugf~section3"@[<2>clause @[%a@]@ trivial by inequations @[%a@]@]"(funk->kC.ppc(CCFormat.listC.pp)trace);Util.incr_statstat_rat_trivial_ineq_steps;true)(C.litsc)inUtil.exit_profprof_rat_trivial_ineq;res(* allow traces of depth at most 3 *)letmax_ineq_demod_steps=3(* rewrite a literal [l] into a smaller literal [l'], such that [l] and
the current set of unit clauses imply [l']; then compute the
transitive closure of this relation. If we obtain an absurd
literal, then [l] is absurd (we keep a trace of literals used).
We use continuations to deal with the multiple choices.
Each step looks like: from [l == (t <= u) && l' == (l <= t)]
we deduce [l <= u]. If at some point we deduce [⊥], we win. *)letrecineq_find_necessary_~ord~traceclitk=matchlitwith|_whenAL.is_absurdlit->k(trace,lit)|_whenList.lengthtrace>=max_ineq_demod_steps->()(* need another step, but it would exceed the limit *)|{AL.op=AL.Less;_}whenIter.existsT.is_var(AL.Seq.termslit)->()(* too costly (will match too many things) *)|{AL.op=AL.Less;_}->Util.incr_statstat_rat_demod_ineq;Util.debugf~section5"(@[try_ineq_find_necessary@ :lit `%a`@ :trace (@[%a@])@])"(funk->kAL.pplit(Util.pp_listC.pp)trace);AL.fold_terms~vars:false~which:`Max~ord~subterms:falselit|>Iter.iter(fun(t,pos)->letplit=ALF.get_exnlitposinletis_left=matchposwith|Position.Left_->true|Position.Right_->false|_->assertfalsein(* try to eliminate [t] in passive lit [plit]*)PS.TermIndex.retrieve_generalizations(!_idx_unit_ineq,1)(t,0)|>Iter.iter(fun(_t',with_pos,subst)->letactive_clause=with_pos.C.WithPos.clauseinletactive_pos=with_pos.C.WithPos.posinmatchLits.View.get_rat(C.litsactive_clause)active_poswith|None->assertfalse|Some(ALF.Left(AL.Less,_,_)asalit')whennotis_left->letalit'=ALF.apply_substSubst.Renaming.nonesubst(alit',1)inifC.trail_subsumesactive_clausec&&ALF.is_strictly_max~ordalit'then((* scale *)letplit,_alit'=ALF.scaleplitalit'inletmf1',m2'=matchLits.View.get_rat(C.litsactive_clause)active_poswith|Some(ALF.Left(_,mf1',m2'))->mf1',m2'|_->assertfalseinletmf1'=MF.apply_substSubst.Renaming.nonesubst(mf1',1)inletm2'=M.apply_substSubst.Renaming.nonesubst(m2',1)in(* from m1 ≤ t+mf2 and t+mf1' ≤ m2', we deduce
m1 + mf1' ≤ mf2 + m2'. If this literal is absurd
then so is [m1 ≤ t+mf2].
We replace [t] with [m2'-mf1'] *)letnew_plit=ALF.replaceplit(M.differencem2'(MF.restmf1'))in(* transitive closure *)lettrace=active_clause::traceinineq_find_necessary_~ord~tracecnew_plitk)|Some(ALF.Right(AL.Less,_,_)asalit')whenis_left->(* symmetric case *)letalit'=ALF.apply_substSubst.Renaming.nonesubst(alit',1)inifC.trail_subsumesactive_clausec&&ALF.is_strictly_max~ordalit'then((* scale *)letplit,_alit'=ALF.scaleplitalit'inletm1',mf2'=matchLits.View.get_rat(C.litsactive_clause)active_poswith|Some(ALF.Right(_,m1',mf2'))->m1',mf2'|_->assertfalseinletmf2'=MF.apply_substSubst.Renaming.nonesubst(mf2',1)inletm1'=M.apply_substSubst.Renaming.nonesubst(m1',1)inletnew_plit=ALF.replaceplit(M.differencem1'(MF.restmf2'))in(* transitive closure *)lettrace=active_clause::traceinineq_find_necessary_~ord~tracecnew_plitk)|Some_->()(* cannot make a sufficient literal *)))|_->()(* is a literal absurd w.r.t the current set of unit clauses *)let_ineq_is_absurd_by_unitclit=matchlitwith|_whenLit.is_triviallit||Lit.is_absurdlit->None(* something more efficient will take care of it *)|Lit.Rat({AL.op=AL.Less;_}asalit)->letord=Ctx.ord()inlettraces=ineq_find_necessary_~ord~trace:[]calit|>Iter.head(* one is enough *)inbeginmatchtraceswith|Some(trace,_lit')->assert(AL.is_absurd_lit');lettrace=CCList.uniq~eq:C.equaltraceinSometrace|None->Noneend|_->None(* demodulate using inequalities *)letdemod_ineqc:C.tSimplM.t=Util.enter_profprof_rat_demod_ineq;letres=CCArray.findi(funilit->match_ineq_is_absurd_by_unitclitwith|None->None|Sometrace->Util.debugf~section3"@[<2>clause @[%a@]@ rewritten by inequations @[%a@]@]"(funk->kC.ppc(CCFormat.listC.pp)trace);Util.incr_statstat_rat_demod_ineq_steps;Some(i,trace))(C.litsc)inletres=matchreswith|None->SimplM.return_samec|Some(i,cs)->letlits=CCArray.except_idx(C.litsc)iinletproof=Proof.Step.simp~tags:[Proof.Tag.T_lra]~rule:(Proof.Rule.mk"rat.demod_ineq")(C.proof_parentc::List.mapC.proof_parentcs)inletc'=C.createlitsproof~penalty:(C.penaltyc)~trail:(C.trailc)inSimplM.return_newc'inUtil.exit_profprof_rat_demod_ineq;res(** {3 Others} *)let_has_ratc=CCArray.existsLit.is_rat(C.litsc)moduleSimp=Simplex.MakeHelp(T)(* tautology check: take the linear system that is the negation
of all a≠b and a≤b, and check its satisfiability *)let_is_tautologyc=Util.enter_profprof_rat_semantic_tautology;(* convert a monome into a rational monome + Q constant *)letconvm=M.coeffsm,M.constmin(* create a list of constraints for some arith lits *)letconstraints=Lits.fold_rat~eligible:C.Eligible.arith(C.litsc)|>Iter.fold(funacc(lit,_)->(* negate the literal and make a constraint out of it *)matchlitwith|{AL.op=AL.Less;left=m1;right=m2}->(* m1 < m2 ----> m1-m2 > 0 ---> m1-m2 ≥ 0 by approx *)letm,c=conv(M.differencem1m2)in(Simp.GreaterEq,m,Q.negc)::acc|_->acc)[]inletsimplex=Simp.add_constraintsSimp.emptyconstraintsinUtil.exit_profprof_rat_semantic_tautology;matchSimp.ksolvesimplexwith|Simp.Unsatisfiable_->true(* negation unsatisfiable *)|Simp.Solution_->false(* cache the result because it's a bit expensive *)letis_tautologyc=ifC.get_flagflag_computed_tautocthenC.get_flagflag_tautocelse((* compute whether [c] is an arith tautology *)letres=_has_ratc&&_is_tautologycinC.set_flagflag_tautocres;C.set_flagflag_computed_tautoctrue;ifresthenUtil.debugf~section4"@[<2>clause@ @[%a@]@ is an arith tautology@]"(funk->kC.ppc);Util.incr_statstat_rat_semantic_tautology;res)(* look for negated literals *)letconvert_litc:C.tSimplM.t=lettype_okt=Type.equalType.rat(T.tyt)inletopenCCOpt.Infixinletconv_litilit=matchlitwith|Lit.Equation(l,r,false)whentype_okl->Monome.Rat.of_terml>>=funm1->Monome.Rat.of_termr>|=funm2->i,[Lit.mk_rat_lessm1m2;Lit.mk_rat_lessm2m1]|Equation(lhs,rhs,true)whenT.equalrhsT.true_||T.equalrhsT.false_->beginmatchT.viewlhs,T.equalrhsT.true_with|T.AppBuiltin(Builtin.Less,[_;l;r]),falsewhentype_okl->Monome.Rat.of_terml>>=funm1->Monome.Rat.of_termr>|=funm2->(* ¬(l<r) --> l=r ∨ r<l *)i,[Lit.mk_rat_eqm1m2;Lit.mk_rat_lessm2m1]|T.AppBuiltin(Builtin.Less,[_;l;r]),truewhentype_okl->Monome.Rat.of_terml>>=funm1->Monome.Rat.of_termr>|=funm2->i,[Lit.mk_rat_lessm1m2]|T.AppBuiltin(Builtin.Lesseq,[_;l;r]),truewhentype_okl->Monome.Rat.of_terml>>=funm1->Monome.Rat.of_termr>|=funm2->(* l≤r --> l=r ∨ l<r *)i,[Lit.mk_rat_eqm1m2;Lit.mk_rat_lessm1m2]|T.AppBuiltin(Builtin.Lesseq,[_;l;r]),falsewhentype_okl->Monome.Rat.of_terml>>=funm1->Monome.Rat.of_termr>|=funm2->(* ¬(l≤r) --> r<l *)i,[Lit.mk_rat_lessm2m1]|T.AppBuiltin(Builtin.Eq,[_;l;r]),truewhentype_okl->Monome.Rat.of_terml>>=funm1->Monome.Rat.of_termr>|=funm2->i,[Lit.mk_rat_eqm1m2]|T.AppBuiltin(Builtin.Eq,[_;l;r]),falsewhentype_okl->Monome.Rat.of_terml>>=funm1->Monome.Rat.of_termr>|=funm2->(* ¬(l=r) --> l<r ∨ r<l *)i,[Lit.mk_rat_lessm1m2;Lit.mk_rat_lessm2m1]|_->Noneend|_->NoneinbeginmatchCCArray.findiconv_lit(C.litsc)with|None->SimplM.return_samec|Some(i,new_lits)->letlits=new_lits@CCArray.except_idx(C.litsc)iandproof=Proof.Step.simp~tags:[Proof.Tag.T_lra]~rule:(Proof.Rule.mk"convert_lit")[C.proof_parentc]inletc'=C.create~trail:(C.trailc)~penalty:(C.penaltyc)litsproofinUtil.debugf~section5"(@[convert@ :from %a@ :to %a@])"(funk->kC.ppcC.ppc');SimplM.return_newc'end(** {6 Variable Elimination Procedure} *)letunshielded_varslits=Literals.unshielded_varslits~filter:(funvar->Type.equal(HVar.tyvar)Type.rat)let_negate_lits=List.mapLit.negatemoduleElim_var=structtypet={var:T.var;lower:Q.tM.tlist;(* monomes smaller than x *)upper:Q.tM.tlist;(* monomes bigger than x *)eq:Q.tM.tlist;(* monomes equal to x *)side_lits:Literal.tlist;(* other literals *)initial_lits:Literals.t;}letppout(e:t)=letpp_m=CCFormat.within"`""`"M.ppinletpp_m_loutl=Format.fprintfout"(@[<hv>%a@])"(Util.pp_list~sep:" "pp_m)linFormat.fprintfout"(@[<v>:var %a@ :lower %a@ :upper %a@ :eq %a@ :side (@[%a@])@])"T.pp_vare.varpp_m_le.lowerpp_m_le.upperpp_m_le.eq(Util.pp_list~sep:" "Literal.pp)e.side_lits(* quick and dirty CNF *)moduleForm=structtypeform=|AtomofLiteral.t|Andofformlist|Orofformlist|True|Falseletatoml=Atomlletor_=function[]->False|[t]->t|l->Orlletand_=function[]->True|[t]->t|l->Andlletreccnf(f:form):Lit.tlistlist=matchfwith|Atomlit->[[lit]]|True->[[Lit.mk_tauto]]|False->[[Lit.mk_absurd]]|And[]|Or[]->assertfalse|And[f]|Or[f]->cnff|Andl->CCList.flat_mapcnfl|Orl->Util.map_product~f:cnflletrecppout(f:form):unit=matchfwith|True->CCFormat.stringout"⊤"|False->CCFormat.stringout"⊥"|Atomlit->Lit.ppoutlit|Orl->Format.fprintfout"(@[<hv>or@ %a@])"(Util.pp_list~sep:" "pp)l|Andl->Format.fprintfout"(@[<hv>and@ %a@])"(Util.pp_list~sep:" "pp)lend(* variable elimination. First, build formula; then perform CNF. *)letto_clauses(e:t):Literal.tlistlist=(* let i range over e.eq
j range over e.lower
k range over e.upper.
produce:
[∨_j ∨_k (m_j < m_k ∨ ∨_i (m_i = m_j ∧ m_i = m_k))]
*)letform_l=letopenCCList.Infixine.lower>>=funm_j->e.upper>>=funm_k->letf_diseq=Form.atom(Lit.mk_rat_lessm_jm_k)inletf_eq=e.eq>|=funm_i->Form.and_[Form.atom(Lit.mk_rat_eqm_im_j);Form.atom(Lit.mk_rat_eqm_im_k);]inCCList.return(Form.or_(f_diseq::f_eq))inletform=Form.or_form_linUtil.debugf~section5"(@[<2>elim_var_non_cnf :var %a@ :clause %a@ :state %a@ :form %a@])"(funk->kT.pp_vare.varLits.ppe.initial_litsppeForm.ppform);beginForm.cnfform|>List.rev_map(funlits->List.rev_appende.side_litslits)endexceptionMake_err(* builder *)letmake_exn(lits:Literals.t)(x:T.var):t=assert(not(Literals.is_shieldedxlits));(* gather literals *)letlower=ref[]inletupper=ref[]inleteq=ref[]inletside=ref[]inletpush_l=CCList.Ref.pushinlett_x=T.varxinArray.iter(funlit->matchlitwith|Lit.Rat{Rat_lit.op;left=m1;right=m2}->beginmatchM.findm1t_x,M.findm2t_xwith|None,None->push_lsidelit|Some_,Some_->raiseMake_err(* cancellations are possible *)|Somec1,None->letm=M.Rat.divide(M.differencem2(M.removem1t_x))c1inbeginmatchopwith|Rat_lit.Equal->push_leqm|Rat_lit.Less->push_luppermend|None,Somec2->letm=M.Rat.divide(M.differencem1(M.removem2t_x))c2inbeginmatchopwith|Rat_lit.Equal->push_leqm|Rat_lit.Less->push_llowermendend|Lit.Equation(t,u,true)whenT.equaltt_x->push_leq(M.Rat.singletonQ.oneu)|Lit.Equation(t,u,true)whenT.equalut_x->push_leq(M.Rat.singletonQ.onet)|Lit.Equation(t,_,false)whenT.equaltt_x->raiseMake_err|Lit.Equation(_,u,false)whenT.equalut_x->raiseMake_err|_->assert(not(Lit.var_occursxlit));(* shielding *)push_lsidelit)lits;{var=x;lower=!lower;upper=!upper;eq=!eq;side_lits=!side;initial_lits=lits;}letmakelitsx:toption=trySome(make_exnlitsx)withMake_err->Noneendleteliminate_unshielded(c:C.t):C.tlistoption=letmoduleE=Elim_varinletnvars=unshielded_vars(C.litsc)inbeginmatchnvarswith|[]->None|x::_->beginmatchE.make(C.litsc)xwith|None->None|Somee->letclauses=E.to_clauseseinletproof=Proof.Step.simp[C.proof_parentc]~tags:[Proof.Tag.T_lra]~rule:(Proof.Rule.mkf"elim_var(%a)"T.pp_varx)inletnew_c=List.map(funlits->C.createlitsproof~penalty:(C.penaltyc)~trail:(C.trailc))clausesinUtil.debugf~section4"(@[<2>elim_var :var %a@ :clause %a@ :yields (@[<hv>%a@])@]@)"(funk->kT.pp_varxC.ppc(Util.pp_listC.pp)new_c);Somenew_cendend(** {2 Setup} *)(* print index into file *)let_print_idxfileidx=CCIO.with_outfile(funoc->letpp_leaf__=()inletout=Format.formatter_of_out_channelocinFormat.fprintfout"@[<2>%a@]@."(PS.TermIndex.to_dotpp_leaf)idx;flushoc)letsetup_dot_printers()=CCOpt.iter(funf->Signal.onceSignals.on_dot_output(fun()->_print_idxf!_idx_unit_eq))!dot_unit_;()letregister()=Util.debug~section2"rat-arith: setup env";(* add inference rules *)Env.add_binary_inf"rat_sup_active"canc_sup_active;Env.add_binary_inf"rat_sup_passive"canc_sup_passive;Env.add_unary_inf"rat_cancellation"cancellation;Env.add_unary_inf"rat_eq_factoring"canc_equality_factoring;Env.add_binary_inf"rat_ineq_chaining"canc_ineq_chaining;Env.add_unary_inf"rat_ineq_factoring"canc_ineq_factoring;Env.add_multi_simpl_ruleeliminate_unshielded;Env.add_unary_simplifycanc_demodulation;Env.add_backward_simplifycanc_backward_demodulation;Env.add_is_trivialis_tautology;Env.add_unary_simplifyconvert_lit;if!enable_trivial_ineq_then(Env.add_redundantis_redundant_by_ineq;);if!enable_demod_ineq_then(Env.add_active_simplifydemod_ineq;);Env.add_multi_simpl_ruleeliminate_unshielded;(* completeness? I don't think so *)Ctx.lost_completeness();(* enable AC-property of sum *)(* FIXME: currently AC doesn't handle builtins
if !_enable_ac then begin
let sum = ID.Arith.sum in
let ty = Signature.find_exn Signature.TPTP.Arith.full sum in
let module A = Env.flex_get AC.key_ac in
A.add sum ty;
end;
*)setup_dot_printers();()endletk_should_register=Flex_state.create_key()letk_has_rat=Flex_state.create_key()letextension=letenv_actionenv=letmoduleE=(valenv:Env.S)inifE.flex_getk_should_registerthen(letmoduleI=Make(E)inI.register())elseifE.flex_getk_has_ratthen((* arith not enabled, so we cannot solve the problem, do not answer "sat" *)E.Ctx.lost_completeness();)andpost_typing_actionstmtsstate=letmodulePT=TypedSTerminlethas_rat=CCVector.to_seqstmts|>Iter.flat_mapStmt.Seq.to_seq|>Iter.flat_map(function|`ID_->Iter.empty|`Tyty->Iter.returnty|`Formt|`Termt->PT.Seq.subtermst|>Iter.filter_mapPT.ty)|>Iter.exists(PT.Ty.equalPT.Ty.rat)inletshould_reg=!enable_rat_&&has_ratinUtil.debugf~section2"decision to register rat-arith: %B"(funk->kshould_reg);state|>Flex_state.addk_should_registershould_reg|>Flex_state.addk_has_rathas_ratin{Extensions.defaultwithExtensions.name="arith_rat";post_typing_actions=[post_typing_action];env_actions=[env_action];}let()=Params.add_opts["--rat-no-semantic-tauto",Arg.Clearenable_semantic_tauto_," disable rational arithmetic semantic tautology check";"--rat-arith",Arg.Setenable_rat_," enable axiomatic rational arithmetic";"--no-arith",Arg.Clearenable_rat_," disable axiomatic rational arithmetic";"--rat-ac",Arg.Setenable_ac_," enable AC axioms for rational arithmetic (sum)";"--dot-rat-unit",Arg.String(funs->dot_unit_:=Somes)," print arith-rat-unit index into file"];()