@@ -297,17 +297,43 @@ impl<T: Ord + Copy> Relation<T> {
297297 {
298298 extend_with:: ExtendWith :: from ( self , key_func)
299299 }
300- }
301300
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
311337 {
312338 extend_anti:: ExtendAnti :: from ( self , key_func)
313339 }
@@ -419,63 +445,45 @@ pub(crate) mod extend_anti {
419445
420446 use super :: { binary_search, Leaper , Relation } ;
421447 use crate :: join:: gallop;
448+ use crate :: Split ;
422449
423450 /// 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 > ) > ,
435455 }
436456
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 > {
444458 /// 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 }
452461 }
453462 }
454463
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 >
457465 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 ,
462470 {
463- fn count ( & mut self , _prefix : & Tuple ) -> usize {
471+ fn count ( & mut self , _prefix : & S ) -> usize {
464472 usize:: max_value ( )
465473 }
466- fn propose ( & mut self , _prefix : & Tuple , _values : & mut Vec < Val > ) {
474+ fn propose ( & mut self , _prefix : & S , _values : & mut Vec < T :: Suffix > ) {
467475 panic ! ( "ExtendAnti::propose(): variable apparently unbound." ) ;
468476 }
469- fn intersect ( & mut self , prefix : & Tuple , values : & mut Vec < Val > ) {
477+ fn intersect ( & mut self , prefix : & S , values : & mut Vec < T :: Suffix > ) {
470478 let key = ( self . key_func ) ( prefix) ;
471479
472480 let range = match self . old_key . as_ref ( ) {
473481 Some ( ( old, range) ) if old == & key => range. clone ( ) ,
474482
475483 _ => {
476- let start = binary_search ( & self . relation . elements , |x| & x. 0 < & key) ;
484+ let start = binary_search ( & self . relation . elements , |x| & x. prefix ( ) < & key) ;
477485 let slice1 = & self . relation [ start..] ;
478- let slice2 = gallop ( slice1, |x| & x. 0 <= & key) ;
486+ let slice2 = gallop ( slice1, |x| & x. prefix ( ) <= & key) ;
479487 let range = start..self . relation . len ( ) -slice2. len ( ) ;
480488
481489 self . old_key = Some ( ( key, range. clone ( ) ) ) ;
@@ -487,8 +495,8 @@ pub(crate) mod extend_anti {
487495 let mut slice = & self . relation [ range] ;
488496 if !slice. is_empty ( ) {
489497 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)
492500 } ) ;
493501 }
494502 }
0 commit comments