Incr_mapSourceFunctions 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.
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.
val of_set :
?instrumentation:Instrumentation.t ->
(('k, 'cmp) Core.Set.t, 'w) Incremental.t ->
(('k, unit, 'cmp) Core.Map.t, 'w) Incremental.tval filter_mapi :
?instrumentation:Instrumentation.t ->
?data_equal:('v1 -> 'v1 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> data:'v1 -> 'v2 option) ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.tval mapi :
?instrumentation:Instrumentation.t ->
?data_equal:('v1 -> 'v1 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> data:'v1 -> 'v2) ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.tval filter_map :
?instrumentation:Instrumentation.t ->
?data_equal:('v1 -> 'v1 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:('v1 -> 'v2 option) ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.tval map :
?instrumentation:Instrumentation.t ->
?data_equal:('v1 -> 'v1 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:('v1 -> 'v2) ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.tval filter_mapi' :
?instrumentation:Instrumentation.t ->
?cutoff:'v1 Incremental.Cutoff.t ->
?data_equal:('v1 -> 'v1 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> data:('v1, 'w) Incremental.t -> ('v2 option, 'w) Incremental.t) ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.tval map' :
?instrumentation:Instrumentation.t ->
?cutoff:'v1 Incremental.Cutoff.t ->
?data_equal:('v1 -> 'v1 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:(('v1, 'w) Incremental.t -> ('v2, 'w) Incremental.t) ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.tval filter_map' :
?instrumentation:Instrumentation.t ->
?cutoff:'v1 Incremental.Cutoff.t ->
?data_equal:('v1 -> 'v1 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:(('v1, 'w) Incremental.t -> ('v2 option, 'w) Incremental.t) ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.tval mapi' :
?instrumentation:Instrumentation.t ->
?cutoff:'v1 Incremental.Cutoff.t ->
?data_equal:('v1 -> 'v1 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> data:('v1, 'w) Incremental.t -> ('v2, 'w) Incremental.t) ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.tval partition_mapi :
?instrumentation:Instrumentation.t ->
?data_equal:('v1 -> 'v1 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> data:'v1 -> ('v2, 'v3) Core.Either.t) ->
(('k, 'v2, 'cmp) Core.Map.t * ('k, 'v3, 'cmp) Core.Map.t, 'w) Incremental.tval partition_mapi' :
?instrumentation:Instrumentation.t ->
?cutoff:'v1 Incremental.Cutoff.t ->
?data_equal:('v1 -> 'v1 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:
(key:'k ->
data:('v1, 'w) Incremental.t ->
(('v2, 'v3) Core.Either.t, 'w) Incremental.t) ->
(('k, 'v2, 'cmp) Core.Map.t * ('k, 'v3, 'cmp) Core.Map.t, 'w) Incremental.tval unordered_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) Core.Map.t -> 'acc) ->
?finalize:('acc -> 'acc) ->
?revert_to_init_when_empty:bool ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.t ->
init:'acc ->
add:(key:'k -> data:'v -> 'acc -> 'acc) ->
remove:(key:'k -> data:'v -> 'acc -> 'acc) ->
('acc, 'w) Incremental.tunordered_fold i ~init ~add ~remove constructs a more incremental version of:
let%map m = i in
Map.fold m ~init ~f:addassuming 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.
val unordered_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) Core.Map.t -> 'extra -> 'acc) ->
?finalize:('acc -> 'acc) ->
?revert_to_init_when_empty:bool ->
(('k, 'v, 'e) Core.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) Core.Map.t ->
'acc ->
'acc) ->
('acc, 'w) Incremental.tunordered_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.
val cutoff :
?instrumentation:Instrumentation.t ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.t ->
cutoff:'v Incremental.Cutoff.t ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.tcutoff 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.
val mapi_count :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k1, 'v, 'cmp1) Core.Map.t, 'w) Incremental.t ->
comparator:('k2, 'cmp2) Core.Comparator.Module.t ->
f:(key:'k1 -> data:'v -> 'k2) ->
(('k2, int, 'cmp2) Core.Map.t, 'w) Incremental.tGiven 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
val map_count :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k1, 'v, 'cmp1) Core.Map.t, 'w) Incremental.t ->
comparator:('k2, 'cmp2) Core.Comparator.Module.t ->
f:('v -> 'k2) ->
(('k2, int, 'cmp2) Core.Map.t, 'w) Incremental.tThe same as mapi_count but the f function only gets to see the data instead of both the key and the data.
val mapi_min :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
comparator:('r, _) Core.Comparator.Module.t ->
f:(key:'k -> data:'v -> 'r) ->
('r option, 'w) Incremental.tComputes the smallest r where r is computed for each kv-pair in the input map.
val mapi_max :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
comparator:('r, _) Core.Comparator.Module.t ->
f:(key:'k -> data:'v -> 'r) ->
('r option, 'w) Incremental.tComputes the largest r where r is computed for each kv-pair in the input map.
val map_min :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
comparator:('r, _) Core.Comparator.Module.t ->
f:('v -> 'r) ->
('r option, 'w) Incremental.tComputes the smallest r where r is computed for each kv-pair in the input map.
val map_max :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
comparator:('r, _) Core.Comparator.Module.t ->
f:('v -> 'r) ->
('r option, 'w) Incremental.tComputes the largest r where r is computed for each kv-pair in the input map.
val min_value :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
comparator:('v, _) Core.Comparator.Module.t ->
('v option, 'w) Incremental.tComputes the smallest data value from the input map.
val max_value :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
comparator:('v, _) Core.Comparator.Module.t ->
('v option, 'w) Incremental.tComputes the largest data value from the input map.
val mapi_bounds :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
comparator:('r, _) Core.Comparator.Module.t ->
f:(key:'k -> data:'v -> 'r) ->
(('r * 'r) option, 'w) Incremental.tComputes min * max where the value is computed for each kv-pair in the input map
val map_bounds :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
comparator:('r, _) Core.Comparator.Module.t ->
f:('v -> 'r) ->
(('r * 'r) option, 'w) Incremental.tComputes min * max where the value is computed for each kv-pair in the input map
val value_bounds :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
comparator:('v, _) Core.Comparator.Module.t ->
(('v * 'v) option, 'w) Incremental.tComputes the smallest and largest data value from the input map.
val merge :
?instrumentation:Instrumentation.t ->
?data_equal_left:('v1 -> 'v1 -> bool) ->
?data_equal_right:('v2 -> 'v2 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> ('v1, 'v2) Core.Map.Merge_element.t -> 'v3 option) ->
(('k, 'v3, 'cmp) Core.Map.t, 'w) Incremental.tLike merge in Base.Map.merge. Note that f is called at most once per key in any given stabilization.
val merge_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) Core.Map.t, 'w) Incremental.t ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> 'v1 -> 'v2 -> 'v3) ->
(('k, 'v3, 'cmp) Core.Map.t, 'w) Incremental.tmerge_both_same is like merge, but optimized for the case where you only care about the case where both maps contain a particular key.
val merge' :
?instrumentation:Instrumentation.t ->
?cutoff:('v1, 'v2) Core.Map.Merge_element.t Incremental.Cutoff.t ->
?data_equal_left:('v1 -> 'v1 -> bool) ->
?data_equal_right:('v2 -> 'v2 -> bool) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t ->
(('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:
(key:'k ->
(('v1, 'v2) Core.Map.Merge_element.t, 'w) Incremental.t ->
('v3 option, 'w) Incremental.t) ->
(('k, 'v3, 'cmp) Core.Map.t, 'w) Incremental.tLike merge, but operating using incremental nodes. This is a good use case for ppx_pattern_bind.
val unzip :
?instrumentation:Instrumentation.t ->
?left_result_equal:('a -> 'a -> bool) ->
?right_result_equal:('b -> 'b -> bool) ->
(('k, 'a * 'b, 'cmp) Core.Map.t, 'w) Incremental.t ->
(('k, 'a, 'cmp) Core.Map.t, 'w) Incremental.t
* (('k, 'b, 'cmp) Core.Map.t, 'w) Incremental.tval unzip_mapi :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
?left_result_equal:('v1 -> 'v1 -> bool) ->
?right_result_equal:('v2 -> 'v2 -> bool) ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> data:'v -> 'v1 * 'v2) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t
* (('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.tunzip_mapi is similar to List.unzip, but for incremental maps. Note that f may be called multiple times on a single element.
val unzip_mapi' :
?instrumentation:Instrumentation.t ->
?cutoff:'v Incremental.Cutoff.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.t ->
f:
(key:'k ->
data:('v, 'w) Incremental.t ->
('v1, 'w) Incremental.t * ('v2, 'w) Incremental.t) ->
(('k, 'v1, 'cmp) Core.Map.t, 'w) Incremental.t
* (('k, 'v2, 'cmp) Core.Map.t, 'w) Incremental.tunzip_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, rightval flatten :
'w Incremental.State.t ->
('k, ('v, 'w) Incremental.t, 'cmp) Core.Map.t ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.tThis is the "easy" version of join
val join :
?instrumentation:Instrumentation.t ->
(('k, ('v, 'w) Incremental.t, 'cmp) Core.Map.t, 'w) Incremental.t ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.tThe 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.
val separate :
?instrumentation:Instrumentation.t ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.t ->
data_equal:('v -> 'v -> bool) ->
(('k, ('v, 'w) Incremental.t, 'cmp) Core.Map.t, 'w) Incremental.tval keys :
?instrumentation:Instrumentation.t ->
(('k, 'v, 'c) Core.Map.t, 'w) Incremental.t ->
(('k, 'c) Core.Set.t, 'w) Incremental.tval rank :
?instrumentation:Instrumentation.t ->
(('k, 'v, 'cmp) Base.Map.t, 'state_witness) Incremental.t ->
('k, 'state_witness) Incremental.t ->
(int option, 'state_witness) Incremental.tComputes 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
val subrange :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.t ->
(('k Core.Maybe_bound.As_lower_bound.t * 'k Core.Maybe_bound.As_upper_bound.t)
option,
'w)
Incremental.t ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.tsubrange 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.
val subrange_by_rank :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.t ->
(int Core.Maybe_bound.As_lower_bound.t
* int Core.Maybe_bound.As_upper_bound.t,
'w)
Incremental.t ->
(('k, 'v, 'cmp) Core.Map.t, 'w) Incremental.tsubrange_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:
val rekey :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k1, 'v, 'cmp1) Core.Map.t, 'w) Incremental.t ->
comparator:('k2, 'cmp2) Core.Comparator.Module.t ->
f:(key:'k1 -> data:'v -> 'k2) ->
(('k2, 'v, 'cmp2) Core.Map.t, 'w) Incremental.trekey 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.
val index_byi :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('inner_key, 'v, 'inner_cmp) Core.Map.t, 'w) Incremental.t ->
comparator:('outer_key, 'outer_cmp) Core.Comparator.Module.t ->
index:(key:'inner_key -> data:'v -> 'outer_key option) ->
(('outer_key, ('inner_key, 'v, 'inner_cmp) Core.Map.t, 'outer_cmp) Core.Map.t,
'w)
Incremental.tindex_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))
;;val index_by :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('inner_key, 'v, 'inner_cmp) Core.Map.t, 'w) Incremental.t ->
comparator:('outer_key, 'outer_cmp) Core.Comparator.Module.t ->
index:('v -> 'outer_key option) ->
(('outer_key, ('inner_key, 'v, 'inner_cmp) Core.Map.t, 'outer_cmp) Core.Map.t,
'w)
Incremental.tindex_by map ~comparator ~index is like index_byi map ~comparator ~index, but the index function does not take the inner map's key.
val unordered_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) Core.Map.t, 'outer_cmp) Core.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.tval transpose :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
('k2, 'k2_cmp) Core.Comparator.Module.t ->
(('k1, ('k2, 'v, 'k2_cmp) Core.Map.t, 'k1_cmp) Core.Map.t, 'w) Incremental.t ->
(('k2, ('k1, 'v, 'k1_cmp) Core.Map.t, 'k2_cmp) Core.Map.t, 'w) Incremental.ttranspose flips the order of a doubly nested incremental map.
All inner map instances will have at least one element.
val collapse :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('outer_key, ('inner_key, 'v, 'inner_cmp) Core.Map.t, 'outer_cmp) Core.Map.t,
'w)
Incremental.t ->
comparator:('inner_key, 'inner_cmp) Core.Comparator.Module.t ->
(('outer_key * 'inner_key,
'v,
('outer_cmp, 'inner_cmp) Core.Tuple2.comparator_witness)
Core.Map.t,
'w)
Incremental.tval collapse_by :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('outer_key, ('inner_key, 'v, 'inner_cmp) Core.Map.t, 'outer_cmp) Core.Map.t,
'w)
Incremental.t ->
merge_keys:('outer_key -> 'inner_key -> 'combined_key) ->
comparator:('combined_key, 'combined_cmp) Core.Comparator.Module.t ->
(('combined_key, 'v, 'combined_cmp) Core.Map.t, 'w) Incremental.tcollapse_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.
val expand :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('outer_key * 'inner_key, 'v, 'tuple_cmp) Core.Map.t, 'w) Incremental.t ->
outer_comparator:('outer_key, 'outer_cmp) Core.Comparator.Module.t ->
inner_comparator:('inner_key, 'inner_cmp) Core.Comparator.Module.t ->
(('outer_key, ('inner_key, 'v, 'inner_cmp) Core.Map.t, 'outer_cmp) Core.Map.t,
'w)
Incremental.tConvert 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.
val counti :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> data:'v -> bool) ->
(int, 'w) Incremental.tval count :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
((_, 'v, _) Core.Map.t, 'w) Incremental.t ->
f:('v -> bool) ->
(int, 'w) Incremental.tval for_alli :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> data:'v -> bool) ->
(bool, 'w) Incremental.tval for_all :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
((_, 'v, _) Core.Map.t, 'w) Incremental.t ->
f:('v -> bool) ->
(bool, 'w) Incremental.tval existsi :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
(('k, 'v, _) Core.Map.t, 'w) Incremental.t ->
f:(key:'k -> data:'v -> bool) ->
(bool, 'w) Incremental.tval exists :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
((_, 'v, _) Core.Map.t, 'w) Incremental.t ->
f:('v -> bool) ->
(bool, 'w) Incremental.tval sum :
?instrumentation:Instrumentation.t ->
?data_equal:('v -> 'v -> bool) ->
((_, 'v, _) Core.Map.t, 'w) Incremental.t ->
(module Abstract_algebra.Commutative_group.Without_sexp with type t = 'u) ->
f:('v -> 'u) ->
('u, 'w) Incremental.tIncrementally 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.
('k, 'v) Lookup.t provides a way to lookup keys in a map which uses symmetric diffs to trigger updates of the lookups.
module Make
(Incr : Incremental.S) :
S with type state_witness := Incr.state_witness and module Incr := Incr