Expertsystemen

 

Calling graphs — with or without iteration

To call a graph, you use a call graph icon call graph action (Actions > Call Graph (desktop) or Add a rule > Call Graph (web)).

A graph can be called with or without an explicit iteration number. Without is the default.

iteration toggle
iteration toggle

It is important to understand how these different ways of calling a graph impact the model’s behaviour.

Call without explicit iteration

Calling a graph without an explicit iteration implicitly creates new graph iterations each time it is called.

Node A calling some_graph without an iteration will create the graph with an iteration of ‘last iteration + 1’, plus it also tracks that it is called from A.

Calling some_graph from B will yield another graph iteration.

Example without explicit iteration

See the linked model callgraphsdemo.mdl to follow this example.

In the figure below, the graph ginfo is called three times, each time without an explicit iteration, in the following three nodes:

  • twice in node callnexts and once in EITHER
  • node left OR
  • node right

The node decision, which you’ll also see, asks the user whether they want to go to the ‘left’ or ‘right’ side.

The first time, in node callnexts, a graph ginfo with iteration 0 is created and executed.

The second time, still in node callnexts, the decision engine will see the first iteration and create a new graph: ginfo with iteration 1.

The third time (either in node left or right), the decision engine will see the first two iterations and, again, create a new graph: ginfo, now with iteration 2.

Multiple implicit calls to the same graph
Multiple implicit calls to the same graph

If you walk to the right node, the graph iterations will look like this:

ginfo[0]  (called from callnexts)
ginfo[1]  (second time from callnexts)
ginfo[2]  (called from right)

If you insert a value in the ginfo graph called from the right (e.g., ‘hello’), and go back to choose left, the value will be empty. However, if you insert a value, go back, and choose right, the original value ‘hello’ will show.

So the decision engine does not only look at the iterations; it also checks where the graph is called from. So internally, if you go back from the right node to the left, the list will be like this:

ginfo[0]  (called from callnexts)
ginfo[1]  (second time from callnexts)
ginfo[2]  (called from left)
hidden ginfo[3]  (called from right)

If you go back to the choice, the list will be like:

ginfo[0]  (called from callnexts)
ginfo[1]  (second time from callnexts)
hidden ginfo[2]  (called from left)
hidden ginfo[3]  (called from right)

If you choose right, the decision engine will ignore iteration 2, see that iteration 3 is the one we want, and change the order:

ginfo[0]  (called from callnexts)
ginfo[1]  (second time from callnexts)
ginfo[2]  (called from right)
hidden ginfo[3]  (called from left)

Call with Iteration

The call using an iteration is always clear: a call to graph X iteration 1 is always graph X, iteration 1. If you change your model, calling graph X from node A instead of B will still result in graph X, iteration 1.

If you call graph X with iteration 1 two or more times consecutively, each call after the first will be skipped. You can observe this in the calltoiteration4 node in the example model:

Multiple calls with an explicit iteration
Multiple calls with an explicit iteration

In the model, we now go to node decisionwithcalls. Again, we choose left or right, but in the nodes that follow (leftcall and rightcall), both of them call ginfo explicitly with an iteration: 4. If you go right, give the value ‘sunshine’, and go back to choose left, the value ‘sunshine’ will already be there.

Calling with the iteration forces the decision engine to take that exact iteration. If we continue to node calltoiteration4, you can see a call to that iteration 4 yet again. However, if you play the model, you will find that the graph is not executed because it has already been executed.

Source code

In the source, using an explicit iteration translates to call <graphname>[<iteration>].

The way without an explicit iteration translates to callnext <graphname> , as it is the ‘next’ iteration that gets called.

Quotes

Quotes ( ^{graphname.nodename.data} ) on screen or in text fragments are very powerful. But it can be confusing or prone to errors when calling graphs without explicit iteration.

A quote can be hard-coded to the iteration of the graph using ^{graphname[#].nodename.data} where # is the iteration. Most of the time the iteration is implicit, as in: ^{graphname.nodename.data}. Now the decision engine has to figure it out, and it does so like this:

Say graph main calls Z[0]. Graph main also calls X[1], which in turn calls Y[2]. And we want to quote from within graph Y.

Let’s quote Y.node.data. The decision engine will see that we are on Y, iteration 2, so it will get the data of iteration 2: Y[2].node.data.

Let’s quote X.node.data. The decision engine will see that the quote is not from Y, and will follow all the calling graphs (up until graph main). It sees Y being called by X. And it will take iteration 1, because X[1] was the iteration being executed. So X.node.data will resolve to X[1].node.data.

Let’s quote Z.node.data. Quoting outside the graph chain is tricky. The decision engine will see that Z has nothing to do with Y or the calling graphs. In other words, it is not present in the call chain.

It will look at the same iteration as the current iteration of Y, which is 2, and start looking for Z[2]. It fails, because there is no Z[2]. It will fall back to Z[0], which does exist. Thus resolving to Z[0].node.data.

But if we had the same situation as in the example model, it is quite possible that there are ‘hidden’ graphs, called from nodes which are not in the path anymore, or from a case where in the first version the graph was called from A, but now from B. In this case, there is a Z[2], but it is hidden. Now the decision engine will not fall back to 0, but will see iteration 2, see it is hidden, and return ‘’.

So if you are quoting outside the graph, not from the calling graphs, be aware of the hidden graphs. In this case, use a Z[0].node.data to make sure you are quoting the right graph.