Source file recompute_heap.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
open Core
open Import
module As_recompute_list = Node.Packed.As_list (struct
let next (Node.Packed.T node) = node.next_in_recompute_heap
end)
module Nodes_by_height = struct
type t = As_recompute_list.t Uniform_array.t [@@deriving sexp_of]
let sexp_of_t t =
let max_nonempty_index = ref (-1) in
Uniform_array.iteri t ~f:(fun i l -> if Uopt.is_some l then max_nonempty_index := i);
Uniform_array.sub t ~pos:0 ~len:(!max_nonempty_index + 1) |> [%sexp_of: t]
;;
end
type t = Types.Recompute_heap.t =
{ mutable length : int
; mutable height_lower_bound : int
; mutable nodes_by_height : Nodes_by_height.t
}
[@@deriving fields, sexp_of]
let max_height_allowed t = Uniform_array.length t.nodes_by_height - 1
let is_empty t = t.length = 0
let invariant t =
Invariant.invariant [%here] t [%sexp_of: t] (fun () ->
let check f = Invariant.check_field t f in
Fields.iter
~length:
(check (fun length ->
let actual_length = ref 0 in
Uniform_array.iter t.nodes_by_height ~f:(fun node ->
actual_length := !actual_length + As_recompute_list.length node);
[%test_eq: int] length !actual_length))
~height_lower_bound:
(check (fun height_lower_bound ->
assert (height_lower_bound >= 0);
assert (height_lower_bound <= Uniform_array.length t.nodes_by_height);
for height = 0 to height_lower_bound - 1 do
assert (Uopt.is_none (Uniform_array.get t.nodes_by_height height))
done))
~nodes_by_height:
(check (fun nodes_by_height ->
Uniform_array.iteri nodes_by_height ~f:(fun height node ->
As_recompute_list.iter node ~f:(fun (T node) ->
assert (node.height_in_recompute_heap = height);
assert (Node.needs_to_be_computed node))))))
;;
let create_nodes_by_height ~max_height_allowed =
Uniform_array.create ~len:(max_height_allowed + 1) Uopt.none
;;
let set_max_height_allowed t max_height_allowed =
if debug
then
for i = max_height_allowed + 1 to Uniform_array.length t.nodes_by_height - 1 do
assert (Uopt.is_none (Uniform_array.get t.nodes_by_height i))
done;
let src = t.nodes_by_height in
let dst = create_nodes_by_height ~max_height_allowed in
Uniform_array.blit
~src
~src_pos:0
~dst
~dst_pos:0
~len:(min (Uniform_array.length src) (Uniform_array.length dst));
t.nodes_by_height <- dst;
t.height_lower_bound <- min t.height_lower_bound (Uniform_array.length dst)
;;
let create ~max_height_allowed =
{ length = 0
; height_lower_bound = max_height_allowed + 1
; nodes_by_height = create_nodes_by_height ~max_height_allowed
}
;;
let set_next (prev : Node.Packed.t Uopt.t) ~next =
if Uopt.is_some prev
then (
let (T prev) = Uopt.unsafe_value prev in
prev.next_in_recompute_heap <- next)
;;
let set_prev (next : Node.Packed.t Uopt.t) ~prev =
if Uopt.is_some next
then (
let (T next) = Uopt.unsafe_value next in
next.prev_in_recompute_heap <- prev)
;;
let link (type a) t (node : a Node.t) =
let height = node.height in
if debug then assert (height <= max_height_allowed t);
node.height_in_recompute_heap <- height;
let next = Uniform_array.get t.nodes_by_height height in
node.next_in_recompute_heap <- next;
set_prev next ~prev:(Uopt.some (Node.Packed.T node));
Uniform_array.unsafe_set t.nodes_by_height height (Uopt.some (Node.Packed.T node))
;;
let unlink (type a) t (node : a Node.t) =
let prev = node.prev_in_recompute_heap in
let next = node.next_in_recompute_heap in
if phys_same
(Uopt.some node)
(Uniform_array.get t.nodes_by_height node.height_in_recompute_heap)
then Uniform_array.unsafe_set t.nodes_by_height node.height_in_recompute_heap next;
set_prev next ~prev;
set_next prev ~next;
node.prev_in_recompute_heap <- Uopt.none
;;
let add (type a) t (node : a Node.t) =
if debug && (Node.is_in_recompute_heap node || not (Node.needs_to_be_computed node))
then
failwiths
~here:[%here]
"incorrect attempt to add node to recompute heap"
node
[%sexp_of: _ Node.t];
if debug then assert (node.height <= max_height_allowed t);
let height = node.height in
if height < t.height_lower_bound then t.height_lower_bound <- height;
link t node;
t.length <- t.length + 1
;;
let remove (type a) t (node : a Node.t) =
if debug && ((not (Node.is_in_recompute_heap node)) || Node.needs_to_be_computed node)
then
failwiths
~here:[%here]
"incorrect [remove] of node from recompute heap"
node
[%sexp_of: _ Node.t];
unlink t node;
node.next_in_recompute_heap <- Uopt.none;
node.height_in_recompute_heap <- -1;
t.length <- t.length - 1
;;
let increase_height (type a) t (node : a Node.t) =
if debug
then (
assert (node.height > node.height_in_recompute_heap);
assert (node.height <= max_height_allowed t);
assert (Node.is_in_recompute_heap node));
unlink t node;
link t node
;;
let min_height t =
if t.length = 0
then t.height_lower_bound <- Uniform_array.length t.nodes_by_height
else (
let nodes_by_height = t.nodes_by_height in
while Uopt.is_none (Uniform_array.get nodes_by_height t.height_lower_bound) do
t.height_lower_bound <- t.height_lower_bound + 1
done);
t.height_lower_bound
;;
let remove_min t : Node.Packed.t =
if debug then assert (not (is_empty t));
let nodes_by_height = t.nodes_by_height in
let node = ref (Uniform_array.get nodes_by_height t.height_lower_bound) in
while Uopt.is_none !node do
t.height_lower_bound <- t.height_lower_bound + 1;
if debug && t.height_lower_bound >= Uniform_array.length t.nodes_by_height
then
failwiths
~here:[%here]
"Recompute_heap.remove_min unexpectedly reached end of heap"
t
[%sexp_of: t];
node := Uniform_array.get nodes_by_height t.height_lower_bound
done;
let (T node) = Uopt.unsafe_value !node in
node.height_in_recompute_heap <- -1;
t.length <- t.length - 1;
let next = node.next_in_recompute_heap in
Uniform_array.set t.nodes_by_height t.height_lower_bound next;
set_prev next ~prev:Uopt.none;
if debug then assert (Uopt.is_none node.prev_in_recompute_heap);
node.next_in_recompute_heap <- Uopt.none;
T node
;;