123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195openCoreopenImportmoduleAs_recompute_list=Node.Packed.As_list(structletnext(Node.Packed.Tnode)=node.next_in_recompute_heapend)moduleNodes_by_height=structtypet=As_recompute_list.tUniform_array.t[@@derivingsexp_of](* We display the smallest prefix of [nodes_by_height] that includes all nodes. *)letsexp_of_tt=letmax_nonempty_index=ref(-1)inUniform_array.iterit~f:(funil->ifUopt.is_somelthenmax_nonempty_index:=i);Uniform_array.subt~pos:0~len:(!max_nonempty_index+1)|>[%sexp_of:t];;endtypet=Types.Recompute_heap.t={mutablelength:int;mutableheight_lower_bound:int;mutablenodes_by_height:Nodes_by_height.t}[@@derivingfields,sexp_of]letmax_height_allowedt=Uniform_array.lengtht.nodes_by_height-1letis_emptyt=t.length=0letinvariantt=Invariant.invariant[%here]t[%sexp_of:t](fun()->letcheckf=Invariant.check_fieldtfinFields.iter~length:(check(funlength->letactual_length=ref0inUniform_array.itert.nodes_by_height~f:(funnode->actual_length:=!actual_length+As_recompute_list.lengthnode);[%test_eq:int]length!actual_length))~height_lower_bound:(check(funheight_lower_bound->assert(height_lower_bound>=0);assert(height_lower_bound<=Uniform_array.lengtht.nodes_by_height);forheight=0toheight_lower_bound-1doassert(Uopt.is_none(Uniform_array.gett.nodes_by_heightheight))done))~nodes_by_height:(check(funnodes_by_height->Uniform_array.iterinodes_by_height~f:(funheightnode->As_recompute_list.iternode~f:(fun(Tnode)->assert(node.height_in_recompute_heap=height);assert(Node.needs_to_be_computednode))))));;letcreate_nodes_by_height~max_height_allowed=Uniform_array.create~len:(max_height_allowed+1)Uopt.none;;letset_max_height_allowedtmax_height_allowed=ifdebugthenfori=max_height_allowed+1toUniform_array.lengtht.nodes_by_height-1doassert(Uopt.is_none(Uniform_array.gett.nodes_by_heighti))done;letsrc=t.nodes_by_heightinletdst=create_nodes_by_height~max_height_allowedinUniform_array.blit~src~src_pos:0~dst~dst_pos:0~len:(min(Uniform_array.lengthsrc)(Uniform_array.lengthdst));t.nodes_by_height<-dst;t.height_lower_bound<-mint.height_lower_bound(Uniform_array.lengthdst);;letcreate~max_height_allowed={length=0;height_lower_bound=max_height_allowed+1;nodes_by_height=create_nodes_by_height~max_height_allowed};;letset_next(prev:Node.Packed.tUopt.t)~next=ifUopt.is_someprevthen(let(Tprev)=Uopt.unsafe_valueprevinprev.next_in_recompute_heap<-next);;letset_prev(next:Node.Packed.tUopt.t)~prev=ifUopt.is_somenextthen(let(Tnext)=Uopt.unsafe_valuenextinnext.prev_in_recompute_heap<-prev);;letlink(typea)t(node:aNode.t)=letheight=node.heightinifdebugthenassert(height<=max_height_allowedt);node.height_in_recompute_heap<-height;letnext=Uniform_array.gett.nodes_by_heightheightinnode.next_in_recompute_heap<-next;set_prevnext~prev:(Uopt.some(Node.Packed.Tnode));Uniform_array.unsafe_sett.nodes_by_heightheight(Uopt.some(Node.Packed.Tnode));;letunlink(typea)t(node:aNode.t)=letprev=node.prev_in_recompute_heapinletnext=node.next_in_recompute_heapinifphys_same(Uopt.somenode)(Uniform_array.gett.nodes_by_heightnode.height_in_recompute_heap)thenUniform_array.unsafe_sett.nodes_by_heightnode.height_in_recompute_heapnext;set_prevnext~prev;set_nextprev~next;node.prev_in_recompute_heap<-Uopt.none;;(* We don't set [node.next_in_recompute_heap] here, but rather after calling [unlink]. *)letadd(typea)t(node:aNode.t)=ifdebug&&(Node.is_in_recompute_heapnode||not(Node.needs_to_be_computednode))thenfailwiths~here:[%here]"incorrect attempt to add node to recompute heap"node[%sexp_of:_Node.t];ifdebugthenassert(node.height<=max_height_allowedt);letheight=node.heightinifheight<t.height_lower_boundthent.height_lower_bound<-height;linktnode;t.length<-t.length+1;;letremove(typea)t(node:aNode.t)=ifdebug&&((not(Node.is_in_recompute_heapnode))||Node.needs_to_be_computednode)thenfailwiths~here:[%here]"incorrect [remove] of node from recompute heap"node[%sexp_of:_Node.t];unlinktnode;node.next_in_recompute_heap<-Uopt.none;node.height_in_recompute_heap<--1;t.length<-t.length-1;;letincrease_height(typea)t(node:aNode.t)=ifdebugthen(assert(node.height>node.height_in_recompute_heap);assert(node.height<=max_height_allowedt);assert(Node.is_in_recompute_heapnode));unlinktnode;linktnode;;letmin_heightt=ift.length=0thent.height_lower_bound<-Uniform_array.lengtht.nodes_by_heightelse(letnodes_by_height=t.nodes_by_heightinwhileUopt.is_none(Uniform_array.getnodes_by_heightt.height_lower_bound)dot.height_lower_bound<-t.height_lower_bound+1done);t.height_lower_bound;;letremove_mint:Node.Packed.t=ifdebugthenassert(not(is_emptyt));letnodes_by_height=t.nodes_by_heightinletnode=ref(Uniform_array.getnodes_by_heightt.height_lower_bound)inwhileUopt.is_none!nodedot.height_lower_bound<-t.height_lower_bound+1;ifdebug&&t.height_lower_bound>=Uniform_array.lengtht.nodes_by_heightthenfailwiths~here:[%here]"Recompute_heap.remove_min unexpectedly reached end of heap"t[%sexp_of:t];node:=Uniform_array.getnodes_by_heightt.height_lower_bounddone;let(Tnode)=Uopt.unsafe_value!nodeinnode.height_in_recompute_heap<--1;t.length<-t.length-1;letnext=node.next_in_recompute_heapinUniform_array.sett.nodes_by_heightt.height_lower_boundnext;set_prevnext~prev:Uopt.none;ifdebugthenassert(Uopt.is_nonenode.prev_in_recompute_heap);node.next_in_recompute_heap<-Uopt.none;Tnode;;