1
- // ===--- LeftCanonicalForm .cpp - Left canonical form of a rewrite path ----===//
1
+ // ===--- NormalizeRewritePath .cpp - Canonical form of a rewrite path -- ----===//
2
2
//
3
3
// This source file is part of the Swift.org open source project
4
4
//
@@ -144,50 +144,91 @@ bool RewriteStep::maybeSwapRewriteSteps(RewriteStep &other,
144
144
// / This does not change either endpoint of the path, and the path does
145
145
// / not necessarily need to be a loop.
146
146
bool RewritePath::computeFreelyReducedForm () {
147
- SmallVector<RewriteStep, 4 > newSteps;
148
- bool changed = false ;
149
-
150
- for (const auto &step : Steps) {
151
- if (!newSteps.empty () &&
152
- newSteps.back ().isInverseOf (step)) {
153
- changed = true ;
154
- newSteps.pop_back ();
155
- continue ;
147
+ unsigned j = 0 ;
148
+
149
+ for (unsigned i = 0 , e = Steps.size (); i < e; ++i) {
150
+ // Pre-condition:
151
+ // - Steps in the range [0, j-1] are freely reduced.
152
+ // - Steps in the range [i, e-1] remain to be considered.
153
+ if (j > 0 ) {
154
+ // If Steps[j-1] and Steps[i] are inverses of each other,
155
+ // discard both Steps[j-1] and Steps[i].
156
+ const auto &otherStep = Steps[j - 1 ];
157
+ const auto &step = Steps[i];
158
+
159
+ if (otherStep.isInverseOf (step)) {
160
+ --j;
161
+ continue ;
162
+ }
156
163
}
157
164
158
- newSteps.push_back (step);
165
+ // Post-condition:
166
+ // - Steps in the range [0, j] are freely reduced.
167
+ // - Steps in the range [i+1, e-1] remain to be considered.
168
+ Steps[j] = Steps[i];
169
+ ++j;
159
170
}
160
171
161
- if (!changed )
172
+ if (j == Steps. size () )
162
173
return false ;
163
- std::swap (newSteps, Steps);
164
- return changed;
174
+
175
+ Steps.erase (Steps.begin () + j, Steps.end ());
176
+ return true ;
165
177
}
166
178
167
179
// / Apply the interchange rule until fixed point (see maybeSwapRewriteSteps()).
168
180
bool RewritePath::computeLeftCanonicalForm (const RewriteSystem &system) {
169
181
bool changed = false ;
170
182
171
183
for (unsigned i = 1 , e = Steps.size (); i < e; ++i) {
172
- auto &prevStep = Steps[i - 1 ];
173
- auto &step = Steps[i];
184
+ // Pre-condition: steps in the range [0, i-1] are in left-canonical
185
+ // normal form.
186
+ //
187
+ // If Steps[i] can be swapped with Steps[i-1], swap them, and check
188
+ // if Steps[i-1] (the old Steps[i]) can be swapped with Steps[i-2],
189
+ // etc.
190
+ for (unsigned j = i; j >= 1 ; --j) {
191
+ auto &prevStep = Steps[j - 1 ];
192
+ auto &step = Steps[j];
193
+
194
+ if (!prevStep.maybeSwapRewriteSteps (step, system))
195
+ break ;
174
196
175
- if (prevStep.maybeSwapRewriteSteps (step, system))
176
197
changed = true ;
198
+ }
199
+
200
+ // Post-condition: steps in the range [0, i] are in left-canonical
201
+ // normal form.
177
202
}
178
203
179
204
return changed;
180
205
}
181
206
182
207
// / Compute freely-reduced left-canonical normal form of a path.
183
- void RewritePath::computeNormalForm (const RewriteSystem &system) {
184
- // FIXME: This can be more efficient.
185
- bool changed;
186
- do {
187
- changed = false ;
188
- changed |= computeFreelyReducedForm ();
189
- changed |= computeLeftCanonicalForm (system);
190
- } while (changed);
208
+ bool RewritePath::computeNormalForm (const RewriteSystem &system) {
209
+ // Note that computeFreelyReducedForm() and computeLeftCanonicalForm()
210
+ // are both idempotent, but their composition is not.
211
+
212
+ // Begin by freely reducing the path.
213
+ bool changed = computeFreelyReducedForm ();
214
+
215
+ // Then, bring it into left canonical form.
216
+ while (computeLeftCanonicalForm (system)) {
217
+ changed = true ;
218
+
219
+ // If it was not already in left-canonical form, freely reduce it
220
+ // again.
221
+ if (!computeFreelyReducedForm ()) {
222
+ // If it was already freely reduced, then we're done, because it
223
+ // is freely reduced *and* in left-canonical form.
224
+ break ;
225
+ }
226
+
227
+ // Otherwise, perform another round, since freely reducing may have
228
+ // opened up new opportunities for left-canonicalization.
229
+ }
230
+
231
+ return changed;
191
232
}
192
233
193
234
// / Given a path that is a loop around the given basepoint, cancels out
@@ -227,15 +268,9 @@ bool RewritePath::computeCyclicallyReducedForm(MutableTerm &basepoint,
227
268
228
269
// / Compute cyclically-reduced left-canonical normal form of a loop.
229
270
void RewriteLoop::computeNormalForm (const RewriteSystem &system) {
230
- // FIXME: This can be more efficient.
231
- bool changed;
232
- do {
233
- changed = false ;
234
- changed |= Path.computeFreelyReducedForm ();
235
- changed |= Path.computeCyclicallyReducedForm (Basepoint, system);
236
- changed |= Path.computeLeftCanonicalForm (system);
237
-
238
- if (changed)
239
- markDirty ();
240
- } while (changed);
271
+ bool changed = Path.computeNormalForm (system);
272
+ changed |= Path.computeCyclicallyReducedForm (Basepoint, system);
273
+
274
+ if (changed)
275
+ markDirty ();
241
276
}
0 commit comments