package core_kernel
Industrial strength alternative to OCaml's standard library
Install
Dune Dependency
Authors
Maintainers
Sources
core_kernel-v0.16.0.tar.gz
sha256=e37370bad978cfb71fdaf2b1a25ab1506b98ef0b91e0dbd189ffd9d853245ce2
doc/src/core_kernel.balanced_reducer/balanced_reducer.ml.html
Source file balanced_reducer.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
open! Base (* The [data] array is an implicit binary tree with [children_length * 2 - 1] nodes, with each node being the sum of the two child nodes and the root node being the 0th node. The leaves of the tree are the last [num_leaves] nodes. The children are not necessarily all at the same level of the tree. For instance if you have 3 children [| a; b; c |]: {v o / \ o c / \ a b v} We want this tree to be representated as [| o; o; c; a; b |], i.e. we need to apply first a rotation then a translation to convert an index in [| a; b; c |] to a (leaf) index in [| o; o; c; a; b |]. *) type 'a t = { data : 'a Option_array.t ; num_leaves : int ; num_leaves_not_in_bottom_level : int ; reduce : 'a -> 'a -> 'a ; sexp_of_a : 'a -> Sexp.t } let length t = t.num_leaves (* {v parent: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ... left child: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 ... right child: 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 ... v} *) let parent_index ~child_index = (child_index - 1) / 2 let left_child_index ~parent_index = (parent_index * 2) + 1 let right_child_index ~left_child_index = left_child_index + 1 (* The first [num_leaves-1] elements are internal nodes of the tree. The next [num_leaves] elements are the leaves. *) let num_branches t = t.num_leaves - 1 let index_is_leaf t i = i >= num_branches t (* The tree is complete, but not necessarily perfect, so we perform some rotation of the leaves to ensure that our reductions preserve ordering. *) let leaf_index t i = (* The tree layout is level order. Any leaves in the second to last level need to occur in the array before the leaves in the bottom level. *) let rotated_index = let offset_from_start_of_leaves_in_array = i + t.num_leaves_not_in_bottom_level in if offset_from_start_of_leaves_in_array < t.num_leaves then offset_from_start_of_leaves_in_array else offset_from_start_of_leaves_in_array - t.num_leaves in (* The leaves occur after the branches in the array. *) rotated_index + num_branches t ;; let get_leaf t i = Option_array.get t.data (leaf_index t i) let to_list t = List.init (length t) ~f:(fun i -> get_leaf t i) let sexp_of_t sexp_of_a t = [%sexp (to_list t : a option list)] let invariant invariant_a t = let data = t.data in for i = 0 to Option_array.length data - 1 do match Option_array.get data i with | None -> () | Some a -> invariant_a a done; for i = 0 to num_branches t - 1 do let left = left_child_index ~parent_index:i in let right = right_child_index ~left_child_index:left in let left_is_none = Option_array.is_none data left in let right_is_none = Option_array.is_none data right in if Option_array.is_some data i then assert (not (left_is_none || right_is_none)) else assert ( index_is_leaf t left || index_is_leaf t right || left_is_none || right_is_none) done ;; let create_exn ?(sexp_of_a = [%sexp_of: _]) () ~len:num_leaves ~reduce = if num_leaves < 1 then raise_s [%message "non-positive number of leaves in balanced reducer" (num_leaves : int)]; let num_branches = num_leaves - 1 in let num_leaves_not_in_bottom_level = Int.ceil_pow2 num_leaves - num_leaves in let data = Option_array.create ~len:(num_branches + num_leaves) in { data; num_leaves; num_leaves_not_in_bottom_level; reduce; sexp_of_a } ;; let validate_index t i = if i < 0 then raise_s [%message "attempt to access negative index in balanced reducer" ~index:(i : int)]; let length = t.num_leaves in if i >= length then raise_s [%message "attempt to access out of bounds index in balanced reducer" ~index:(i : int) (length : int)] ;; let set_exn t i a = validate_index t i; let data = t.data in let i = ref (leaf_index t i) in Option_array.set_some data !i a; while !i <> 0 do let parent = parent_index ~child_index:!i in if Option_array.is_none data parent then i := 0 else ( Option_array.unsafe_set_none data parent; i := parent) done ;; let get_exn t i = validate_index t i; Option_array.get_some_exn t.data (leaf_index t i) ;; let rec compute_exn t i = if Option_array.is_some t.data i then Option_array.unsafe_get_some_exn t.data i else ( let left = left_child_index ~parent_index:i in let right = right_child_index ~left_child_index:left in if left >= Option_array.length t.data then ( (* If we get here, the parent was an unset leaf. *) let sexp_of_a = t.sexp_of_a in raise_s [%message "attempt to compute balanced reducer with unset elements" ~balanced_reducer:(t : a t)]); let a = t.reduce (compute_exn t left) (compute_exn t right) in Option_array.unsafe_set_some t.data i a; a) ;; let compute_exn t = compute_exn t 0
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>