123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218(**************************************************************************)(* This file is part of the Codex semantics library. *)(* *)(* Copyright (C) 2013-2025 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file LICENSE). *)(* *)(**************************************************************************)moduletypeKey=sigtypetvalnearest_common_ancestor:t->t->tvalis_prefix:t->t->boolvalequal:t->t->boolvalpretty:Format.formatter->t->unitend(* let res = Key.nearest_common_ancestor 0b10111 0b10101;; *)moduleMake_no_empty(Key:Key)=structtype'at=|Nodeof{key:Key.t;value:'a;children:'atlist};;letleafkeyvalue=Node{key;value;children=[]};;letget_key=function|Node{key}->key;;letfindkey_to_findmap=(* Invariant of this loop: key_to_find is a suffix of the key of map. *)letrecfindkey_to_find=function|Node{key;value}whenKey.equalkeykey_to_find->value(* avoids iteration on the children. *)|Node{key;value;children}->assert(Key.is_prefixkeykey_to_find);(* Try to find a more precise children. *)letrecloop=function(* No children correspond: returns value. *)|[]->value|(Node{key=child_key}ashd)::tl->ifKey.is_prefixchild_keykey_to_findthenfindkey_to_findhdelselooptlinloopchildreninletNode{key}=mapinifKey.is_prefixkeykey_to_findthenfindkey_to_findmapelseassertfalse(* Trying to find a key that was never mapped. *)(* Codex_log.fatal *)(* Codex_log.feedback "Trying to find for a key outside of this map: %a %a"
* Key.pretty key Key.pretty key_to_find; *);;(* The general idea: select the branch with the longest prefix match, and insert an interior node where they diverge. To find which son is the good one, we use nearest_common_ancestor between the son and the key to insert; if it goes further than the parent, then the son goes in the right direction.
*)(* We take a key, a group, and we maintain a structure such that for
all elements in the tree, we have the product of all the values
of the group with operation inter. *)letupdate_allintervalue_to_inserttrie=letrecloop=function(* | Leaf{key;value} -> Leaf{key;value=inter value value_to_insert} *)|Node{key;value;children}->letchildren=List.maploopchildreninletvalue=matchvaluewith(* | None -> Some value_to_insert *)|x->interxvalue_to_insertinNode{key;value;children}inlooptrie;;letrecrefinekey_to_insert~inter~joinvalue_to_inserttrie=matchtriewith|Node{key;value;children}whenKey.equalkeykey_to_insert->update_allintervalue_to_inserttrie|Node{key;value;children}->letnca=Key.nearest_common_ancestorkeykey_to_insertinifKey.equalncakey_to_insertthen(* Add a new interior node, and change everythng beneath *)Node{key=key_to_insert;value=intervaluevalue_to_insert;children=[update_allintervalue_to_inserttrie]}elseifKey.equalncakeythen(* Insert somewhere in the tree, either further down, or as a
new child. *)letrecloop=function|[]->(* No children correspond: add a new. *)[leafkey_to_insert(intervaluevalue_to_insert)]|hd::tl->letchild_key=get_keyhdin(* If it progresses in the right direction, go see this children, else try the next. *)if(Key.equal(Key.nearest_common_ancestorchild_keykey_to_insert)key)thenhd::(looptl)else(refinekey_to_insert~inter~joinvalue_to_inserthd)::tlinNode{key;value;children=loopchildren}elseletjoined_value=joinvaluevalue_to_insertin(* The two keys are on different branches. *)Node{key=nca;value=joined_value;children=[trie;leafkey_to_insertvalue_to_insert]};;letsingletonkeyvalue=leafkeyvalueletrecmake_prettyfvaluefmt=function|Node{key;value;children;}->Format.fprintffmt"%a -> %a@\n"Key.prettykeyfvaluevalue;ifchildren!=[]thenbeginFormat.fprintffmt"[ @[<v>";children|>List.iter(funx->Format.fprintffmt"%a"(make_prettyfvalue)x);Format.fprintffmt"@]]"end;;endmoduleMake(Key:Key)=structmoduleM=Make_no_empty(Key)type'at='aM.toptionletrefinekey_to_insert~inter~joinvalue_to_inserttrie=matchtriewith|None->Some(M.singletonkey_to_insertvalue_to_insert)|Somex->Some(M.refinekey_to_insert~inter~joinvalue_to_insertx)letfindkey=function|None->(* Codex_log.feedback "Find with key %a" Key.pretty key; *)raiseNot_found|Somex->M.findkeyxletempty=Noneletrefinekey_to_insert~inter~joinvalue_to_inserttrie=(* Codex_log.feedback "Treemap.refine key %a" Key.pretty key_to_insert; *)refinekey_to_insert~inter~joinvalue_to_inserttrie;;letmake_prettyfvaluefmt=function|None->Format.fprintffmt"<empty>"|Somex->M.make_prettyfvaluefmtx;;end(**************** Testing code. ****************)(* ocamlc treemap.ml && ./a.out *)(* A map from a set having tree elements. *)(* module Key:Key with type t = int = struct
*
* type t = int
*
* let parent x = x lsr 1
*
* let equal a b = a = b
*
* (\* Leq means is prefix in the tree order, or is on the path to the root *\)
* let rec is_prefix a b =
* if b < a then false (\* Speedup *\)
* else if a = b then true
* else is_prefix a (parent b)
*
* let rec nearest_common_ancestor a b =
* if a = b
* then a
* else if a < b
* then nearest_common_ancestor a (parent b)
* else nearest_common_ancestor (parent a) b
* ;;
*
* let pretty fmt x = Format.fprintf fmt "%d" x
*
* end
*
*
* module M = Make_no_empty(Key)
* let refine key value trie = M.refine key (^) (^) value trie;;
*
* let treei = M.singleton 0b1 "i";;
* let tree0 = refine 0b101 "a" treei;;
* let tree1 = refine 0b01010 "b" tree0;;
* let tree2 = refine 0b101 "c" tree1;;
* let tree3 = refine 0b1111 "d" tree2;;
* let tree4 = refine 0b1100 "e" tree3;;
*
* let find = M.find;;
* find 0b1111 tree4;;
* find 0b1100 tree4;;
* find 0b1 tree4;;
* find 0b01010 tree4;;
* find 0b101 tree4;;
* find 0b11 tree4;;
* find 0b1011 tree4;;
*
* let tree2_i = M.singleton 0b1110 "a";;
* let tree2_1 = refine 0b1111 "b" tree2_i;; *)