Skip to content

Conditional Iteration

Scott Johnston edited this page May 2, 2018 · 30 revisions

This is a conditional iterator that counts down to zero before starting over:

func main() {

        flowgraph.TraceLevel = flowgraph.V

        e,n := flowgraph.MakeGraph(7,5)

        e[3].Const(1)
        e[5].Val = 0

        n[0] = tbi(e[0])
        n[1] = flowgraph.FuncRdy(e[0], e[5], e[1])
        n[2] = flowgraph.FuncEither(e[1], e[6], e[2])
        n[3] = flowgraph.FuncSub(e[2], e[3], e[4])
        n[4] = flowgraph.FuncSteerc(e[4], e[5], e[6])

        flowgraph.RunAll(n, time.Second)

}

FuncRdy waits for two values before passing on the first. FuncEither expects a single value at a time, and does nothing to preserve the second if it shows up at the same time as the first. FuncArbit would be the choice if two values can arrive at the same time.

FuncSteerc is a simpler version of FuncSteerv. Instead of steering a second value to one of two destinations, it steers the condition itself.

In this case there is only an input test bench (tbi). It produces random numbers from 1 to 16. It waits until an ack is received from downstream before generating the next random number:

func tbi(x flowgraph.Edge) flowgraph.Node {
        node := flowgraph.MakeNode(
                "tbi", 
                nil, []*flowgraph.Edge{&x}, // src and dst Edge's
                nil,                        // NodeRdy func
                func(n *flowgraph.Node) {   // NodeFire func
                        n.Dsts[0].DstPut(rand.Intn(15)+1) })
	return node
}

When run and grep'ed for either, the countdown is evident as the conditional iterator alternates between receiving a new countdown value (via the e1 Edge) to decrementing that value as it circulates (via the e6 Edge):

either(2:0) e1=7,e6=_;e2=7
either(2:1) e1=_,e6=6;e2=6
either(2:2) e1=_,e6=5;e2=5
either(2:3) e1=_,e6=4;e2=4
either(2:4) e1=_,e6=3;e2=3
either(2:5) e1=_,e6=2;e2=2
either(2:6) e1=_,e6=1;e2=1
either(2:7) e1=3,e6=_;e2=3
either(2:8) e1=_,e6=2;e2=2
either(2:9) e1=_,e6=1;e2=1
either(2:10) e1=2,e6=_;e2=2
either(2:11) e1=_,e6=1;e2=1
either(2:12) e1=1,e6=_;e2=1
either(2:13) e1=7,e6=_;e2=7
either(2:14) e1=_,e6=6:e2=6
either(2:15) e1=_,e6=5;e2=5
either(2:16) e1=_,e6=4;e2=4
either(2:17) e1=_,e6=3;e2=3
either(2:18) e1=_,e6=2;e2=2
either(2:19) e1=_,e6=1;e2=1
either(2:20) e1=5,e6=_;e2=5
...

The above example is as simple as it gets for conditional iterators, with only one circulating value. Things get interesting when two or more values are circulating in a conditionally iterating ring, because it becomes necessary to guarantee that one value does not lap any others. This requires a point (or line) of synchronization in the flowgraph where all values from one iteration have to traverse this point before any value from the next iteration can traverse it. GCD (greatest common denominator) is a conditional iterator with two values, M and N, that circulate until the result of a modulo operator is zero:

In GCD the mod Node provides this synchronization, requiring both M and N values to arrive before computing the termination condition (when mod returns zero).

For the full example see the tbgcd Makefile target in http://github.com/vectaport/flowgraph_test.

Clone this wiki locally