|
| 1 | +type id = int |
| 2 | +type update = {id: id ; previous_size: int ; current_size: int} |
| 3 | +type updates = update list |
| 4 | + |
| 5 | +type t = |
| 6 | + { |
| 7 | + rep: int option Mods.DynArray.t ; |
| 8 | + back: Mods.IntSet.t Mods.DynArray.t ; |
| 9 | + size: int Mods.DynArray.t; |
| 10 | + |
| 11 | + blackboard : int option Mods.DynArray.t ; |
| 12 | + blackboard_keys: id list ; |
| 13 | + to_check: Mods.IntSet.t ; |
| 14 | + updates: update option Mods.DynArray.t ; |
| 15 | + update_keys: id list; |
| 16 | + } |
| 17 | + |
| 18 | +(*val bind: t -> id -> id -> t |
| 19 | +val check: neightboor:(id -> id list) -> t -> id list -> t |
| 20 | +val flush_updates: t -> t * updates |
| 21 | +val convert_updates: updates -> (int * int * int) list *) |
| 22 | + |
| 23 | +let init = |
| 24 | + { |
| 25 | + blackboard = Mods.DynArray.create 0 None ; |
| 26 | + blackboard_keys = []; |
| 27 | + to_check = Mods.IntSet.empty ; |
| 28 | + updates = Mods.DynArray.create 0 None; |
| 29 | + update_keys = [] ; |
| 30 | + rep = Mods.DynArray.create 0 None ; |
| 31 | + size = Mods.DynArray.create 0 0 ; |
| 32 | + back = Mods.DynArray.create 0 (Mods.IntSet.empty); |
| 33 | + } |
| 34 | + |
| 35 | +let get_rep t i = |
| 36 | + let rec aux t x l = |
| 37 | + let rep_opt = Mods.DynArray.get t.rep x in |
| 38 | + match rep_opt with |
| 39 | + | Some rep -> |
| 40 | + if x = rep then |
| 41 | + let t = List.fold_left (fun t x -> let () = Mods.DynArray.set t.rep x (Some rep) in t) t l in |
| 42 | + t, rep |
| 43 | + else |
| 44 | + aux t rep (x::l) |
| 45 | + | None -> (* TO DO ERROR *) assert false |
| 46 | + in aux t i [] |
| 47 | + |
| 48 | +let get_rep_size t i = |
| 49 | + t, Mods.DynArray.get t.size i |
| 50 | + |
| 51 | +let get_size t i = |
| 52 | + let t, rep = get_rep t i in |
| 53 | + get_rep_size t rep |
| 54 | + |
| 55 | +let add_update t update = |
| 56 | + match |
| 57 | + Mods.DynArray.get t.updates update.id |
| 58 | + with |
| 59 | + | None -> |
| 60 | + let t, previous_size = get_size t update.id in |
| 61 | + if previous_size = update.current_size then |
| 62 | + t |
| 63 | + else |
| 64 | + let id = update.id in |
| 65 | + let () = |
| 66 | + Mods.DynArray.set |
| 67 | + t.updates |
| 68 | + |
| 69 | + update.id |
| 70 | + (Some {id ; previous_size; current_size = update.current_size}) |
| 71 | + in |
| 72 | + let update_keys = id :: t.update_keys in |
| 73 | + {t with update_keys} |
| 74 | + |
| 75 | + | Some last -> |
| 76 | + let () = |
| 77 | + Mods.DynArray.set t.updates update.id (Some {last with current_size = update.current_size}) |
| 78 | + in t |
| 79 | + |
| 80 | +let flush_updates t = |
| 81 | + let updates, l = |
| 82 | + List.fold_left |
| 83 | + (fun (updates,l) i -> |
| 84 | + match Mods.DynArray.get t.updates i with |
| 85 | + | None -> (updates, l) |
| 86 | + | Some u -> |
| 87 | + let () = Mods.DynArray.set updates i None in |
| 88 | + updates, |
| 89 | + (u)::l) |
| 90 | + (t.updates,[]) |
| 91 | + t.update_keys |
| 92 | + in |
| 93 | + {t with updates}, l |
| 94 | + |
| 95 | +let create t i = |
| 96 | + let () = Mods.DynArray.set t.rep i (Some i) in |
| 97 | + let () = Mods.DynArray.set t.size i 1 in |
| 98 | + let () = Mods.DynArray.set t.back i (Mods.IntSet.singleton i) in |
| 99 | + add_update t {id=i; previous_size=0; current_size=1} |
| 100 | + |
| 101 | +let get_back_set t i = Mods.DynArray.get t.back i |
| 102 | + |
| 103 | +let bind t i j = |
| 104 | + let t, repi = get_rep t i in |
| 105 | + let t, repj = get_rep t j in |
| 106 | + if repi = repj then |
| 107 | + t |
| 108 | + else |
| 109 | + let t, sizei = get_size t repi in |
| 110 | + let t, sizej = get_size t repj in |
| 111 | + let size = sizei + sizej in |
| 112 | + let repi, repj = if repi < repj then repi, repj else repj, repi in |
| 113 | + let () = Mods.DynArray.set t.rep repj (Some repi) in |
| 114 | + let () = Mods.DynArray.set t.size repi size in |
| 115 | + let cc = Mods.IntSet.union (get_back_set t repi) (get_back_set t repj) in |
| 116 | + let () = Mods.DynArray.set t.back repi cc in |
| 117 | + let () = Mods.DynArray.set t.back repj (Mods.IntSet.empty) in |
| 118 | + t |
| 119 | + |
| 120 | +(* TO DO *) |
| 121 | +let unbind t i j = |
| 122 | + let to_check = t.to_check in |
| 123 | + let to_check = Mods.IntSet.add i to_check in |
| 124 | + let to_check = Mods.IntSet.add j to_check in |
| 125 | + {t with to_check} |
| 126 | + |
| 127 | +let degrade ~neightbor:f t i = |
| 128 | + let list = f i in |
| 129 | + List.fold_left |
| 130 | + (fun t j -> unbind t i j) |
| 131 | + t list |
| 132 | + |
| 133 | +let scan i l = |
| 134 | + let rec aux i l acc = |
| 135 | + match l with |
| 136 | + | (k,d)::t when k = i -> (List.rev acc)@t, Some d |
| 137 | + | (k,d)::t -> aux i t ((k,d)::t) |
| 138 | + | [] -> List.rev acc, None |
| 139 | + in |
| 140 | + aux i l [] |
| 141 | + |
| 142 | +let scan2 i l l' = |
| 143 | + match scan i l with |
| 144 | + | l, Some a -> Some a, l, l' |
| 145 | + | _, None -> |
| 146 | + begin |
| 147 | + let l', a = scan i l' in a, l, l' |
| 148 | + end |
| 149 | + |
| 150 | + |
| 151 | +let flush ~neightbor:f t = |
| 152 | + let set = t.to_check in |
| 153 | + let l = Mods.IntSet.fold (fun i l -> (i,[i])::l) set [] in |
| 154 | + let rec aux to_visit to_visit_after t alias = |
| 155 | + match to_visit, to_visit_after with |
| 156 | + | [],[] -> t, alias |
| 157 | + | [], _ -> aux (List.rev to_visit_after) [] t alias |
| 158 | + | (_, [])::tail', _ -> aux tail' to_visit_after t alias |
| 159 | + | (i,(h::tail))::tail', _ -> |
| 160 | + begin |
| 161 | + match Mods.DynArray.get t.blackboard h with |
| 162 | + | None -> |
| 163 | + let () = Mods.DynArray.set t.blackboard h (Some i) in |
| 164 | + let blackboard_keys = h::t.blackboard_keys in |
| 165 | + let t = {t with blackboard_keys} in |
| 166 | + let tail = |
| 167 | + List.fold_left |
| 168 | + (fun l x -> x::l) |
| 169 | + tail (f h) |
| 170 | + in |
| 171 | + aux tail' ((i,tail)::to_visit_after) t alias |
| 172 | + | Some i' when i=i' -> |
| 173 | + (* already seen, nothing to do *) |
| 174 | + aux tail' ((i,tail)::to_visit_after) t alias |
| 175 | + | Some i' -> |
| 176 | + (* seen in another equialent class -> merge *) |
| 177 | + merge (i,tail) i' tail' to_visit_after t ((i,i')::alias) |
| 178 | + end |
| 179 | + |
| 180 | + and merge (i,l1) j to_visit to_visit_after t alias = |
| 181 | + let lj_opt, to_visit, to_visit_after = scan2 j to_visit to_visit_after in |
| 182 | + match lj_opt with |
| 183 | + | None -> assert false |
| 184 | + | Some l2 -> |
| 185 | + begin |
| 186 | + match to_visit, to_visit_after with |
| 187 | + | [], [] -> t, [] |
| 188 | + | _, _ -> |
| 189 | + let l = l1@l2 in |
| 190 | + let i = min i j in |
| 191 | + let to_visit_after = (i,l)::to_visit_after in |
| 192 | + aux to_visit to_visit_after t alias |
| 193 | + end |
| 194 | + in |
| 195 | + let t, aliases = aux l [] t [] in |
| 196 | + let t = |
| 197 | + match aliases with |
| 198 | + | [] -> t |
| 199 | + | _ -> |
| 200 | + begin |
| 201 | + let aliases = List.rev_map (fun (i,j) -> if i<j then i,j else j,i) aliases in |
| 202 | + let aliases = List.sort (fun (a,_) (b,_) -> compare a b) aliases in |
| 203 | + let aliases = |
| 204 | + List.fold_left |
| 205 | + (fun m (i,j) -> |
| 206 | + let im = |
| 207 | + match Mods.IntMap.find_option i m with |
| 208 | + | None -> i |
| 209 | + | Some j -> j |
| 210 | + in |
| 211 | + Mods.IntMap.add j im m) |
| 212 | + Mods.IntMap.empty aliases |
| 213 | + in |
| 214 | + let rec split l m = |
| 215 | + match l with |
| 216 | + | [] -> m |
| 217 | + | h::q -> |
| 218 | + begin |
| 219 | + match Mods.IntMap.find_option h aliases with |
| 220 | + | None -> assert false |
| 221 | + | Some a -> |
| 222 | + let oldset = |
| 223 | + match Mods.IntMap.find_option a m with |
| 224 | + | None -> [] |
| 225 | + | Some a -> a |
| 226 | + in |
| 227 | + split q (Mods.IntMap.add a (h::oldset) m) |
| 228 | + end |
| 229 | + in |
| 230 | + let m = split t.blackboard_keys Mods.IntMap.empty in |
| 231 | + let _ = m in |
| 232 | + (* iterate over blackboard_keys, to change representant *) |
| 233 | + (* iterater *) |
| 234 | + t |
| 235 | + end |
| 236 | + in |
| 237 | + flush_updates t |
0 commit comments