123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375(* This file is free software, part of Logtk. See file "license" for more details. *)(** {1 Pragmatic variant of JP algorithm} *)moduleU=Unif_substmoduleT=TermmoduleH=HVarmoduleS=SubstmoduleP=PatternUnifmoduleParams=PragUnifParamsmoduleI=Int32moduleIntSet=CCSet.Make(CCInt)modulePUP=PragUnifParamsletelim_vars=refIntSet.emptyletident_vars=refIntSet.emptytypeop=|ProjApp|ImitFlex|ImitRigid|Ident|Elimlet(<<<)=I.shift_leftlet(>>>)=I.shift_right_logicallet(&&&)=I.logandlet(|||)=I.logorlet(~~~)=I.lognotlet(i63)=I.of_int63letop_masks=[ProjApp,(i63,(0),"proj");ImitFlex,(i63<<<6,6,"imit_flex");ImitRigid,(i63<<<12,12,"imit_rigid");Ident,(i63<<<18,18,"ident");Elim,(i63<<<24,24,"elim")]letget_opflagop=letmask,shift,_=List.assocopop_masksinI.to_int((flag&&&mask)>>>shift)letget_depthflag=letops=[ProjApp;ImitFlex;ImitRigid;Ident;Elim]inList.fold_left(funacco->get_opflago+acc)0opsletinc_opflagop=letold=get_opflagopinletmask,shift,_=List.assocopop_masksinletop_val=(I.succ((flag&&&mask)>>>shift))<<<shiftinletres=(flag&&&(~~~mask))|||op_valinassert(old+1=(get_opresop));resletpp_flagoutflag=List.iter(fun(op,(_,_,name))->CCFormat.fprintfout"|%s:%d"name(get_opflagop);)op_masks(* Create substitution: v |-> λ u1 ... um. u_i (H1 u1 ... um) ... (Hn u1 ... um)
where type of u_i is τ1 -> ... τn -> τ where τ is atomic and H_i have correct
type. This substitution is called a projection. *)letproject_hs_one~counterpref_typesitype_ui=letpref_types_ui,_=Type.open_funtype_uiinletn_args_free=List.lengthpref_typesinletpref_args=List.mapi(funity->T.bvar~ty(n_args_free-i-1))pref_typesinletnew_vars=List.map(funty->letnew_ty=(Type.arrowpref_typesty)inT.var(H.fresh_cnt~counter~ty:new_ty()))pref_types_uiinletnew_vars_applied=List.map(funnv->T.appnvpref_args)new_varsinletmatrix_hd=T.bvar~ty:type_ui(n_args_free-i-1)inletmatrix=T.appmatrix_hdnew_vars_appliedinT.fun_lpref_typesmatrix(* Create substitution: v |-> λ u1 ... um. f (H1 u1 ... um) ... (Hn u1 ... um)
where type of f is τ1 -> ... τn -> τ where τ is atomic, H_i have correct
type and f is a constant. This substitution is called an imitation.*)letimitate_one~scope~counterst=tryOSeq.nth0(JP_unif.imitate_onesided~scope~counterst)withNot_found->invalid_arg"no_imits"letproj_lr~counter~scope~subststflagmax_app_projs=lethd_s,args_s=CCPair.map_fstT.as_var_exn(T.as_apps)inletargss_arr=CCArray.of_listargs_sinlethd_t,_=T.as_app(snd(T.open_funt))inletpref_tys,hd_ret_ty=Type.open_fun(HVar.tyhd_s)inpref_tys|>List.mapi(funity->i,ty)|>(funl->(* if we performed more than N projections that applied the
bound variable we back off *)ifget_opflagProjApp<max_app_projsthenlelseList.filter(fun(_,ty)->List.length(Type.expected_argsty)=0)l)(* If heads are different constants, do not project to those subterms *)|>CCList.filter_map(fun((i,_)asp)->ifi<List.lengthargs_sthen(lets_i=snd(T.open_funargss_arr.(i))inlethd_si=T.head_terms_iinif((T.is_consthd_si&&T.is_consthd_t&&(not(T.equalhd_sihd_t)))||(T.is_bvarargss_arr.(i)&&T.is_bvarhd_t&&(not(T.equalargss_arr.(i)hd_t))))thenNoneelseSomep)elseSomep)|>CCList.filter_map(fun(i,ty)->let_,arg_ret_ty=Type.open_funtyinmatchPatternUnif.unif_simple~subst~scope(T.of_tyarg_ret_ty)(T.of_tyhd_ret_ty)with|Somesubst'->(* we project only to arguments of appropriate type *)letsubst'=Unif_subst.substsubst'inletpr_bind=project_hs_one~counterpref_tysityinletmax_num_of_apps=List.length@@Type.expected_argstyinletflag'=ifmax_num_of_apps>0theninc_opflagProjAppelseflagin(* let flag' = inc_op flag ProjApp in *)Some(Subst.FO.bind'subst'(hd_s,scope)(pr_bind,scope),flag')|None->None)letproj_hs~counter~scope~flexs=CCList.mapfst@@proj_lr~counter~scope~subst:Subst.emptyflexsInt32.zeromax_intletk_subset~kl=letrecauxiaccl=ifi=0thenOSeq.returnaccelseifi>List.lengthlthenOSeq.emptyelse(matchlwith|x::xs->OSeq.interleave(auxiaccxs)(aux(i-1)(x::acc)xs)|[]->assert(false))inassert(k>=0);auxk[]lletelim_subsets_rule?(max_elims=None)~elim_vars~counter~scopetudepth=lethd_t,args_t=T.head_termt,Array.of_list(T.argst)inlethd_u,args_u=T.head_termu,Array.of_list(T.argsu)inassert(T.is_varhd_t);assert(T.is_varhd_u);assert(T.equalhd_thd_u);lethd_var=T.as_var_exnhd_tinletvar_id=!counterinelim_vars:=IntSet.addvar_id!elim_vars;incrcounter;letpref_tys,ret_ty=Type.open_fun(T.tyhd_t)inletpref_len=List.lengthpref_tysinletsame_args,diff_args=List.mapi(funity->ifi<Array.lengthargs_t&&i<Array.lengthargs_u&&T.equalargs_t.(i)args_u.(i)then`Left(T.bvar~ty(pref_len-i-1))else`Right(T.bvar~ty(pref_len-i-1)))pref_tys|>CCList.partition_mapCCFun.idinletdiff_args_num=List.lengthdiff_argsinletend_=matchmax_elimswith|None->0|Somex->assert(x>0);diff_args_num-xinletstart,step=max(diff_args_num-1)0,-1inCCList.range_bystart(maxend_0)~step|>OSeq.of_list|>OSeq.flat_map(funk->k_subset~kdiff_args|>OSeq.map(fundiff_args_subset->assert(List.lengthdiff_args_subset=k);letall_args=diff_args_subset@same_argsinassert(List.lengthall_args<=pref_len);letarg_tys=List.mapT.tyall_argsinletty=Type.arrowarg_tysret_tyinletmatrix=T.app(T.var(HVar.make~tyvar_id))all_argsinletsubs_term=T.fun_lpref_tysmatrixinassert(T.DB.is_closedsubs_term);(Subst.FO.bind'Subst.empty(hd_var,scope)(subs_term,scope),(depth+(diff_args_num-k)))))letsubset_elimination~max_elims~counter~scopetu=elim_subsets_rule~elim_vars~max_elims~counter~scopetu0|>OSeq.map(funsub_flag->fstsub_flag,(sndsub_flag))moduleMake(St:sigvalst:Flex_state.tend)=structmodulePUP=PragUnifParamsmoduleSU=SolidUnif.Make(St)letget_optionk=Flex_state.get_exnkSt.stletdelay_res=res(*Create all possible projection and imitation bindings. *)letproj_imit_lr?(disable_imit=false)~counter~scope~subststflag=tryletsimp_proj,func_proj=letis_ident_last=lethd_var_id=HVar.id(T.as_var_exn(T.head_terms))inIntSet.memhd_var_id!ident_varsinifis_ident_lastthen[],[]else(proj_lr~counter~scope~subststflag(get_optionPUP.k_max_app_projections)|>CCList.partition_map(fun((sub,_)asr)->letbinding,_=Subst.FO.derefsub(T.head_terms,scope)inlet_,body=T.open_funbindinginifT.is_bvarbodythen`Left(Somer)else`Right(Somer)))inletimit_binding=tryifnotdisable_imit&¬(Term.is_var(T.head_termt))&&get_opflagImitRigid<get_optionPUP.k_max_rigid_imitationsthen(letflag'=inc_opflagImitRigidin[Some(U.subst@@imitate_one~scope~counterst,flag')])else[]withInvalid_argumentswhenString.equals"no_imits"->[]in(* OSeq.of_list (simp_proj @ imit_binding @ func_proj) *)(* OSeq.append
(OSeq.of_list simp_proj)
(delay (get_depth flag) @@ OSeq.append (OSeq.of_list imit_binding) (OSeq.of_list func_proj)) *)OSeq.append(OSeq.append(OSeq.of_listsimp_proj)(OSeq.of_listimit_binding))((OSeq.of_listfunc_proj))withInvalid_argumentswhenString.equals"as_var_exn"->OSeq.emptyletelim_rule~counter~scopet_flag=leteliminate_at_idxvk=letprefix_types,return_type=Type.open_fun(HVar.tyv)inletm=List.lengthprefix_typesinletbvars=List.mapi(funity->T.bvar~ty(m-1-i))prefix_typesinletprefix_types'=CCList.remove_at_idxkprefix_typesinletnew_ty=Type.arrowprefix_types'return_typeinletbvars'=CCList.remove_at_idxkbvarsinletmatrix_head=T.var(H.fresh_cnt~counter~ty:new_ty())inletmatrix=T.appmatrix_headbvars'inletsubst_value=T.fun_lprefix_typesmatrixinletsubst=S.FO.bind'Subst.empty(v,scope)(subst_value,scope)insubstinleteliminate_onet=lethd,args=T.as_apptinifT.is_varhd&&List.lengthargs>0then(CCList.range0((List.lengthargs)-1)|>List.map(eliminate_at_idx(T.as_var_exnhd)))else[]ineliminate_onet|>List.map(funx->Some(x,inc_opflagElim))(* removes all arguments of an applied variable
v |-> λ u1 ... um. x
*)letelim_trivial~scope~counterv=letprefix_types,return_type=Type.open_fun(HVar.tyv)inletmatrix_head=T.var(H.fresh_cnt~counter~ty:return_type())inletsubst_value=T.fun_lprefix_typesmatrix_headinletsubst=Subst.FO.bind'Subst.empty(v,scope)(subst_value,scope)insubstletflex_flex_diff_trivial~scope~counterxy=letprefix_types_x,return_type_x=Type.open_fun(HVar.tyx)inletprefix_types_y,return_type_y=Type.open_fun(HVar.tyy)inassert(Type.equalreturn_type_xreturn_type_y);letmatrix_head=T.var(H.fresh_cnt~counter~ty:return_type_x())inletsubst_value_x=T.fun_lprefix_types_xmatrix_headinletsubst_value_y=T.fun_lprefix_types_ymatrix_headinletsubst=Subst.FO.bind'Subst.empty(x,scope)(subst_value_x,scope)inletsubst=Subst.FO.bind'subst(y,scope)(subst_value_y,scope)insubstletrenamer~countert0st1s=letlhs,rhs,unifscope,us=U.FO.rename_to_new_scope~countert0st1sinlhs,rhs,unifscope,U.substusletdeciders~counter()=letpattern=ifget_optionPUP.k_pattern_deciderthen[(funstsub->[(U.subst@@PatternUnif.unify_scoped~subst:(U.of_substsub)~counterst)])]else[]inletsolid=ifget_optionPUP.k_solid_deciderthen[(funstsub->(List.mapU.subst@@SU.unify_scoped~subst:(U.of_substsub)~counterst))]else[]inletfixpoint=ifget_optionPUP.k_fixpoint_deciderthen[(funstsub->[(U.subst@@FixpointUnif.unify_scoped~subst:(U.of_substsub)~counterst)])]else[]infixpoint@pattern@solidlethead_classifiers=matchT.view@@T.head_termswith|T.Varx->`Flexx|_->`Rigidletoracle~counter~scope~subst(s,_)(t,_)(flag:I.t)=letdepth=get_depthflaginletres=ifdepth<get_optionPUP.k_max_depththen(matchhead_classifiers,head_classifiertwith|`Flexx,`FlexywhenHVar.equalType.equalxy->letnum_elims=get_opflagEliminletremaining_elims=get_optionPUP.k_max_elims-num_elimsinifremaining_elims>0then((subset_elimination~max_elims:(Someremaining_elims)~counter~scopest|>OSeq.map(fun(sub,inc)->letflag'=CCList.fold_left(funacc_->inc_opaccElim)flag(CCList.replicateincNone)inSome(sub,flag'))))elseOSeq.return(Some(elim_trivial~counter~scopex,flag))|`Flexx,`Flexy->(* all rules *)letident=ifget_opflagIdent<get_optionPUP.k_max_identificationsthen(JP_unif.identify~scope~counterst[]|>OSeq.map(funx->letsubst=U.substxin(* variable introduced by identification *)letsubs_t=T.of_term_unsafe@@fst(snd(List.hd(Subst.to_listsubst)))inletnew_var,_=T.as_app(snd(T.open_funsubs_t))inletnew_var_id=HVar.id(T.as_var_exnnew_var)in(* remembering that we introduced this var in identification *)ident_vars:=IntSet.addnew_var_id!ident_vars;Some(subst,inc_opflagIdent)))elseOSeq.emptyinletprojs=OSeq.append(proj_imit_lr~disable_imit:true~scope~counter~subststflag)(proj_imit_lr~disable_imit:true~scope~counter~substtsflag)inletprojs_ident=ifOSeq.is_emptyprojs&&OSeq.is_emptyidentthenOSeq.emptyelseOSeq.appendprojs(delaydepthident)inifnot(OSeq.is_emptyprojs_ident)thenprojs_identelseOSeq.return(Some(flex_flex_diff_trivial~scope~counterxy,flag))|`Flex_,`Rigid|`Rigid,`Flex_->OSeq.append(proj_imit_lr~counter~scope~subststflag)(proj_imit_lr~counter~scope~substtsflag)|_->CCFormat.printf"Did not disassemble properly: [%a]\n[%a]@."T.ppsT.ppt;assertfalse)elseOSeq.emptyinlethd_t,hd_s=T.head_terms,T.head_termtinifT.is_varhd_t&&T.is_varhd_s&&T.equalhd_shd_t&&IntSet.mem(HVar.id@@T.as_var_exnhd_t)!elim_varsthen(OSeq.empty)elseresletunify_scoped=letcounter=ref0inletmodulePragUnifParams=structexceptionNotInFragment=PatternUnif.NotInFragmentexceptionNotUnifiable=PatternUnif.NotUnifiabletypeflag_type=int32letflex_state=St.stletinit_flag=(Int32.zero:flag_type)letidentify_scope=renamer~counterletfrag_algs=deciders~counter(*[]*)letpb_oraclest(f:flag_type)substscope=oracle~counter~scope~subststfletoracle_composer=Flex_state.get_exnPUP.k_oracle_composerSt.stendinletmodulePragUnif=UnifFramework.Make(PragUnifParams)in(funxy->elim_vars:=IntSet.empty;ident_vars:=IntSet.empty;letres=PragUnif.unify_scopedxyinOSeq.map(CCOpt.mapUnif_subst.of_subst)(res))end