123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353moduleTS=Term.SetmoduleT=TermmoduleVT=T.VarTblmoduleL=LiteralmoduleLs=LiteralsmoduleIntSet=Set.Make(CCInt)modulePUP=PragUnifParams(* Meta subst *)moduleMS=Term.VarMapexceptionSolidMatchFailexceptionUnsupportedLiteralKindmoduleMake(S:sigvalst:Flex_state.tend)=structmoduleSU=SolidUnif.Make(S)letget_opk=Flex_state.get_exnkS.st(* Multiterm is built more or less like a normal term,
except that at any point (at any constructor) there is an
alternative way to see this term -- as a bound variable corresponding
to some argument of a __solid pattern__.CCArray
For example let s = F a (f b) be a solid pattern.
For a term t = g (f a) (f b) multiterm
{g} [{f} [{a,1}] {}; {f} [{b}] {0} ] {}
represents exponentially many ways to match term t using pattern s
(in this case 2*2=4) *)typemultiterm=(* Application of Builtin constant to a list of multiterms.
Third argument are possible replacements. *)|AppBuiltinofBuiltin.t*multitermlist*TS.t(* Application of constants or bound variables to a list of multiterms.
Head can be represented possibly in many ways!
Third argument are possible replacements. *)|AppofTS.t*multitermlist*TS.t(* Lambda abstraction of multiterms *)|FunofType.t*multiterm(* Replacements that are either bound variables or constants *)|ReplofTS.tletbvar_or_constt=Term.is_constt||Term.is_bvartletapp_builtinbargsrepls=ifTS.for_allbvar_or_constreplsthen(AppBuiltin(b,args,repls))elseinvalid_arg"replacements must be bound vars or constants"letapphdargsrepls=ifTS.for_allbvar_or_consthdthen(ifTS.for_allbvar_or_constreplsthenApp(hd,args,repls)elseinvalid_arg"replacements must be bound vars or constants")elseinvalid_arg"head of multiterm is bound var or constant"letfun_tybody=Fun(ty,body)letfun_lty_argsbody=List.fold_rightfun_ty_argsbodyletopen_builtin=function|AppBuiltin(hd,args,repls)->(hd,args,repls)|_->invalid_arg"cannot open builtin"letopen_app=function|App(hds,args,repls)->(hds,args,repls)|_->invalid_arg"cannot open app"letopen_fun=function|Fun(ty,bodys)->(ty,bodys)|_->invalid_arg"cannot open fun"letopen_repl=function|Replrepls->repls|_->invalid_arg"cannot open repl"letreplrepls=ifTS.for_allbvar_or_constreplsthen(Replrepls)else(leterr_msg=CCFormat.sprintf"replacements must be ground: @[%a@]"(TS.ppT.pp)replsininvalid_argerr_msg)letrecof_termterm=matchT.viewtermwith|AppBuiltin(b,args)->app_builtinb(List.mapof_termargs)TS.empty|App(hd,args)->app(TS.singletonhd)(List.mapof_termargs)TS.empty|Fun(ty,body)->fun_ty(of_termbody)|_->repl(TS.singletonterm)letrecppout=letsepc=CCFormat.return",@,"inletsepw=CCFormat.return"@ "infunction|AppBuiltin(b,args,repls)->CCFormat.fprintfout"|@[%a@](@[%a@])|@[%a@]|"Builtin.ppb(Util.pp_list~sep:","pp)args(TS.pp~pp_sep:sepwT.pp)repls;|App(hds,args,repls)->CCFormat.fprintfout"|{@[%a@]}(@[%a@])|@[%a@]|"(TS.pp~pp_sep:sepcT.pp)hds(CCList.pp~pp_sep:sepcpp)args(TS.pp~pp_sep:sepwT.pp)repls;|Fun(ty,repls)->CCFormat.fprintfout"|l@[%a@].@[%a@]|"Type.pptypprepls;|Replrepls->CCFormat.fprintfout"{r:@[%a@]}"(TS.pp~pp_sep:sepwT.pp)replsletcovertsolids:multiterm=letn=List.lengthsolidsinletrecaux~depths_argst:multiterm=(* All the ways in which we can represent term t using solids *)letsols_as_db=List.mapi(funit->(t,T.bvar~ty:(T.tyt)(n-i-1+depth)))s_argsinletmatches_of_solidstarget=(CCList.filter_map(fun(s,s_db)->ifT.equalstargetthenSomes_dbelseNone)sols_as_db)|>TS.of_listinletdb_hits=matches_of_solidstinmatchT.viewtwith|AppBuiltin(hd,args)->app_builtinhd(List.map(aux~depths_args)args)db_hits|App(hd,args)->assert(not(CCList.is_emptyargs));assert(bvar_or_consthd);lethds=TS.addhd@@matches_of_solidshdinletargs=List.map(aux~depths_args)argsinapphdsargsdb_hits|Fun_->letty_args,body=T.open_funtinletd_inc=List.lengthty_argsinlets_args'=List.map(T.DB.shiftd_inc)s_argsinletres=aux~depth:(depth+d_inc)s_args'bodyinfun_lty_argsres|DBiwheni>=depth->ifTS.is_emptydb_hitsthenraiseSolidMatchFailelserepldb_hits|_->repl(TS.addtdb_hits)inaux~depth:0solidstletterm_intersectionst=letrecauxst=matchswith|AppBuiltin(s_b,s_args,s_repls)->let(t_b,t_args,t_repls)=open_builtintinifs_b=t_bthen(letargs=List.map(fun(s,t)->auxst)@@List.combines_argst_argsinapp_builtins_bargs(TS.inters_replst_repls))elseraiseSolidMatchFail|App(s_hds,s_args,s_repls)->let(t_hds,t_args,t_repls)=open_apptinleti_hds=TS.inters_hdst_hdsinifnot@@TS.is_emptyi_hdsthen(letargs=List.map(fun(s,t)->auxst)@@List.combines_argst_argsinappi_hdsargs(TS.inters_replst_repls))elseraiseSolidMatchFail|Fun(s_ty,s_bodys)->lett_ty,t_bodys=open_funtinifType.equals_tyt_tythen(fun_s_ty(auxs_bodyst_bodys))elseraiseSolidMatchFail|Repl(repls)->letres=TS.interrepls(open_replt)inifTS.is_emptyresthenraiseSolidMatchFailelsereplresintryauxstwithInvalid_arguments->Util.debugf3"Incompatible constructors: %s"(funk->ks);raiseSolidMatchFailletrefine_subst_w_termsubstvart=ifnot@@MS.memvarsubstthen(MS.addvartsubst)else(letold=CCOpt.get_exn@@MS.getvarsubstinMS.addvar(term_intersectionoldt)subst)letrefine_subst_w_substmetasubstsubst=letres=refmetasubstinSubst.FO.iter(fun(v,_)(t,_)->res:=refine_subst_w_term!resv(of_termt);)subst;!resletsolid_match~subst~pattern~target=assert(T.is_groundtarget);letrecauxsubstlr=matchT.viewlwith|AppBuiltin(b,args)->beginmatchT.viewrwith|AppBuiltin(b',args')whenBuiltin.equalbb'&&List.lengthargs=List.lengthargs'->letargs,args'=Unif.norm_logical_disagreementsbargsargs'inList.fold_left(funsubst(l',r')->auxsubstl'r')subst(List.combineargsargs')|_->raiseSolidMatchFailend|App(hd,args)whenT.is_varhd->refine_subst_w_termsubst(T.as_var_exnhd)(coverrargs)|App(hd,args)->assert(T.is_consthd||T.is_bvarhd);beginmatchT.viewrwith|App(hd',args')whenT.equalhdhd'->assert(List.lengthargs=List.lengthargs');List.fold_left(funsubst(l',r')->auxsubstl'r')subst(List.combineargsargs')|_->raiseSolidMatchFailend|Fun_->letprefix,body=T.open_funlinletprefix',body'=T.open_funrinassert(List.lengthprefix=List.lengthprefix');auxsubstbodybody'|Varx->refine_subst_w_termsubstx(coverr[])|_->ifT.equallrthensubstelseraiseSolidMatchFailinifType.equal(T.typattern)(T.tytarget)&&(*if terms are first-order we should not deal with them
since LFHO would have already done it. *)not(T.is_fo_termpattern)&¬(T.is_fo_termtarget)thenauxsubstpatterntargetelseraiseSolidMatchFailletnormaize_clausessubsumertarget=tryleteta_exp_snf?(f=CCFun.id)=Ls.map(funt->f@@Lambda.eta_expand@@Lambda.snf@@t)inlettarget'=Ls.ground_lits@@eta_exp_snftargetinletsubsumer'=eta_exp_snf~f:(SU.solidify~limit:false)subsumerin(* We populate app_var_map to contain indices of all arguments that
should be removed *)subsumer',target'withPatternUnif.NotInFragment->raiseUnsupportedLiteralKindletsignl=letres=matchlwith|L.Equation(_,_,sign)->sign|L.False->false|_->trueinifresthen1else-1letcmp_by_signl1l2=CCOrd.int(signl1)(signl2)letcmp_by_weightl1l2=CCOrd.int(L.ho_weightl1)(L.ho_weightl2)letsubsumption_cmpl1l2=letsign_res=cmp_by_signl1l2inifsign_res!=0thensign_reselseifget_opPUP.k_use_weight_for_solid_subsumptionthencmp_by_weightl1l2else0letclassic_match~subst~pattern~target=tryUnif.FO.matching_same_scope~subst~pattern~scope:0targetwithUnif.Fail->raiseSolidMatchFailletlit_matchers~subst~pattern~targetk=beginmatchpatternwith|L.Equation(lhs,rhs,sign)->beginmatchtargetwith|L.Equation(lhs',rhs',sign')->assert(T.is_groundlhs');assert(T.is_groundrhs');(* let res_list = ref [] in *)ifsign=sign'then((tryletc_subst=classic_match~subst:Subst.empty~pattern:lhs~target:lhs'inletc_subst=classic_match~subst:c_subst~pattern:rhs~target:rhs'ink(refine_subst_w_substsubstc_subst)withSolidMatchFail->());(tryletc_subst=classic_match~subst:Subst.empty~pattern:lhs~target:rhs'inletc_subst=classic_match~subst:c_subst~pattern:rhs~target:lhs'ink(refine_subst_w_substsubstc_subst)withSolidMatchFail->());(tryletsubst1=(solid_match~subst~pattern:lhs~target:lhs')ink(solid_match~subst:subst1~pattern:rhs~target:rhs')withSolidMatchFail->());(tryletsubst2=(solid_match~subst~pattern:lhs~target:rhs')ink(solid_match~subst:subst2~pattern:rhs~target:lhs')withSolidMatchFail->()););|_->()end|L.True->beginmatchtargetwith|L.True->ksubst|_->()end|L.False->beginmatchtargetwith|L.False->ksubst|_->()endendletcheck_subsumption_possibilitysubsumertarget=letis_more_specificpatterntarget=not@@Iter.is_empty(lit_matchers~subst:MS.empty~pattern~target)inletneg_s,neg_t=CCPair.map_same(CCArray.fold(funaccl->ifsignl=(-1)thenacc+1elseacc)0)(subsumer,target)inletpos_s,pos_t=CCPair.map_same(CCArray.fold(funaccl->ifsignl=1thenacc+1elseacc)0)(subsumer,target)in(not@@get_opPUP.k_use_weight_for_solid_subsumption||Ls.weightsubsumer<=Ls.weighttarget)&&neg_s<=neg_t&&pos_s<=pos_t&&(not(neg_t>=3||pos_t>=3)||CCArray.for_all(funl->CCArray.exists(is_more_specificl)target)subsumer)letsubsumessubsumertarget=letn=Array.lengthsubsumerin(* let subsumer_o, target_o = subsumer, target in *)letrecaux?(i=0)picklistsubstsubsumertarget_i=ifi>=nthentrueelse(letlit=subsumer.(i)inCCArray.exists(fun(j,lit')->ifCCBV.getpicklistj||cmp_by_signlitlit'!=0||(get_opPUP.k_use_weight_for_solid_subsumption&&cmp_by_weightlitlit'>0)thenfalseelse(letmatchers=lit_matchers~subst~pattern:lit~target:lit'inIter.exists(funsubst'->CCBV.setpicklistj;letres=aux~i:(i+1)picklistsubst'subsumertarget_iinCCBV.resetpicklistj;res)matchers))target_i)inletsubsumer,target=normaize_clausessubsumertargetinCCArray.sortsubsumption_cmpsubsumer;CCArray.sortsubsumption_cmptarget;ifcheck_subsumption_possibilitysubsumertargetthen(letpicklist=CCBV.create~size:(Array.lengthtarget)falseinlettarget_i=CCArray.mapi(funil->(i,l))targetinletres=auxpicklistMS.emptysubsumertarget_iinres)elsefalseend