|
| 1 | +/** |
| 2 | + * INTERNAL: This module may be replaced without notice. |
| 3 | + * |
| 4 | + * Provides a module to create first-class representations of sets of values. |
| 5 | + */ |
| 6 | + |
| 7 | +/** The input signature for `MakeSets`. */ |
| 8 | +signature module MkSetsInp { |
| 9 | + class Key; |
| 10 | + |
| 11 | + class Value; |
| 12 | + |
| 13 | + Value getAValue(Key k); |
| 14 | + |
| 15 | + int totalorder(Value v); |
| 16 | +} |
| 17 | + |
| 18 | +/** |
| 19 | + * Given a binary predicate `getAValue`, this module groups the `Value` column |
| 20 | + * by `Key` and constructs the corresponding sets of `Value`s as single entities. |
| 21 | + * |
| 22 | + * The output is a functional predicate, `getValueSet`, such that |
| 23 | + * `getValueSet(k).contains(v)` is equivalent to `v = getAValue(k)`, and a |
| 24 | + * class, `ValueSet`, that canonically represents a set of `Value`s. In |
| 25 | + * particular, if two keys `k1` and `k2` relate to the same set of values, then |
| 26 | + * `getValueSet(k1) = getValueSet(k2)`. |
| 27 | + */ |
| 28 | +module MakeSets<MkSetsInp Inp> { |
| 29 | + private import Inp |
| 30 | + |
| 31 | + private predicate rankedValue(Key k, Value v, int r) { |
| 32 | + v = rank[r](Value v0 | v0 = getAValue(k) | v0 order by totalorder(v0)) |
| 33 | + } |
| 34 | + |
| 35 | + private int maxRank(Key k) { result = max(int r | rankedValue(k, _, r)) } |
| 36 | + |
| 37 | + predicate consistency(int r, int bs) { bs = strictcount(Value v | totalorder(v) = r) and bs != 1 } |
| 38 | + |
| 39 | + private newtype TValList = |
| 40 | + TValListNil() or |
| 41 | + TValListCons(Value head, int r, TValList tail) { hasValListCons(_, head, r, tail) } |
| 42 | + |
| 43 | + private predicate hasValListCons(Key k, Value head, int r, TValList tail) { |
| 44 | + rankedValue(k, head, r) and |
| 45 | + hasValList(k, r - 1, tail) |
| 46 | + } |
| 47 | + |
| 48 | + private predicate hasValList(Key k, int r, TValList l) { |
| 49 | + exists(getAValue(k)) and r = 0 and l = TValListNil() |
| 50 | + or |
| 51 | + exists(Value head, TValList tail | |
| 52 | + l = TValListCons(head, r, tail) and |
| 53 | + hasValListCons(k, head, r, tail) |
| 54 | + ) |
| 55 | + } |
| 56 | + |
| 57 | + private predicate hasValueSet(Key k, TValListCons vs) { hasValList(k, maxRank(k), vs) } |
| 58 | + |
| 59 | + /** A set of `Value`s. */ |
| 60 | + class ValueSet extends TValListCons { |
| 61 | + ValueSet() { hasValueSet(_, this) } |
| 62 | + |
| 63 | + string toString() { result = "ValueSet" } |
| 64 | + |
| 65 | + private predicate sublist(TValListCons l) { |
| 66 | + this = l or |
| 67 | + this.sublist(TValListCons(_, _, l)) |
| 68 | + } |
| 69 | + |
| 70 | + /** Holds if this set contains `v`. */ |
| 71 | + predicate contains(Value v) { this.sublist(TValListCons(v, _, _)) } |
| 72 | + } |
| 73 | + |
| 74 | + /** |
| 75 | + * Gets the set of values such that `getValueSet(k).contains(v)` is equivalent |
| 76 | + * to `v = getAValue(k)`. |
| 77 | + */ |
| 78 | + ValueSet getValueSet(Key k) { hasValueSet(k, result) } |
| 79 | +} |
0 commit comments