1- /// A [Cache] implementation with incremental computation features. 
1+ //! A [Cache] implementation with incremental computation features. 
2+ use  std:: collections:: { HashMap ,  HashSet } ; 
23
34use  super :: { BlackholedError ,  Cache ,  CacheIndex ,  Closure ,  Environment ,  IdentKind } ; 
45use  crate :: { 
@@ -15,6 +16,12 @@ pub enum IncNodeState {
1516    Evaluated , 
1617} 
1718
19+ #[ derive( Debug ,  Copy ,  Clone ,  Eq ,  PartialEq ) ]  
20+ pub  struct  DependencyLink  { 
21+     id :  Ident , 
22+     idx :  CacheIndex , 
23+ } 
24+ 
1825/// A node in the dependent computation graph stored in [IncCache]. 
1926#[ derive( Debug ,  Clone ) ]  
2027pub  struct  IncNode  { 
@@ -26,8 +33,10 @@ pub struct IncNode {
2633    bty :  BindingType , 
2734    // The state of the node. 
2835    state :  IncNodeState , 
36+     // Forward links to dependencies. 
37+     fwdlinks :  Vec < DependencyLink > , 
2938    // Backlinks to nodes depending on this node. 
30-     backlinks :  Vec < CacheIndex > , 
39+     backlinks :  Vec < DependencyLink > , 
3140} 
3241
3342impl  IncNode  { 
@@ -38,6 +47,7 @@ impl IncNode {
3847            kind, 
3948            bty, 
4049            state :  IncNodeState :: default ( ) , 
50+             fwdlinks :  Vec :: new ( ) , 
4151            backlinks :  Vec :: new ( ) , 
4252        } 
4353    } 
@@ -60,7 +70,7 @@ impl IncCache {
6070        idx
6171    } 
6272
63-     fn  revnode_as_explicit_fun < ' a ,  I > ( node :  & IncNode ,  args :  I )  ->  IncNode 
73+     fn  revnode_as_explicit_fun < ' a ,  I > ( node :  & mut   IncNode ,  args :  I ) 
6474    where 
6575        I :  DoubleEndedIterator < Item  = & ' a  Ident > , 
6676    { 
@@ -75,18 +85,141 @@ impl IncCache {
7585                let  as_function =
7686                    args. rfold ( body,  |built,  id| RichTerm :: from ( Term :: Fun ( * id,  built) ) ) ; 
7787
78-                 IncNode :: new ( 
79-                     Closure  { 
80-                         body :  as_function, 
81-                         env, 
82-                     } , 
83-                     node. kind , 
84-                     node. bty . clone ( ) , 
85-                 ) 
88+                 node. orig  = Closure  { 
89+                     body :  as_function, 
90+                     env, 
91+                 } 
8692            } 
87-             _ => node. clone ( ) , 
93+             _ => ( ) , 
94+         } 
95+     } 
96+ 
97+     fn  update_backlinks ( & mut  self ,  idx :  CacheIndex )  { 
98+         let  node = self . store . get ( idx) . unwrap ( ) . clone ( ) ; 
99+         for  i in  node. fwdlinks  { 
100+             let  n = self . store . get_mut ( i. idx ) . unwrap ( ) ; 
101+             n. backlinks . push ( DependencyLink  {  id :  i. id ,  idx :  idx } ) ; 
102+         } 
103+     } 
104+ 
105+     fn  propagate_dirty ( & mut  self ,  idx :  CacheIndex )  { 
106+         let  mut  node = self . store . get_mut ( idx) . unwrap ( ) ; 
107+         node. cached  = None ; 
108+         node. state  = IncNodeState :: Suspended ; 
109+ 
110+         let  mut  visited = HashSet :: new ( ) ; 
111+         let  mut  stack = node. backlinks . clone ( ) ; 
112+ 
113+         visited. insert ( idx) ; 
114+ 
115+         while  !stack. is_empty ( )  { 
116+             let  i = stack. pop ( ) . unwrap ( ) ; 
117+             visited. insert ( i. idx ) ; 
118+             let  mut  current_node = self . store . get_mut ( i. idx ) . unwrap ( ) ; 
119+             current_node. cached  = None ; 
120+             current_node. state  = IncNodeState :: Suspended ; 
121+             stack. extend ( 
122+                 current_node
123+                     . backlinks 
124+                     . iter ( ) 
125+                     . filter ( |x| !visited. contains ( & x. idx ) ) , 
126+             ) 
127+         } 
128+     } 
129+ 
130+     fn  propagate_dirty_vec ( & mut  self ,  indices :  Vec < CacheIndex > )  { 
131+         let  mut  visited = HashSet :: new ( ) ; 
132+         let  mut  stack = indices; 
133+ 
134+         while  !stack. is_empty ( )  { 
135+             let  i = stack. pop ( ) . unwrap ( ) ; 
136+             visited. insert ( i) ; 
137+             let  mut  current_node = self . store . get_mut ( i) . unwrap ( ) ; 
138+             current_node. cached  = None ; 
139+             current_node. state  = IncNodeState :: Suspended ; 
140+             println ! ( "IDX: {:?} BLs: {:?}" ,  i,  current_node. backlinks) ; 
141+             stack. extend ( 
142+                 current_node
143+                     . backlinks 
144+                     . iter ( ) 
145+                     . map ( |x| x. idx ) 
146+                     . filter ( |x| !visited. contains ( & x) ) , 
147+             ) 
88148        } 
89149    } 
150+ 
151+     /* Do we need this when we can revert in place? 
152+ 
153+     fn propagate_revert(&mut self, id: Ident, idx: CacheIndex) -> HashMap<Ident, CacheIndex> { 
154+         let mut nodes_reverted = HashMap::new(); 
155+ 
156+         let mut visited = HashSet::new(); 
157+         let mut stack = vec![idx]; 
158+ 
159+         while !stack.is_empty() { 
160+             let i = stack.pop().unwrap(); 
161+             visited.insert(i); 
162+ 
163+             let idx_reverted = self.revert(&idx); 
164+             //FIXME: use the actual node's id 
165+             let node_id = Ident::from("TODO!"); 
166+             nodes_reverted.insert(node_id, idx_reverted); 
167+ 
168+             let current_node = self.store.get(i).unwrap(); 
169+ 
170+             stack.extend( 
171+                 current_node 
172+                     .backlinks 
173+                     .iter() 
174+                     .map(|x| x.idx) 
175+                     .filter(|x| !visited.contains(x)), 
176+             ) 
177+         } 
178+ 
179+         nodes_reverted 
180+     } */ 
181+ 
182+     fn  smart_clone ( & mut  self ,  v :  Vec < CacheIndex > )  -> HashMap < CacheIndex ,  CacheIndex >  { 
183+         let  mut  new_indices = HashMap :: new ( ) ; 
184+ 
185+         for  i in  v. iter ( )  { 
186+             let  current_node = self . store . get ( * i) . unwrap ( ) . clone ( ) ; 
187+             new_indices. insert ( * i,  self . add_node ( current_node) ) ; 
188+         } 
189+ 
190+         for  i in  new_indices. values ( )  { 
191+             let  current_node = self . store . get_mut ( * i) . unwrap ( ) ; 
192+ 
193+             for  dep in  current_node. backlinks . iter_mut ( )  { 
194+                 dep. idx  = if  let  Some ( idx)  = new_indices. get ( & dep. idx )  { 
195+                     * idx
196+                 }  else  { 
197+                     dep. idx 
198+                 } 
199+             } 
200+ 
201+             let  mut  to_be_updated = vec ! [ ] ; 
202+ 
203+             for  dep in  current_node. fwdlinks . iter_mut ( )  { 
204+                 dep. idx  = if  let  Some ( idx)  = new_indices. get ( & dep. idx )  { 
205+                     * idx
206+                 }  else  { 
207+                     to_be_updated. push ( dep. clone ( ) ) ; 
208+                     dep. idx 
209+                 } 
210+             } 
211+ 
212+             for  dep in  to_be_updated { 
213+                 let  target_node = self . store . get_mut ( dep. idx ) . unwrap ( ) ; 
214+                 target_node. backlinks . push ( DependencyLink  { 
215+                     id :  dep. id , 
216+                     idx :  * i, 
217+                 } ) ; 
218+             } 
219+         } 
220+ 
221+         new_indices
222+     } 
90223} 
91224
92225impl  Cache  for  IncCache  { 
@@ -204,9 +337,12 @@ impl Cache for IncCache {
204337            kind :  node. kind , 
205338            bty :  node. bty . clone ( ) , 
206339            state :  node. state , 
340+             fwdlinks :  node. fwdlinks . clone ( ) , 
207341            backlinks :  node. backlinks . clone ( ) , 
208342        } ; 
209343
344+         // TODO: Should this push the dependencies? 
345+ 
210346        self . add_node ( new_node) 
211347    } 
212348
@@ -224,13 +360,19 @@ impl Cache for IncCache {
224360            BindingType :: Revertible ( ref  deps)  => match  deps { 
225361                FieldDeps :: Unknown  => new_cached. env . extend ( rec_env. iter ( ) . cloned ( ) ) , 
226362                FieldDeps :: Known ( deps)  if  deps. is_empty ( )  => ( ) , 
227-                 FieldDeps :: Known ( deps)  => new_cached
228-                     . env 
229-                     . extend ( rec_env. iter ( ) . filter ( |( id,  _) | deps. contains ( id) ) . cloned ( ) ) , 
363+                 FieldDeps :: Known ( deps)  => { 
364+                     let  deps = rec_env. iter ( ) . filter ( |( id,  _) | deps. contains ( id) ) . cloned ( ) ; 
365+                     node. fwdlinks  = deps
366+                         . clone ( ) 
367+                         . map ( |( id,  idx) | DependencyLink  {  id,  idx } ) 
368+                         . collect ( ) ; 
369+                     new_cached. env . extend ( deps) ; 
370+                 } 
230371            } , 
231372        } 
232373
233374        node. cached  = Some ( new_cached) ; 
375+         self . update_backlinks ( * idx) ; 
234376    } 
235377
236378    fn  saturate < ' a ,  I :  DoubleEndedIterator < Item  = & ' a  Ident >  + Clone > ( 
@@ -239,7 +381,7 @@ impl Cache for IncCache {
239381        env :  & mut  Environment , 
240382        fields :  I , 
241383    )  -> RichTerm  { 
242-         let  node = self . store . get ( idx) . unwrap ( ) ; 
384+         let  node = self . store . get_mut ( idx) . unwrap ( ) ; 
243385
244386        let  mut  deps_filter:  Box < dyn  FnMut ( & & Ident )  -> bool >  = match  node. bty . clone ( )  { 
245387            BindingType :: Revertible ( FieldDeps :: Known ( deps) )  => { 
@@ -249,13 +391,10 @@ impl Cache for IncCache {
249391            BindingType :: Normal  => Box :: new ( |_:  & & Ident | false ) , 
250392        } ; 
251393
252-         let  node_as_function = self . add_node ( IncCache :: revnode_as_explicit_fun ( 
253-             node, 
254-             fields. clone ( ) . filter ( & mut  deps_filter) , 
255-         ) ) ; 
394+         IncCache :: revnode_as_explicit_fun ( node,  fields. clone ( ) . filter ( & mut  deps_filter) ) ; 
256395
257396        let  fresh_var = Ident :: fresh ( ) ; 
258-         env. insert ( fresh_var,  node_as_function ) ; 
397+         env. insert ( fresh_var,  idx ) ; 
259398
260399        let  as_function_closurized = RichTerm :: from ( Term :: Var ( fresh_var) ) ; 
261400        let  args = fields. filter_map ( |id| deps_filter ( & id) . then ( || RichTerm :: from ( Term :: Var ( * id) ) ) ) ; 
@@ -264,4 +403,12 @@ impl Cache for IncCache {
264403            RichTerm :: from ( Term :: App ( partial_app,  arg) ) 
265404        } ) 
266405    } 
406+ 
407+     fn  smart_clone ( & mut  self ,  v :  Vec < CacheIndex > )  -> HashMap < CacheIndex ,  CacheIndex >  { 
408+         self . smart_clone ( v) 
409+     } 
410+ 
411+     fn  propagate_dirty ( & mut  self ,  indices :  Vec < CacheIndex > )  { 
412+         self . propagate_dirty_vec ( indices) ; 
413+     } 
267414} 
0 commit comments