Search code examples
modellogicmodel-checkingnusmv

How can i change psuedo-code to NuSMV code?


My professor decide to give us math student a code to change into NuSMV and i can't seem to find anywhere else for help and i read the textbook it like 6 pages only and only describe what certain property does. Module main is an example of NuSMV code and he said to use that format example to write the psuedo code. I don't know how to write the while loop and set what to be true? and would flag1 be a state and turn be also another state?

 while(true) do
  flag1 := true
    while flag2 do
     if turn=2
       flag1 := false;
       wait until turn = 1;
       flag1 := true
  Critical section
  turn := 2
  flag1 := false;

Solution

  • It looks like you're trying to model Dekker/Dijkstra's algorithm for mutual exclusion among two processes.

    The steps of your interest, based on your question, should only be 1-4. I added some more to provide a more complete picture of what can be achieved with NuSMV.

    I used a slightly different version of the same algorithm, though the underlying idea is the same.


    IDEA: there exists a methodology for converting pseudo-code into a NuSMV model:

    1. Label the entry and exit point of each statement in your code:

      --     void p(iflag, turn, id) {
      -- l0:   while(true) do
      -- l1:     flag := true
      -- l2:     while iflag do
      -- l3:       if turn != id
      -- l4:         flag := false;
      -- l5:         wait until turn = id;
      -- l6:         flag := true
      -- l7:     // Critical section
      -- l8:     turn := 1 - id
      -- l9:     flag := false;
      --     }
      

      Note that some statements, e.g. while iflag do, might have more than one exit point depending on the value of the guard: if iflag is true, then the exit point is l3, otherwise the exit point is l7.

    2. Create a corresponding module that takes the same inputs and has a state variable which evaluates to the newly introduced labels.

      MODULE p(iflag, turn, id)
      VAR
        state : { l0, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, error };
        flag : boolean;
      

      Here, notice that i added the special state error. This is only to ensure that during the definition the transition relation for state we are not leaving out any correct transition step. In general, it should be omitted as it does not belong to the original code.

    3. Define the transition relation for state:

      ASSIGN
        init(state) := l0;
        next(state) := case
          state = l0              : l1;
          state = l1              : l2;
          state = l2 & iflag      : l3;
          state = l2 & !iflag     : l7;
          state = l3 & turn != id : l4;
          state = l3 & turn = id  : l2;
          state = l4              : l5;
          state = l5 & turn != id : l5;
          state = l5 & turn = id  : l6;
          state = l6              : l2;
          state = l7              : l8;
          state = l8              : l9;
          state = l9              : l0;
          TRUE                    : error; -- if you match this then the above
                                           -- description of transitions are incomplete
        esac;
      

      As you can see, I simply connected every entry point with the corresponding exit point. Moreover, wherever more than one exit point is defined for a given entry point I also added other state conditions to determine what line is executed next.

    4. Add the transition relation for flag:

      init(flag) := FALSE;
      next(flag) := case
        state = l1 | state = l6 : TRUE;
        state = l4 | state = l9 : FALSE;
        TRUE                    : flag;
      esac;
      
    5. Add some definitions to identify which sections of code the process is executing:

      DEFINE
        critical_section := (state = l7);
        trying_section := (state = l1 | state = l2 | state = l3 |
                           state = l4 | state = l5 | state = l6);
      
    6. Create a main module which creates two instances of p:

      MODULE main ()
      VAR
        turn : {0, 1};
        p1   : p(p2.flag, turn, 0);
        p2   : p(p1.flag, turn, 1);
      
      ASSIGN
        init(turn) := 0;
        next(turn) := case
          p1.state = l8 : 1;
          p2.state = l8 : 0;
          TRUE          : turn;
        esac;
      
    7. Add some very typical mutual exclusion properties to be verified by the model checker:

        --*-- PROPERTIES --*--
      
      -- Safety: two processes are never in the critical section at the same time
      CTLSPEC AG !(p1.critical_section & p2.critical_section);
      
      -- Liveness: if a process is in the trying section, then sooner or later
      --           it will access the critical section.
      CTLSPEC AG (p1.trying_section -> AF p1.critical_section);
      
      -- Absence of Starvation
      CTLSPEC ! EF AG (p1.trying_section & p2.trying_section);
      
      -- Never in Error State 
      CTLSPEC AG !(p1.state = error);
      
    8. Run the tool

      ~$ NuSMV -int
      

      and check that all properties are verified:

      NuSMV > reset; read_model -i dekker.smv; go; check_property
      -- specification AG !(p1.critical_section & p2.critical_section)  is true
      -- specification AG (p1.trying_section -> AF p1.critical_section)  is true
      -- specification !(EF (AG (p1.trying_section & p2.trying_section)))  is true
      -- specification AG !(p1.state = error)  is true 
      

    NOTES:

    1. If you look closely at steps 1 and 3, several states look redundant. For instance, it is always possible to collapse contiguous states that have only one entry and exit points. I'll leave this to you as an exercise.

    2. Notice that I used the synchronous composition of modules for simplicity. In practice the verification would be more meaningful by letting the two processes to be run asynchronously. However, this would require making the model more complex than your question really required, and it is thus beyond the scope of my answer.

    3. If you would like to learn more about NuSMV, you can take a look at its documentation or look at the second part of this course.