Part I Background
5.5 Control tools: working on transitions
5.5.1 Synchronized processes
Sometimes may be crucial that a specific reaction (or a set of reactions) should be ex- ecuted as soon as possible. This may be due to some biological knowledge stating, for instance, that a reaction is catalyzed by a very strong enzyme and therefore should take place as soon as all the needed metabolites are present. Since we have no direct con- trol on the choice of the next transition that the model checker will explore, we decided to partially circumvent this problem coupling the execution of the main process with another one running synchronously with it. This “control” process will direct the execu- tion of the non–deterministic one, checking at each step if the reaction of interest may
take place. If this is the case, the reaction is performed, and after the control returns to the main process where one of the possible other reactions is non-deterministically chosen. This strategy is implemented using synchronization channels, i.e. a handshaking communication between the two processes. The reaction of interest is contained in the control process, and is executed only if all the metabolites are available. At each step the control process will try to execute the reaction, and after it will return the control to the main process. The details of the implementation are given in the Promela code
/* THE METABOLITE VARIABLES */ byte GC = 2; byte GO = 2; byte AL= 2; byte GL=2; byte PY=2; byte OX=2;
/* CHANNELS AND MSG FOR THE SYNCHRONIZATION PART*/
chan R_goes_chan[2] = [0] of mtype; // An array of two channels. chan S_goes_chan = [0] of mtype; // A channel
mtype token; // the token passed on the channels. /* THE REACTION PROCESS */
proctype R_process() { do
/* INTERNAL REACTION N. 1: GC → GO */
:: atomic{ R_goes_chan[((GC > 0) -> 1 : 0)]?token → GC=GC-1; GO=GO+1; S_goes_chan!token} /* INTERNAL REACTION N. 3: GL → GO */
:: atomic{ R_goes_chan[((GL > 0) -> 1 : 0)]?token → GL=GL-1; GO=GO+1; S_goes_chan!token} /* INTERNAL REACTION N. 4: GO → OX */
:: atomic{ R_goes_chan[((GO > 0) -> 1 : 0)]?token → GO=GO-1; OX=OX+1; S_goes_chan!token} od
}
/* THE CONTROL PROCESS */ proctype S_process(){
atomic{ do
::S_goes_chan?token; if
/* INTERNAL REACTION N. 2: GO + AL → GL + PY */
:: ((GO > 0) && (AL > 0)) → GO=GO-1; AL=AL-1; GL=GL+1; PY=PY+1 :: else;
fi;
// THE CONTROL IS PASSED BACK TO THE REACTION PROCESS R_goes_chan[1]!token;
od } }
/*ANTI-DEADLOCK PROCESS, ACTIVATES S_PROC*/ proctype Once_process(){
S_goes_chan!token; }
/* START THE PROCESSES */ init{
atomic{
run Once_process(); // runs first the Once_process to avoid deadlock run S_process();
run R_process(); }
}
Promela code snippet 8:
snippet 8. Three process are now present: the principal one, called “R process”, contain- ing all the reactions that should be non-deterministically chosen; the control one, called “S process”, containing only the reaction of interest; and the “Once process” containing the first activation of the channel. This last process is essential to avoid an initial dead- lock state. In fact, the principal and control processes may communicate only through a synchronous handshake: this means that one process should be sending and the other one
5.5 Control tools: working on transitions 61 receiving, or vice-versa. However, in the first state they are both in a receiving state. The Once process passes the token to the control process, and then terminates. The control process contains the reaction of interest, that is executed if all the needed metabolites are present. After, the control is passed to the main process. As before, this process contains a do statement, expressing the non-deterministic choice between the contained reactions. However, it may happens that the selected instruction is not executable due to the lack of some metabolites. To avoid deadlocks, the receiving instruction may be executed only if all the metabolites are available: in fact, only in in this case the logical expression in the receiving clause will evaluate to one, thus matching the channel array id of the send. In all other cases it will evaluate to zero: this index corresponds to a dummy channel expressly built to deflect handshake attempts that should fail.
Of course, this approach may be used together with the verification/filtering tech- niques described in section 5.4. However, the property instructions must be placed with some care: to be sure of their executability they should be placed before a synchronization point (i.e. before a write instruction). Hence, the best place for an assert clause is in the S process, right before it passes back the control to the main process: this guarantee that it is evaluated at each cycle of execution. The flags for the monotonicity check should be placed as usual in the atomic clause surrounding the reaction of interest, but before the token passing, that should be the last instruction. Instead, a timeout clause may be safely placed as before at the end of the do cycle in the main process: if no reaction is executable when the control passes back to the main process, then the system is in a deadlock state that will trigger the timeout.
This strategy can be used both to simply constrain the execution space, filtering out the more meaningful behaviours, both to perturb the model. For instance it can be used to simulate the expression, suppression or over-expression of a gene involved in the production of an enzyme, that in turn controls presence, absence or over-usage of a reaction, as briefly described in the following sections.
Switching Reactions on/off
The handshaking strategy above described may be used to specify a reaction that should always take place in a normal model (usually called Wild Type model). Hence, the pres- ence of the control process assures that the reaction is performed each time the needed metabolites are available, thus simulating the preference of the Wild Type (WT) model for the executions in which the reaction of interest works well. A simple change in the code of the Snippet 8 makes it possible to switch off a reaction: it suffices to put a skip instruction in place of the reaction execution to simulate a diseased model (called also Loss of Function or Knock-Out model).
Multiple Execution of a Reaction (Gene Overexpression)
Another biological feature that may be simulated using the handshaking approach above described is the over–usage of a reaction. This can be obtained altering the ”speed of the execution“: normally a reaction takes place only once in a single ”time unit“ (i.e. an execution step). Instead, to represent over-expression, a reaction is performed as many times as possible in a single time unit, and this process is limited only by the availability of the right amounts of the needed metabolites. This is obtained simply substituting a do cycle to the if block in the controller process, as shown in the Promela code snippet 9. With this construct, the essential behaviour of an enzyme over-expression is modeled: the correspondent reaction takes place more rapidly than in a normal system, provided that the needed metabolites are present.
/* THE CONTROL PROCESS */ proctype S_process(){ atomic{ do ::S_goes_chan?token; do /* OVEREXPRESSION OF REACTION N. 2: GO + AL → GL + PY */ :: ((GO > 0) && (AL > 0)) → GO=GO-1; AL=AL-1; GL=GL+1; PY=PY+1 :: else-> break;
od;
// THE CONTROL IS PASSED BACK TO THE REACTION PROCESS R_goes_chan[1]!token;
od } }
Promela code snippet 9:This code fragment shows how the control process is changed to implement the multiple execution of a reaction. All other parts remained unchanged (see Promela code snippet 8)