123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2018-2019 The MOPSA Project. *)(* *)(* This program is free software: you can redistribute it and/or modify *)(* it under the terms of the GNU Lesser General Public License as published *)(* by the Free Software Foundation, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)(**
InvRelation - Relations with access to inverse images.
*)openInvRelationSigmoduleMake(Dom:OrderedType)(CoDom:OrderedType)=structmoduleDomSet=SetExt.Make(Dom)moduleDomMap=MapExt.Make(Dom)moduleCoDomSet=SetExt.Make(CoDom)moduleCoDomMap=MapExt.Make(CoDom)typet={img:CoDomSet.tDomMap.t;inv:DomSet.tCoDomMap.t}(** We maintain both the image of each domain element and the
inverse image of each codomain element.
*)typedom=Dom.ttypedom_set=DomSet.ttypecodom=CoDom.ttypecodom_set=CoDomSet.ttypebinding=dom*codomletempty={img=DomMap.empty;inv=CoDomMap.empty;}letimagexr=tryDomMap.findxr.imgwithNot_found->CoDomSet.emptyletinverseyr=tryCoDomMap.findyr.invwithNot_found->DomSet.emptyletis_image_emptyxr=not(DomMap.memxr.img)letis_inverse_emptyyr=not(CoDomMap.memyr.inv)letis_emptyr=DomMap.is_emptyr.imgletsingletonxy={img=DomMap.singletonx(CoDomSet.singletony);inv=CoDomMap.singletony(DomSet.singletonx);}(* internal function, to update fields *)letmkrimginv=ifr.img==img&&r.inv==invthenrelse{img;inv;}(* internal function: does not update inv *)letset_imgxysr=ifCoDomSet.is_emptyysthenmkr(DomMap.removexr.img)r.invelsemkr(DomMap.addxysr.img)r.inv(* internal function: does not update img *)letset_invyxsr=ifDomSet.is_emptyxsthenmkrr.img(CoDomMap.removeyr.inv)elsemkrr.img(CoDomMap.addyxsr.inv)letset_imagexysr=(* update inv *)CoDomSet.fold2_diff(funyr->set_invy(DomSet.removex(inverseyr))r)(funyr->set_invy(DomSet.addx(inverseyr))r)(imagexr)ys(* update img *)(set_imgxysr)letset_inverseyxsr=(* update img *)DomSet.fold2_diff(funxr->set_imgx(CoDomSet.removey(imagexr))r)(funxr->set_imgx(CoDomSet.addy(imagexr))r)(inverseyr)xs(* update inv *)(set_invyxsr)letaddxyr=mkr(DomMap.addx(CoDomSet.addy(imagexr))r.img)(CoDomMap.addy(DomSet.addx(inverseyr))r.inv)letremovexyr=set_imgx(CoDomSet.removey(imagexr))r|>set_invy(DomSet.removex(inverseyr))letadd_image_setxysr=set_imagex(CoDomSet.union(imagexr)ys)rletadd_inverse_setyxsr=set_inversey(DomSet.union(inverseyr)xs)rletremove_image_setxysr=set_imagex(CoDomSet.diff(imagexr)ys)rletremove_inverse_setyxsr=set_inversey(DomSet.diff(inverseyr)xs)rletremove_imagexr=set_imagexCoDomSet.emptyrletremove_inverseyr=set_inverseyDomSet.emptyrletmemxyr=CoDomSet.memy(imagexr)letmem_domainxr=DomMap.memxr.imgletmem_codomainxr=CoDomMap.memxr.invletof_listl=List.fold_left(funr(x,y)->addxyr)emptylletmin_bindingr=letx,ys=DomMap.min_bindingr.imginx,CoDomSet.min_eltysletmax_bindingr=letx,ys=DomMap.max_bindingr.imginx,CoDomSet.max_eltysletchooser=letx,ys=DomMap.chooser.imginx,CoDomSet.chooseysletcardinalr=DomMap.fold(fun_ir->r+CoDomSet.cardinali)r.img0letiterfr=DomMap.iter(funxi->CoDomSet.iter(funy->fxy)i)r.imgletfoldfracc=DomMap.fold(funxiacc->CoDomSet.fold(funyacc->fxyacc)iacc)r.imgaccletbindingsr=List.rev(fold(funxyl->(x,y)::l)r[])letmapfr=fold(funxyacc->letx',y'=fxyinaddx'y'acc)remptyletdomain_mapfr=DomMap.fold(funxysr->add_image_set(fx)ysr)r.imgemptyletcodomain_mapfr=CoDomMap.fold(funyxsr->add_inverse_set(fy)xsr)r.invemptyletfor_allfr=DomMap.for_all(funxi->CoDomSet.for_all(funy->fxy)i)r.imgletexistsfr=DomMap.exists(funxi->CoDomSet.exists(funy->fxy)i)r.imgletfilterfr=DomMap.fold(funxysr->CoDomSet.fold(funyr->iffxythenrelseremovexyr)ysr)r.imgr(* binary operations *)letcomparer1r2=DomMap.compareCoDomSet.comparer1.imgr2.imgletequalr1r2=DomMap.equalCoDomSet.equalr1.imgr2.imgletsubsetr1r2=DomMap.for_all2zo(fun__->false)(fun__->true)(fun_s1s2->CoDomSet.subsets1s2)r1.imgr2.imgletunionr1r2=(* apply union separately to the img relation and to the inv relation *)mkr1(DomMap.map2zo(fun_ys->ys)(fun_ys->ys)(fun_->CoDomSet.union)r1.imgr2.img)(CoDomMap.map2zo(fun_xs->xs)(fun_xs->xs)(fun_->DomSet.union)r1.invr2.inv)letinterr1r2=(* apply intersection separately to the img relation and to the inv relation *)r1|>DomMap.fold2zo(funx_r->mkr(DomMap.removexr.img)r.inv)(fun__r->r)(funxys1ys2r->set_imgx(CoDomSet.interys1ys2)r)r1.imgr2.img|>CoDomMap.fold2zo(funy_r->mkrr.img(CoDomMap.removeyr.inv))(fun__r->r)(funyxs1xs2r->set_invy(DomSet.interxs1xs2)r)r1.invr2.invletdiffr1r2=(* apply difference separately to the img relation and to the inv relation *)r1|>DomMap.fold2zo(fun__r->r)(fun__r->r)(funxys1ys2r->set_imgx(CoDomSet.diffys1ys2)r)r1.imgr2.img|>CoDomMap.fold2zo(fun__r->r)(fun__r->r)(funyxs1xs2r->set_invy(DomSet.diffxs1xs2)r)r1.invr2.invletiter2f1f2fr1r2=DomMap.iter2o(funx->CoDomSet.iter(f1x))(funx->CoDomSet.iter(f2x))(funx->CoDomSet.iter2(f1x)(f2x)(fx))r1.imgr2.imgletiter2_difff1f2r1r2=DomMap.iter2o(funx->CoDomSet.iter(f1x))(funx->CoDomSet.iter(f2x))(funx->CoDomSet.iter2_diff(f1x)(f2x))r1.imgr2.imgletfold2f1f2fr1r2acc=DomMap.fold2o(funx->CoDomSet.fold(f1x))(funx->CoDomSet.fold(f2x))(funx->CoDomSet.fold2(f1x)(f2x)(fx))r1.imgr2.imgaccletfold2_difff1f2r1r2=DomMap.fold2zo(funx->CoDomSet.fold(f1x))(funx->CoDomSet.fold(f2x))(funx->CoDomSet.fold2_diff(f1x)(f2x))r1.imgr2.imgletfor_all2f1f2fr1r2=DomMap.for_all2o(funx->CoDomSet.for_all(f1x))(funx->CoDomSet.for_all(f2x))(funx->CoDomSet.for_all2(f1x)(f2x)(fx))r1.imgr2.imgletfor_all2_difff1f2r1r2=DomMap.for_all2o(funx->CoDomSet.for_all(f1x))(funx->CoDomSet.for_all(f2x))(funx->CoDomSet.for_all2_diff(f1x)(f2x))r1.imgr2.imgletexists2f1f2fr1r2=DomMap.exists2o(funx->CoDomSet.exists(f1x))(funx->CoDomSet.exists(f2x))(funx->CoDomSet.exists2(f1x)(f2x)(fx))r1.imgr2.imgletexists2_difff1f2r1r2=DomMap.exists2o(funx->CoDomSet.exists(f1x))(funx->CoDomSet.exists(f2x))(funx->CoDomSet.exists2_diff(f1x)(f2x))r1.imgr2.img(* domain operations *)letiter_domainfr=DomMap.iterfr.imgletfold_domainfracc=DomMap.foldfr.imgaccletmap_domainfr=DomMap.fold(funxir->set_imagex(fxi)r)r.imgemptyletmap2_domainfr1r2=DomMap.fold2(funxys1ys2r->set_imagex(fxys1ys2)r)r1.imgr2.imgr1letmap2o_domainf1f2fr1r2=DomMap.fold2o(funxysr->set_imagex(f1xys)r)(funxysr->set_imagex(f2xys)r)(funxys1ys2r->set_imagex(fxys1ys2)r)r1.imgr2.imgr1letmap2zo_domainf1f2fr1r2=DomMap.fold2zo(funxysr->set_imagex(f1xys)r)(funxysr->set_imagex(f2xys)r)(funxys1ys2r->set_imagex(fxys1ys2)r)r1.imgr2.imgr1letfor_all_domainfr=DomMap.for_allfr.imgletexists_domainfr=DomMap.existsfr.imgletfilter_domainfr=DomMap.fold(funxysr->iffxysthenrelseremove_imagexr)r.imgrletmin_domainr=fst(DomMap.min_bindingr.img)letmax_domainr=fst(DomMap.max_bindingr.img)letchoose_domainr=fst(DomMap.chooser.img)letcardinal_domainr=DomMap.cardinalr.imgletelements_domainr=List.rev(DomMap.fold(funx_l->x::l)r.img[])(* codomain operations *)letiter_codomainfr=CoDomMap.iterfr.invletfold_codomainfracc=CoDomMap.foldfr.invaccletmap_codomainfr=CoDomMap.fold(funyir->set_inversey(fyi)r)r.invemptyletfor_all_codomainfr=CoDomMap.for_allfr.invletexists_codomainfr=CoDomMap.existsfr.invletfilter_codomainfr=CoDomMap.fold(funyxsr->iffyxsthenrelseremove_inverseyr)r.invrletmin_codomainr=fst(CoDomMap.min_bindingr.inv)letmax_codomainr=fst(CoDomMap.max_bindingr.inv)letchoose_codomainr=fst(CoDomMap.chooser.inv)letcardinal_codomainr=CoDomMap.cardinalr.invletelements_codomainr=List.rev(CoDomMap.fold(funy_l->y::l)r.inv[])(* printing *)typerelation_printer={print_empty:string;print_begin:string;print_open:string;print_comma:string;print_close:string;print_sep:string;print_end:string;}letprinter_default={print_empty="{}";print_begin="{";print_open="(";print_comma=",";print_close=")";print_sep=";";print_end="}";}letprint_genoprinterdomcodomchs=ifis_emptysthenochprinter.print_emptyelse(letfirst=reftrueinochprinter.print_begin;iter(funxy->if!firstthenfirst:=falseelseochprinter.print_sep;ochprinter.print_open;domchx;ochprinter.print_comma;codomchy;ochprinter.print_close;)s;ochprinter.print_end)(* internal printing helper *)letprintprinterdomcodomchl=print_genoutput_stringprinterdomcodomchlletbprintprinterdomcodomchl=print_genBuffer.add_stringprinterdomcodomchlletfprintprinterdomcodomchl=print_genFormat.pp_print_stringprinterdomcodomchlletto_stringprinterdomcodoml=letb=Buffer.create10inprint_gen(fun()s->Buffer.add_stringbs)printer(fun()k->Buffer.add_stringb(domk))(fun()k->Buffer.add_stringb(codomk))()l;Buffer.contentsbend