123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-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/>. *)(* *)(****************************************************************************)(** Powerset lattice with finite cardinality elements or ⊺. *)openMopsa_utilsopenCore.AllopenTopmoduletypeELT=sigtypetvalcompare:t->t->intvalprint:printer->t->unitendmoduleMake(Elt:ELT)=structmoduleSet=SetExt.Make(Elt)typev=Set.ttypet=vwith_topletbottom:t=NtSet.emptylettop:t=TOPletis_top(abs:t)=abs=TOPletsubset(abs1:t)(abs2:t):bool=top_includedSet.subsetabs1abs2letequal(abs1:t)(abs2:t):bool=top_equalSet.equalabs1abs2letcompare(abs1:t)(abs2:t):int=matchabs1,abs2with|TOP,TOP->0|TOP,_->-1|_,TOP->1|Ntx1,Ntx2->Set.comparex1x2letjoin(abs1:t)(abs2:t):t=ifabs1==abs2thenabs1elsetop_lift2Set.unionabs1abs2letmeet(abs1:t)(abs2:t):t=ifabs1==abs2thenabs1elsetop_neutral2Set.interabs1abs2letunion=joinletinter=meetletdiff(abs1:t)(abs2:t):t=ifis_topabs2thenbottomelsetop_lift2Set.diffabs1abs2letwidenctx(abs1:t)(abs2:t):t=top_absorb2(funs1s2->ifSet.subsets2s1thenabs2elseTOP)abs1abs2letprintprinter(abs:t)=matchabswith|Top.TOP->pp_stringprinter"⊤"|Top.Nts->ifSet.is_emptysthenpp_stringprinter"∅"elsepp_setElt.printprinter(Set.to_poly_sets)~sopen:"{"~ssep:","~sclose:"}"letaddv(abs:t):t=top_lift1(Set.addv)absletfold(f:Elt.t->'a->'a)(abs:t)(init:'a):'a=top_to_exnabs|>(funs->Set.foldfsinit)letremove(v:Elt.t)(abs:t):t=top_lift1(Set.removev)absletmem(v:Elt.t)(abs:t):bool=top_dfl1true(Set.memv)absletfilterf(abs:t):t=top_lift1(Set.filterf)absletpartitionf(abs:t):t*t=matchabswith|TOP->TOP,TOP|Nta->letr1,r2=Set.partitionfainNtr1,Ntr2letexistsf(abs:t):bool=top_to_exnabs|>(funs->Set.existsfs)letfor_allf(abs:t):bool=top_to_exnabs|>(funs->Set.for_allfs)letcardinal(abs:t):int=top_to_exnabs|>(funs->Set.cardinals)letfindf(abs:t):Elt.t=top_to_exnabs|>(funs->Set.findfs)letchoose(abs:t):Elt.t=top_to_exnabs|>(funs->Set.chooses)letsingleton(x:Elt.t):t=Nt(Set.singletonx)letof_list(l:Elt.tlist)=Nt(Set.of_listl)letis_empty(abs:t)=top_dfl1falseSet.is_emptyabsletis_singletona=top_apply(funs->Set.cardinals=1(* FIXME: computing the cardinal for this check is inefficient *))falsealetempty=bottomletis_bottom=is_emptyletelements(abs:t)=top_to_exnabs|>Set.elementsletmap(f:Elt.t->Elt.t)(abs:t):t=top_lift1(Set.mapf)absletiter(f:Elt.t->unit)(abs:t):unit=top_to_exnabs|>Set.iterfletapply(f:Set.t->'a)(dfl:'a)(abs:t):'a=Top.top_applyfdflabsend