123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121openConvenience(******************************************************************)(* PARTS *)(******************************************************************)(* A part is a _finite_ sub-enumeration corresponding to a given depth.
* The depth is roughly the number of constructors. *)type'apart={(* Cardinal of this part. *)p_cardinal:Big_int.big_int;(* Compute the element corresponding to the given index. *)compute:(Big_int.big_int->'a);}letget_cardinalp=p.p_cardinal(* Debug: we try two modes. Standard and Shuffled.
* In shuffled mode, values in parts are (deterministically) shuffled. *)typemode=Standard|Shuffledletmode=Shuffledletshufflepart=matchmodewith|Standard->part|Shuffled->{p_cardinal=part.p_cardinal;compute=Shuffle.compute_shufflepart.p_cardinalpart.compute}(* The EMPTY part *)letempty_part={p_cardinal=bigzero;compute=(fun_->assertfalse);}(* A DUMMY part, for cells that remain to be initialized. *)letuninitialized_part={p_cardinal=bigzero;compute=(fun_->assertfalse);}(* Maps a part through a presumably bijective function f. *)letmap_partfpart={p_cardinal=part.p_cardinal;compute=(funindex->f(part.computeindex))}(* Builds a part from a finite list of values. *)letpart_from_listvalues=letavalues=Array.of_listvaluesin{p_cardinal=boi(Array.lengthavalues);compute=(funn->avalues.(iobn))}(*** Union ***)(* Finds in which part (of the given list) is the given index. *)letrecstandard_compute_union_auxpartlistindex=matchpartlistwith|[]->(* Index is out of part list. Cannot happen. *)assertfalse|p::ps->ifp.p_cardinal<==indexthenstandard_compute_union_auxps(index--p.p_cardinal)else(p,index)(* Disjoint union of these parts. *)letunion_partsparts=letwhichpart=standard_compute_union_auxpartsinletcomputeindex=let(p,index)=whichpartindexinp.computeindexin(* The cardinal of the disjoint union is the sum of cardinals. *)letpre_result={p_cardinal=myfoldpartsbigzero(funacup->acu++p.p_cardinal);compute}inshufflepre_result(*** Product ***)(* Split the index into coordinates in the different parts.
* We use div & mod. *)letreccompute_product_vectorindexpart_revvectoracu=matchpart_revvectorwith|[]->acu|pcard::others->assert(signpcard=1);let(index',mod')=quomodindexpcardincompute_product_vectorindex'others(mod'::acu)letstandard_compute_product_auxparts=letpart_revvector=myrevmappartsget_cardinalinfunindex->compute_product_vectorindexpart_revvector[](* Cartesian product of these parts.
* Caution! compute returns a (product) value in the reversed order of the part list. *)letproduct_partsparts=letwhichindexes=standard_compute_product_auxpartsinletcomputeindex=letvector=whichindexesindexin(* Result is reversed. *)myrevmap2vectorparts(funindexp->p.computeindex)inletp_cardinal=myfoldpartsbigone(funacup->acu**p.p_cardinal)in(* The cardinal of the product it the product of cardinals. *)letpre_result={p_cardinal;compute}inshufflepre_result