Skip to content

Commit a093eca

Browse files
committed
Add timeline checker and testcases
1 parent 56ebfb2 commit a093eca

4 files changed

Lines changed: 645 additions & 1 deletion

File tree

‎ymmsl/v0_2/component.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from ymmsl.util import remove_trailing_whitespace
77
from ymmsl.v0_2.identity import Reference
8-
from ymmsl.v0_2.ports import Ports
8+
from ymmsl.v0_2.ports import Ports, Timeline
99

1010

1111
class Component:
@@ -30,6 +30,9 @@ class Component:
3030
implementation: A Model or Program implementing this component
3131
optional: Whether this component is optional
3232
multiplicity: The shape of the set of instances
33+
timeline: The resolved (absolute) timeline for this component inside the model.
34+
This will be ``None`` until resolved by
35+
:meth:`~ymmsl.v0_2.timeline_resolver.resolve_timelines()`.
3336
"""
3437

3538
def __init__(
@@ -56,6 +59,7 @@ def __init__(
5659
self.ports = ports
5760
self.description = description
5861
self.optional = optional
62+
self.timeline: Optional[Timeline] = None
5963

6064
if implementation is not None:
6165
self.implementation: Optional[Reference] = Reference(implementation)
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
from pathlib import Path
2+
3+
import pytest
4+
5+
import ymmsl
6+
from ymmsl.v0_2 import ConduitFilter, Configuration, Timeline
7+
from ymmsl.v0_2 import Reference as Ref
8+
from ymmsl.v0_2.timeline_resolver import (
9+
ROOT_TIMELINE,
10+
ConduitTimelineError,
11+
CyclicDependency,
12+
InconsistentTimelines,
13+
TooManyReducerFilters,
14+
resolve_timelines,
15+
)
16+
17+
18+
@pytest.fixture()
19+
def timelines_configuration() -> Configuration:
20+
return ymmsl.load_as(
21+
Configuration, Path(__file__).parent / "ymmsl1/timelines.ymmsl"
22+
)
23+
24+
25+
def test_consistent_configuration(timelines_configuration: Configuration) -> None:
26+
timelines_configuration.check_consistent()
27+
28+
29+
def test_dispatch(timelines_configuration: Configuration) -> None:
30+
model = timelines_configuration.models[Ref("dispatch")]
31+
resolve_timelines(model)
32+
assert model.components[Ref("first")].timeline == ROOT_TIMELINE
33+
assert model.components[Ref("second")].timeline == ROOT_TIMELINE
34+
35+
36+
def test_macromicro(timelines_configuration: Configuration) -> None:
37+
model = timelines_configuration.models[Ref("macromicro")]
38+
resolve_timelines(model)
39+
assert model.components[Ref("macro")].timeline == ROOT_TIMELINE
40+
assert model.components[Ref("micro")].timeline == Timeline(":macro")
41+
42+
# Check that ports have the correct relative timelines:
43+
macro = model.components[Ref("macro")]
44+
assert macro.ports["init"].timeline == Timeline("")
45+
assert macro.ports["out"].timeline == Timeline("macro")
46+
assert macro.ports["in"].timeline == Timeline("macro")
47+
48+
for micro_port in model.components[Ref("micro")].ports.values():
49+
assert micro_port.timeline == Timeline("")
50+
51+
52+
def test_cycle(timelines_configuration: Configuration) -> None:
53+
with pytest.raises(CyclicDependency, match="cycle in model"):
54+
resolve_timelines(timelines_configuration.models[Ref("cycle")])
55+
56+
57+
def test_reducer(timelines_configuration: Configuration) -> None:
58+
model = timelines_configuration.models[Ref("reducer")]
59+
resolve_timelines(model)
60+
assert model.components[Ref("first")].timeline == ROOT_TIMELINE
61+
assert model.components[Ref("second")].timeline == ROOT_TIMELINE
62+
63+
64+
def test_too_many_reducers(timelines_configuration: Configuration) -> None:
65+
model = timelines_configuration.models[Ref("reducer")]
66+
model.conduits[-1].filters.append(model.conduits[-1].filters[0])
67+
with pytest.raises(TooManyReducerFilters, match="too many reducer filters"):
68+
resolve_timelines(model)
69+
70+
71+
def test_inconsistent_timelines(timelines_configuration: Configuration) -> None:
72+
with pytest.raises(InconsistentTimelines):
73+
resolve_timelines(timelines_configuration.models[Ref("inconsistent")])
74+
75+
76+
def test_repeaters(timelines_configuration: Configuration) -> None:
77+
model = timelines_configuration.models[Ref("repeaters")]
78+
resolve_timelines(model)
79+
assert model.components[Ref("macro")].timeline == ROOT_TIMELINE
80+
assert model.components[Ref("meso")].timeline == Timeline(":macro")
81+
assert model.components[Ref("micro")].timeline == Timeline(":macro:meso")
82+
83+
84+
def test_too_many_repeaters(timelines_configuration: Configuration) -> None:
85+
model = timelines_configuration.models[Ref("repeaters")]
86+
model.conduits[-2].filters.append(ConduitFilter.REPEAT)
87+
with pytest.raises(ConduitTimelineError, match="remove a repeater"):
88+
resolve_timelines(model)
89+
90+
91+
def test_too_few_repeaters(timelines_configuration: Configuration) -> None:
92+
model = timelines_configuration.models[Ref("repeaters")]
93+
model.conduits[-1].filters.pop()
94+
with pytest.raises(ConduitTimelineError, match="add a repeater"):
95+
resolve_timelines(model)
96+
97+
98+
def test_repeater_and_too_many_reducers(timelines_configuration: Configuration) -> None:
99+
model = timelines_configuration.models[Ref("repeaters")]
100+
model.conduits[-1].filters.insert(0, ConduitFilter.LAST)
101+
with pytest.raises(TooManyReducerFilters, match="too many reducer filters"):
102+
resolve_timelines(model)
103+
104+
105+
def test_repeater_after_reducer(timelines_configuration: Configuration) -> None:
106+
model = timelines_configuration.models[Ref("repeater_reducer")]
107+
resolve_timelines(model)
108+
assert model.components[Ref("macro1")].timeline == ROOT_TIMELINE
109+
assert model.components[Ref("macro2")].timeline == ROOT_TIMELINE
110+
assert model.components[Ref("micro1")].timeline == Timeline(":macro1")
111+
assert model.components[Ref("micro2")].timeline == Timeline(":macro2")
112+
113+
# Remove filters on the last conduit to make the incoming timelines inconsistent
114+
model.conduits[-1].filters = []
115+
with pytest.raises(InconsistentTimelines, match="different timelines"):
116+
resolve_timelines(model)
117+
118+
119+
def test_repeater_after_reducer_error(timelines_configuration: Configuration) -> None:
120+
model = timelines_configuration.models[Ref("repeater_reducer_error")]
121+
with pytest.raises(ConduitTimelineError, match="remove a repeater and reducer"):
122+
resolve_timelines(model)
123+
model.conduits[-1].filters = []
124+
resolve_timelines(model)
125+
assert model.components[Ref("macro")].timeline == ROOT_TIMELINE
126+
assert model.components[Ref("micro1")].timeline == Timeline(":macro")
127+
assert model.components[Ref("micro2")].timeline == Timeline(":macro")
128+
129+
130+
def test_inconsistent_interact(timelines_configuration: Configuration) -> None:
131+
model = timelines_configuration.models[Ref("inconsistent_interact")]
132+
with pytest.raises(ConduitTimelineError, match="missing timeline annotations"):
133+
resolve_timelines(model)
134+
model.components[Ref("B")].ports["out"].timeline = Timeline("A")
135+
model.components[Ref("B")].ports["in"].timeline = Timeline("A")
136+
resolve_timelines(model)
137+
138+
139+
def test_model_ports(timelines_configuration: Configuration) -> None:
140+
model = timelines_configuration.models[Ref("model_ports")]
141+
resolve_timelines(model)
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
ymmsl_version: v0.2
2+
description: Test models for determining timelines
3+
models:
4+
dispatch:
5+
ports:
6+
f_init: init
7+
components:
8+
first:
9+
description: First component
10+
ports:
11+
f_init: init
12+
o_f: final
13+
second:
14+
description: Second component
15+
ports:
16+
f_init: init
17+
conduits:
18+
init: first.init
19+
first.final: second.init
20+
21+
macromicro:
22+
ports:
23+
f_init: init
24+
components:
25+
macro:
26+
description: Macro component
27+
ports:
28+
f_init: init
29+
o_i: out
30+
s: in
31+
micro:
32+
description: Micro component
33+
ports:
34+
f_init: init1 init2
35+
o_f: final
36+
conduits:
37+
init:
38+
- macro.init
39+
- repeat micro.init1 # Test repeater filter
40+
macro.out: micro.init2
41+
micro.final: macro.in
42+
43+
cycle:
44+
components:
45+
first:
46+
description: First component
47+
ports:
48+
f_init: init
49+
o_f: final
50+
second:
51+
description: Second component
52+
ports:
53+
f_init: init
54+
o_f: final
55+
conduits:
56+
first.final: second.init
57+
second.final: first.init
58+
59+
reducer:
60+
components:
61+
first:
62+
description: First component
63+
ports:
64+
o_i: out
65+
o_f: final
66+
second:
67+
description: Second component
68+
ports:
69+
f_init: init1 init2
70+
conduits:
71+
first.final: second.init1
72+
first.out: last second.init2
73+
74+
inconsistent:
75+
components:
76+
macro:
77+
description: Macro component
78+
ports:
79+
o_i: out
80+
o_f: final
81+
micro:
82+
description: Micro component
83+
ports:
84+
f_init: in
85+
o_f: final
86+
inconsistent:
87+
description: Component with inconsistent timelines
88+
ports:
89+
f_init: init1 init2
90+
conduits:
91+
macro.out: micro.in
92+
macro.final: inconsistent.init1
93+
micro.final: inconsistent.init2
94+
95+
repeaters:
96+
ports:
97+
f_init: init
98+
components:
99+
macro:
100+
description: Macro component
101+
ports:
102+
f_init: init
103+
o_i: out
104+
s: in
105+
meso:
106+
description: Meso component
107+
ports:
108+
f_init: init init2
109+
o_i: out
110+
s: in
111+
o_f: final
112+
micro:
113+
description: Micro component
114+
ports:
115+
f_init: init init2
116+
o_f: final
117+
conduits:
118+
macro.out: meso.init
119+
meso.final: macro.in
120+
meso.out: micro.init
121+
micro.final: meso.in
122+
init:
123+
- macro.init
124+
- repeat meso.init2
125+
- pad pad micro.init2
126+
127+
repeater_reducer:
128+
components:
129+
macro1:
130+
description: First macro component
131+
ports:
132+
o_i: out
133+
o_f: final
134+
micro1:
135+
description: First micro
136+
ports:
137+
f_init: init
138+
o_f: final
139+
macro2:
140+
description: Second macro component
141+
ports:
142+
f_init: init
143+
o_i: out
144+
micro2:
145+
description: Second micro
146+
ports:
147+
f_init: init_micro1 init_macro2
148+
conduits:
149+
macro1.out: micro1.init
150+
macro1.final: macro2.init
151+
macro2.out: micro2.init_macro2
152+
micro1.final: last repeat micro2.init_micro1
153+
154+
repeater_reducer_error:
155+
components:
156+
macro:
157+
description: Macro component
158+
ports:
159+
o_i: out
160+
micro1:
161+
description: First micro
162+
ports:
163+
f_init: init
164+
o_f: final
165+
micro2:
166+
description: Second micro
167+
ports:
168+
f_init: init1 init2
169+
conduits:
170+
macro.out:
171+
- micro1.init
172+
- micro2.init1
173+
micro1.final: last pad micro2.init2
174+
175+
inconsistent_interact:
176+
components:
177+
A:
178+
description: A
179+
ports:
180+
o_i: out
181+
s: in
182+
B:
183+
description: A
184+
ports:
185+
o_i: out
186+
s: in
187+
conduits:
188+
A.out: B.in
189+
B.out: A.in
190+
191+
model_ports:
192+
components:
193+
macro:
194+
description: macro
195+
ports:
196+
f_init: init
197+
o_i: out
198+
s: in
199+
o_f: final
200+
meso:
201+
description: meso
202+
ports:
203+
f_init: init
204+
o_i: out
205+
s: in
206+
o_f: final
207+
ports:
208+
f_init: init
209+
+macro:meso:
210+
o_i: out
211+
s: in
212+
o_f: final
213+
conduits:
214+
init: macro.init
215+
macro.out: meso.init
216+
meso.out: out
217+
in: meso.in
218+
meso.final: macro.in
219+
macro.final: final

0 commit comments

Comments
 (0)