(* * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. *) (** Multiset - Set with multiplicity for each element *) open NS0 include Multiset_intf module Make (Mul : MULTIPLICITY) (Elt : sig type t [@@deriving compare, sexp_of] end) = struct module M = Map.Make (Elt) type mul = Mul.t type elt = Elt.t type t = Mul.t M.t let compare = M.compare Mul.compare let equal = M.equal Mul.equal let hash_fold_t hash_fold_elt s m = let hash_fold_mul s i = Hash.fold_int s (Mul.hash i) in M.fold m ~init:(Hash.fold_int s (M.length m)) ~f:(fun ~key ~data state -> hash_fold_mul (hash_fold_elt state key) data ) let sexp_of_t s = List.sexp_of_t (Sexplib.Conv.sexp_of_pair Elt.sexp_of_t Mul.sexp_of_t) (M.to_alist s) let t_of_sexp elt_of_sexp sexp = List.fold_left ~f:(fun m (key, data) -> M.add_exn m ~key ~data) ~init:M.empty (List.t_of_sexp (Sexplib.Conv.pair_of_sexp elt_of_sexp Mul.t_of_sexp) sexp) let pp sep pp_elt fs s = List.pp sep pp_elt fs (M.to_alist s) let empty = M.empty let of_ x i = if Mul.equal Mul.zero i then empty else M.singleton x i let if_nz i = if Mul.equal Mul.zero i then None else Some i let add m x i = M.change m x ~f:(function | Some j -> if_nz (Mul.add i j) | None -> if_nz i ) let remove m x = M.remove m x let find_and_remove = M.find_and_remove let union m n = M.union m n ~f:(fun _ i j -> if_nz (Mul.add i j)) let diff m n = M.merge m n ~f:(fun ~key:_ -> function | `Both (i, j) -> if_nz (Mul.sub i j) | `Left i -> Some i | `Right j -> Some (Mul.neg j) ) let partition = M.partition let map m ~f = let m' = empty in let m, m' = M.fold m ~init:(m, m') ~f:(fun ~key:x ~data:i (m, m') -> let x', i' = f x i in if x' == x then if Mul.equal i' i then (m, m') else (M.set m ~key:x ~data:i', m') else (M.remove m x, add m' x' i') ) in union m m' let map_counts m ~f = M.map ~f m let mapi_counts m ~f = M.mapi ~f:(fun ~key ~data -> f key data) m let flat_map m ~f = let m' = empty in let m, m' = M.fold m ~init:(m, m') ~f:(fun ~key:x ~data:i (m, m') -> let d = f x i in match M.only_binding d with | Some (x', i') -> if x' == x then if Mul.equal i' i then (m, m') else (M.set m ~key:x ~data:i', m') else (M.remove m x, union m' d) | None -> (M.remove m x, union m' d) ) in union m m' let is_empty = M.is_empty let is_singleton = M.is_singleton let length m = M.length m let count m x = match M.find m x with Some q -> q | None -> Mul.zero let only_elt = M.only_binding let classify = M.classify let choose = M.choose let choose_exn = M.choose_exn let pop = M.pop let min_elt = M.min_binding let pop_min_elt = M.pop_min_binding let to_list m = M.to_alist m let iter m ~f = M.iteri ~f:(fun ~key ~data -> f key data) m let exists m ~f = M.existsi ~f:(fun ~key ~data -> f key data) m let for_all m ~f = M.for_alli ~f:(fun ~key ~data -> f key data) m let fold m ~init ~f = M.fold ~f:(fun ~key ~data -> f key data) m ~init end