@@ -61,6 +61,10 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
61
61
Some ( i) => i,
62
62
None => {
63
63
self . elements . push ( a) ;
64
+
65
+ // if we changed the dimensions, clear the cache
66
+ * self . closure . borrow_mut ( ) = None ;
67
+
64
68
Index ( self . elements . len ( ) - 1 )
65
69
}
66
70
}
@@ -73,17 +77,17 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
73
77
let edge = Edge { source : a, target : b } ;
74
78
if !self . edges . contains ( & edge) {
75
79
self . edges . push ( edge) ;
76
- }
77
80
78
- // clear cached closure, if any
79
- * self . closure . borrow_mut ( ) = None ;
81
+ // added an edge, clear the cache
82
+ * self . closure . borrow_mut ( ) = None ;
83
+ }
80
84
}
81
85
82
86
/// Check whether `a < target` (transitively)
83
87
pub fn contains ( & self , a : & T , b : & T ) -> bool {
84
88
match ( self . index ( a) , self . index ( b) ) {
85
89
( Some ( a) , Some ( b) ) =>
86
- self . take_closure ( |closure| closure. contains ( a. 0 , b. 0 ) ) ,
90
+ self . with_closure ( |closure| closure. contains ( a. 0 , b. 0 ) ) ,
87
91
( None , _) | ( _, None ) =>
88
92
false ,
89
93
}
@@ -102,7 +106,8 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
102
106
/// itself is not fully sufficient).
103
107
///
104
108
/// Examples are probably clearer than any prose I could write
105
- /// (there are corresponding tests below, btw):
109
+ /// (there are corresponding tests below, btw). In each case,
110
+ /// the query is `best_upper_bound(a, b)`:
106
111
///
107
112
/// ```
108
113
/// // returns Some(x), which is also LUB
@@ -140,7 +145,11 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
140
145
/// Returns the set of bounds `X` such that:
141
146
///
142
147
/// - `a < X` and `b < X`
143
- /// - there is no `Y` such that `a < Y` and `Y < X`
148
+ /// - there is no `Y != X` such that `a < Y` and `Y < X`
149
+ /// - except for the case where `X < a` (i.e., a strongly connected
150
+ /// component in the graph). In that case, the smallest
151
+ /// representative of the SCC is returned (as determined by the
152
+ /// internal indices).
144
153
///
145
154
/// Note that this set can, in principle, have any size.
146
155
pub fn minimal_upper_bounds ( & self , a : & T , b : & T ) -> Vec < & T > {
@@ -157,7 +166,7 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
157
166
mem:: swap ( & mut a, & mut b) ;
158
167
}
159
168
160
- let lub_indices = self . take_closure ( |closure| {
169
+ let lub_indices = self . with_closure ( |closure| {
161
170
// Easy case is when either a < b or b < a:
162
171
if closure. contains ( a. 0 , b. 0 ) {
163
172
return vec ! [ b. 0 ] ;
@@ -178,18 +187,28 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
178
187
// to the steps below.
179
188
// - This vector contains upper bounds, but they are
180
189
// not minimal upper bounds. So you may have e.g.
181
- // `[a, b, tcx, x]` where `a < tcx` and `b < tcx` and
182
- // `x < a` and `x < b`. This could be reduced to
183
- // just `[x]`.
190
+ // `[x, y, tcx, z]` where `x < tcx` and `y < tcx` and
191
+ // `z < x` and `z < y`:
192
+ //
193
+ // z --+---> x ----+----> tcx
194
+ // | |
195
+ // | |
196
+ // +---> y ----+
197
+ //
198
+ // In this case, we really want to return just `[z]`.
199
+ // The following steps below achieve this by gradually
200
+ // reducing the list.
184
201
// 2. Pare down the vector using `pare_down`. This will
185
202
// remove elements from the vector that can be reached
186
203
// by an earlier element.
187
- // - In the example above, this would convert
188
- // `[a, b, tcx, x]` to `[a, b, x]`. Note that `x`
189
- // remains because `x < a` but not `a < x.`
204
+ // - In the example above, this would convert `[x, y,
205
+ // tcx, z]` to `[x, y, z]`. Note that `x` and `y` are
206
+ // still in the vector; this is because while `z < x`
207
+ // (and `z < y`) holds, `z` comes after them in the
208
+ // vector.
190
209
// 3. Reverse the vector and repeat the pare down process.
191
210
// - In the example above, we would reverse to
192
- // `[x, b, a ]` and then pare down to `[x ]`.
211
+ // `[z, y, x ]` and then pare down to `[z ]`.
193
212
// 4. Reverse once more just so that we yield a vector in
194
213
// increasing order of index. Maybe this is silly.
195
214
//
@@ -213,7 +232,7 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
213
232
. collect ( )
214
233
}
215
234
216
- fn take_closure < OP , R > ( & self , op : OP ) -> R
235
+ fn with_closure < OP , R > ( & self , op : OP ) -> R
217
236
where OP : FnOnce ( & BitMatrix ) -> R
218
237
{
219
238
let mut closure_cell = self . closure . borrow_mut ( ) ;
@@ -248,7 +267,8 @@ impl<T:Debug+PartialEq> TransitiveRelation<T> {
248
267
/// there exists an earlier element i<j such that i -> j. That is,
249
268
/// after you run `pare_down`, you know that for all elements that
250
269
/// remain in candidates, they cannot reach any of the elements that
251
- /// come after them.
270
+ /// come after them. (Note that it may permute the ordering in some
271
+ /// cases.)
252
272
///
253
273
/// Examples follow. Assume that a -> b -> c and x -> y -> z.
254
274
///
@@ -264,9 +284,13 @@ fn pare_down(candidates: &mut Vec<usize>, closure: &BitMatrix) {
264
284
let mut j = i;
265
285
while j < candidates. len ( ) {
266
286
if closure. contains ( candidate, candidates[ j] ) {
267
- // if i can reach j, then we can remove j
268
- println ! ( "pare_down: candidates[{:?}]={:?} candidates[{:?}] = {:?}" ,
269
- i-1 , candidate, j, candidates[ j] ) ;
287
+ // If `i` can reach `j`, then we can remove `j`. Given
288
+ // how careful this algorithm is about ordering, it
289
+ // may seem odd to use swap-remove. The reason it is
290
+ // ok is that we are swapping two elements (`j` and
291
+ // `max`) that are both to the right of our cursor
292
+ // `i`, and the invariant that we are establishing
293
+ // continues to hold for everything left of `i`.
270
294
candidates. swap_remove ( j) ;
271
295
} else {
272
296
j += 1 ;
@@ -371,9 +395,8 @@ fn mubs_best_choice2() {
371
395
372
396
#[ test]
373
397
fn mubs_no_best_choice ( ) {
374
- // in this case, the intersection yields [1, 2],
375
- // and we need the first "pare down" call to narrow
376
- // this down to [2]
398
+ // in this case, the intersection yields [1, 2], and the "pare
399
+ // down" calls find nothing to remove.
377
400
let mut relation = TransitiveRelation :: new ( ) ;
378
401
relation. add ( "0" , "1" ) ;
379
402
relation. add ( "0" , "2" ) ;
0 commit comments