123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355(* This file is free software, part of Logtk. See file "license" for more details. *)(** {1 Skolem symbols} *)moduleT=TypedSTermmoduleStmt=StatementmoduleFmt=CCFormattypetype_=TypedSTerm.ttypeterm=TypedSTerm.ttypeform=TypedSTerm.tletsection=Util.Section.(make"skolem")typepolarity=[`Pos|`Neg|`Both]letpp_polarityout=function|`Pos->CCFormat.stringout"+"|`Neg->CCFormat.stringout"-"|`Both->CCFormat.stringout"+/-"typeform_definition={form:form;proxy_id:ID.t;(* name *)(* the defined object *)proxy:term;(* atom/term standing for the defined object *)proxy_ty:type_;(* type of [proxy_id] *)rw_rules:bool;(* do we add the add rules
[proxy -> true if form]
[proxy -> false if not form] (depending on polarity) *)polarity:polarity;proof:Proof.step;(* source for this definition *)as_stmt:Statement.input_tlistlazy_t;}typeterm_definition={td_id:ID.t;td_ty:type_;td_rules:(form,term,type_)Statement.def_rulelist;td_as_def:(form,term,type_)Statement.def;td_proof:Proof.step;td_stmt:Statement.input_tlistlazy_t;}typedefinition=|Def_formofform_definition|Def_termofterm_definitiontypectx={sc_prefix:string;sc_prop_prefix:string;mutablesc_counter:int;mutablesc_gensym:(string,int)Hashtbl.t;(* prefix -> count *)mutablesc_new_defs:definitionlist;(* "new" definitions *)mutablesc_new_ids:(ID.t*type_)list;(* "new" symbols *)sc_on_new:ID.t->type_->unit;}letcreate?(prefix="zip_sk_")?(prop_prefix="zip_prop")?(on_new=fun__->())()=letctx={sc_prefix=prefix;sc_prop_prefix=prop_prefix;sc_counter=0;sc_new_defs=[];sc_gensym=Hashtbl.create16;sc_new_ids=[];sc_on_new=on_new;}inctxletincr_counterctx=ctx.sc_counter<-ctx.sc_counter+1letfresh_id?(start0=false)~ctxprefix=letn=CCHashtbl.get_or~default:0ctx.sc_gensymprefixinHashtbl.replacectx.sc_gensymprefix(n+1);letname=ifn=0&¬start0thenprefixelseprefix^"_"^string_of_intninID.makenameletfresh_skolem_prefix~ctx~typrefix=incr_counterctx;lets=fresh_id~ctxprefixinletkind=ifInd_ty.is_inductive_simple_typetythenID.K_indelseID.K_normalinID.set_payloads(ID.Attr_skolemkind);ctx.sc_new_ids<-(s,ty)::ctx.sc_new_ids;ctx.sc_on_newsty;Util.debugf~section3"@[<2>new skolem symbol `%a`@ with type `@[%a@]`@]"(funk->kID.ppsT.ppty);sletfresh_skolem~ctx~ty=fresh_skolem_prefix~ctx~tyctx.sc_prefixletcollect_varssubstf=(* traverse [t] and return free variables, dereferencing on the fly *)letrecvars_seqt=T.Seq.free_varst|>Iter.flat_map(funv->matchVar.Subst.findsubstvwith|None->Iter.return(Var.update_ty~f:(T.Subst.evalsubst)v)|Somet'->vars_seqt')inletis_ty_varv=T.Ty.is_tType(Var.tyv)invars_seqf|>Var.Set.of_iter|>Var.Set.to_list|>List.partitionis_ty_varletty_forall?locvty=ifT.Ty.is_tType(Var.tyv)&&T.Ty.returns_tTypetythenT.Ty.fun_?loc[T.Ty.tType]ty(* [forall v:type. t] becomes [type -> t] *)elseT.Ty.forall?locvtyletty_forall_l=List.fold_rightty_forallletskolem_form~ctxsubstvarform=incr_counterctx;lettyvars,vars=collect_varssubstforminUtil.debugf~section5"@[<2>creating skolem for@ `@[%a@]`@ with tyvars=[@[%a@]],@ vars=[@[%a@]],@ subst={@[%a@]}@]"(funk->kT.ppform(Util.pp_listVar.pp_full)tyvars(Util.pp_listVar.pp_full)vars(Var.Subst.ppT.pp)subst);lettyvars_t=List.map(funv->T.Ty.varv)tyvarsinletvars_t=List.map(funv->T.varv|>T.Subst.evalsubst)varsin(* type of the symbol: quantify over type vars, apply to vars' types *)letty_var=T.Subst.evalsubst(Var.tyvar)inletty=ty_forall_ltyvars(T.Ty.fun_(List.mapVar.tyvars)ty_var)inletprefix="sk_"inletf=fresh_skolem_prefix~ctx~typrefixinletskolem_t=T.app~ty:ty_var(T.const~tyf)(tyvars_t@vars_t)inT.Subst.evalsubstskolem_tletpop_new_skolem_symbols~ctx=letl=ctx.sc_new_idsinctx.sc_new_ids<-[];lletcounterctx=ctx.sc_counter(** {2 Definitions} *)letpp_form_definitionoutdef=Format.fprintfout"(@[<hv>def %a@ for: %a@ rw_rules: %B@ polarity: %a@])"T.ppdef.proxyT.ppdef.formdef.rw_rulespp_polaritydef.polarityletpp_term_definitionoutdef=letpp_ruleoutr=Stmt.pp_def_ruleT.ppT.ppT.ppoutrinFormat.fprintfout"(@[<hv>def_term `%a : %a`@ rules: (@[<hv>%a@])@])"ID.ppdef.td_idT.ppdef.td_ty(Util.pp_listpp_rule)def.td_rulesletpp_definitionout=function|Def_formf->pp_form_definitionoutf|Def_termt->pp_term_definitionouttletstmt_of_formrw_rulespolarityproxyproxy_idproxy_tyformproof=letmoduleF=T.Forminletvars=T.varsproxyinifrw_rulesthen((* introduce the required definition as an axiom, with polarity as needed *)letrule:_Stmt.def_rule=letlhs,polarity,rhs=matchpolaritywith|`Neg->SLiteral.atom_falseproxy,`Imply,F.not_form|`Pos->SLiteral.atom_trueproxy,`Imply,form|`Both->SLiteral.atom_trueproxy,`Equiv,forminStmt.Def_form{vars;lhs;rhs=[rhs];polarity;as_form=[form]}inletproof=proofin[Stmt.def~proof[Stmt.mk_def~rewrite:trueproxy_idproxy_ty[rule]]])else((* introduce the required axiom, with polarity as needed *)letf'=F.forall_lvars(matchpolaritywith|`Pos->F.implyproxyform|`Neg->F.implyformproxy|`Both->F.equivproxyform)inletproof=proofin[Stmt.ty_decl~proofproxy_idproxy_ty;Stmt.assert_~prooff'])letfind_def_in_ctx~ctxform=CCList.find_map(fundef->matchdefwith|Def_formdefwhennotdef.rw_rules->letdef_form=def.forminletdf_vars,f_vars=CCPair.map_same(funx->Var.Set.of_iter(T.Seq.varsx))(def_form,form)inifnot(Var.Set.intersection_emptydf_varsf_vars)thenNoneelseCCOpt.map(funsubst->def,subst)(TypedSTerm.try_alpha_renamingdef_formform)|_->None)ctx.sc_new_defsletdefine_form?(pattern="zip_tseitin")~ctx~rw_rules~polarity~parentsform=letcreate_new~ctx~rw_rules~polarity~parents~form=incr_counterctx;lettyvars,vars=collect_varsVar.Subst.emptyforminletvars_t=List.map(funv->T.varv)varsinlettyvars_t=List.map(funv->T.Ty.varv)tyvarsin(* similar to {!skolem_form}, but always return [prop] *)letty=ty_forall_ltyvars(T.Ty.fun_(List.mapVar.tyvars)T.Ty.prop)in(* not a skolem (but a defined term). Will be defined, not declared. *)letf=fresh_id~start0:true~ctxpatterninID.set_payloadfID.Attr_cnf_def;letproxy=T.app~ty:T.Ty.prop(T.const~tyf)(tyvars_t@vars_t)inletproof=Proof.Step.define_internalfparentsin(* register the new definition *)letdef={form;proxy_id=f;proxy_ty=ty;rw_rules;proxy;polarity;proof;as_stmt=lazy(stmt_of_formrw_rulespolarityproxyftyformproof);}inctx.sc_new_defs<-Def_formdef::ctx.sc_new_defs;Util.debugf~section5"@[<2>define_form@ %a@ :proof %a@]"(funk->kpp_form_definitiondefProof.Step.ppproof);definletres=ifnotrw_rulesthen((* Format.printf "defining:@ @[%a@]\n" T.pp form; *)matchfind_def_in_ctx~ctxformwith|Some(def,subst)->(* def.form is alpha renaming *)assert(T.equalform(T.Subst.eval~rename_binders:falsesubstdef.form));(* nothing is bound in form *)assert(T.equalform(T.Subst.eval~rename_binders:falsesubstform));Util.debugf~section1"@[<1>Reusing definition %a@ with type %a.@ Old def: %a.@ New def: %a]"(funk->kT.ppdef.proxyT.ppdef.proxy_tyT.ppdef.formT.ppform);letproxy=T.Subst.evalsubstdef.proxyinletproof=Proof.Step.define_internaldef.proxy_idparentsinletres={defwithform;proxy;proof;polarity;as_stmt=lazy(stmt_of_formrw_rulespolarityproxydef.proxy_iddef.proxy_tyformproof);}inifdef.polarity!=polaritythen(incr_counterctx;ctx.sc_new_defs<-Def_formres::ctx.sc_new_defs);res|None->create_new~ctx~rw_rules~polarity~parents~form)else(create_new~ctx~rw_rules~polarity~parents~form)inresletpp_rules=Fmt.(Util.pp_listDump.(pair(listT.pp_inner|>hovbox)T.pp)|>hovbox)letstmt_of_termidtyrulesproof:Stmt.input_tlist=letmoduleF=T.Formin[Stmt.def~proof[Stmt.mk_def~rewrite:trueidtyrules]]letdefine_term?(pattern="fun_")~ctx~parentsrules:term_definition=Util.debugf~section5"(@[<hv2>define_term@ :rules (@[<hv>%a@])@])"(funk->kpp_rulesrules);incr_counterctx;letsome_args,ty_ret=matchruleswith|[]->assertfalse|(args,rhs)::_->args,T.ty_exnrhsin(* separate type variables and type of arguments *)letty_vars,ty_args=CCList.partition_map(funt->matchT.viewtwith|T.VarvwhenT.Ty.is_tType(Var.tyv)->`Leftv|_->`Right(T.ty_exnt))some_argsin(* checks *)List.iter(fun(args,_)->letargs'=CCList.drop(List.lengthty_vars)argsinassert(List.lengthargs'=List.lengthty_args);assert(List.for_all2(funtty->T.Ty.equalty(T.ty_exnt))args'ty_args);())rules;letty=T.Ty.forall_lty_vars(T.Ty.fun_ty_argsty_ret)inletis_prop=T.Ty.is_propty_retin(* NOTE: not a skolem, just a mere constant undeclared so far. Will be
a defined constant later on. *)letid=fresh_id~start0:true~ctxpatternin(* convert rules *)letrules=List.map(fun(args,rhs)->letall_vars=Iter.of_list(rhs::args)|>Iter.flat_mapT.Seq.free_vars|>Var.Set.of_iter|>Var.Set.to_listinifis_propthen(letatom=T.app~ty:ty_ret(T.const~tyid)argsinStmt.Def_form{vars=all_vars;lhs=SLiteral.atomatomtrue;rhs=[rhs];polarity=`Equiv;as_form=[T.Form.eqatomrhs|>T.Form.close_forall];})else(Stmt.Def_term{vars=all_vars;id;ty;args;rhs;as_form=T.Form.eq(T.app(T.const~tyid)~ty:(T.ty_exnrhs)args)rhs|>T.Form.close_forall;}))rulesinlettd_as_def=Stmt.mk_def~rewrite:trueidtyrulesinletproof=Proof.Step.define_internalidparentsinletdef={td_id=id;td_ty=ty;td_rules=rules;td_as_def;td_proof=proof;td_stmt=lazy(stmt_of_termidtyrulesproof);}inctx.sc_new_defs<-Def_termdef::ctx.sc_new_defs;Util.debugf~section4"@[<2>define_term@ %a@ :proof %a@]"(funk->kpp_term_definitiondefProof.Step.ppproof);defletnew_definitions~ctx=ctx.sc_new_defsletpop_new_definitions~ctx=letl=ctx.sc_new_defsinctx.sc_new_defs<-[];lletrule_def=Proof.Rule.mk"define"letdef_as_stmt(d:definition):Stmt.input_tlist=matchdwith|Def_formd->Lazy.forced.as_stmt|Def_termd->Lazy.forced.td_stmt