1+ ------------------------------------------------------------------------------------
2+ --@header
3+ --@doc Copyright Leo Freitas 2019-2023
4+ --@doc Bag as an abstract data type (inspired by SPARK ADTs and Z/Eves bags)
5+ ------------------------------------------------------------------------------------
6+ module StrBag
7+ exports
8+ types
9+ Bag;
10+ struct String;
11+ functions
12+ empty: () -> Bag;
13+ isEmpty: Bag -> bool;
14+ bset: Bag -> set of String;
15+ inbag: String * Bag -> bool;
16+ count: Bag -> (String -> nat);
17+ amount: Bag * String -> nat;
18+ post_amount: Bag * String * nat +> bool;
19+ subbageq: Bag * Bag -> bool;
20+ scale: nat * Bag -> Bag;
21+ bunion: Bag * Bag -> Bag;
22+ post_bunion: Bag * Bag * Bag +> bool;
23+ difference: Bag * Bag -> Bag;
24+ post_difference: Bag * Bag * Bag +> bool;
25+ items: seq of String -> Bag;
26+ definitions
27+ types
28+ String = seq1 of char;
29+ Bag = map String to nat1;
30+
31+ functions
32+ empty: () -> Bag
33+ empty() == {|->};
34+
35+ isEmpty: Bag -> bool
36+ isEmpty(b) == b = empty()
37+ post
38+ RESULT <=> b = empty();
39+
40+ bset: Bag -> set of String
41+ bset(b) == dom b;
42+
43+ inbag: String * Bag -> bool
44+ inbag(x, b) == x in set bset(b)
45+ post
46+ RESULT <=> x in set bset(b);
47+
48+ count: Bag -> (String -> nat)
49+ count(b) == (lambda x: String & amount(b, x));
50+
51+ amount: Bag * String -> nat
52+ amount(b, x) ==
53+ if inbag(x, b) then b(x) else 0
54+ post
55+ (inbag(x, b) <=> is_nat1(RESULT));
56+
57+ --@QuickCheck String = nat;
58+ subbageq: Bag * Bag -> bool
59+ subbageq(a, b) ==
60+ forall xa in set dom a & inbag(xa, b) and amount(a, xa) <= amount(b, xa)
61+ post
62+ RESULT <=>
63+ (bset(a) subset bset(b)
64+ and
65+ forall x in set bset(a) & amount(a, x) <= amount(b, x)
66+ );
67+
68+ --@doc ZEves scale definition is wrong! wrt to theorem bagscaleBy1 (!
69+ --@QuickCheck String = nat;
70+ scale: nat * Bag -> Bag
71+ scale(n, b) ==
72+ if n = 0 then
73+ empty()
74+ else
75+ { x |-> n * b(x) | x in set dom b }
76+ post
77+ bset(RESULT) = (if n = 0 then {} else bset(b))
78+ and
79+ (forall x in set bset(b) & amount(RESULT, x) = n * amount(b, x));
80+
81+ --@QuickCheck String = nat;
82+ bunion: Bag * Bag -> Bag
83+ bunion(a, b) ==
84+ --@doc unique of a + unique of b + common with summed amounts
85+ (bset(b) <-: a)
86+ munion
87+ (bset(a) <-: b)
88+ munion
89+ { x |-> a(x) + b(x) | x in set dom a inter dom b }
90+ post
91+ bset(RESULT) = bset(a) union bset(b)
92+ and
93+ (forall x in set bset(a) inter bset(b) & amount(RESULT, x) = amount(a, x) + amount(b, x))
94+ and
95+ (forall x in set bset(a) \ bset(b) & amount(RESULT, x) = amount(a, x))
96+ and
97+ (forall x in set bset(b) \ bset(a) & amount(RESULT, x) = amount(b, x));
98+
99+ --@QuickCheck String = nat;
100+ difference: Bag * Bag -> Bag
101+ difference(a, b) ==
102+ --@doc unique of a with subtraction over common with b (or removal)
103+ bset(b) <-: a
104+ munion
105+ { x |-> a(x) - b(x) | x in set bset(a) inter bset(b) & a(x) > b(x) }
106+ post
107+ --@doc resulting bag has elements of a with elements of b subtracted (or removed)
108+ (forall x in set bset(RESULT) &
109+ amount(RESULT, x) = max(0, amount(a, x) - amount(b, x)));
110+
111+ max: int * int -> int
112+ max(a, b) == if a >= b then a else b;
113+
114+ --@QuickCheck String = nat;
115+ filter: seq of String * (String -> bool) -> seq of String
116+ filter(s, f) == [ s(i) | i in set inds s & f(s(i)) ]
117+ post
118+ RESULT <> [] <=> (forall x in set elems RESULT & f(x));
119+ -- RESULT <> [] <=> elems RESULT = {x};
120+
121+ --@QuickCheck String = nat;
122+ items: seq of String -> Bag
123+ items(s) == { s(i) |-> len filter(s, (lambda x: String & s(i) = x)) | i in set inds s }
124+ post
125+ elems s = bset(RESULT);
126+
127+ end StrBag
0 commit comments