# Arrays

Dans le document Symbolic model-checking with Set Rewriting (Page 100-107)

Thus, we decided to let the user choose how to implement non-linear rules. For ex-ample, the following pattern simulates the copy rule, presented earlier, for natural numbers:map(i, \$n, \$p){map(stackElt, \$n, map(i, \$n, \$p)):

doubleVar={suc(\$n1){doubleVar(0, 0, suc(\$n1)),

0{doubleVar(0, 0, 0)}

duplicateVar={ doubleVar(\$n1, \$n2, suc(\$n3)){

doubleVar(suc(\$n1), suc(\$n2), \$n3)} extractValue={ map(\$v, doubleVar(\$n1, \$n2, 0), \$s){

map(stackH, \$n1, map(\$v, \$n2, \$s))} copy= Sequence(

One2(Sequence(doubleVar,

Fixpoint(RewriteSet(duplicateVar))), extractValue)

This principle can be generalized for any sort, if one can define an inductive copy (rulesduplicateVar) of the values based on the generators (0,succ induplicateVar).

The strategyRewriteSet remembers the number rewritten by duplicateVar. It forces the strategy to also keep the terms that were not rewritten. This is one of the few cases where the strategies do not shield the user from the effects of dealing with sets. The pattern needs to be defined only once.

### 6.6 Arrays

We do not discuss the complete translation of arrays in this section but only the way they are implemented.

In our setting array operations have a special property that differentiates them from normal variables: the position of the data in the term is determined dynamically. Let us first introduce a data type for arrays based on the mappings that we already have in Table 6.4. Our new signature is shown in Table 6.5. We focus first only in the generators section of the table.

In Table6.5we introduce two new definitions. We declare a new sortarray, and we modified the definition ofmappingto handle both arrays and integers with two different operationsmapIntandmapArr. In Example6.6.1we present a state of a system using the signature.

Example 6.6.1 Let us consider a system with two variables, an integer variableiand an array variableaof size two. Its representation using the signature in Table6.5 is the followingmapInt(i, 0, mapArr(a, arr(0, arr(0, emptyArr)), emptyArr)) Now, we have seen that we can declare a strategy capable of putting the value of an integer variable on top of our stack. This can be done easily because we know the

82 Chapter 6. Semantics Using Set Rewriting Sorts: mapping,vname,int,guarded,bool,array

Generators: v1: vname

...

vn: vname empty: mapping

mapInt: vname, int, mapping 7→ mapping mapArr: vname, array, mapping 7→ mapping arr: int, array 7→ array

emptyArr: array

test: bool, mapping 7→ guarded

Operations: getArr: int, array 7→ array readVal: int, array 7→ array valIndex: int, nat 7→ int

Table6.5 – SOSrules forDivine

name of the variable when we define the strategy, and it allows us to find it in our term. In a similar way, we can declare a strategy to put one predefined element of an array in the stack. The problem is when we have statements like this: a[i]. Indeed, in such cases, our strategy has to figure out at runtime the position of the value a[i]. The problem becomes worse if we have an expression where the position in the array depends on a computation. Thus, the heart of the problem is that at the time of the definition of the strategy we know the name of the array but we do not know the position within it that we need to read or write.

To solve overcome this problem we define strategies that read or write array vari-ables and that take their position from the stack. It is clear that such a strategy would solve all of our problems. We already have operations to read variables and put them on top of the stack, and also to perform all kind of operations and put them on top of the stack. Thus, we can add the following operations to the basic operations defined in Section6.5.4.

:hst, ρi → hpush(ρ(a)[top(st)], ρ), ρi writeArra :Stack× M→ Stack× M

:hst, ρi → hpop(pop(st)), ρ[a[top(st)]=top(pop(st))], ρi

In the definition above, we useρ(a)[i] to note thei-th element of arraya. Now let us consider the strategies needed to implementreadArraandwriteArra. To implement these operations we use the declarations used in the operations section of Table 6.5.

The getArrandreadVal operations are used in two different contexts. The former is used to find the right position in the array, i.e., when we are searching for the right position where to apply the read or write operation, and the latter is used to extract the value from the array and make it go up in the same way that we did with the stack in thereadvoperation. To illustrate process of reading and writing an array we rely on a

6.6. Arrays 83 full example in Example6.6.2.

Example 6.6.2 Let us suppose that we have the following state:

mapInt(sE, 1, mapInt(i, 0, mapArr(a, arr(0, arr(5, emptyArr)), empty))) (6.4) The state represents the same state in Example6.6.1 with a stack that contains 1 on top. If we apply the readArraoperation to the state we obtain the following state:

mapInt(sE, 5, mapInt(i, 0, mapArr(a, arr(0, arr(5, emptyArr)), empty)))

This is, the value of the second element (or at index 1) of the array (5) becomes the element on top of the stack. To achieve this result we proceed step by step:

1. First we take the stack element to the position where it should be,i.e., next just before themapArrterm. To do this we do the downSwapGet strategy defined as follows:

downSwapGet= {

mapInt(sE ,\$i1, mapInt(\$v1, \$i2, \$s1)){

mapInt( \$v1, \$i2, mapInt(sE, \$i1, \$s1)),

mapInt (sE , \$i1, mapArr( \$v1, \$a1, \$s1)){

mapArr( \$v1, \$a1, mapInt(sE ,\$i1 ,\$s1))}

The downSwapGet strategy needs to be applied until the stack element is next to the array. To do this we use the downAndThen strategy. This strategy takes two parameters and proceeds as follows. It first tries to apply its second parameter and if it does not succeed it applies the second one followed by calling itself recursively on the third subterm. Its definition is as follows:

downAndThen(V1,V2)=Choice(V2,

Sequence(V1,One(downAndThen(V1,V2),3))) Using these two strategies we can take move the top of the stack to the term where it needs to be applied and the apply another strategy. Let us suppose that we apply the strategy downAndThen(downSwapGet,V2) to the initial term in (6.4). We would obtain the following:

mapInt(i, 0,V2[mapInt(sE, 1, mapArr(a, arr(0, arr(5, emptyArr)), empty)))] (6.5) V2 is not part of the term but represents the application of the V2strategy to subterm between the square brackets. Of course, V2 needs to be designed to fail when it is not applied to the right variable. Hence, we need to define the strategy that handles only the stack and the array at the first position. We show how to do that in step 2.

84 Chapter 6. Semantics Using Set Rewriting 2. In the second step we tackle another subproblem. This time, we want to create a strategy that will enter the array until the position given by the stack. Note that the strategy defined in this step is not V2but only the first part of it.

insertGet= {mapInt (sE, \$i1, mapArr(\$v ,\$a1 ,\$s1)){

mapArr(\$v, getArr(\$i1, \$a1), \$s1)}

Once we have the getArr operation in the array, we proceed to use the same trick that we used in step 1 for the stack. However, this time we decrement the

getArr each time we down swap it. The two strategies that we need are the following:

arrayDownAndThen(V1,V2)=Choice(V2, Sequence(V1,

One(arrayDownAndThen(V1,V2),2))) arrDown={getArr(suc(\$n1), arr(\$i1, \$a1)) {

arr(\$i1, getArr(\$n1, \$a1))}

Thus, when applying Sequence(insertGet,arrayDownAndThen(arrDown,V2)) to the term between the brackets in6.5we obtain:

mapArr(a, arr(0,V2[getArr(0, arr(5, emptyArr))]), empty) (6.6) Once again, V2needs to be designed to fail whengetArris not yet zero.

3. Once we are at the right position we proceed to copy the integer at the position and then we put it into thereadValterm. After doing this, the technique is exactly the same as the one used to read a variable,i.e.,we move the term up until it is

on top of the stack.

### 6.7 Summary

In this chapter we presented how to translate the semantics of formalisms to our strate-gies. It is clear that our approach is very expressive and allows to describe both simple formalisms asPNsand more complex, imperative ones likeDiViNE.

6.7. Summary 85

// peterson mutual exclusion protocol for N processes byte pos ;

byte step ;

process P_0 { byte j=0 , k =0;

state NCS , CS , wait ,q2 , q3 ; init NCS ;

trans

NCS -> wait { effect j = 1; },

wait -> q2 { guard j < 3; effect pos  = j;} , q2 -> q3 { effect step [j -1] = 0, k = 0; },

q3 -> q3 { guard k < 3 && (k == 0 || pos [k] < j ); effect k = k +1;} , q3 -> wait { guard pos [j -1] != 0 || k == 3; effect j = j +1;} ,

wait -> CS { guard j == 3; }, CS -> NCS { effect pos  = 0;};

}

process P_1 { byte j=0 , k =0;

state NCS , CS , wait ,q2 , q3 ; init NCS ;

trans

NCS -> wait { effect j = 1; },

wait -> q2 { guard j < 3; effect pos  = j;} , q2 -> q3 { effect step [j -1] = 1, k = 0; },

q3 -> q3 { guard k < 3 && (k == 1 || pos [k] < j ); effect k = k +1;} , q3 -> wait { guard pos [j -1] != 1 || k == 3; effect j = j +1;} ,

wait -> CS { guard j == 3; }, CS -> NCS { effect pos  = 0;};

}

process P_2 { byte j=0 , k =0;

state NCS , CS , wait ,q2 , q3 ; init NCS ;

trans

NCS -> wait { effect j = 1; },

wait -> q2 { guard j < 3; effect pos  = j;} , q2 -> q3 { effect step [j -1] = 2, k = 0; },

q3 -> q3 { guard k < 3 && (k == 2 || pos [k] < j ); effect k = k +1;} , q3 -> wait { guard pos [j -1] != 2 || k == 3; effect j = j +1;} ,

wait -> CS { guard j == 3; }, CS -> NCS { effect pos  = 0;};

}

system async ;

Figure6.5 – Peterson mutual exclusion algorithm inDiViNE

86 Chapter 6. Semantics Using Set Rewriting

## Chapter 7

### Model Checking Using Set Rewriting

In the previous chapter we presented a systematic approach to express the semantics of a system using strategies. However strategies allow to go further. One can use strategies to describe for example model checking algorithms.

In this chapter we illustrate how to use strategies for this purpose. Model checking being an extremely performance intensive task, we also provide some hints to optimize our semantics for this use.

### 7.1 Computing The State Space

One of the simplest model checking computations is computing the state space. How-ever its simplicity is only theoretical. Even for small systems it is extremely diffi -cult to compute the state space of a system, because of the State Space Explosion (SSE)[Val98] problem.

Given a system and a functionnext: P(Γ) → P(Γ) that gives the set of successor states of a set of states, we can define the set of states as the least fixpoint of this function. The state space is thus expressed in classicalµ-calculus[Par76] notation as follows.

StateSpace= µX.(Id(X)∪next(X))

We have already shown how to use our strategies to give semantics to transitions of transition system. The strategies obtained in the previous chapter allow to compute the functionnextbut only for one transition at a time. However we can use theUnion strategy to combine all the transition strategies into one strategy capable of computing thenextfunction. Thus, given the strategies that describe the transitions of a system tStrat1, tStrat2, . . . ,tStratn, we definenextStrat, which computes the functionnext, as follows:

nextStrat= Union(

Union(· · ·Union(Union(Try(tStrat1),Try(tStrat2)),tStrat3),· · ·), tStratn)

87

88 Chapter 7. Model Checking Using Set Rewriting The Trystrategy is defined as Try(S) = Choice(S,Identity). We use it because otherwise theUnionwill fail if one of the transitions cannot be executed in any of the provided states.

The next step is to compute the fixed point of the function Next. By Knaster-Tarsky’s theorem [Tar55,Kna28], we know that we can compute the least fixed point by starting from the initial state and applying repeatedly applying a continuous and monotone function. Our nextStrat strategy is not always monotonous, but we can make it so by joining it to the Identitystrategy. The strategy that computes the state space is given below:

StateSpaceStrat= Fixpoint(Union(Identity,nextStrat)) (7.1)

Dans le document Symbolic model-checking with Set Rewriting (Page 100-107)