Cycles
The interconnection pattern for a collection of reactors can form a cycle, but some care is required. Consider the following example:
reactor A { input x:int; output y:int; reaction(x) -> y } reactor B { input x:int; output y:int; reaction(x) reaction(startup) -> y } main reactor { a = new A(); b = new B(); a.y -> b.x; b.y -> a.x; }
reactor A { input x:int; output y:int; reaction(x) -> y } reactor B { input x:int; output y:int; reaction(x) reaction(startup) -> y } main reactor { a = new A(); b = new B(); a.y -> b.x; b.y -> a.x; }
reactor A { input x; output y; reaction(x) -> y } reactor B { input x; output y; reaction(x) reaction(startup) -> y } main reactor { a = new A(); b = new B(); a.y -> b.x; b.y -> a.x; }
reactor A { input x:number output y:number reaction(x) -> y } reactor B { input x:number output y:number reaction(x) reaction(startup) -> y } main reactor { a = new A() b = new B() a.y -> b.x b.y -> a.x }
reactor A { input x:u32; output y:u32; reaction(x) -> y } reactor B { input x:u32; output y:u32; reaction(x) reaction(startup) -> y } main reactor { a = new A(); b = new B(); a.y -> b.x; b.y -> a.x; }
This program yields the following diagram:
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.
Cycles with Delays
One way to break the causality loop and get an executable program is to introduce a logical delay into the loop, as shown below:
reactor A { input x:int; output y:int; reaction(x) -> y } reactor B { input x:int; output y:int; reaction(x) reaction(startup) -> y } main reactor { a = new A(); b = new B(); a.y -> b.x after 0; b.y -> a.x; }
reactor A { input x:int; output y:int; reaction(x) -> y } reactor B { input x:int; output y:int; reaction(x) reaction(startup) -> y } main reactor { a = new A(); b = new B(); a.y -> b.x after 0; b.y -> a.x; }
reactor A { input x; output y; reaction(x) -> y } reactor B { input x; output y; reaction(x) reaction(startup) -> y } main reactor { a = new A(); b = new B(); a.y -> b.x after 0; b.y -> a.x; }
reactor A { input x:number output y:number reaction(x) -> y } reactor B { input x:number output y:number reaction(x) reaction(startup) -> y } main reactor { a = new A() b = new B() a.y -> b.x after 0 b.y -> a.x }
reactor A { input x:u32; output y:u32; reaction(x) -> y } reactor B { input x:u32; output y:u32; reaction(x) reaction(startup) -> y } main reactor { a = new A(); b = new B(); a.y -> b.x after 0; b.y -> a.x; }
Here, we have used a delay of 0, which results in a delay of one microstep. We could equally well have specified a positive time value.
Reaction Order
Frequently, a program will have such cycles, but you don’t want a logical delay in the loop. To get a cycle without logical delays, the reactions need to be reordered, as shown below:
reactor A { input x:int; output y:int; reaction(x) -> y } reactor B { input x:int; output y:int; reaction(startup) -> y reaction(x) } main reactor { a = new A(); b = new B(); a.y -> b.x; b.y -> a.x; }
reactor A { input x:int; output y:int; reaction(x) -> y } reactor B { input x:int; output y:int; reaction(startup) -> y reaction(x) } main reactor { a = new A(); b = new B(); a.y -> b.x; b.y -> a.x; }
reactor A { input x; output y; reaction(x) -> y } reactor B { input x; output y; reaction(startup) -> y reaction(x) } main reactor { a = new A(); b = new B(); a.y -> b.x; b.y -> a.x; }
reactor A { input x:number output y:number reaction(x) -> y } reactor B { input x:number output y:number reaction(startup) -> y reaction(x) } main reactor { a = new A() b = new B() a.y -> b.x b.y -> a.x }
reactor A { input x:u32; output y:u32; reaction(x) -> y } reactor B { input x:u32; output y:u32; reaction(startup) -> y reaction(x) } main reactor { a = new A(); b = new B(); a.y -> b.x; b.y -> a.x; }
There is no longer any causality loop.