@@ -297,17 +297,43 @@ impl<T: Ord + Copy> Relation<T> {
297
297
{
298
298
extend_with:: ExtendWith :: from ( self , key_func)
299
299
}
300
- }
301
300
302
- impl < Key : Ord , Val : Ord > Relation < ( Key , Val ) > {
303
- /// Extend with `Val` using the complement of the relation.
304
- pub fn extend_anti < ' leap , Tuple : Ord , Func : Fn ( & Tuple ) -> Key > (
305
- & ' leap self ,
306
- key_func : Func ,
307
- ) -> extend_anti:: ExtendAnti < ' leap , Key , Val , Tuple , Func >
308
- where
309
- Key : ' leap ,
310
- Val : ' leap ,
301
+ /// Extend with `<T as Split<P>>::Suffix` using the complement of the relation.
302
+ ///
303
+ /// This leaper *removes* proposed values when
304
+ /// * `key_func(src)` matches the prefix (`P`) of a tuple in this relation,
305
+ /// * *AND* the proposed value matches the suffix of that same tuple.
306
+ ///
307
+ /// It is used when a negative atom depends on a variable that is proposed by another leaper.
308
+ /// For example:
309
+ ///
310
+ /// ```prolog
311
+ /// var_init_at(V, Q) :-
312
+ /// var_init_at(V, P), /* leapjoin source */
313
+ /// cfg_edge(P, Q), /* extend_with */
314
+ /// !var_moved_at(V, Q). /* extend_anti */
315
+ /// ```
316
+ ///
317
+ /// For each source tuple in `var_init_at`, `cfg_edge` will propose some number of CFG nodes
318
+ /// (`Q`). The `!var_moved_at` atom should be expressed as `extend_anti(|(v, _p)| v)`. That is,
319
+ /// it extracts `V` from the source tuple (the prefix), and eliminates proposed tuples with
320
+ /// that prefix whose suffix is `Q`.
321
+ ///
322
+ /// **FIXME:** The fact that `P` determines both the prefix (in the source) *and* the suffix (the
323
+ /// proposed value) is more restrictive than necessary. You could imagine a more complex program
324
+ /// where the proposed value contains more information than we need for the negative atom.
325
+ ///
326
+ /// ```prolog
327
+ /// x(A, B2, C2) :-
328
+ /// x(A, B1, C1), /* leapjoin source */
329
+ /// t(B1, C1, B2, C2) /* Proposes `(B2, C2)` */
330
+ /// !f(A, B2). /* Doesn't use `C2`! */
331
+ /// ```
332
+ ///
333
+ /// That would require a separate `val_func` (in addition to `key_func`) to extract the
334
+ /// relevant part of the proposed value.
335
+ pub fn extend_anti < P , F , S > ( & self , key_func : F ) -> extend_anti:: ExtendAnti < ' _ , P , T , F >
336
+ where F : Fn ( & S ) -> P
311
337
{
312
338
extend_anti:: ExtendAnti :: from ( self , key_func)
313
339
}
@@ -419,63 +445,45 @@ pub(crate) mod extend_anti {
419
445
420
446
use super :: { binary_search, Leaper , Relation } ;
421
447
use crate :: join:: gallop;
448
+ use crate :: Split ;
422
449
423
450
/// Wraps a Relation<Tuple> as a leaper.
424
- pub struct ExtendAnti < ' leap , Key , Val , Tuple , Func >
425
- where
426
- Key : Ord + ' leap ,
427
- Val : Ord + ' leap ,
428
- Tuple : Ord ,
429
- Func : Fn ( & Tuple ) -> Key ,
430
- {
431
- relation : & ' leap Relation < ( Key , Val ) > ,
432
- key_func : Func ,
433
- old_key : Option < ( Key , Range < usize > ) > ,
434
- phantom : :: std:: marker:: PhantomData < Tuple > ,
451
+ pub struct ExtendAnti < ' a , P , T , F > {
452
+ relation : & ' a Relation < T > ,
453
+ key_func : F ,
454
+ old_key : Option < ( P , Range < usize > ) > ,
435
455
}
436
456
437
- impl < ' leap , Key , Val , Tuple , Func > ExtendAnti < ' leap , Key , Val , Tuple , Func >
438
- where
439
- Key : Ord + ' leap ,
440
- Val : Ord + ' leap ,
441
- Tuple : Ord ,
442
- Func : Fn ( & Tuple ) -> Key ,
443
- {
457
+ impl < ' a , P , T , F > ExtendAnti < ' a , P , T , F > {
444
458
/// Constructs a ExtendAnti from a relation and key and value function.
445
- pub fn from ( relation : & ' leap Relation < ( Key , Val ) > , key_func : Func ) -> Self {
446
- ExtendAnti {
447
- relation,
448
- key_func,
449
- old_key : None ,
450
- phantom : :: std:: marker:: PhantomData ,
451
- }
459
+ pub fn from ( relation : & ' a Relation < T > , key_func : F ) -> Self {
460
+ ExtendAnti { relation, key_func, old_key : None }
452
461
}
453
462
}
454
463
455
- impl < ' leap , Key : Ord , Val : Ord + ' leap , Tuple : Ord , Func > Leaper < Tuple , Val >
456
- for ExtendAnti < ' leap , Key , Val , Tuple , Func >
464
+ impl < P , T , S , F > Leaper < S , T :: Suffix > for ExtendAnti < ' _ , P , T , F >
457
465
where
458
- Key : Ord + ' leap ,
459
- Val : Ord + ' leap ,
460
- Tuple : Ord ,
461
- Func : Fn ( & Tuple ) -> Key ,
466
+ T : Copy + Split < P > ,
467
+ P : Ord ,
468
+ T :: Suffix : Ord ,
469
+ F : Fn ( & S ) -> P ,
462
470
{
463
- fn count ( & mut self , _prefix : & Tuple ) -> usize {
471
+ fn count ( & mut self , _prefix : & S ) -> usize {
464
472
usize:: max_value ( )
465
473
}
466
- fn propose ( & mut self , _prefix : & Tuple , _values : & mut Vec < Val > ) {
474
+ fn propose ( & mut self , _prefix : & S , _values : & mut Vec < T :: Suffix > ) {
467
475
panic ! ( "ExtendAnti::propose(): variable apparently unbound." ) ;
468
476
}
469
- fn intersect ( & mut self , prefix : & Tuple , values : & mut Vec < Val > ) {
477
+ fn intersect ( & mut self , prefix : & S , values : & mut Vec < T :: Suffix > ) {
470
478
let key = ( self . key_func ) ( prefix) ;
471
479
472
480
let range = match self . old_key . as_ref ( ) {
473
481
Some ( ( old, range) ) if old == & key => range. clone ( ) ,
474
482
475
483
_ => {
476
- let start = binary_search ( & self . relation . elements , |x| & x. 0 < & key) ;
484
+ let start = binary_search ( & self . relation . elements , |x| & x. prefix ( ) < & key) ;
477
485
let slice1 = & self . relation [ start..] ;
478
- let slice2 = gallop ( slice1, |x| & x. 0 <= & key) ;
486
+ let slice2 = gallop ( slice1, |x| & x. prefix ( ) <= & key) ;
479
487
let range = start..self . relation . len ( ) -slice2. len ( ) ;
480
488
481
489
self . old_key = Some ( ( key, range. clone ( ) ) ) ;
@@ -487,8 +495,8 @@ pub(crate) mod extend_anti {
487
495
let mut slice = & self . relation [ range] ;
488
496
if !slice. is_empty ( ) {
489
497
values. retain ( |v| {
490
- slice = gallop ( slice, |kv| & kv. 1 < v) ;
491
- slice. get ( 0 ) . map ( |kv| & kv. 1 ) != Some ( v)
498
+ slice = gallop ( slice, |kv| & kv. suffix ( ) < v) ;
499
+ slice. get ( 0 ) . map ( |kv| kv. suffix ( ) ) . as_ref ( ) != Some ( v)
492
500
} ) ;
493
501
}
494
502
}
0 commit comments