Hi,
Apalache has a number of expression simplifications that rewrite
constraints over cardinalities into simpler forms, when possible. You
can see the exact list in [1]. For example:
- Cardinality(a..b) is equivalent to IF a =< b THEN (b - a) + 1 ELSE 0
- Cardinality(SUBSET S) is equivalent to 2^Cardinality(S)
- Cardinality(Set) = 0 iff Set = {} (the one you have also mentioned)
- There is a special encoding for constraints like Cardinality(S) >= k.
In general, however, Apalache has a heavy encoding of Cardinality in
SMT. It essentially reduces over a set, but producing symbolic
constraints instead of concrete values:
```
MyCardinality(S) ==
LET \* @type: (Int, a) => Int;
Add(n, elem) == n + 1
IN
ApaFoldSet(Add, 0, S)
```
You can find the complete example in [2] and the definition of
ApaFoldSet via RECURSIVE operators in [3] (this definition is similar
to FoldSet from the community modules [4]).
[1]
https://github.com/apalache-mc/apalache/blob/884dcbcfbbbed577492dc65f623b30f8e509f4e3/tla-pp/src/main/scala/at/forsyte/apalache/tla/pp/ExprOptimizer.scala#L140
[2]
https://github.com/apalache-mc/apalache/blob/8af6eae3011f2c0544a517267901327c38c43c94/src/tla/Apalache.tla#L134
[3]
https://github.com/apalache-mc/apalache/blob/main/test/tla/TestCardinalityAsFold.tla
[4]
https://github.com/tlaplus/CommunityModules/blob/master/modules/FiniteSetsExt.tla#L12
Best regards,
Igor