1use std::collections::HashMap;
2
3use petgraph::algo::is_cyclic_directed;
4use petgraph::Outgoing;
5use serde::{Deserialize, Serialize};
6
7use super::{Ordered, OrderedTrait, TypedTrait};
8use crate::hir::{Hir, SRef};
9use crate::modes::dependencies::ExtendedDepGraph;
10use crate::modes::{DepAnaTrait, DependencyGraph, HirMode};
11
12impl OrderedTrait for Ordered {
13 fn stream_layers(&self, sr: SRef) -> StreamLayers {
14 self.stream_layers[&sr]
15 }
16}
17
18#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)]
20pub struct Layer(usize);
21
22#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)]
24pub struct StreamLayers {
25 spawn: Layer,
26 #[cfg(feature = "shift_layer")]
27 shift: Layer,
28 evaluation: Layer,
29}
30
31impl StreamLayers {
32 #[cfg(not(feature = "shift_layer"))]
33 pub(crate) fn new(spawn_layer: Layer, evaluation_layer: Layer) -> StreamLayers {
35 StreamLayers {
36 spawn: spawn_layer,
37 evaluation: evaluation_layer,
38 }
39 }
40
41 #[cfg(feature = "shift_layer")]
42 pub(crate) fn new(
44 spawn_layer: Layer,
45 shift_layer: Layer,
46 evaluation_layer: Layer,
47 ) -> StreamLayers {
48 StreamLayers {
49 spawn: spawn_layer,
50 shift: shift_layer,
51 evaluation: evaluation_layer,
52 }
53 }
54
55 pub fn spawn_layer(&self) -> Layer {
57 self.spawn
58 }
59
60 #[cfg(feature = "shift_layer")]
61 pub fn shift_layer(&self) -> Layer {
63 self.shift
64 }
65
66 pub fn evaluation_layer(&self) -> Layer {
68 self.evaluation
69 }
70}
71
72impl From<Layer> for usize {
73 fn from(layer: Layer) -> usize {
74 layer.0
75 }
76}
77
78impl Layer {
79 pub fn new(layer: usize) -> Self {
81 Layer(layer)
82 }
83
84 pub fn inner(self) -> usize {
86 self.0
87 }
88}
89
90impl Ordered {
91 pub(crate) fn analyze<M>(spec: &Hir<M>) -> Ordered
97 where
98 M: HirMode + DepAnaTrait + TypedTrait,
99 {
100 let stream_layers = Self::compute_layers(spec, spec.graph());
102 Ordered { stream_layers }
103 }
104
105 fn compute_layers<M>(spec: &Hir<M>, graph: &DependencyGraph) -> HashMap<SRef, StreamLayers>
112 where
113 M: HirMode + DepAnaTrait + TypedTrait,
114 {
115 let graph = &graph
117 .clone()
118 .without_negative_offset_edges()
119 .without_close()
120 .without_different_pacing(spec);
121 let spawn_graph = &graph.clone().only_spawn();
122 #[cfg(feature = "shift_layer")]
123 let shift_graph = &graph.clone().only_filter();
124
125 debug_assert!(
126 !is_cyclic_directed(graph),
127 "This should be already checked in the dependency analysis."
128 );
129
130 let mut evaluation_layers = spec
132 .inputs()
133 .map(|i| {
134 (
135 i.sr,
136 Layer::new(if cfg!(feature = "shift_layer") { 1 } else { 0 }),
137 )
138 })
139 .collect::<HashMap<SRef, Layer>>();
140 let mut spawn_layers = spec
141 .inputs()
142 .map(|i| (i.sr, Layer::new(0)))
143 .collect::<HashMap<SRef, Layer>>();
144 #[cfg(feature = "shift_layer")]
145 let mut shift_layers = spec
146 .inputs()
147 .map(|i| (i.sr, Layer::new(0)))
148 .collect::<HashMap<SRef, Layer>>();
149
150 while graph.node_count() != evaluation_layers.len() {
151 spawn_graph.node_indices().for_each(|node| {
153 let sref = spawn_graph.node_weight(node).unwrap();
154 if !spawn_layers.contains_key(sref) {
156 let neighbor_layers: Vec<_> = spawn_graph
158 .neighbors_directed(node, Outgoing)
159 .map(|outgoing_neighbor| {
160 evaluation_layers
161 .get(spawn_graph.node_weight(outgoing_neighbor).unwrap())
162 .copied()
163 })
164 .collect();
165 let computed_spawn_layer = if neighbor_layers.is_empty() {
166 Some(Layer::new(0))
167 } else {
168 neighbor_layers
169 .into_iter()
170 .try_fold(Layer::new(0), |cur_res_layer, neighbor_layer| {
171 neighbor_layer.map(|nl| std::cmp::max(cur_res_layer, nl))
172 })
173 .map(|layer| Layer::new(layer.inner() + 1))
174 };
175 if let Some(layer) = computed_spawn_layer {
176 spawn_layers.insert(*sref, layer);
177 }
178 }
179 });
180 #[cfg(feature = "shift_layer")]
181 shift_graph.node_indices().for_each(|node| {
182 let sref = shift_graph.node_weight(node).unwrap();
183 if !shift_layers.contains_key(sref)
185 && !evaluation_layers.contains_key(sref)
186 && spawn_layers.contains_key(sref)
187 {
188 let neighbor_layers: Vec<_> = shift_graph
190 .neighbors_directed(node, Outgoing)
191 .flat_map(|outgoing_neighbor| {
192 (outgoing_neighbor != node).then_some(outgoing_neighbor)
194 })
195 .map(|outgoing_neighbor| {
196 evaluation_layers
197 .get(shift_graph.node_weight(outgoing_neighbor).unwrap())
198 .copied()
199 })
200 .collect();
201 let computed_shift_layer = if neighbor_layers.is_empty() {
202 Some(Layer::new(1))
204 } else {
205 neighbor_layers
206 .into_iter()
207 .try_fold(Layer::new(0), |cur_res_layer, neighbor_layer| {
208 neighbor_layer.map(|nl| std::cmp::max(cur_res_layer, nl))
209 })
210 .map(|layer| Layer::new(layer.inner() + 1))
211 };
212 if let Some(layer) = computed_shift_layer {
213 let layer = if spawn_layers[sref] < layer {
215 layer
216 } else {
217 Layer::new(spawn_layers[sref].inner() + 1)
218 };
219 shift_layers.insert(*sref, layer);
220 }
221 }
222 });
223
224 #[cfg(feature = "shift_layer")]
225 let previous_layers = &shift_layers;
226 #[cfg(not(feature = "shift_layer"))]
227 let previous_layers = &spawn_layers;
228
229 graph.node_indices().for_each(|node| {
230 let sref = graph.node_weight(node).unwrap();
231 if !evaluation_layers.contains_key(sref) && previous_layers.contains_key(sref) {
233 let neighbor_layers: Vec<_> = graph
235 .neighbors_directed(node, Outgoing)
236 .flat_map(|outgoing_neighbor| {
237 (outgoing_neighbor != node).then_some(outgoing_neighbor)
239 })
240 .map(|outgoing_neighbor| {
241 evaluation_layers
242 .get(graph.node_weight(outgoing_neighbor).unwrap())
243 .copied()
244 })
245 .collect();
246 let computed_evaluation_layer = if neighbor_layers.is_empty() {
247 Some(Layer::new(if cfg!(feature = "shift_layer") {
249 2
250 } else {
251 1
252 }))
253 } else {
254 neighbor_layers
256 .into_iter()
257 .try_fold(Layer::new(0), |cur_res_layer, neighbor_layer| {
258 neighbor_layer.map(|nl| std::cmp::max(cur_res_layer, nl))
259 })
260 .map(|layer| Layer::new(layer.inner() + 1))
261 };
262 if let Some(layer) = computed_evaluation_layer {
263 let layer = if previous_layers[sref] < layer {
265 layer
266 } else {
267 Layer::new(previous_layers[sref].inner() + 1)
268 };
269 evaluation_layers.insert(*sref, layer);
270 }
271 }
272 });
273 }
274 evaluation_layers
275 .into_iter()
276 .map(|(key, evaluation_layer)| {
277 #[cfg(feature = "shift_layer")]
278 let layer = (
279 key,
280 StreamLayers::new(spawn_layers[&key], shift_layers[&key], evaluation_layer),
281 );
282 #[cfg(not(feature = "shift_layer"))]
283 let layer = (key, StreamLayers::new(spawn_layers[&key], evaluation_layer));
284 layer
285 })
286 .collect::<HashMap<SRef, StreamLayers>>()
287 }
288}
289
290#[cfg(test)]
291fn check_eval_order_for_spec(spec: &str, ref_layers: HashMap<SRef, StreamLayers>) {
292 use crate::{config::FrontendConfig, BaseMode};
293 use rtlola_parser::{parse, ParserConfig};
294
295 let parser_config = ParserConfig::for_string(spec.to_string());
296 let frontend_config = FrontendConfig::from(&parser_config);
297 let ast = parse(&parser_config).unwrap_or_else(|e| panic!("{:?}", e));
298 let hir = Hir::<BaseMode>::from_ast(ast)
299 .unwrap()
300 .check_types(&frontend_config)
301 .unwrap()
302 .analyze_dependencies(&frontend_config)
303 .unwrap();
304 let order = Ordered::analyze(&hir);
305 let Ordered { stream_layers } = order;
306 assert_eq!(stream_layers.len(), ref_layers.len());
307 stream_layers.iter().for_each(|(sr, layers)| {
308 let ref_layers = &ref_layers[sr];
309 assert_eq!(ref_layers.spawn_layer(), layers.spawn_layer());
310 assert_eq!(ref_layers.evaluation_layer(), layers.evaluation_layer());
311 #[cfg(feature = "shift_layer")]
312 assert_eq!(ref_layers.shift_layer(), layers.shift_layer());
313 });
314}
315
316#[cfg(test)]
317#[cfg(not(feature = "shift_layer"))]
318mod tests {
319 use super::*;
320
321 #[test]
322 fn synchronous_lookup() {
323 let spec = "input a: UInt8\noutput b: UInt8 := a\noutput c:UInt8 := b";
324 let sname_to_sref = vec![("a", SRef::In(0)), ("b", SRef::Out(0)), ("c", SRef::Out(1))]
325 .into_iter()
326 .collect::<HashMap<&str, SRef>>();
327 let event_layers = vec![
328 (
329 sname_to_sref["a"],
330 StreamLayers::new(Layer::new(0), Layer::new(0)),
331 ),
332 (
333 sname_to_sref["b"],
334 StreamLayers::new(Layer::new(0), Layer::new(1)),
335 ),
336 (
337 sname_to_sref["c"],
338 StreamLayers::new(Layer::new(0), Layer::new(2)),
339 ),
340 ]
341 .into_iter()
342 .collect();
343 check_eval_order_for_spec(spec, event_layers)
344 }
345
346 #[test]
347 fn hold_lookup() {
348 let spec =
349 "input a: UInt8\ninput b:UInt8\noutput c: UInt8 := a.hold().defaults(to: 0) + b\noutput d: UInt8 := c.hold().defaults(to: 0) + a";
350 let sname_to_sref = vec![
351 ("a", SRef::In(0)),
352 ("b", SRef::In(1)),
353 ("c", SRef::Out(0)),
354 ("d", SRef::Out(1)),
355 ]
356 .into_iter()
357 .collect::<HashMap<&str, SRef>>();
358 let event_layers = vec![
359 (
360 sname_to_sref["a"],
361 StreamLayers::new(Layer::new(0), Layer::new(0)),
362 ),
363 (
364 sname_to_sref["b"],
365 StreamLayers::new(Layer::new(0), Layer::new(0)),
366 ),
367 (
368 sname_to_sref["c"],
369 StreamLayers::new(Layer::new(0), Layer::new(1)),
370 ),
371 (
372 sname_to_sref["d"],
373 StreamLayers::new(Layer::new(0), Layer::new(2)),
374 ),
375 ]
376 .into_iter()
377 .collect();
378 check_eval_order_for_spec(spec, event_layers)
379 }
380
381 #[test]
382 fn offset_lookup() {
383 let spec = "input a: UInt8\noutput b: UInt8 := a.offset(by: -1).defaults(to: 0)\noutput c: UInt8 := b.offset(by: -1).defaults(to: 0)";
384 let sname_to_sref = vec![("a", SRef::In(0)), ("b", SRef::Out(0)), ("c", SRef::Out(1))]
385 .into_iter()
386 .collect::<HashMap<&str, SRef>>();
387 let event_layers = vec![
388 (
389 sname_to_sref["a"],
390 StreamLayers::new(Layer::new(0), Layer::new(0)),
391 ),
392 (
393 sname_to_sref["b"],
394 StreamLayers::new(Layer::new(0), Layer::new(1)),
395 ),
396 (
397 sname_to_sref["c"],
398 StreamLayers::new(Layer::new(0), Layer::new(1)),
399 ),
400 ]
401 .into_iter()
402 .collect();
403 check_eval_order_for_spec(spec, event_layers)
404 }
405
406 #[test]
407 fn sliding_window_lookup() {
408 let spec = "input a: UInt8\noutput b: UInt8 @1Hz := a.aggregate(over: 1s, using: sum)\noutput c: UInt8 := a + 3\noutput d: UInt8 @1Hz := c.aggregate(over: 1s, using: sum)\noutput e: UInt8 := b + d\noutput f: UInt8 @2Hz := e.hold().defaults(to: 0)";
409 let sname_to_sref = vec![
410 ("a", SRef::In(0)),
411 ("b", SRef::Out(0)),
412 ("c", SRef::Out(1)),
413 ("d", SRef::Out(2)),
414 ("e", SRef::Out(3)),
415 ("f", SRef::Out(4)),
416 ]
417 .into_iter()
418 .collect::<HashMap<&str, SRef>>();
419 let ref_layers = vec![
420 (
421 sname_to_sref["a"],
422 StreamLayers::new(Layer::new(0), Layer::new(0)),
423 ),
424 (
425 sname_to_sref["c"],
426 StreamLayers::new(Layer::new(0), Layer::new(1)),
427 ),
428 (
429 sname_to_sref["b"],
430 StreamLayers::new(Layer::new(0), Layer::new(1)),
431 ),
432 (
433 sname_to_sref["d"],
434 StreamLayers::new(Layer::new(0), Layer::new(1)),
435 ),
436 (
437 sname_to_sref["e"],
438 StreamLayers::new(Layer::new(0), Layer::new(2)),
439 ),
440 (
441 sname_to_sref["f"],
442 StreamLayers::new(Layer::new(0), Layer::new(3)),
443 ),
444 ]
445 .into_iter()
446 .collect();
447 check_eval_order_for_spec(spec, ref_layers)
448 }
449
450 #[test]
451 fn discrete_window_lookup() {
452 let spec = "input a: UInt8\n\
453 output b: UInt8 := a.aggregate(over_discrete: 5, using: sum)\n\
454 output c: UInt8 := a + 3\n\
455 output d: UInt8 := c.aggregate(over_discrete: 5, using: sum)";
456
457 let sname_to_sref = vec![
458 ("a", SRef::In(0)),
459 ("b", SRef::Out(0)),
460 ("c", SRef::Out(1)),
461 ("d", SRef::Out(2)),
462 ]
463 .into_iter()
464 .collect::<HashMap<&str, SRef>>();
465 let ref_layers = vec![
466 (
467 sname_to_sref["a"],
468 StreamLayers::new(Layer::new(0), Layer::new(0)),
469 ),
470 (
471 sname_to_sref["b"],
472 StreamLayers::new(Layer::new(0), Layer::new(1)),
473 ),
474 (
475 sname_to_sref["c"],
476 StreamLayers::new(Layer::new(0), Layer::new(1)),
477 ),
478 (
479 sname_to_sref["d"],
480 StreamLayers::new(Layer::new(0), Layer::new(2)),
481 ),
482 ]
483 .into_iter()
484 .collect();
485 check_eval_order_for_spec(spec, ref_layers)
486 }
487
488 #[test]
489 fn offset_lookups() {
490 let spec = "input a: UInt8\noutput b: UInt8 := a.offset(by:-1).defaults(to: 0)\noutput c: UInt8 := a.offset(by:-2).defaults(to: 0)\noutput d: UInt8 := a.offset(by:-3).defaults(to: 0)\noutput e: UInt8 := a.offset(by:-4).defaults(to: 0)";
491 let sname_to_sref = vec![
492 ("a", SRef::In(0)),
493 ("b", SRef::Out(0)),
494 ("c", SRef::Out(1)),
495 ("d", SRef::Out(2)),
496 ("e", SRef::Out(3)),
497 ]
498 .into_iter()
499 .collect::<HashMap<&str, SRef>>();
500 let event_layers = vec![
501 (
502 sname_to_sref["a"],
503 StreamLayers::new(Layer::new(0), Layer::new(0)),
504 ),
505 (
506 sname_to_sref["b"],
507 StreamLayers::new(Layer::new(0), Layer::new(1)),
508 ),
509 (
510 sname_to_sref["c"],
511 StreamLayers::new(Layer::new(0), Layer::new(1)),
512 ),
513 (
514 sname_to_sref["d"],
515 StreamLayers::new(Layer::new(0), Layer::new(1)),
516 ),
517 (
518 sname_to_sref["e"],
519 StreamLayers::new(Layer::new(0), Layer::new(1)),
520 ),
521 ]
522 .into_iter()
523 .collect();
524 check_eval_order_for_spec(spec, event_layers)
525 }
526 #[test]
527 fn negative_loop_different_offsets() {
528 let spec = "input a: Int8\noutput b: Int8 := a.offset(by: -1).defaults(to: 0) + d.offset(by:-2).defaults(to:0)\noutput c: Int8 := b.offset(by:-3).defaults(to: 0)\noutput d: Int8 := c.offset(by:-4).defaults(to: 0)";
529 let sname_to_sref = vec![
530 ("a", SRef::In(0)),
531 ("b", SRef::Out(0)),
532 ("c", SRef::Out(1)),
533 ("d", SRef::Out(2)),
534 ]
535 .into_iter()
536 .collect::<HashMap<&str, SRef>>();
537 let event_layers = vec![
538 (
539 sname_to_sref["a"],
540 StreamLayers::new(Layer::new(0), Layer::new(0)),
541 ),
542 (
543 sname_to_sref["b"],
544 StreamLayers::new(Layer::new(0), Layer::new(1)),
545 ),
546 (
547 sname_to_sref["c"],
548 StreamLayers::new(Layer::new(0), Layer::new(1)),
549 ),
550 (
551 sname_to_sref["d"],
552 StreamLayers::new(Layer::new(0), Layer::new(1)),
553 ),
554 ]
555 .into_iter()
556 .collect();
557 check_eval_order_for_spec(spec, event_layers)
558 }
559
560 #[test]
561 fn lookup_chain() {
562 let spec = "input a: Int8\noutput b: Int8 := a + d.hold().defaults(to:0)\noutput c: Int8 := b\noutput d: Int8 := c.offset(by:-4).defaults(to: 0)";
563 let sname_to_sref = vec![
564 ("a", SRef::In(0)),
565 ("b", SRef::Out(0)),
566 ("c", SRef::Out(1)),
567 ("d", SRef::Out(2)),
568 ]
569 .into_iter()
570 .collect::<HashMap<&str, SRef>>();
571 let event_layers = vec![
572 (
573 sname_to_sref["a"],
574 StreamLayers::new(Layer::new(0), Layer::new(0)),
575 ),
576 (
577 sname_to_sref["b"],
578 StreamLayers::new(Layer::new(0), Layer::new(2)),
579 ),
580 (
581 sname_to_sref["c"],
582 StreamLayers::new(Layer::new(0), Layer::new(3)),
583 ),
584 (
585 sname_to_sref["d"],
586 StreamLayers::new(Layer::new(0), Layer::new(1)),
587 ),
588 ]
589 .into_iter()
590 .collect();
591 check_eval_order_for_spec(spec, event_layers)
592 }
593
594 #[test]
595 fn multiple_input_stream() {
596 let spec = "input a: Int8\ninput b: Int8\noutput c: Int8 := a + b.hold().defaults(to:0)\noutput d: Int8 := a + c.offset(by: -1).defaults(to: 0)\noutput e: Int8 := c + 3\noutput f: Int8 := c + 6\noutput g: Int8 := b + 3\noutput h: Int8 := g + f";
597 let sname_to_sref = vec![
598 ("a", SRef::In(0)),
599 ("b", SRef::In(1)),
600 ("c", SRef::Out(0)),
601 ("d", SRef::Out(1)),
602 ("e", SRef::Out(2)),
603 ("f", SRef::Out(3)),
604 ("g", SRef::Out(4)),
605 ("h", SRef::Out(5)),
606 ]
607 .into_iter()
608 .collect::<HashMap<&str, SRef>>();
609 let event_layers = vec![
610 (
611 sname_to_sref["a"],
612 StreamLayers::new(Layer::new(0), Layer::new(0)),
613 ),
614 (
615 sname_to_sref["b"],
616 StreamLayers::new(Layer::new(0), Layer::new(0)),
617 ),
618 (
619 sname_to_sref["c"],
620 StreamLayers::new(Layer::new(0), Layer::new(1)),
621 ),
622 (
623 sname_to_sref["d"],
624 StreamLayers::new(Layer::new(0), Layer::new(1)),
625 ),
626 (
627 sname_to_sref["e"],
628 StreamLayers::new(Layer::new(0), Layer::new(2)),
629 ),
630 (
631 sname_to_sref["f"],
632 StreamLayers::new(Layer::new(0), Layer::new(2)),
633 ),
634 (
635 sname_to_sref["g"],
636 StreamLayers::new(Layer::new(0), Layer::new(1)),
637 ),
638 (
639 sname_to_sref["h"],
640 StreamLayers::new(Layer::new(0), Layer::new(3)),
641 ),
642 ]
643 .into_iter()
644 .collect();
645 check_eval_order_for_spec(spec, event_layers)
646 }
647
648 #[test]
649 fn event_and_periodic_stream_mix() {
650 let spec =
651 "input a : Int8 \ninput b :Int8\noutput c @2Hz := a.hold().defaults(to: 0) + 3\noutput d @1Hz := a.hold().defaults(to: 0) + c\noutput e := a + b";
652 let sname_to_sref = vec![
653 ("a", SRef::In(0)),
654 ("b", SRef::In(1)),
655 ("c", SRef::Out(0)),
656 ("d", SRef::Out(1)),
657 ("e", SRef::Out(2)),
658 ]
659 .into_iter()
660 .collect::<HashMap<&str, SRef>>();
661 let ref_layers = vec![
662 (
663 sname_to_sref["a"],
664 StreamLayers::new(Layer::new(0), Layer::new(0)),
665 ),
666 (
667 sname_to_sref["b"],
668 StreamLayers::new(Layer::new(0), Layer::new(0)),
669 ),
670 (
671 sname_to_sref["e"],
672 StreamLayers::new(Layer::new(0), Layer::new(1)),
673 ),
674 (
675 sname_to_sref["c"],
676 StreamLayers::new(Layer::new(0), Layer::new(1)),
677 ),
678 (
679 sname_to_sref["d"],
680 StreamLayers::new(Layer::new(0), Layer::new(2)),
681 ),
682 ]
683 .into_iter()
684 .collect();
685 check_eval_order_for_spec(spec, ref_layers)
686 }
687
688 #[test]
689 fn negative_and_postive_lookups_as_loop() {
690 let spec = "input a: Int8\noutput b: Int8 := a + d.offset(by:-1).defaults(to:0)\noutput c: Int8 := b\noutput d: Int8 := c";
691 let sname_to_sref = vec![
692 ("a", SRef::In(0)),
693 ("b", SRef::Out(0)),
694 ("c", SRef::Out(1)),
695 ("d", SRef::Out(2)),
696 ]
697 .into_iter()
698 .collect::<HashMap<&str, SRef>>();
699 let event_layers = vec![
700 (
701 sname_to_sref["a"],
702 StreamLayers::new(Layer::new(0), Layer::new(0)),
703 ),
704 (
705 sname_to_sref["b"],
706 StreamLayers::new(Layer::new(0), Layer::new(1)),
707 ),
708 (
709 sname_to_sref["c"],
710 StreamLayers::new(Layer::new(0), Layer::new(2)),
711 ),
712 (
713 sname_to_sref["d"],
714 StreamLayers::new(Layer::new(0), Layer::new(3)),
715 ),
716 ]
717 .into_iter()
718 .collect();
719 check_eval_order_for_spec(spec, event_layers)
720 }
721 #[test]
722 fn sliding_windows_chain_and_hold_lookup() {
723 let spec = "input a: Int8\noutput b@1Hz := a.aggregate(over: 1s, using: sum) + d.offset(by: -1).defaults(to: 0)\noutput c@2Hz := b.aggregate(over: 1s, using: sum)\noutput d@2Hz := b.hold().defaults(to: 0)";
724 let sname_to_sref = vec![
725 ("a", SRef::In(0)),
726 ("b", SRef::Out(0)),
727 ("c", SRef::Out(1)),
728 ("d", SRef::Out(2)),
729 ]
730 .into_iter()
731 .collect::<HashMap<&str, SRef>>();
732 let ref_layers = vec![
733 (
734 sname_to_sref["b"],
735 StreamLayers::new(Layer::new(0), Layer::new(1)),
736 ),
737 (
738 sname_to_sref["c"],
739 StreamLayers::new(Layer::new(0), Layer::new(2)),
740 ),
741 (
742 sname_to_sref["d"],
743 StreamLayers::new(Layer::new(0), Layer::new(2)),
744 ),
745 (
746 sname_to_sref["a"],
747 StreamLayers::new(Layer::new(0), Layer::new(0)),
748 ),
749 ]
750 .into_iter()
751 .collect();
752 check_eval_order_for_spec(spec, ref_layers)
753 }
754
755 #[test]
756 fn simple_chain_with_parameter() {
757 let spec =
758 "input a: Int8\noutput b := a + 5\noutput c(para) spawn with b eval with para + a";
759 let sname_to_sref = vec![("a", SRef::In(0)), ("b", SRef::Out(0)), ("c", SRef::Out(1))]
760 .into_iter()
761 .collect::<HashMap<&str, SRef>>();
762 let event_layers = vec![
763 (
764 sname_to_sref["a"],
765 StreamLayers::new(Layer::new(0), Layer::new(0)),
766 ),
767 (
768 sname_to_sref["b"],
769 StreamLayers::new(Layer::new(0), Layer::new(1)),
770 ),
771 (
772 sname_to_sref["c"],
773 StreamLayers::new(Layer::new(2), Layer::new(3)),
774 ),
775 ]
776 .into_iter()
777 .collect();
778 check_eval_order_for_spec(spec, event_layers)
779 }
780
781 #[test]
782 fn lookup_chain_with_parametrization() {
783 let spec = "input a: Int8\noutput b(para) spawn with a when a > 6 eval with a + para\noutput c(para) spawn with a when a > 6 eval with a + b(para)\noutput d(para) spawn with a when a > 6 eval with a + c(para)";
784 let sname_to_sref = vec![
785 ("a", SRef::In(0)),
786 ("b", SRef::Out(0)),
787 ("c", SRef::Out(1)),
788 ("d", SRef::Out(2)),
789 ]
790 .into_iter()
791 .collect::<HashMap<&str, SRef>>();
792 let event_layers = vec![
793 (
794 sname_to_sref["a"],
795 StreamLayers::new(Layer::new(0), Layer::new(0)),
796 ),
797 (
798 sname_to_sref["b"],
799 StreamLayers::new(Layer::new(1), Layer::new(2)),
800 ),
801 (
802 sname_to_sref["c"],
803 StreamLayers::new(Layer::new(1), Layer::new(3)),
804 ),
805 (
806 sname_to_sref["d"],
807 StreamLayers::new(Layer::new(1), Layer::new(4)),
808 ),
809 ]
810 .into_iter()
811 .collect();
812 check_eval_order_for_spec(spec, event_layers)
813 }
814
815 #[test]
816 fn parameter_loop_with_lookup_in_close() {
817 let spec = "\
818 input a: Int8\n\
819 input b: Int8\n\
820 output c(p) \n\
821 spawn with a when a < b\n\
822 eval with p + b + g(p).hold().defaults(to: 0)\n\
823 output d(p) \n\
824 spawn with b when c(4).hold().defaults(to: 0) < 4\n\
825 eval with b + 5\n\
826 output e(p)\n\
827 spawn with b\n\
828 eval with d(p).hold().defaults(to: 0) + b\n\
829 output f(p)\n\
830 spawn with b\n\
831 eval when e(p).hold().defaults(to: 0) < 6 with b + 5\n\
832 output g(p)\n\
833 spawn with b close @true when f(p).hold().defaults(to: 0) < 6\n\
834 eval with b + 5";
835 let sname_to_sref = vec![
836 ("a", SRef::In(0)),
837 ("b", SRef::In(1)),
838 ("c", SRef::Out(0)),
839 ("d", SRef::Out(1)),
840 ("e", SRef::Out(2)),
841 ("f", SRef::Out(3)),
842 ("g", SRef::Out(4)),
843 ]
844 .into_iter()
845 .collect::<HashMap<&str, SRef>>();
846 let event_layers = vec![
847 (
848 sname_to_sref["a"],
849 StreamLayers::new(Layer::new(0), Layer::new(0)),
850 ),
851 (
852 sname_to_sref["b"],
853 StreamLayers::new(Layer::new(0), Layer::new(0)),
854 ),
855 (
856 sname_to_sref["c"],
857 StreamLayers::new(Layer::new(1), Layer::new(3)),
858 ),
859 (
860 sname_to_sref["d"],
861 StreamLayers::new(Layer::new(4), Layer::new(5)),
862 ),
863 (
864 sname_to_sref["e"],
865 StreamLayers::new(Layer::new(1), Layer::new(6)),
866 ),
867 (
868 sname_to_sref["f"],
869 StreamLayers::new(Layer::new(1), Layer::new(7)),
870 ),
871 (
872 sname_to_sref["g"],
873 StreamLayers::new(Layer::new(1), Layer::new(2)),
874 ),
875 ]
876 .into_iter()
877 .collect();
878 check_eval_order_for_spec(spec, event_layers)
879 }
880
881 #[test]
882 fn parameter_nested_lookup_implicit() {
883 let spec = "input a: Int8\n input b: Int8\n output c(p) spawn with a eval with p + b\noutput d := c(c(b).hold().defaults(to: 0)).hold().defaults(to: 0)";
884 let sname_to_sref = vec![
885 ("a", SRef::In(0)),
886 ("b", SRef::In(1)),
887 ("c", SRef::Out(0)),
888 ("d", SRef::Out(1)),
889 ]
890 .into_iter()
891 .collect::<HashMap<&str, SRef>>();
892 let event_layers = vec![
893 (
894 sname_to_sref["a"],
895 StreamLayers::new(Layer::new(0), Layer::new(0)),
896 ),
897 (
898 sname_to_sref["b"],
899 StreamLayers::new(Layer::new(0), Layer::new(0)),
900 ),
901 (
902 sname_to_sref["c"],
903 StreamLayers::new(Layer::new(1), Layer::new(2)),
904 ),
905 (
906 sname_to_sref["d"],
907 StreamLayers::new(Layer::new(0), Layer::new(3)),
908 ),
909 ]
910 .into_iter()
911 .collect();
912 check_eval_order_for_spec(spec, event_layers)
913 }
914
915 #[test]
916 fn parameter_nested_lookup_explicit() {
917 let spec = "input a: Int8\n input b: Int8\n output c(p) spawn with a eval with p + b\noutput d := c(b).hold().defaults(to: 0)\noutput e := c(d).hold().defaults(to: 0)";
918 let sname_to_sref = vec![
919 ("a", SRef::In(0)),
920 ("b", SRef::In(1)),
921 ("c", SRef::Out(0)),
922 ("d", SRef::Out(1)),
923 ("e", SRef::Out(2)),
924 ]
925 .into_iter()
926 .collect::<HashMap<&str, SRef>>();
927 let event_layers = vec![
928 (
929 sname_to_sref["a"],
930 StreamLayers::new(Layer::new(0), Layer::new(0)),
931 ),
932 (
933 sname_to_sref["b"],
934 StreamLayers::new(Layer::new(0), Layer::new(0)),
935 ),
936 (
937 sname_to_sref["c"],
938 StreamLayers::new(Layer::new(1), Layer::new(2)),
939 ),
940 (
941 sname_to_sref["d"],
942 StreamLayers::new(Layer::new(0), Layer::new(3)),
943 ),
944 (
945 sname_to_sref["e"],
946 StreamLayers::new(Layer::new(0), Layer::new(4)),
947 ),
948 ]
949 .into_iter()
950 .collect();
951 check_eval_order_for_spec(spec, event_layers)
952 }
953
954 #[test]
955 fn test_spawn_eventbased() {
956 let spec = "input a: Int32\n\
957 output b(x: Int32) spawn with a eval with x + a";
958 let sname_to_sref = vec![("a", SRef::In(0)), ("b", SRef::Out(0))]
959 .into_iter()
960 .collect::<HashMap<&str, SRef>>();
961 let event_layers = vec![
962 (
963 sname_to_sref["a"],
964 StreamLayers::new(Layer::new(0), Layer::new(0)),
965 ),
966 (
967 sname_to_sref["b"],
968 StreamLayers::new(Layer::new(1), Layer::new(2)),
969 ),
970 ]
971 .into_iter()
972 .collect();
973 check_eval_order_for_spec(spec, event_layers)
974 }
975
976 #[test]
977 fn test_delay() {
978 let spec = "input a: UInt64\n\
979 output a_counter: UInt64 @a := a_counter.offset(by: -1).defaults(to: 0) + 1\n\
980 output b(p: UInt64) spawn with a_counter when a = 1 close when if true then true else b(p) eval @1Hz with a.hold(or: 0) == 2";
981 let sname_to_sref = vec![
982 ("a", SRef::In(0)),
983 ("a_counter", SRef::Out(0)),
984 ("b", SRef::Out(1)),
985 ]
986 .into_iter()
987 .collect::<HashMap<&str, SRef>>();
988 let ref_layers = vec![
989 (
990 sname_to_sref["a"],
991 StreamLayers::new(Layer::new(0), Layer::new(0)),
992 ),
993 (
994 sname_to_sref["a_counter"],
995 StreamLayers::new(Layer::new(0), Layer::new(1)),
996 ),
997 (
998 sname_to_sref["b"],
999 StreamLayers::new(Layer::new(2), Layer::new(3)),
1000 ),
1001 ]
1002 .into_iter()
1003 .collect();
1004 check_eval_order_for_spec(spec, ref_layers)
1005 }
1006
1007 #[test]
1008 fn test_instance_aggregation() {
1009 let spec = "input a: Int32\n\
1010 output b (p) spawn with a eval when a > 5 with b(p).offset(by: -1).defaults(to: 0) + a\n\
1011 output c eval with b.aggregate(over_instances: fresh, using: Σ)\n";
1012 let sname_to_sref = vec![("a", SRef::In(0)), ("b", SRef::Out(0)), ("c", SRef::Out(1))]
1013 .into_iter()
1014 .collect::<HashMap<&str, SRef>>();
1015 let event_layers = vec![
1016 (
1017 sname_to_sref["a"],
1018 StreamLayers::new(Layer::new(0), Layer::new(0)),
1019 ),
1020 (
1021 sname_to_sref["b"],
1022 StreamLayers::new(Layer::new(1), Layer::new(2)),
1023 ),
1024 (
1025 sname_to_sref["c"],
1026 StreamLayers::new(Layer::new(0), Layer::new(3)),
1027 ),
1028 ]
1029 .into_iter()
1030 .collect();
1031 check_eval_order_for_spec(spec, event_layers)
1032 }
1033}
1034
1035#[cfg(test)]
1036#[cfg(feature = "shift_layer")]
1037mod tests {
1038 use std::collections::HashMap;
1039
1040 use crate::hir::SRef;
1041
1042 use super::{check_eval_order_for_spec, Layer, StreamLayers};
1043
1044 #[test]
1045 fn synchronous_lookup() {
1046 let spec = "input a: UInt8\noutput b: UInt8 := a\noutput c:UInt8 := b";
1047 let sname_to_sref = vec![("a", SRef::In(0)), ("b", SRef::Out(0)), ("c", SRef::Out(1))]
1048 .into_iter()
1049 .collect::<HashMap<&str, SRef>>();
1050 let event_layers = vec![
1051 (
1052 sname_to_sref["a"],
1053 StreamLayers::new(Layer::new(0), Layer::new(0), Layer::new(1)),
1054 ),
1055 (
1056 sname_to_sref["b"],
1057 StreamLayers::new(Layer::new(0), Layer::new(1), Layer::new(2)),
1058 ),
1059 (
1060 sname_to_sref["c"],
1061 StreamLayers::new(Layer::new(0), Layer::new(1), Layer::new(3)),
1062 ),
1063 ]
1064 .into_iter()
1065 .collect();
1066 check_eval_order_for_spec(spec, event_layers)
1067 }
1068
1069 #[test]
1070 fn filtered_spec() {
1071 let spec = "input a: UInt8
1072 output b := a + 1
1073 output c eval when b == 0 with a
1074 output d eval when a == 0 with c.hold(or: 0)";
1075 let sname_to_sref = vec![
1076 ("a", SRef::In(0)),
1077 ("b", SRef::Out(0)),
1078 ("c", SRef::Out(1)),
1079 ("d", SRef::Out(2)),
1080 ]
1081 .into_iter()
1082 .collect::<HashMap<&str, SRef>>();
1083 let event_layers = vec![
1084 (
1085 sname_to_sref["a"],
1086 StreamLayers::new(Layer::new(0), Layer::new(0), Layer::new(1)),
1087 ),
1088 (
1089 sname_to_sref["b"],
1090 StreamLayers::new(Layer::new(0), Layer::new(1), Layer::new(2)),
1091 ),
1092 (
1093 sname_to_sref["c"],
1094 StreamLayers::new(Layer::new(0), Layer::new(3), Layer::new(4)),
1095 ),
1096 (
1097 sname_to_sref["d"],
1098 StreamLayers::new(Layer::new(0), Layer::new(2), Layer::new(5)),
1099 ),
1100 ]
1101 .into_iter()
1102 .collect();
1103 check_eval_order_for_spec(spec, event_layers)
1104 }
1105
1106 #[test]
1107 fn filtered_spec_offset() {
1108 let spec = "input a: UInt8
1109 output b := a + 1
1110 output c eval when b == 0 with a
1111 output d eval when b == 0 with c.last(or: 0)";
1112 let sname_to_sref = vec![
1113 ("a", SRef::In(0)),
1114 ("b", SRef::Out(0)),
1115 ("c", SRef::Out(1)),
1116 ("d", SRef::Out(2)),
1117 ]
1118 .into_iter()
1119 .collect::<HashMap<&str, SRef>>();
1120 let event_layers = vec![
1121 (
1122 sname_to_sref["a"],
1123 StreamLayers::new(Layer::new(0), Layer::new(0), Layer::new(1)),
1124 ),
1125 (
1126 sname_to_sref["b"],
1127 StreamLayers::new(Layer::new(0), Layer::new(1), Layer::new(2)),
1128 ),
1129 (
1130 sname_to_sref["c"],
1131 StreamLayers::new(Layer::new(0), Layer::new(3), Layer::new(4)),
1132 ),
1133 (
1134 sname_to_sref["d"],
1135 StreamLayers::new(Layer::new(0), Layer::new(3), Layer::new(4)),
1136 ),
1137 ]
1138 .into_iter()
1139 .collect();
1140 check_eval_order_for_spec(spec, event_layers)
1141 }
1142}