You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<AsynchronousSVGtitle="Lingua Franca diagram: Asynchronous"role="img"width="350" />
145
147
146
148
Physical actions are the mechanism for obtaining input from the outside world. Because they are assigned a logical time derived from the physical clock, their logical time can be interpreted as a measure of the time at which some external event occurred.
<CycleSVGtitle="Lingua Franca diagram: Cycle"role="img"width="400" />
30
32
31
33
The diagram highlights a **causality loop** in the program. At each tag, in reactor `B`, the first reaction has to execute before the second if it is enabled, a precedence indicated with the red dashed arrow. But the first can't execute until the reaction of `A` has executed, and that reaction cannot execute until the second reaction `B` has executed. There is no way to satisfy these requirements, so the tools refuse to generated code.
32
34
@@ -42,7 +44,9 @@ import TS_CycleWithDelay from '../assets/code/ts/src/CycleWithDelay.lf';
<CycleWithDelaySVGtitle="Lingua Franca diagram: CycleWithDelay"role="img"width="400" />
46
50
47
51
Here, we have used a delay of 0, which results in a delay of one [microstep](<../writing-reactors/Superdense Time.mdx>). We could equally well have specified a positive time value.
48
52
@@ -58,6 +62,8 @@ import TS_CycleReordered from '../assets/code/ts/src/CycleReordered.lf';
Copy file name to clipboardExpand all lines: docs/writing-reactors/Composing Reactors.mdx
+12-4
Original file line number
Diff line number
Diff line change
@@ -29,7 +29,9 @@ import TS_RegressionTest from '../assets/code/ts/src/RegressionTest.lf';
29
29
30
30
As soon as programs consist of more than one reactor, it becomes particularly useful to reference the diagrams that are automatically created and displayed by the Lingua Franca IDEs. The diagram for the above program is as follows:
31
31
32
-
<imgalt="Lingua Franca diagram"src="./../assets/images/diagrams/RegressionTest.svg"width="500"/>
<RegressionTestSVGtitle="Lingua Franca diagram: RegressionTest"role="img"width="500" />
33
35
34
36
In this diagram, the timer is represented by a clock-like icon, the reactions by chevron shapes, and the $shutdown$ event by a diamond. If there were a $startup$ event in this program, it would appear as a circle.
35
37
@@ -111,7 +113,9 @@ A destination port (on the right) can only be connected to a single source port
111
113
</ShowIf>
112
114
</ShowIfs>
113
115
114
-
<imgalt="Lingua Franca diagram"src="./../assets/images/diagrams/Multicast.svg"width="250"/>
<PhysicalConnectionSVGtitle="Lingua Franca diagram: PhysicalConnection"role="img"width="200" />
187
195
188
196
In such a connection, the logical time at the recipient is derived from the local physical clock rather than being equal to the logical time at the sender. The physical time will always exceed the logical time of the sender (unless fast is set to `true`), so this type of connection incurs a nondeterministic positive logical time delay. Physical connections are useful sometimes in [Distributed-Execution](<../writing-reactors/Distributed Execution.mdx>) in situations where the nondeterministic logical delay is tolerable. Such connections are more efficient because timestamps need not be transmitted and messages do not need to flow through through a centralized coordinator (if a centralized coordinator is being used).
<ExtendsSVGtitle="Lingua Franca diagram: Extends"role="img"width="350" />
27
29
28
30
Here, the base class `A` has a single output that it writes to in reaction to an input. The subclass inherits the input, the output, and the reaction of `A`, and adds its own input `b` and reaction. When an input event `a` arrives, both reactions will be invoked, but, once again, in a well-defined order. The reactions of the base class are invoked before those of the derived class. So in this case, `B` will overwrite the output produced by `A`.
<local_time_traceSVGtitle="Illustration of local time (trace): local_time_trace" />
139
143
140
144
Above is the execution trace of the first 4 seconds of this program.
141
145
Below the timeline is the currently active mode and above the timeline are the model elements that are executed at certain points in time, together with indicating triggering and their relation through time.
@@ -145,7 +149,9 @@ The timing diagram illustrates the different handling of time between history tr
145
149
Specifically, when mode `One` is re-entered via a history transition, at time 2000 msec, the action triggered by `T1` before, at time 850 msec, resumes.
146
150
In contrast, when mode `Two` is re-entered via a reset transition, at time 3000 msec, the action triggered by `T2` before, at time 1850 msec, gets discarded.
147
151
148
-
<imgalt="Illustration of local time (plot)"src="./../assets/images/modal_models/local_time_plot.svg"width="300"/>
<BankToBankMultiportSVGtitle="Lingua Franca diagram: BankToBankMultiport"role="img"width="300" />
156
160
157
161
If the `Source` and `Destination` reactors have multiport inputs and outputs, as in the examples above, then a warning will be issued if the total width on the left does not match the total width on the right. For example, the following is balanced:
158
162
@@ -224,7 +228,9 @@ import TS_ChildBank from '../assets/code/ts/src/ChildBank.lf';
<ChildBankSVGtitle="Lingua Franca diagram: ChildBank"role="img"width="150" />
228
234
229
235
In this program, the `Parent` reactor contains a bank of `Child` reactor instances
230
236
with a width of 2. In the main reactor, a bank of `Parent` reactors is
@@ -275,7 +281,9 @@ import TS_ChildParentBank2 from '../assets/code/ts/src/ChildParentBank2.lf';
275
281
276
282
<NoSelectorTargetCodeBlockc={C_ChildParentBank2}cpp={Cpp_ChildParentBank2}py={Py_ChildParentBank2}rs={"ChildParentBank2.lf missing for Rust"}ts={TS_ChildParentBank2}lf />
277
283
278
-
<imgalt="Lingua Franca diagram"src="./../assets/images/diagrams/ChildParentBank2.svg"width="250"/>
<MultiportToBankSVGtitle="Lingua Franca diagram: MultiportToBank"role="img"width="300" />
327
337
328
338
The three outputs from the `Source` instance `a` will be sent, respectively, to each of three instances of `Destination`, `b[0]`, `b[1]`, and `b[2]`. The result of the program will be something like the following:
329
339
@@ -376,7 +386,9 @@ import Py_Interleaved from '../assets/code/py/src/Interleaved.lf';
<InterleavedSVGtitle="Lingua Franca diagram: Interleaved"role="img"width="250" />
380
392
381
393
In the above program, four instance of `Node` are created, and, at startup, each instance sends 42 to its second (index 1) output channel. The result is that the second bank member (`bank_index` 1) will receive the number 42 on each input channel of its multiport input. Running this program gives something like the following:
382
394
@@ -395,11 +407,11 @@ In bank index 1, the 0-th channel receives from `bank_index` 0, the 1-th channel
395
407
396
408
This style of connection is accomplished using the new keyword $interleaved$ in the connection. Normally, a port reference such as `nodes.out` where `nodes` is a bank and `out` is a multiport, would list all the individual ports by first iterating over the banks and then, for each bank index, iterating over the ports. If we consider the tuple (b,p) to denote the index b within the bank and the index p within the multiport, then the following list is created: (0,0), (0,1), (0,2), (0,3), (1,0), (1,1), (1,2), (1,3), (2,0), (2,1), (2,2), (2,3), (3,0), (3,1), (3,2), (3,3). However, if we use $interleaved$`(nodes.out)` instead, the connection logic will iterate over the ports first and then the banks, creating the following list: (0,0), (1,0), (2,0), (3,0), (0,1), (1,1), (2,1), (3,1), (0,2), (1,2), (2,2), (3,2), (0,3), (1,3), (2,3), (3,3). By combining a normal port reference with a interleaved reference, we can construct a fully connected network. The figure below visualizes this how this pattern would look without banks or multiports:
397
409
398
-
<imgalt="Lingua Franca diagram"src="./../assets/images/diagrams/AddressableDesugared.png"width="600"/>
410
+

399
411
400
412
If we were to use a normal connection `nodes.out -> nodes.in;` instead of the $interleaved$ connection, then the following pattern would be created:
401
413
402
-
<imgalt="Lingua Franca diagram"src="./../assets/images/diagrams/AddressableNaiveDesugared.png"width="600"/>
414
+

403
415
404
416
Effectively, this connects each reactor instance to itself, which isn't very useful.
<SimultaneousSVGtitle="Lingua Franca diagram: Simultaneous"role="img"width="400" />
56
60
57
61
The `Destination` reactor has two inputs, `x` and `y`, and it reports in a reaction to either input what is the logical time, the microstep, and which input is present. The main reactor reacts to $startup$ by sending data to the `x` input of `Destination`. It then schedules a `repeat` action with an `<offset>` of zero. The `repeat` reaction is invoked **strictly later**, one **microstep** later. The output printed, therefore, will look like this:
0 commit comments