6
6
module Permutations {
7
7
import NatArith
8
8
9
+ /* ************************************************************************************
10
+ * Defines the notion of a permutation and establishes that the formula
11
+ * `NumberOfPermutationsOf` is correct, in the sense that:
12
+ * - NumberOfPermutationsOf(s) == |CalculateAllPermutationsOf(s)|
13
+ * - (iset p | p in CalculateAllPermutationsOf(s)) == iset p | IsPermutationOf(p, s)
14
+ *************************************************************************************/
15
+
9
16
/* ***********
10
17
Definitions
11
18
************/
12
19
13
- function NumberOfPermutationsOf< T (==)> (s: seq < T> ): nat {
14
- |CalculateAllPermutationsOf (s)|
20
+ predicate IsPermutationOf< T (==)> (p: seq < T> , s: seq < T> ) {
21
+ multiset (p) == multiset (s)
22
+ }
23
+
24
+ function NumberOfPermutationsOf< T (==)> (s: seq < T> ): (n: nat )
25
+ ensures n != 0
26
+ {
27
+ if |s| <= 1 then
28
+ 1
29
+ else
30
+ var multiplicity := multiset (s)[s[0]];
31
+ var length := |s|;
32
+ (length / multiplicity) * NumberOfPermutationsOf (s[1..])
33
+ }
34
+
35
+ ghost function AllPermutationsOf< T (!new)> (s: seq < T> ): iset < seq < T>> {
36
+ iset p | IsPermutationOf (p, s)
15
37
}
16
38
17
39
function CalculateAllPermutationsOf< T (==)> (s: seq < T> ): (x: set < seq < T>> )
@@ -23,16 +45,48 @@ module Permutations {
23
45
set p, i | p in CalculateAllPermutationsOf (s[1..]) && 0 <= i <= |s|- 1 :: InsertAt (p, s[0], i)
24
46
}
25
47
48
+ function DeleteAt< T> (s: seq < T> , i: nat ): seq < T>
49
+ requires i < |s|
50
+ {
51
+ s[.. i] + s[i+ 1.. ]
52
+ }
53
+
26
54
function InsertAt< T> (s: seq < T> , x: T, i: nat ): seq < T>
27
55
requires i <= |s|
28
56
{
29
57
s[.. i] + [x] + s[i.. ]
30
58
}
31
59
60
+ function FirstOccurrence< T (==)> (p: seq < T> , x: T): (i: nat )
61
+ requires x in multiset (p)
62
+ ensures i < |p|
63
+ ensures p[i] == x
64
+ {
65
+ if p[0] == x then
66
+ 0
67
+ else
68
+ FirstOccurrence (p[1..], x) + 1
69
+ }
70
+
71
+ function Swap< T> (s: seq < T> , i: nat , j: nat ): (t: seq < T> )
72
+ requires i <= j
73
+ requires 0 <= i < |s|
74
+ requires 0 <= j < |s|
75
+ ensures |s| == |t|
76
+ {
77
+ if i == j then
78
+ s
79
+ else
80
+ s[.. i] + [s[j]] + s[i+ 1.. j] + [s[i]] + s[j+ 1.. ]
81
+ }
82
+
32
83
/* ******
33
84
Lemmas
34
85
*******/
35
86
87
+ lemma {:axiom} CorrectnessOfNumberOfPermutationsOf< T (==)> (s: seq < T> )
88
+ ensures NumberOfPermutationsOf (s) == |CalculateAllPermutationsOf (s)|
89
+
36
90
lemma CalculateAllPermutationsOfIsNonEmpty< T> (s: seq < T> )
37
91
ensures s in CalculateAllPermutationsOf (s)
38
92
ensures NumberOfPermutationsOf (s) > 0
@@ -47,4 +101,127 @@ module Permutations {
47
101
}
48
102
}
49
103
}
104
+
105
+ lemma CorrectnessOfCalculateAllPermutationsOf< T (!new)> (s: seq < T> )
106
+ ensures (iset p | p in CalculateAllPermutationsOf(s)) == AllPermutationsOf (s)
107
+ {
108
+ assert (iset p | p in CalculateAllPermutationsOf (s)) == AllPermutationsOf (s) by {
109
+ assert forall p :: p in CalculateAllPermutationsOf (s) <= => p in AllPermutationsOf (s) by {
110
+ forall p
111
+ ensures p in CalculateAllPermutationsOf (s) <= => p in AllPermutationsOf (s)
112
+ {
113
+ CorrectnessOfCalculateAllPermutationsOfImplicationOne (s, p);
114
+ CorrectnessOfCalculateAllPermutationsOfImplicationTwo (s, p);
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ lemma CorrectnessOfCalculateAllPermutationsOfImplicationOne< T (!new)> (s: seq < T> , p: seq < T> )
121
+ ensures p in CalculateAllPermutationsOf (s) ==> p in AllPermutationsOf (s)
122
+ {
123
+ if |s| == 0 {
124
+ // induction base, no proof hints needed
125
+ } else {
126
+ // induction step
127
+ if p in CalculateAllPermutationsOf (s) {
128
+ assert p in AllPermutationsOf (s) by {
129
+ assert IsPermutationOf (p, s) by {
130
+ var p', i :| p' in CalculateAllPermutationsOf (s[1..]) && 0 <= i <= |p'| && p == InsertAt (p', s[0], i);
131
+ calc == {
132
+ multiset (p);
133
+ multiset (InsertAt(p', s[0], i));
134
+ { MultisetAfterInsertAt (p', s[0], i); }
135
+ multiset ([s[0]]) + multiset (p');
136
+ { CorrectnessOfCalculateAllPermutationsOfImplicationOne (s[1..], p'); } // induction hypothesis
137
+ multiset ([s[0]]) + multiset (s[1..]);
138
+ multiset ([s[0]] + s[1..]);
139
+ { assert [s[0]] + s[1.. ] == s; }
140
+ multiset (s);
141
+ }
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
147
+
148
+ lemma CorrectnessOfCalculateAllPermutationsOfImplicationTwo< T (!new)> (s: seq < T> , p: seq < T> )
149
+ ensures p in CalculateAllPermutationsOf (s) <= = p in AllPermutationsOf (s)
150
+ {
151
+ if |s| == 0 {
152
+ // induction base, no proof hints needed
153
+ } else {
154
+ // induction step
155
+ if p in AllPermutationsOf (s) {
156
+ assert p in CalculateAllPermutationsOf (s) by {
157
+ var i := FirstOccurrence (p, s[0]);
158
+ var p' := DeleteAt (p, i);
159
+ assert p' in CalculateAllPermutationsOf (s[1..]) by {
160
+ assert p' in AllPermutationsOf (s[1..]) by {
161
+ PermutationBeforeAndAfterDeletionAt (p, s, i, 0);
162
+ }
163
+ CorrectnessOfCalculateAllPermutationsOfImplicationTwo (s[1..], p'); // induction hypothesis
164
+ }
165
+ assert p == InsertAt (p', s[0], i) by {
166
+ InsertAfterDeleteAt (p, i);
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+
173
+ lemma MultisetAfterInsertAt< T> (s: seq < T> , x: T, i: nat )
174
+ requires i <= |s|
175
+ ensures multiset (InsertAt(s, x, i)) == multiset ([x]) + multiset (s)
176
+ {
177
+ calc == {
178
+ multiset (InsertAt(s, x, i));
179
+ multiset (s[..i] + [x] + s[i..]);
180
+ multiset (s[..i]) + multiset ([x]) + multiset (s[i..]);
181
+ multiset ([x]) + multiset (s[..i]) + multiset (s[i..]);
182
+ multiset ([x]) + multiset (s[..i] + s[i..]);
183
+ { assert s[.. i] + s[i.. ] == s; }
184
+ multiset ([x]) + multiset (s);
185
+ }
186
+ }
187
+
188
+ lemma PermutationBeforeAndAfterDeletionAt< T> (p: seq < T> , s: seq < T> , i: nat , j: nat )
189
+ requires IsPermutationOf (p, s)
190
+ requires i < |p|
191
+ requires j < |s|
192
+ requires p[i] == s[j]
193
+ ensures IsPermutationOf (DeleteAt(p, i), DeleteAt (s, j))
194
+ {
195
+ assert IsPermutationOf (DeleteAt(p, i), DeleteAt (s, j)) by {
196
+ calc == {
197
+ multiset (DeleteAt(p, i));
198
+ multiset (p[..i] + p[i+1..]);
199
+ multiset (p[..i]) + multiset (p[i+1..]);
200
+ multiset (p[..i]) + multiset ([p[i]]) + multiset (p[i+1..]) - multiset ([p[i]]);
201
+ multiset (p[..i] + [p[i]] + p[i+1..]) - multiset ([p[i]]);
202
+ { assert p[.. i] + [p[i]] + p[i+ 1.. ] == p; }
203
+ multiset (p) - multiset ([p[i]]);
204
+ multiset (s) - multiset ([s[j]]);
205
+ { assert s[.. j] + [s[j]] + s[j+ 1.. ] == s; }
206
+ multiset (s[..j] + [s[j]] + s[j+1..]) - multiset ([s[j]]);
207
+ multiset (s[..j]) + multiset ([s[j]]) + multiset (s[j+1..]) - multiset ([s[j]]);
208
+ multiset (s[..j]) + multiset (s[j+1..]);
209
+ multiset (s[..j] + s[j+1..]);
210
+ multiset (DeleteAt(s, j));
211
+ }
212
+ }
213
+ }
214
+
215
+ lemma InsertAfterDeleteAt< T> (s: seq < T> , i: nat )
216
+ requires i < |s|
217
+ ensures s == InsertAt (DeleteAt(s, i), s[i], i)
218
+ {}
219
+
220
+ lemma PermutationsPreserveCardinality< T> (p: seq < T> , s: seq < T> )
221
+ requires multiset (p) == multiset (s)
222
+ ensures |p| == |s|
223
+ {
224
+ assume {:axiom} false ;
225
+ }
226
+
50
227
}
0 commit comments