123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301(******************************************************************************)(* *)(* Fix *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under the *)(* terms of the GNU Library General Public License version 2, with a *)(* special exception on linking, as described in the file LICENSE. *)(* *)(******************************************************************************)openPrintf(* A suspension is used to represent a cardinal-that-may-still-be-unknown. *)(* Earlier versions used the definition [type 'n cardinal = int Lazy.t]. We
now use the stronger definition that follows. This new definition forces
the equality ['n = unit]. This equality remains invisible outside of this
module. Inside this module, it lets the type-checker regard all phantom
indices as equal. This allows [equal] and [assert_equal] to be well-typed;
with the weaker definition, they would be ill-typed. *)type'ncardinal=Cardinal:intLazy.t->unitcardinal[@@ocaml.unboxed](* The function [cardinal] forces the cardinal to become fixed. Up to the
type annotations, it is equivalent to [Lazy.force]. *)letcardinal(typen)(Cardinal(lazyn):ncardinal)=nletis_fixed(typen)(Cardinalc:ncardinal)=Lazy.is_valctype(_,_)eq=Refl:('a,'a)eqletequal(typenm)(n:ncardinal)(m:mcardinal):(n,m)eqoption=letCardinal(lazyn)=ninletCardinal(lazym)=minifn=mthenSomeReflelseNoneletassert_equal(typenm)(n:ncardinal)(m:mcardinal):(n,m)eq=letCardinal(lazyn)=ninletCardinal(lazym)=minifn=mthenReflelsesprintf"Fix.Indexing.assert_equal: cardinals are not equal (%d <> %d).\n%s\n"nm__LOC__|>invalid_argtype'nindex=intmoduletypeCARDINAL=sigtypenvaln:ncardinalend(* [Empty] and [Const] produce sets whose cardinal is known. *)moduleEmpty=structtypen=unitletn=Cardinal(lazy0)endmoduleConst(X:sigvalcardinal:intend):CARDINAL=structtypen=unitlet()=assert(X.cardinal>=0)letn=Cardinal(lazyX.cardinal)endletconstc:(moduleCARDINAL)=assert(c>=0);(modulestructtypen=unitletn=Cardinal(lazyc)end)(* [Gensym] produces a set whose cardinal is a priori unknown. A new reference
stores the current cardinal, which grows when [fresh()] is invoked. [fresh]
fails if the suspension [n] has been forced. *)moduleGensym()=structtypen=unitletcounter=ref0letn=Cardinal(lazy!counter)letfresh()=assert(not(is_fixedn));letresult=!counterinincrcounter;resultendtype('l,'r)either=|Lof'l|Rof'rmoduletypeSUM=sigtypelandrincludeCARDINALvalinj_l:lindex->nindexvalinj_r:rindex->nindexvalprj:nindex->(lindex,rindex)eitherendmoduleSum(L:CARDINAL)(R:CARDINAL)=structtypen=unittypel=L.ntyper=R.n(* The cardinal [l] of the left-hand set becomes fixed now (if it
wasn't already). We need it to be fixed for our injections and
projections to make sense. *)letl:int=cardinalL.n(* The right-hand set can remain open-ended. *)letr:rcardinal=R.nletn:ncardinal=(* We optimize the case where [r] is fixed already, but the code
in the [else] branch would work always. *)ifis_fixedrthenletn=l+cardinalrinCardinal(lazyn)elseCardinal(lazy(l+cardinalr))(* Injections. The two sets are numbered side by side. *)letinj_lx=xletinj_ry=l+y(* Projection. *)letprjx=ifx<lthenLxelseR(x-l)endletsum(typelr)(l:lcardinal)(r:rcardinal)=letmoduleL=structtypen=lletn=lendinletmoduleR=structtypen=rletn=rendin(moduleSum(L)(R):SUMwithtypel=landtyper=r)moduleIndex=structtype'nt='nindexletof_int(n:'ncardinal)i:'nindex=letn=cardinalninif0<=i&&i<nthenielsesprintf"Fix.Indexing.Index.of_int: \
the index %d is not in the range [0, %d).\n%s\n"in__LOC__|>invalid_arglet[@inline]to_inti=ilet[@inline]iter(n:'ncardinal)(yield:'nindex->unit)=letn=cardinalninfori=0ton-1doyieldidonelet[@inline]rev_iter(n:'ncardinal)(yield:'nindex->unit)=letn=cardinalninfori=n-1downto0doyieldidoneexceptionEnd_of_setletenumerate(n:'ncardinal):unit->'nindex=letn=cardinalninletnext=ref0infun()->leti=!nextinifn<=ithenraiseEnd_of_set;incrnext;iendtype('n,'a)vector=Vector:'aarray->(unit,'a)vector[@@ocaml.unboxed]moduleVector=structtype('n,'a)t=('n,'a)vectorlet[@inline]as_array(typen)(Vectora:(n,_)t)=alet[@inline]get(typen)(Vectora:(n,_)t)i=Array.unsafe_getailet[@inline]set(typen)(Vectora:(n,_)t)ix=Array.unsafe_setaixlet[@inline]set_constix=setti(x::getti)letlength(typen)(Vectora:(n,_)t):ncardinal=letn=Array.lengthainCardinal(lazyn)letempty:(Empty.n,_)t=Vector[||]letmake(typen)(Cardinaln:ncardinal)x:(n,_)t=Vector(Array.make(Lazy.forcen)x)letmake'(typen)(Cardinaln:ncardinal)f:(n,_)t=matchLazy.forcenwith|0->empty|n->Vector(Array.maken(f()))letinit(typen)(Cardinaln:ncardinal)f:(n,_)t=Vector(Array.init(Lazy.forcen)f)letmap(typen)f(Vectora:(n,_)t):(n,_)t=Vector(Array.mapfa)letmapi(typen)f(Vectora:(n,_)t):(n,_)t=Vector(Array.mapifa)letcopy(typen)(Vectora:(n,_)t):(n,_)t=Vector(Array.copya)letiter(typen)f(Vectora:(n,_)t)=Array.iterfaletiteri(typen)f(Vectora:(n,_)t)=Array.iterifaletiter2(typen)f(Vectora:(n,_)t)(Vectorb:(n,_)t)=Array.iter2fabletfold_left(typen)facc(Vectora:(n,_)t)=Array.fold_leftfaccaletfold_right(typen)f(Vectora:(n,_)t)acc=Array.fold_rightfaaccletfold_left2(typen)facc(Vectora:(n,_)t)(Vectorb:(n,_)t)=letacc=refaccinfori=0toArray.lengtha-1doacc:=f!acc(Array.unsafe_getai)(Array.unsafe_getbi)done;!accletfold_right2(typen)f(Vectora:(n,_)t)(Vectorb:(n,_)t)acc=letacc=refaccinfori=Array.lengtha-1downto0doacc:=f(Array.unsafe_getai)(Array.unsafe_getbi)!accdone;!accletto_list(typen)(Vectora:(n,_)t)=Array.to_listaletsort(typen)cmp(Vectora:(n,_)t)=Array.sortcmpaletof_array(typen)(Cardinaln:ncardinal)a:(n,_)t=letn=Lazy.forcenandm=Array.lengthainifn=mthenVectoraelsesprintf"Fix.Indexing.Vector.of_array: \
cardinal and array length do not match (%d <> %d).\n%s\n"nm__LOC__|>invalid_argletinvert(typem)(typen)(n:ncardinal)(v:(m,nindex)t):(n,mindexoption)t=(* We assume that [v] represents an injection of [m] into [n].
We want to tabulate the inverse function [w], a partial function. *)letw=makenNoneinv|>iteri@@beginfunij->assert(getwj=None);setwj(Somei);end;wmoduletypeV=sigtypentypeavalvector:(n,a)tendmoduleOf_array(A:sigtypeavalarray:aarrayend)=structtypen=unittypea=A.aletvector=VectorA.arrayendend