AmateurB

Embedding formal methods in Clojure since 2016.

Set Literals

Empty Set

The empty set is a literal:

lisb=> #{}   ;; B: {}
#{}

Enumeration Set

Sets can contain one or more elements. Note that in B, you may write duplicates that are removed (by putting them into a set). lisb, on the other hand, uses Clojure sets to represent a set, so duplicates yield an error in the reader.

lisb=> #{1 3 2}   ;; B: {1, 3, 2}
#{1 3 2}

Comprehension Sets

Sets can also be created by providing a predicate that shall be fulfilled by the elements:

lisb=> (comprehension-set [:x] (and (< 0 :x 10) (= 0 (mod :x 2))))   ;; B: {x|0 < x & x < 10 & 0=x mod 2}
#{4 6 2 8}
lisb=> #{[:x] | (and (< 0 :x 10) (= 0 (mod :x 2)))}   ;; B: {x|0 < x & x < 10 & 0=x mod 2}
#{4 6 2 8}

Subset Operators

The powerset POW is the set of all subsets of the argument. The POW1 operator does not include the empty set.

lisb=> (pow #{1 3 2})   ;; B: POW({1, 3, 2})
#{#{} #{3} #{2} #{1} #{1 3 2} #{1 3} #{1 2} #{3 2}}
lisb=> (pow1 #{1 3 2})   ;; B: POW1({1, 3, 2})
#{#{3} #{2} #{1} #{1 3 2} #{1 3} #{1 2} #{3 2}}

Similarly, all finite subsets are generated with the FIN operator, while FIN1 does also not include the empty set.

lisb=> (pow #{1 3 2})   ;; B: POW({1, 3, 2})
#{#{} #{3} #{2} #{1} #{1 3 2} #{1 3} #{1 2} #{3 2}}
lisb=> (pow1 #{1 3 2})   ;; B: POW1({1, 3, 2})
#{#{3} #{2} #{1} #{1 3 2} #{1 3} #{1 2} #{3 2}}

Cardinality / Size of Set

You can get the number of elements contained in a set by using card:

lisb=> (card #{1 3 2})   ;; B: card({1, 3, 2})
3

Set Union, Intersection, Difference

lisb=> (union #{1 2} #{1 3})   ;; B: {1, 2}\/{1, 3}
#{1 3 2}
lisb=> (intersection #{1 3 2} #{4 3})   ;; B: {1, 3, 2}/\{4, 3}
#{3}
lisb=> (set- #{1 3 2} #{4 3})   ;; B: {1, 3, 2}\{4, 3}
#{1 2}

Membership Test

lisb=> (member? 1 #{1 3 2})   ;; B: 1:{1, 3, 2}
{} ;; TRUE, no bindings
lisb=> (member? 0 #{1 3 2})   ;; B: 0:{1, 3, 2}
nil ;; FALSE
lisb=> (contains? #{1 3 2} 1)   ;; B: 1:{1, 3, 2}
{} ;; TRUE, no bindings
lisb=> (contains? #{1 3 2} 1 2)   ;; B: 1:{1, 3, 2} & 2:{1, 3, 2}
{} ;; TRUE, no bindings
lisb=> (contains? #{1 3 2} 1 2 3 4)   ;; B: 1:{1, 3, 2} & 2:{1, 3, 2} & 3:{1, 3, 2} & 4:{1, 3, 2}
nil ;; FALSE

B also has an operator to check that an element is not contained set. In lisb, you wrap the member? predicate in (not ...).

lisb=> (not (member? 42 #{1 3 2}))   ;; B: 42/:{1, 3, 2}
{} ;; TRUE, no bindings

Subset Test

lisb=> (subset? #{1 2} nat-set)   ;; B: {1, 2}<:NAT
{} ;; TRUE, no bindings
lisb=> (subset? #{1 4 3 2 5} nat-set)   ;; B: {1, 4, 3, 2, 5}<:NAT
nil ;; FALSE
lisb=> (not (subset? #{1 4 3 2 5} nat-set))   ;; B: {1, 4, 3, 2, 5}/<:NAT
{} ;; TRUE, no bindings
lisb=> (superset? #{0 1 4 3 2 5} nat-set)   ;; B: NAT<:{0, 1, 4, 3, 2, 5}
{} ;; TRUE, no bindings
lisb=> (strict-subset? #{0 1 3 2} nat-set)   ;; B: {0, 1, 3, 2}<<:NAT
nil ;; FALSE

Generalised Operators

lisb=> (unite-sets #{#{4 3} #{1 2}})   ;; B: union({{4, 3}, {1, 2}})
#{1 4 3 2}
lisb=> (intersect-sets #{#{4 3 2} #{1 3 2}})   ;; B: inter({{4, 3, 2}, {1, 3, 2}})
#{3 2}
lisb=> (union-pe [:x] (subset? :x #{7 9 8}) #{(card :x)})   ;; B: UNION(x).(x<:{7, 9, 8}|{card(x)})
#{0 1 3 2}
lisb=> (intersection-pe [:x] (subset? :x #{7 9 8}) #{(card :x)})   ;; B: INTER(x).(x<:{7, 9, 8}|{card(x)})
#{}

Cartesian Product

lisb=> (cartesian-product #{1 2} #{4 3})   ;; B: {1, 2}*{4, 3}
#{[2 -> 4] [1 -> 4] [2 -> 3] [1 -> 3]}

Interval

lisb=> (interval 1 5)   ;; B: 1..5
#{1 4 3 2 5}
lisb=> (range 1 5)   ;; B: 1..pred(5)
#{1 4 3 2}