author | wenzelm |
Thu, 02 Jan 2025 16:59:42 +0100 | |
changeset 81710 | c914db7419a3 |
parent 80809 | 4a64fc4d1cde |
permissions | -rw-r--r-- |
79074 | 1 |
(* Title: Pure/General/bitset.ML |
2 |
Author: Makarius |
|
3 |
||
79080 | 4 |
Compact representation of sets of integers. |
79074 | 5 |
*) |
6 |
||
7 |
signature BITSET = |
|
8 |
sig |
|
79080 | 9 |
type elem = int |
79077 | 10 |
val make_elem: int * int -> elem (*exception*) |
11 |
val dest_elem: elem -> int * int |
|
79074 | 12 |
type T |
13 |
val empty: T |
|
14 |
val build: (T -> T) -> T |
|
15 |
val is_empty: T -> bool |
|
79075 | 16 |
val fold: (elem -> 'a -> 'a) -> T -> 'a -> 'a |
17 |
val fold_rev: (elem -> 'a -> 'a) -> T -> 'a -> 'a |
|
18 |
val dest: T -> elem list |
|
79079 | 19 |
val is_unique: T -> bool |
79075 | 20 |
val min: T -> elem option |
21 |
val max: T -> elem option |
|
22 |
val get_first: (elem -> 'a option) -> T -> 'a option |
|
23 |
val exists: (elem -> bool) -> T -> bool |
|
24 |
val forall: (elem -> bool) -> T -> bool |
|
25 |
val member: T -> elem -> bool |
|
79074 | 26 |
val subset: T * T -> bool |
27 |
val eq_set: T * T -> bool |
|
79075 | 28 |
val insert: elem -> T -> T |
29 |
val make: elem list -> T |
|
79074 | 30 |
val merge: T * T -> T |
31 |
val merges: T list -> T |
|
79075 | 32 |
val remove: elem -> T -> T |
79074 | 33 |
val subtract: T -> T -> T |
79075 | 34 |
val restrict: (elem -> bool) -> T -> T |
79074 | 35 |
val inter: T -> T -> T |
36 |
val union: T -> T -> T |
|
37 |
end; |
|
38 |
||
39 |
structure Bitset: BITSET = |
|
40 |
struct |
|
41 |
||
42 |
(* bits and words *) |
|
43 |
||
44 |
exception BAD of int; |
|
45 |
||
46 |
val word_size = Word.wordSize; |
|
47 |
||
48 |
val min_bit = 0; |
|
49 |
val max_bit = word_size - 1; |
|
50 |
fun check_bit n = min_bit <= n andalso n <= max_bit; |
|
51 |
||
52 |
fun make_bit n = if check_bit n then Word.<< (0w1, Word.fromInt n) else raise BAD n; |
|
53 |
val mimimum_bit = make_bit min_bit; |
|
54 |
val maximum_bit = make_bit max_bit; |
|
55 |
||
56 |
fun add_bits v w = Word.orb (v, w); |
|
57 |
fun del_bits v w = Word.andb (Word.notb v, w); |
|
58 |
fun incl_bits v w = add_bits v w = w; |
|
59 |
||
60 |
fun fold_bits f w = |
|
61 |
let |
|
79080 | 62 |
fun app n b a = if incl_bits b w then f n a else a; |
79074 | 63 |
fun bits n b a = |
79080 | 64 |
if n = max_bit then app n b a |
65 |
else bits (n + 1) (Word.<< (b, 0w1)) (app n b a); |
|
79074 | 66 |
in bits min_bit mimimum_bit end; |
67 |
||
68 |
fun fold_rev_bits f w = |
|
69 |
let |
|
79080 | 70 |
fun app n b a = if incl_bits b w then f n a else a; |
79074 | 71 |
fun bits n b a = |
79080 | 72 |
if n = min_bit then app n b a |
73 |
else bits (n - 1) (Word.>> (b, 0w1)) (app n b a); |
|
79074 | 74 |
in bits max_bit maximum_bit end; |
75 |
||
76 |
||
77 |
(* datatype *) |
|
78 |
||
79080 | 79 |
type elem = int; |
79075 | 80 |
|
79077 | 81 |
fun make_elem (m, n) : elem = if check_bit n then m * word_size + n else raise BAD n; |
79075 | 82 |
fun dest_elem (x: elem) = Integer.div_mod x word_size; |
83 |
||
79074 | 84 |
datatype T = Bitset of word Inttab.table; |
85 |
||
79075 | 86 |
|
87 |
(* empty *) |
|
88 |
||
79074 | 89 |
val empty = Bitset Inttab.empty; |
90 |
||
91 |
fun build (f: T -> T) = f empty; |
|
92 |
||
93 |
fun is_empty (Bitset t) = Inttab.is_empty t; |
|
94 |
||
95 |
||
96 |
(* fold combinators *) |
|
97 |
||
98 |
fun fold_set f (Bitset t) = |
|
99 |
Inttab.fold (fn (m, w) => |
|
79077 | 100 |
(if m < 0 then fold_rev_bits else fold_bits) (fn n => f (make_elem (m, n))) w) t; |
79074 | 101 |
|
102 |
fun fold_rev_set f (Bitset t) = |
|
103 |
Inttab.fold_rev (fn (m, w) => |
|
79077 | 104 |
(if m < 0 then fold_bits else fold_rev_bits) (fn n => f (make_elem (m, n))) w) t; |
79074 | 105 |
|
106 |
val dest = Library.build o fold_rev_set cons; |
|
107 |
||
79079 | 108 |
fun is_unique (set as Bitset t) = |
109 |
is_empty set orelse |
|
110 |
Inttab.size t = 1 andalso fold_set (fn _ => Integer.add 1) set 0 = 1; |
|
111 |
||
79074 | 112 |
|
113 |
(* min/max entries *) |
|
114 |
||
115 |
fun min (Bitset t) = |
|
116 |
Inttab.min t |> Option.map (fn (m, w) => |
|
79077 | 117 |
make_elem (m, fold_bits Integer.min w max_bit)); |
79074 | 118 |
|
119 |
fun max (Bitset t) = |
|
120 |
Inttab.max t |> Option.map (fn (m, w) => |
|
79077 | 121 |
make_elem (m, fold_bits Integer.max w min_bit)); |
79074 | 122 |
|
123 |
||
124 |
(* linear search *) |
|
125 |
||
126 |
fun get_first f set = |
|
127 |
let exception FOUND of 'a in |
|
128 |
fold_set (fn x => fn a => (case f x of SOME b => raise FOUND b | NONE => a)) set NONE |
|
129 |
handle FOUND b => SOME b |
|
130 |
end; |
|
131 |
||
132 |
fun exists pred = is_some o get_first (fn x => if pred x then SOME x else NONE); |
|
133 |
fun forall pred = not o exists (not o pred); |
|
134 |
||
135 |
||
136 |
(* member *) |
|
137 |
||
138 |
fun member (Bitset t) x = |
|
79075 | 139 |
let val (m, n) = dest_elem x in |
79074 | 140 |
(case Inttab.lookup t m of |
141 |
NONE => false |
|
142 |
| SOME w => incl_bits (make_bit n) w) |
|
143 |
end; |
|
144 |
||
145 |
||
146 |
(* subset *) |
|
147 |
||
148 |
fun subset (Bitset t1, Bitset t2) = |
|
149 |
pointer_eq (t1, t2) orelse |
|
150 |
Inttab.size t1 <= Inttab.size t2 andalso |
|
151 |
t1 |> Inttab.forall (fn (m, w1) => |
|
152 |
(case Inttab.lookup t2 m of |
|
153 |
NONE => false |
|
154 |
| SOME w2 => incl_bits w1 w2)); |
|
155 |
||
156 |
fun eq_set (set1, set2) = |
|
157 |
pointer_eq (set1, set2) orelse subset (set1, set2) andalso subset (set2, set1); |
|
158 |
||
159 |
||
160 |
(* insert *) |
|
161 |
||
162 |
fun insert x (Bitset t) = |
|
79075 | 163 |
let val (m, n) = dest_elem x |
79074 | 164 |
in Bitset (Inttab.map_default (m, 0w0) (add_bits (make_bit n)) t) end; |
165 |
||
166 |
fun make xs = build (fold insert xs); |
|
167 |
||
168 |
||
169 |
(* merge *) |
|
170 |
||
171 |
fun join_bits (w1, w2) = |
|
172 |
let val w = add_bits w2 w1 |
|
173 |
in if w = w1 then raise Inttab.SAME else w end; |
|
174 |
||
175 |
fun merge (set1 as Bitset t1, set2 as Bitset t2) = |
|
176 |
if pointer_eq (set1, set2) then set1 |
|
177 |
else if is_empty set1 then set2 |
|
178 |
else if is_empty set2 then set1 |
|
179 |
else Bitset (Inttab.join (K join_bits) (t1, t2)); |
|
180 |
||
181 |
fun merges sets = Library.foldl merge (empty, sets); |
|
182 |
||
183 |
||
184 |
(* remove *) |
|
185 |
||
186 |
fun remove x (set as Bitset t) = |
|
79075 | 187 |
let val (m, n) = dest_elem x in |
79074 | 188 |
(case Inttab.lookup t m of |
189 |
NONE => set |
|
190 |
| SOME w => |
|
191 |
let val w' = del_bits (make_bit n) w in |
|
192 |
if w = w' then set |
|
193 |
else if w' = 0w0 then Bitset (Inttab.delete m t) |
|
194 |
else Bitset (Inttab.update (m, w') t) |
|
195 |
end) |
|
196 |
end; |
|
197 |
||
198 |
val subtract = fold_set remove; |
|
199 |
||
200 |
||
201 |
(* conventional set operations *) |
|
202 |
||
203 |
fun restrict pred set = |
|
204 |
fold_set (fn x => not (pred x) ? remove x) set set; |
|
205 |
||
206 |
fun inter set1 set2 = |
|
207 |
if pointer_eq (set1, set2) then set1 |
|
208 |
else if is_empty set1 orelse is_empty set2 then empty |
|
209 |
else restrict (member set1) set2; |
|
210 |
||
211 |
fun union set1 set2 = merge (set2, set1); |
|
212 |
||
213 |
||
214 |
(* ML pretty-printing *) |
|
215 |
||
216 |
val _ = |
|
217 |
ML_system_pp (fn depth => fn _ => fn set => |
|
80809
4a64fc4d1cde
clarified signature: type ML_Pretty.pretty coincides with PolyML.pretty;
wenzelm
parents:
79080
diff
changeset
|
218 |
ML_Pretty.enum "," "{" "}" ML_system_pretty (dest set, depth)); |
79074 | 219 |
|
220 |
||
221 |
(*final declarations of this structure!*) |
|
222 |
val fold = fold_set; |
|
223 |
val fold_rev = fold_rev_set; |
|
224 |
||
225 |
end; |