123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239open!CoremoduleInstrumentation=struct(** All [Incr_map] functions take an optional [instrumentation] parameter that has type
[Instrumentation.t]. A value of this type is a record containing a function which
is polymorphic over a universally-quantified type ['a]. This function is passed
a [unit -> 'a] function, which must be immediately executed, and the result of
which must be returned.
The function passed to the instrumentor will be doing the bulk of the work for the
[Incr_map] function in question (usually a [Map.fold_symmetric_diff]).
You may want to use the Instrumentation API to assist in performance profiling like
so:
{[
let profile name =
{ Incr_map.Instrumentation.f = fun f ->
let before = Time.now () in
let r = f () in
let after = Time.now () in
let delta = Time.sub after before in
printf "%s took %s" name (Time.Span.to_string_hum delta);
r
}
;;
Incr_map.map ~instrumentation:(profile "foo") ~f:map_foo
]} *)typet={f:'a.(unit->'a)->'a}[@@unboxed]end(** [S_gen] is the type of the module returned by [Incr_map.Make]. It is a specialization
of the interface of [Incr_map], with:
- the ['w] state_witness type parameter removed
- the [Incremental.State.t] argument removed
The comments for components of [S_gen] are in [module type Incr_map] below. *)moduletypeS_gen=sigmoduleIncr:sigtype'atmoduleCutoff:sigtype'atendendmoduleInstrumentation=Instrumentationvalof_set:?instrumentation:Instrumentation.t->('k,'cmp)Set.tIncr.t->('k,unit,'cmp)Map.tIncr.tvalfilter_mapi:?instrumentation:Instrumentation.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:(key:'k->data:'v1->'v2option)->('k,'v2,'cmp)Map.tIncr.tvalmapi:?instrumentation:Instrumentation.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:(key:'k->data:'v1->'v2)->('k,'v2,'cmp)Map.tIncr.tvalfilter_map:?instrumentation:Instrumentation.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:('v1->'v2option)->('k,'v2,'cmp)Map.tIncr.tvalmap:?instrumentation:Instrumentation.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:('v1->'v2)->('k,'v2,'cmp)Map.tIncr.tvalfilter_mapi':?instrumentation:Instrumentation.t->?cutoff:'v1Incr.Cutoff.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:(key:'k->data:'v1Incr.t->'v2optionIncr.t)->('k,'v2,'cmp)Map.tIncr.tvalmapi':?instrumentation:Instrumentation.t->?cutoff:'v1Incr.Cutoff.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:(key:'k->data:'v1Incr.t->'v2Incr.t)->('k,'v2,'cmp)Map.tIncr.tvalfilter_map':?instrumentation:Instrumentation.t->?cutoff:'v1Incr.Cutoff.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:('v1Incr.t->'v2optionIncr.t)->('k,'v2,'cmp)Map.tIncr.tvalmap':?instrumentation:Instrumentation.t->?cutoff:'v1Incr.Cutoff.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:('v1Incr.t->'v2Incr.t)->('k,'v2,'cmp)Map.tIncr.tvalpartition_mapi:?instrumentation:Instrumentation.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:(key:'k->data:'v1->('v2,'v3)Either.t)->(('k,'v2,'cmp)Map.t*('k,'v3,'cmp)Map.t)Incr.tvalpartition_mapi':?instrumentation:Instrumentation.t->?cutoff:'v1Incr.Cutoff.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:(key:'k->data:'v1Incr.t->('v2,'v3)Either.tIncr.t)->(('k,'v2,'cmp)Map.t*('k,'v3,'cmp)Map.t)Incr.tvalunordered_fold:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->?update:(key:'k->old_data:'v->new_data:'v->'acc->'acc)->?specialized_initial:(init:'acc->('k,'v,'cmp)Map.t->'acc)->?finalize:('acc->'acc)->?revert_to_init_when_empty:bool->('k,'v,'cmp)Map.tIncr.t->init:'acc->add:(key:'k->data:'v->'acc->'acc)->remove:(key:'k->data:'v->'acc->'acc)->'accIncr.tvalunordered_fold_with_extra:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->?extra_equal:('extra->'extra->bool)->?update:(key:'k->old_data:'v->new_data:'v->'acc->'extra->'acc)->?specialized_initial:(init:'acc->('k,'v,'e)Map.t->'extra->'acc)->?finalize:('acc->'acc)->?revert_to_init_when_empty:bool->('k,'v,'e)Map.tIncr.t->'extraIncr.t->init:'acc->add:(key:'k->data:'v->'acc->'extra->'acc)->remove:(key:'k->data:'v->'acc->'extra->'acc)->extra_changed:(old_extra:'extra->new_extra:'extra->input:('k,'v,'e)Map.t->'acc->'acc)->'accIncr.tvalcutoff:?instrumentation:Instrumentation.t->('k,'v,'cmp)Map.tIncr.t->cutoff:'vIncremental.Cutoff.t->('k,'v,'cmp)Map.tIncr.tvalmapi_count:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k1,'v,'cmp1)Map.tIncr.t->comparator:('k2,'cmp2)Comparator.Module.t->f:(key:'k1->data:'v->'k2)->('k2,int,'cmp2)Map.tIncr.tvalmap_count:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k1,'v,'cmp1)Map.tIncr.t->comparator:('k2,'cmp2)Comparator.Module.t->f:('v->'k2)->('k2,int,'cmp2)Map.tIncr.tvalmapi_min:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->comparator:('r,_)Comparator.Module.t->f:(key:'k->data:'v->'r)->'roptionIncr.tvalmapi_max:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->comparator:('r,_)Comparator.Module.t->f:(key:'k->data:'v->'r)->'roptionIncr.tvalmap_min:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->comparator:('r,_)Comparator.Module.t->f:('v->'r)->'roptionIncr.tvalmap_max:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->comparator:('r,_)Comparator.Module.t->f:('v->'r)->'roptionIncr.tvalmin_value:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->comparator:('v,_)Comparator.Module.t->'voptionIncr.tvalmax_value:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->comparator:('v,_)Comparator.Module.t->'voptionIncr.tvalmapi_bounds:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->comparator:('r,_)Comparator.Module.t->f:(key:'k->data:'v->'r)->('r*'r)optionIncr.tvalmap_bounds:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->comparator:('r,_)Comparator.Module.t->f:('v->'r)->('r*'r)optionIncr.tvalvalue_bounds:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->comparator:('v,_)Comparator.Module.t->('v*'v)optionIncr.tvalmerge:?instrumentation:Instrumentation.t->?data_equal_left:('v1->'v1->bool)->?data_equal_right:('v2->'v2->bool)->('k,'v1,'cmp)Map.tIncr.t->('k,'v2,'cmp)Map.tIncr.t->f:(key:'k->('v1,'v2)Map.Merge_element.t->'v3option)->('k,'v3,'cmp)Map.tIncr.tvalmerge_both_some:?instrumentation:Instrumentation.t->?data_equal_left:('v1->'v1->bool)->?data_equal_right:('v2->'v2->bool)->?out_equal:('v3->'v3->bool)->('k,'v1,'cmp)Map.tIncr.t->('k,'v2,'cmp)Map.tIncr.t->f:(key:'k->'v1->'v2->'v3)->('k,'v3,'cmp)Map.tIncr.tvalunzip:?instrumentation:Instrumentation.t->?left_result_equal:('v1->'v1->bool)->?right_result_equal:('v2->'v2->bool)->('k,'v1*'v2,'cmp)Map.tIncr.t->('k,'v1,'cmp)Map.tIncr.t*('k,'v2,'cmp)Map.tIncr.tvalunzip_mapi:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->?left_result_equal:('v1->'v1->bool)->?right_result_equal:('v2->'v2->bool)->('k,'v,'cmp)Map.tIncr.t->f:(key:'k->data:'v->'v1*'v2)->('k,'v1,'cmp)Map.tIncr.t*('k,'v2,'cmp)Map.tIncr.tvalunzip_mapi':?instrumentation:Instrumentation.t->?cutoff:'vIncr.Cutoff.t->?data_equal:('v->'v->bool)->('k,'v,'cmp)Map.tIncr.t->f:(key:'k->data:'vIncr.t->'v1Incr.t*'v2Incr.t)->('k,'v1,'cmp)Map.tIncr.t*('k,'v2,'cmp)Map.tIncr.tvalmerge':?instrumentation:Instrumentation.t->?cutoff:('v1,'v2)Map.Merge_element.tIncr.Cutoff.t->?data_equal_left:('v1->'v1->bool)->?data_equal_right:('v2->'v2->bool)->('k,'v1,'cmp)Map.tIncr.t->('k,'v2,'cmp)Map.tIncr.t->f:(key:'k->('v1,'v2)Map.Merge_element.tIncr.t->'v3optionIncr.t)->('k,'v3,'cmp)Map.tIncr.tvalflatten:('k,'vIncr.t,'cmp)Map.t->('k,'v,'cmp)Map.tIncr.tvaljoin:?instrumentation:Instrumentation.t->('k,'vIncr.t,'cmp)Map.tIncr.t->('k,'v,'cmp)Map.tIncr.tvalseparate:?instrumentation:Instrumentation.t->('k,'v,'cmp)Map.tIncr.t->data_equal:('v->'v->bool)->('k,'vIncr.t,'cmp)Map.tIncr.tvalkeys:?instrumentation:Instrumentation.t->('k,'v,'c)Map.tIncr.t->('k,'c)Set.tIncr.tvalrank:?instrumentation:Instrumentation.t->('k,'v,'cmp)Base.Map.tIncr.t->'kIncr.t->intoptionIncr.tvalsubrange:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,'cmp)Map.tIncr.t->('kMaybe_bound.As_lower_bound.t*'kMaybe_bound.As_upper_bound.t)optionIncr.t->('k,'v,'cmp)Map.tIncr.tvalsubrange_by_rank:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,'cmp)Map.tIncr.t->(intMaybe_bound.As_lower_bound.t*intMaybe_bound.As_upper_bound.t)Incr.t->('k,'v,'cmp)Map.tIncr.tvalrekey:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k1,'v,'cmp1)Map.tIncr.t->comparator:('k2,'cmp2)Comparator.Module.t->f:(key:'k1->data:'v->'k2)->('k2,'v,'cmp2)Map.tIncr.tvalindex_byi:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('inner_key,'v,'inner_cmp)Map.tIncr.t->comparator:('outer_key,'outer_cmp)Comparator.Module.t->index:(key:'inner_key->data:'v->'outer_keyoption)->('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.tIncr.tvalindex_by:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('inner_key,'v,'inner_cmp)Map.tIncr.t->comparator:('outer_key,'outer_cmp)Comparator.Module.t->index:('v->'outer_keyoption)->('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.tIncr.tvalunordered_fold_nested_maps:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->?revert_to_init_when_empty:bool->?update:(outer_key:'outer_key->inner_key:'inner_key->old_data:'v->new_data:'v->'acc->'acc)->('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.tIncr.t->init:'acc->add:(outer_key:'outer_key->inner_key:'inner_key->data:'v->'acc->'acc)->remove:(outer_key:'outer_key->inner_key:'inner_key->data:'v->'acc->'acc)->'accIncr.tvaltranspose:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k2,'k2_cmp)Comparator.Module.t->('k1,('k2,'v,'k2_cmp)Map.t,'k1_cmp)Map.tIncr.t->('k2,('k1,'v,'k1_cmp)Map.t,'k2_cmp)Map.tIncr.tvalcollapse:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.tIncr.t->comparator:('inner_key,'inner_cmp)Comparator.Module.t->('outer_key*'inner_key,'v,('outer_cmp,'inner_cmp)Tuple2.comparator_witness)Map.tIncr.tvalcollapse_by:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.tIncr.t->merge_keys:('outer_key->'inner_key->'combined_key)->comparator:('combined_key,'combined_cmp)Comparator.Module.t->('combined_key,'v,'combined_cmp)Map.tIncr.tvalexpand:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('outer_key*'inner_key,'v,'tuple_cmp)Map.tIncr.t->outer_comparator:('outer_key,'outer_cmp)Comparator.Module.t->inner_comparator:('inner_key,'inner_cmp)Comparator.Module.t->('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.tIncr.tvalcounti:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->f:(key:'k->data:'v->bool)->intIncr.tvalcount:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(_,'v,_)Map.tIncr.t->f:('v->bool)->intIncr.tvalfor_alli:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->f:(key:'k->data:'v->bool)->boolIncr.tvalfor_all:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(_,'v,_)Map.tIncr.t->f:('v->bool)->boolIncr.tvalexistsi:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,_)Map.tIncr.t->f:(key:'k->data:'v->bool)->boolIncr.tvalexists:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(_,'v,_)Map.tIncr.t->f:('v->bool)->boolIncr.tvalsum:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(_,'v,_)Map.tIncr.t->(moduleAbstract_algebra.Commutative_group.Without_sexpwithtypet='u)->f:('v->'u)->'uIncr.tmoduleLookup:sigtype('k,'v,'cmp)tvalcreate:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k,'v,'cmp)Map.tIncr.t->comparator:('k,'cmp)Comparator.t->('k,'v,'cmp)tvalfind:('k,'v,_)t->'k->'voptionIncr.tmoduleM(K:sigtypettypecomparator_witnessend):sigtypenonrec'vt=(K.t,'v,K.comparator_witness)tendmoduleFor_debug:sigvalsexp_of_t:('k->Sexp.t)->('v->Sexp.t)->('k,'v,'cmp)t->Sexp.tendendmoduleFor_testing:sigvalfind_key_range_linear:from:int->to_:int->('a,'b,'c)Base.Map.t->('a*'aoption)optionendendmoduletypeIncr_map=sig(** Functions for using maps efficiently within Incremental. The goal of the algorithms
here is to do work on the output of the computation proportional to the amount of
work done on the input. i.e., [k] modifications to the input map for some
computation will result in [k] modifications to the output map. The changes to the
input map are typically computed using [Map.symmetric_diff].
Unless stated otherwise, the non-incremental semantics of these functions (i.e..,
ignoring performance) is the same as the corresponding function in Core's [Map]
module. *)moduleInstrumentation=Instrumentationvalof_set:?instrumentation:Instrumentation.t->(('k,'cmp)Set.t,'w)Incremental.t->(('k,unit,'cmp)Map.t,'w)Incremental.tvalfilter_mapi:?instrumentation:Instrumentation.t->?data_equal:('v1->'v1->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->f:(key:'k->data:'v1->'v2option)->(('k,'v2,'cmp)Map.t,'w)Incremental.tvalmapi:?instrumentation:Instrumentation.t->?data_equal:('v1->'v1->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->f:(key:'k->data:'v1->'v2)->(('k,'v2,'cmp)Map.t,'w)Incremental.tvalfilter_map:?instrumentation:Instrumentation.t->?data_equal:('v1->'v1->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->f:('v1->'v2option)->(('k,'v2,'cmp)Map.t,'w)Incremental.tvalmap:?instrumentation:Instrumentation.t->?data_equal:('v1->'v1->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->f:('v1->'v2)->(('k,'v2,'cmp)Map.t,'w)Incremental.tvalfilter_mapi':?instrumentation:Instrumentation.t->?cutoff:'v1Incremental.Cutoff.t->?data_equal:('v1->'v1->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->f:(key:'k->data:('v1,'w)Incremental.t->('v2option,'w)Incremental.t)->(('k,'v2,'cmp)Map.t,'w)Incremental.tvalmap':?instrumentation:Instrumentation.t->?cutoff:'v1Incremental.Cutoff.t->?data_equal:('v1->'v1->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->f:(('v1,'w)Incremental.t->('v2,'w)Incremental.t)->(('k,'v2,'cmp)Map.t,'w)Incremental.tvalfilter_map':?instrumentation:Instrumentation.t->?cutoff:'v1Incremental.Cutoff.t->?data_equal:('v1->'v1->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->f:(('v1,'w)Incremental.t->('v2option,'w)Incremental.t)->(('k,'v2,'cmp)Map.t,'w)Incremental.tvalmapi':?instrumentation:Instrumentation.t->?cutoff:'v1Incremental.Cutoff.t->?data_equal:('v1->'v1->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->f:(key:'k->data:('v1,'w)Incremental.t->('v2,'w)Incremental.t)->(('k,'v2,'cmp)Map.t,'w)Incremental.tvalpartition_mapi:?instrumentation:Instrumentation.t->?data_equal:('v1->'v1->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->f:(key:'k->data:'v1->('v2,'v3)Either.t)->(('k,'v2,'cmp)Map.t*('k,'v3,'cmp)Map.t,'w)Incremental.tvalpartition_mapi':?instrumentation:Instrumentation.t->?cutoff:'v1Incremental.Cutoff.t->?data_equal:('v1->'v1->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->f:(key:'k->data:('v1,'w)Incremental.t->(('v2,'v3)Either.t,'w)Incremental.t)->(('k,'v2,'cmp)Map.t*('k,'v3,'cmp)Map.t,'w)Incremental.t(** [unordered_fold i ~init ~add ~remove] constructs a more incremental version of:
{[
let%map m = i in
Map.fold m ~init ~f:add
]}
assuming that [remove] is the inverse of [add], and that the operations for
different keys can be performed in any order. Note that [data_equal] defaults
to [phys_equal], but a more precise equality can be provided instead.
When the data for a key updates, by default [remove] is called on the old data
and then [add] is called on the new data.
[update] provides an alternative single function to call each time a key's data
updates, and can be used to improve efficiency.
For the initial computation, by default [add] is called on all the elements in the
map. As this can be inefficient, [specialized_initial] can be provided to perform
the computation in a more effective way.
If [revert_to_init_when_empty] is true, then if the input map transitions from
being full to empty, then instead of calling [remove] on every kv-pair, it will
instead just set the output to whatever you've passed as [init].
The default value of [revert_to_init_when_empty] is [false], so this optimization
does not apply automatically.
[finalize] defaults to [Fn.id] is called immediately before the accumulator value
is stored and returned during stabilization. You can use it to e.g. process the
fold operations in a different order. *)valunordered_fold:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->?update:(key:'k->old_data:'v->new_data:'v->'acc->'acc)->?specialized_initial:(init:'acc->('k,'v,'cmp)Map.t->'acc)->?finalize:('acc->'acc)->?revert_to_init_when_empty:bool->(('k,'v,'cmp)Map.t,'w)Incremental.t->init:'acc->add:(key:'k->data:'v->'acc->'acc)->remove:(key:'k->data:'v->'acc->'acc)->('acc,'w)Incremental.t(** [unordered_fold_with_extra] is similar to [unordered_fold], but it also
depends on another arbitrary incremental value which can be factored into
the folding computation. *)valunordered_fold_with_extra:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->?extra_equal:('extra->'extra->bool)->?update:(key:'k->old_data:'v->new_data:'v->'acc->'extra->'acc)->?specialized_initial:(init:'acc->('k,'v,'e)Map.t->'extra->'acc)->?finalize:('acc->'acc)->?revert_to_init_when_empty:bool->(('k,'v,'e)Map.t,'w)Incremental.t->('extra,'w)Incremental.t->init:'acc->add:(key:'k->data:'v->'acc->'extra->'acc)->remove:(key:'k->data:'v->'acc->'extra->'acc)->extra_changed:(old_extra:'extra->new_extra:'extra->input:('k,'v,'e)Map.t->'acc->'acc)->('acc,'w)Incremental.t(** [cutoff] applies a cutoff to values in the map as they pass through the
function. It has the same behavior as calling [Incr_map.map'] with an
[Incr.set_cutoff] inside, but with considerably better performance and
memory usage. *)valcutoff:?instrumentation:Instrumentation.t->(('k,'v,'cmp)Map.t,'w)Incremental.t->cutoff:'vIncremental.Cutoff.t->(('k,'v,'cmp)Map.t,'w)Incremental.t(** Given an input map and a function mapping a kv-pair to a new
value, [mapi_count] will compute a multi-set keyed on that
new value.
Any value that would otherwise have a count of "0" is instead
removed from the map.
It is assumed that [f] is quite fast as the function will be
called more often than strictly necessary, but it does this
in order to avoid allocating an extra map. If [f] is very slow
and you don't mind the extra allocations, use
[Incr_map.index_byi] composed with [Incr_map.map ~f:Map.length] *)valmapi_count:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k1,'v,'cmp1)Map.t,'w)Incremental.t->comparator:('k2,'cmp2)Comparator.Module.t->f:(key:'k1->data:'v->'k2)->(('k2,int,'cmp2)Map.t,'w)Incremental.t(** The same as [mapi_count] but the [f] function only gets to see the
data instead of both the key and the data. *)valmap_count:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k1,'v,'cmp1)Map.t,'w)Incremental.t->comparator:('k2,'cmp2)Comparator.Module.t->f:('v->'k2)->(('k2,int,'cmp2)Map.t,'w)Incremental.t(** Computes the smallest [r] where [r] is computed for each kv-pair in the
input map. *)valmapi_min:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->comparator:('r,_)Comparator.Module.t->f:(key:'k->data:'v->'r)->('roption,'w)Incremental.t(** Computes the largest [r] where [r] is computed for each kv-pair in the
input map. *)valmapi_max:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->comparator:('r,_)Comparator.Module.t->f:(key:'k->data:'v->'r)->('roption,'w)Incremental.t(** Computes the smallest [r] where [r] is computed for each kv-pair in the
input map. *)valmap_min:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->comparator:('r,_)Comparator.Module.t->f:('v->'r)->('roption,'w)Incremental.t(** Computes the largest [r] where [r] is computed for each kv-pair in the
input map. *)valmap_max:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->comparator:('r,_)Comparator.Module.t->f:('v->'r)->('roption,'w)Incremental.t(** Computes the smallest data value from the input map. *)valmin_value:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->comparator:('v,_)Comparator.Module.t->('voption,'w)Incremental.t(** Computes the largest data value from the input map. *)valmax_value:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->comparator:('v,_)Comparator.Module.t->('voption,'w)Incremental.t(** Computes [min * max] where the value is computed for each kv-pair
in the input map *)valmapi_bounds:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->comparator:('r,_)Comparator.Module.t->f:(key:'k->data:'v->'r)->(('r*'r)option,'w)Incremental.t(** Computes [min * max] where the value is computed for each kv-pair
in the input map *)valmap_bounds:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->comparator:('r,_)Comparator.Module.t->f:('v->'r)->(('r*'r)option,'w)Incremental.t(** Computes the smallest and largest data value from the input map. *)valvalue_bounds:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->comparator:('v,_)Comparator.Module.t->(('v*'v)option,'w)Incremental.t(** Like [merge] in [Base.Map.merge]. Note that [f] is called at most once per key in
any given stabilization. *)valmerge:?instrumentation:Instrumentation.t->?data_equal_left:('v1->'v1->bool)->?data_equal_right:('v2->'v2->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->(('k,'v2,'cmp)Map.t,'w)Incremental.t->f:(key:'k->('v1,'v2)Map.Merge_element.t->'v3option)->(('k,'v3,'cmp)Map.t,'w)Incremental.t(** [merge_both_same] is like [merge], but optimized for the case where you only care
about the case where both maps contain a particular key. *)valmerge_both_some:?instrumentation:Instrumentation.t->?data_equal_left:('v1->'v1->bool)->?data_equal_right:('v2->'v2->bool)->?out_equal:('v3->'v3->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->(('k,'v2,'cmp)Map.t,'w)Incremental.t->f:(key:'k->'v1->'v2->'v3)->(('k,'v3,'cmp)Map.t,'w)Incremental.t(** Like [merge], but operating using incremental nodes. This is a good use case for
[ppx_pattern_bind]. *)valmerge':?instrumentation:Instrumentation.t->?cutoff:('v1,'v2)Map.Merge_element.tIncremental.Cutoff.t->?data_equal_left:('v1->'v1->bool)->?data_equal_right:('v2->'v2->bool)->(('k,'v1,'cmp)Map.t,'w)Incremental.t->(('k,'v2,'cmp)Map.t,'w)Incremental.t->f:(key:'k->(('v1,'v2)Map.Merge_element.t,'w)Incremental.t->('v3option,'w)Incremental.t)->(('k,'v3,'cmp)Map.t,'w)Incremental.tvalunzip:?instrumentation:Instrumentation.t->?left_result_equal:('a->'a->bool)->?right_result_equal:('b->'b->bool)->(('k,'a*'b,'cmp)Map.t,'w)Incremental.t->(('k,'a,'cmp)Map.t,'w)Incremental.t*(('k,'b,'cmp)Map.t,'w)Incremental.t(** [unzip_mapi] is similar to [List.unzip], but for incremental maps. Note that [f] may
be called multiple times on a single element. *)valunzip_mapi:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->?left_result_equal:('v1->'v1->bool)->?right_result_equal:('v2->'v2->bool)->(('k,'v,'cmp)Map.t,'w)Incremental.t->f:(key:'k->data:'v->'v1*'v2)->(('k,'v1,'cmp)Map.t,'w)Incremental.t*(('k,'v2,'cmp)Map.t,'w)Incremental.t(** [unzip_mapi'] is like [unzip_mapi], but allows you to define the mapping from the
input map's elements to the output maps' elements incrementally.
The naive implementation (see below) produces worse Incremental graphs.
{[
let temp =
Incr_map.mapi' input ~f:(fun ~key ~data ->
f ~key ~data |> Tuple2.uncurry Incr.both)
in
let left = Incr_map.map temp ~f:Tuple2.get1 in
let right = Incr_map.map temp ~f:Tuple2.get2 in
left, right
]} *)valunzip_mapi':?instrumentation:Instrumentation.t->?cutoff:'vIncremental.Cutoff.t->?data_equal:('v->'v->bool)->(('k,'v,'cmp)Map.t,'w)Incremental.t->f:(key:'k->data:('v,'w)Incremental.t->('v1,'w)Incremental.t*('v2,'w)Incremental.t)->(('k,'v1,'cmp)Map.t,'w)Incremental.t*(('k,'v2,'cmp)Map.t,'w)Incremental.t(** This is the "easy" version of [join] *)valflatten:'wIncremental.State.t->('k,('v,'w)Incremental.t,'cmp)Map.t->(('k,'v,'cmp)Map.t,'w)Incremental.t(** The non-incremental semantics of this function is the identity function. Its
purpose is to collapse the extra level of incrementality at the level of the data of
the map.*)valjoin:?instrumentation:Instrumentation.t->(('k,('v,'w)Incremental.t,'cmp)Map.t,'w)Incremental.t->(('k,'v,'cmp)Map.t,'w)Incremental.tvalseparate:?instrumentation:Instrumentation.t->(('k,'v,'cmp)Map.t,'w)Incremental.t->data_equal:('v->'v->bool)->(('k,('v,'w)Incremental.t,'cmp)Map.t,'w)Incremental.tvalkeys:?instrumentation:Instrumentation.t->(('k,'v,'c)Map.t,'w)Incremental.t->(('k,'c)Set.t,'w)Incremental.t(** Computes the [rank] of a key (given incrementally) inside of a map (also
incremental). The traditional [Map.rank] function is O(n), and this incremental
rank function has the following performance characteristics:
definitions:
n : the size of the map
r : the time to compute [Map.symmetric_diff] between the two maps
k : the change in rank of the key between two stabilizations
note that [r] and [k] are _much_ smaller than [n] for most practical purposes
- O(log n) when the key is not in the map.
This takes precedence over other every other scenario.
- O(n) on the initial stabilization
- O(n) when the key transitions from not being in the map to being in the map
- O(log n + r) when the map changes
- O(log n + k) when the key changes
- O(log n + r + k) when both key and map change *)valrank:?instrumentation:Instrumentation.t->(('k,'v,'cmp)Base.Map.t,'state_witness)Incremental.t->('k,'state_witness)Incremental.t->(intoption,'state_witness)Incremental.t(** [subrange map (min, max)] constructs an incremental submap that includes all of the
keys and data from [map] between [min] and [max], and none of the keys outside the
range.
[subrange map None] is the empty map. [range] being [None] means no elements are
chosen.
Note that incremental changes have a runtime of O((k + m) log n) where k is the size
of the changes to the underlying map and m is the size of the changes to the
elements contained by the range. The complexity of the initial computation is the
same as the incremental computation, with some simplification. k = 0 because we have
not made any changes to the underlying map yet, and m equals the size of the range,
because the initial range is empty. *)valsubrange:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,'cmp)Map.t,'w)Incremental.t->(('kMaybe_bound.As_lower_bound.t*'kMaybe_bound.As_upper_bound.t)option,'w)Incremental.t->(('k,'v,'cmp)Map.t,'w)Incremental.t(** [subrange_by_rank map (s, e)] constructs an incremental submap that includes (e-s+1)
keys between s-th and e-th, inclusive.
If s is greater or equal to map length, the result is empty.
If e is greater or equal to map length, the result contains keys from s-th to the
last one.
Raises for invalid indices - s < 0 or e < s.
Runtime of the initial computation is O(min(e, n-s) + log(n)), i.e. linear,
but optimized for ranges close to beginning or end.
Runtime of the incremental computation is O(log(n) + k + (m+m') * log(n)) where:
- k is the size of the diff
- m is the total impact of map changes on the range, bounded by k (e.g. if we add
1001 keys and remove 1000 below s, then m = 1)
- m' = O( |new s - old s| + |new e - old e| ).
*)valsubrange_by_rank:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,'cmp)Map.t,'w)Incremental.t->(intMaybe_bound.As_lower_bound.t*intMaybe_bound.As_upper_bound.t,'w)Incremental.t->(('k,'v,'cmp)Map.t,'w)Incremental.t(** [rekey] transforms a map by modifying the type of the key. The user is
responsible for ensuring that [f] doesn't return the same output key for
multiple input keys.
This function assumes [f] is cheap to compute and accordingly may call
it multiple times. *)valrekey:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k1,'v,'cmp1)Map.t,'w)Incremental.t->comparator:('k2,'cmp2)Comparator.Module.t->f:(key:'k1->data:'v->'k2)->(('k2,'v,'cmp2)Map.t,'w)Incremental.t(** [index_byi map ~comparator ~index] constructs an incremental map-of-maps where each
key-data pair of the input map is present in one (or none) of the inner maps.
[index] specifies the outer map key under which each original key-data pair is
found.
All of the resulting inner maps are guaranteed to be non-empty; if the inner map
would otherwise be empty, then the key for that map is instead removed from the
outer map.
An all-at-once version of [index_by] would look like:
{[
let index_byi map ~comparator ~index =
Map.to_alist map
|> List.filter_map ~f:(fun (key, data) ->
match index ~key ~data with
| None -> None
| Some index -> Some (index, (key, data)))
|> Map.of_alist_multi comparator
|> Map.map ~f:(Map.of_alist_exn (Map.comparator_s map))
;;
]} *)valindex_byi:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('inner_key,'v,'inner_cmp)Map.t,'w)Incremental.t->comparator:('outer_key,'outer_cmp)Comparator.Module.t->index:(key:'inner_key->data:'v->'outer_keyoption)->(('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.t,'w)Incremental.t(** [index_by map ~comparator ~index] is like [index_byi map ~comparator ~index], but
the [index] function does not take the inner map's [key]. *)valindex_by:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('inner_key,'v,'inner_cmp)Map.t,'w)Incremental.t->comparator:('outer_key,'outer_cmp)Comparator.Module.t->index:('v->'outer_keyoption)->(('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.t,'w)Incremental.tvalunordered_fold_nested_maps:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->?revert_to_init_when_empty:bool->?update:(outer_key:'outer_key->inner_key:'inner_key->old_data:'v->new_data:'v->'acc->'acc)->(('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.t,'w)Incremental.t->init:'acc->add:(outer_key:'outer_key->inner_key:'inner_key->data:'v->'acc->'acc)->remove:(outer_key:'outer_key->inner_key:'inner_key->data:'v->'acc->'acc)->('acc,'w)Incremental.t(** [transpose] flips the order of a doubly nested incremental map.
All inner map instances will have at least one element. *)valtranspose:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->('k2,'k2_cmp)Comparator.Module.t->(('k1,('k2,'v,'k2_cmp)Map.t,'k1_cmp)Map.t,'w)Incremental.t->(('k2,('k1,'v,'k1_cmp)Map.t,'k2_cmp)Map.t,'w)Incremental.tvalcollapse:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.t,'w)Incremental.t->comparator:('inner_key,'inner_cmp)Comparator.Module.t->(('outer_key*'inner_key,'v,('outer_cmp,'inner_cmp)Tuple2.comparator_witness)Map.t,'w)Incremental.t(** [collapse_by] is similar to [collapse], but it allows the user to
choose how to combine the two keys from the outer and inner maps.
This does mean that it's the responsibility of the implementor of the
[merge_keys] function to uphold this invariant:
> a merged-key being equal to another merged-key implies that the
> outer-keys and inner-keys which were used to build the merged keys also
> compare to be equal to one another
The [~comparator] argument the first-class module of the output key, it
usually looks like this:
[ ~comparator:(module Combined_key) ]
but make sure that the module implements the [Comparator.S] signature. *)valcollapse_by:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.t,'w)Incremental.t->merge_keys:('outer_key->'inner_key->'combined_key)->comparator:('combined_key,'combined_cmp)Comparator.Module.t->(('combined_key,'v,'combined_cmp)Map.t,'w)Incremental.t(** Convert a map with tuples for keys into a nested map. This operation is roughly the
inverse of [collapse], though if there are outer keys in the uncollapsed map that
correspond to empty inner maps, the outer keys will be dropped from the expanded
map. *)valexpand:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('outer_key*'inner_key,'v,'tuple_cmp)Map.t,'w)Incremental.t->outer_comparator:('outer_key,'outer_cmp)Comparator.Module.t->inner_comparator:('inner_key,'inner_cmp)Comparator.Module.t->(('outer_key,('inner_key,'v,'inner_cmp)Map.t,'outer_cmp)Map.t,'w)Incremental.tvalcounti:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->f:(key:'k->data:'v->bool)->(int,'w)Incremental.tvalcount:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->((_,'v,_)Map.t,'w)Incremental.t->f:('v->bool)->(int,'w)Incremental.tvalfor_alli:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->f:(key:'k->data:'v->bool)->(bool,'w)Incremental.tvalfor_all:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->((_,'v,_)Map.t,'w)Incremental.t->f:('v->bool)->(bool,'w)Incremental.tvalexistsi:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,_)Map.t,'w)Incremental.t->f:(key:'k->data:'v->bool)->(bool,'w)Incremental.tvalexists:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->((_,'v,_)Map.t,'w)Incremental.t->f:('v->bool)->(bool,'w)Incremental.t(** Incrementally compute the sum of all of the values in the map.
Beware of float's negative infinities. They aren't commutative and will misbehave
here.
*)valsum:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->((_,'v,_)Map.t,'w)Incremental.t->(moduleAbstract_algebra.Commutative_group.Without_sexpwithtypet='u)->f:('v->'u)->('u,'w)Incremental.t(** [('k, 'v) Lookup.t] provides a way to lookup keys in a map which uses symmetric
diffs to trigger updates of the lookups.
The complexity of an update depends on:
- [n]: the number of keys in the larger of the old/updated input map
- [k]: the number of lookup nodes created using [find]
- [m]: the number of elements in the symdiff of the maps
- [symdiff(n)]: the cost of performing the symdiff on the map (m <= symdiff(n) <= n)
Each update should cost [O(symdiff(n) + m * log k)], so this will be efficient when
there are a lot of lookups (close to n) into a map which can be efficiently
symdiffed (and therefore has a small number of changes also). The cost of updating
when performing the same lookups by means of [Incr.map ~f:(fun m -> Map.find m key)]
is [O(k * log n)].
*)moduleLookup:sigtype('k,'v,'cmp,'w)t(** Create the lookup structure on an incremental map. *)valcreate:?instrumentation:Instrumentation.t->?data_equal:('v->'v->bool)->(('k,'v,'cmp)Map.t,'w)Incremental.t->comparator:('k,'cmp)Comparator.t->('k,'v,'cmp,'w)t(** Create a node which performs [Map.find] on the input map.
[find (create incr_map) key] should be equivalent to [Incr.map ~f:(fun m ->
Map.find m key) incr_map], but when you call [find] many times for a single
[create] the nodes should update more efficiently in stabilisation when [incr_map]
changes in a way which can be efficiently diffed.
This will re-use existing nodes when it can, but will not always do so.
*)valfind:('k,'v,_,'w)t->'k->('voption,'w)Incremental.t(** A convenient way to refer to the type for a given key. *)moduleM(K:sigtypettypecomparator_witnessend):sigtypenonrec('v,'w)t=(K.t,'v,K.comparator_witness,'w)tendmoduleFor_debug:sigvalsexp_of_t:('k->Sexp.t)->('v->Sexp.t)->('k,'v,'cmp,_)t->Sexp.tendendmoduleFor_testing:sigvalfind_key_range_linear:from:int->to_:int->('a,'b,'c)Base.Map.t->('a*'aoption)optionendmoduletypeS_gen=S_genmoduletypeS=sigtypestate_witnessincludeS_genwithtype'aIncr.t=('a,state_witness)Incremental.tandtype'aIncr.Cutoff.t='aIncremental.Cutoff.tandtype('k,'v,'cmp)Lookup.t=('k,'v,'cmp,state_witness)Lookup.tendmoduleMake(Incr:Incremental.S):Swithtypestate_witness:=Incr.state_witnessandmoduleIncr:=Incrend