123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443(* This file is free software, part of Zipperposition. See file "license" for more details. *)(** {1 Rewriting} *)openLogtkopenLibzipperpositionmoduleT=TermmoduleRW=RewritemoduleP=Positionletsection=RW.sectionletstat_narrowing_lit=Util.mk_stat"narrow.lit_steps"letstat_narrowing_term=Util.mk_stat"narrow.term_steps"letstat_ctx_narrowing=Util.mk_stat"narrow.ctx_narrow_steps"letprof_narrowing_term=ZProf.make"narrow.term"letprof_narrowing_lit=ZProf.make"narrow.lit"letprof_ctx_narrowing=ZProf.make"narrow.ctx_narrow"letmax_steps=500letrewrite_before_cnf=reffalsemoduleKey=structlethas_rw=Flex_state.create_key()letctx_narrow=Flex_state.create_key()letnarrow=Flex_state.create_key()endletsimpl_termt=lett',rules=RW.Term.normalize_term~max_stepstinifT.equaltt'then(assert(RW.Term.Rule_inst_set.is_emptyrules);None)else(letproof=RW.Rule.set_as_proof_parentsrulesinUtil.debugf~section3"@[<2>@{<green> simpl rewrite@} `@[%a@]`@ :into `@[%a@]`@ :using %a@]"(funk->kT.pptT.ppt'RW.Term.Rule_inst_set.pprules);Some(t',proof))moduleMake(E:Env_intf.S)=structmoduleEnv=EmoduleC=E.C(* simplification rule *)(* perform term narrowing in [c] *)letnarrow_term_passive_c:C.tlist=leteligible=C.Eligible.(resc)inletsc_rule=1inletsc_c=0inLiterals.fold_terms~vars:false~subterms:true~ty_args:false~ord:(C.Ctx.ord())~which:`All~eligible(C.litsc)|>Iter.flat_map(fun(u_p,passive_pos)->RW.Term.narrow_term~scope_rules:sc_rule(u_p,sc_c)|>Iter.filter_map(fun(rule,us)->letrenaming=Subst.Renaming.create()inletsubst=Unif_subst.substusinletc_guard=Literal.of_unif_substrenamingusin(* side literals *)letlits_passive=C.litscinletlits'=Literals.apply_substrenamingsubst(lits_passive,sc_c)in(* substitute in rule *)letrhs=Subst.FO.applyrenamingsubst(RW.Term.Rule.rhsrule,sc_rule)in(* literal in which narrowing took place: replace lhs by rhs *)Literals.Pos.replacelits'~at:passive_pos~by:rhs;(* make new clause *)Util.incr_statstat_narrowing_term;letproof=Proof.Step.inference[C.proof_parent_substrenaming(c,sc_c)subst;Proof.Parent.from_substrenaming(RW.Rule.as_proof(RW.T_rulerule),sc_rule)subst]~rule:(Proof.Rule.mk"narrow")inletc'=C.create~trail:(C.trailc)~penalty:(C.penaltyc)(c_guard@CCArray.to_listlits')proofinUtil.debugf~section3"@[<2>term narrowing:@ from `@[%a@]`@ to `@[%a@]`@ \
using rule `%a`@ and subst @[%a@]@]"(funk->kC.ppcC.ppc'RW.Term.Rule.ppruleUnif_subst.ppus);Somec'))|>Iter.to_rev_listletnarrow_term_passive=ZProf.with_profprof_narrowing_termnarrow_term_passive_(* XXX: for now, we only do one step, and let Env.multi_simplify
manage the fixpoint *)letsimpl_clausec=letlits=C.litscinmatchRW.Lit.normalize_clauselitswith|None->None|Some(clauses,r,subst,sc_r,renaming,tags)->letproof=Proof.Step.simp~rule:(Proof.Rule.mk"rw_clause")~tags[C.proof_parent_substrenaming(c,0)subst;RW.Rule.lit_as_proof_parent_substrenamingsubst(r,sc_r)]inletclauses=List.map(func'->C.create_a~trail:(C.trailc)~penalty:(C.penaltyc)c'proof)clausesinUtil.debugf~section2"@[<2>@{<green>rewrite@} `@[%a@]`@ into `@[<v>%a@]`@]"(funk->kC.ppc(Util.pp_listC.pp)clauses);Someclauses(* narrowing on literals of given clause, using lits rewrite rules *)letnarrow_lits_c=leteligible=C.Eligible.rescinletlits=C.litscinLiterals.fold_lits~eligiblelits|>Iter.fold(funacc(lit,i)->RW.Lit.narrow_lit~scope_rules:1(lit,0)|>Iter.fold(funacc(rule,us,tags)->letsubst=Unif_subst.substusinletrenaming=Subst.Renaming.create()inletc_guard=Literal.of_unif_substrenamingusinletproof=Proof.Step.inference[C.proof_parent_substrenaming(c,0)subst;Proof.Parent.from_substrenaming(RW.Rule.as_proof(RW.L_rulerule),1)subst]~rule:(Proof.Rule.mk"narrow_clause")~tagsinletlits'=CCArray.except_idxlitsiin(* create new clauses that correspond to replacing [lit]
by [rule.rhs] *)letclauses=List.map(func'->letnew_lits=c_guard@Literal.apply_subst_listrenamingsubst(lits',0)@Literal.apply_subst_listrenamingsubst(c',1)inC.create~trail:(C.trailc)~penalty:(C.penaltyc)new_litsproof)(RW.Lit.Rule.rhsrule)inUtil.debugf~section3"@[<2>narrowing of `@[%a@]`@ using `@[%a@]`@ with @[%a@]@ yields @[%a@]@]"(funk->kC.ppcRW.Lit.Rule.ppruleUnif_subst.ppusCCFormat.(list(hovboxC.pp))clauses);Util.incr_statstat_narrowing_lit;List.rev_appendclausesacc)acc)[]letnarrow_litslits=ZProf.with_profprof_narrowing_litnarrow_lits_lits(* find positions in rules' LHS *)letctx_narrow_find(s,sc_a)sc_p:(RW.Rule.t*Position.t*Unif_subst.t)Iter.t=letfind_term(r:RW.Term.rule)=lett=RW.Term.Rule.lhsrinT.all_positions~vars:false~pos:P.stop~ty_args:falset|>Iter.filter(fun(_,p)->not(P.equalpP.stop))(* not root *)|>Iter.filter(fun(t,_)->matchT.Classic.viewtwith|T.Classic.App(id,_)->not(Ind_ty.is_constructorid)|T.Classic.Var_|T.Classic.DB_|T.Classic.AppBuiltin(_,_)|T.Classic.NonFO->false)|>Iter.filter_map(fun(t,p)->tryletsubst=Unif.FO.unify_full(s,sc_a)(t,sc_p)inSome(RW.T_ruler,p,subst)withUnif.Fail->None)andfind_lit(r:RW.Lit.rule)=letlit=RW.Lit.Rule.lhsrinLiteral.fold_termslit~position:P.stop~vars:false~ty_args:false~which:`All~ord:(E.Ctx.ord())~subterms:true|>Iter.filter_map(fun(t,p)->matchpwith|P.LeftP.Stop->None(* not root *)|_->tryletsubst=Unif.FO.unify_full(s,sc_a)(t,sc_p)inSome(RW.L_ruler,p,subst)withUnif.Fail->None)inRewrite.all_rules|>Iter.flat_map(function|RW.T_ruler->find_termr|RW.L_ruler->find_litr)(* do narrowing with [s=t], a literal in [c], and add results to [acc] *)letctx_narrow_with~ordsts_poscacc:C.tlist=letsc_a=1andsc_p=0in(* do narrowing inside this rule? *)letdo_narrowingrulerule_pos(us:Unif_subst.t)=letrule_clauses=matchrulewith|RW.T_ruler->[[|RW.Term.Rule.as_litr|]]|RW.L_ruler->RW.Lit.Rule.as_clausesrinletrenaming=Subst.Renaming.create()inletsubst=Unif_subst.substusinletc_guard=Literal.of_unif_substrenamingusinlets'=Subst.FO.applyrenamingsubst(s,sc_a)inlett'=Subst.FO.applyrenamingsubst(t,sc_a)inifOrdering.compareords't'<>Comparison.Ltthen(Util.incr_statstat_ctx_narrowing;rule_clauses|>List.map(funrule_clause->(* instantiate rule and replace [s'] by [t'] now *)letnew_lits=Literals.apply_substrenamingsubst(rule_clause,sc_p)|>Literals.map(T.replace~old:s'~by:t')|>Array.to_listin(* also instantiate context literals in [c] *)letidx_active=matchs_poswith|P.Arg(n,_)->n|_->assertfalseinletctx=Literal.apply_subst_listrenamingsubst(CCArray.except_idx(C.litsc)idx_active,sc_a)in(* build new clause *)letproof=Proof.Step.inference~rule:(Proof.Rule.mk"contextual_narrowing")[C.proof_parent_substrenaming(c,sc_a)subst;Proof.Parent.from_substrenaming(RW.Rule.as_proofrule,sc_p)subst]in(* add some penalty on every inference *)letpenalty=Array.length(C.litsc)+C.penaltycinletnew_c=C.create(c_guard@new_lits@ctx)proof~trail:(C.trailc)~penaltyinUtil.debugf~section4"(@[<2>ctx_narrow@ :rule %a[%d]@ :clause %a[%d]@ :pos %a@ :subst %a@ :yield %a@])"(funk->kRW.Rule.pprulesc_pC.ppcsc_aP.pprule_posSubst.ppsubstC.ppnew_c);new_c)|>CCOpt.return)elseNoneinctx_narrow_find(s,sc_a)sc_p|>Iter.fold(funacc(rule,rule_pos,subst)->matchdo_narrowingrulerule_possubstwith|None->acc|Somecs->cs@acc)accletcontextual_narrowing_c:C.tlist=(* no literal can be eligible for paramodulation if some are selected.
This checks if inferences with i-th literal are needed? *)leteligible=C.Eligible.paramcinletord=E.Ctx.ord()in(* do the inferences where clause is active; for this,
we try to rewrite conditionally other clauses using
non-minimal sides of every positive literal *)letnew_clauses=Literals.fold_eqn~sign:true~ord~both:true~eligible(C.litsc)|>Iter.fold(funacc(s,t,_,s_pos)->(* rewrite clauses using s *)ctx_narrow_with~ordsts_poscacc)[]innew_clausesletcontextual_narrowingc=ZProf.with_profprof_ctx_narrowingcontextual_narrowing_cletsetup?(ctx_narrow=true)~narrowing~has_rw()=Util.debug~section1"register Rewriting to Env...";E.add_rewrite_rule"rewrite_defs"simpl_term;ifnarrowingthen(E.add_binary_inf"narrow_term_defs"narrow_term_passive;E.add_unary_inf"narrow_lit_defs"narrow_lits);ifctx_narrowthen(E.add_binary_inf"ctx_narrow"contextual_narrowing;);ifhas_rwthenE.Ctx.lost_completeness();E.add_multi_simpl_rule~priority:5simpl_clause;()endletctx_narrow_=reftrueletnarrowing=reftrueletpost_cnfstmtsst=CCVector.iterStatement.scan_stmt_for_defined_cst(ifnot!rewrite_before_cnfthenstmtselse(CCVector.filter(funst->matchStatement.viewstwith|Statement.Rewrite_->false|_->true)stmts));(* check if there are rewrite rules *)lethas_rw=CCVector.to_iterstmts|>Iter.exists(funst->matchStatement.viewstwith|Statement.Rewrite_|Statement.Def_->true|_->false)inst|>Flex_state.addKey.has_rwhas_rw(* let post_typing stmts state =
*)letrewrite_tst_stmtstmt=letauxf=letctx=Type.Conv.create()inlett=Term.Conv.of_simple_term_exnctxfinletsnf=Lambda.snfinCCOpt.map(fun(t',p)->(Term.Conv.to_simple_termctx(snft'),p))(simpl_termt)inletaux_lfs=letts=List.mapauxfsinifList.for_allCCOpt.is_nonetsthenNoneelse(letproof=ref[]inletcombined=CCList.combinefstsinletres=List.map(fun(f,res)->letf',p_list=CCOpt.get_or~default:(f,[])resinproof:=p_list@!proof;f')combinedinSome(res,!proof))inletmk_proof~stmt_parentsf_optorig=CCOpt.map(fun(f',parent_list)->letrule=Proof.Rule.mk"definition expansion"inf',Proof.S.mk_f_simp~ruleorig(parent_list@stmt_parents))f_optinletstmt_parents=[Proof.Parent.from@@Statement.as_proof_istmt]inmatchStatement.viewstmtwith|Assertf->(matchmk_proof~stmt_parents(auxf)fwith|Some(f',proof)->Statement.assert_~proof:(Proof.S.stepproof)f'|None->stmt)|Lemmafs->beginmatchaux_lfswith|Some(fs',parents)->letrule=Proof.Rule.mk"definition expansion"inletfs_parents=(List.map(funf->Proof.Parent.from(Proof.S.mk_f_esa~rulefstmt_parents))fs)@parentsinletproof=Proof.Step.simp~rulefs_parentsinStatement.lemma~prooffs'|None->stmtend|Goalg->(matchmk_proof~stmt_parents(auxg)gwith|Some(g',proof)->Statement.goal~proof:(Proof.S.stepproof)g'|None->stmt)|NegatedGoal(skolems,ngs)->beginmatchaux_lngswith|Some(ng',parents)->letrule=Proof.Rule.mk"definition expansion"inletng_parents=(List.map(funf->Proof.Parent.from(Proof.S.mk_f_esa~rulefstmt_parents))ngs)@parentsinletproof=Proof.Step.simp~ruleng_parentsinStatement.neg_goal~skolems~proofng'|None->stmtend|_->stmtletunfold_def_before_cnfstmts=if!rewrite_before_cnfthen(letcnt=ref0inCCVector.map(funstmt->incrcnt;letres=rewrite_tst_stmtstmtinUtil.debugf~section1"rewriting @[%a@]:@. @[%a@]@."(funk->kStatement.pp_inputstmtStatement.pp_inputres);res)stmts)elsestmtsletpost_tyingstmtsst=if!rewrite_before_cnfthen(CCVector.iterStatement.scan_tst_rewritestmts;lethas_rw=CCVector.to_iterstmts|>Iter.exists(funst->matchStatement.viewstwith|Statement.Rewrite_->true|_->false)inFlex_state.addKey.has_rwhas_rwst)elsest(* add a term simplification that normalizes terms w.r.t the set of rules *)letnormalize_simpl(moduleE:Env_intf.S)=letmoduleM=Make(E)inlethas_rw=E.flex_getKey.has_rwinE.flex_addKey.ctx_narrow!ctx_narrow_;E.flex_addKey.narrow!narrowing;M.setup~has_rw~narrowing:!narrowing~ctx_narrow:!ctx_narrow_()letextension=letopenExtensionsin{defaultwithname="rewriting";post_typing_actions=[post_tying];post_cnf_actions=[post_cnf];env_actions=[normalize_simpl];}let()=Options.add_opts["--rw-ctx-narrow",Arg.Setctx_narrow_," enable contextual narrowing";"--no-rw-ctx-narrow",Arg.Clearctx_narrow_," disable contextual narrowing";"--rewrite-before-cnf",Arg.Bool(funv->rewrite_before_cnf:=v)," enable/disable rewriting before CNF"];Params.add_to_modes["ho-complete-basic";"ho-pragmatic";"ho-competitive";"fo-complete-basic";"lambda-free-intensional";"lambda-free-extensional";"ho-comb-complete";"lambda-free-purify-intensional";"lambda-free-purify-extensional"](fun()->narrowing:=false;ctx_narrow_:=false;);