Case conditions are not exhaustive? - model-checking

I am writing two modules in NuSMV but I am receiving the error, "Case conditions are not exhaustive" This error points to the last case statement I have in the code. I am not sure how to fix this because the cases that I currently have there are the only cases that the variable requires. The first module "train" is instantiated twice so that two trains can be on one track. The module "controller" acts as a controller which receives input from the two trains and prevents them both from being on a bridge at the same time.
Here is the code:
MODULE main
VAR
trainE : Train(controller1.signalE);
trainW : Train(controller1.signalW);
controller1 : controller(trainE.out, trainW.out);
INVARSPEC(!(trainE.mode = bridge & trainW.mode = bridge))
MODULE Train(signal)
VAR
mode: {away, wait, bridge};
out: {None, arrive, leave};
ASSIGN
init(mode) := away;
init(out) := None;
--Task A1
next(out) := case
mode = away: arrive;
mode = bridge: leave;
TRUE: None;
esac;
--Task A2
next(mode) := case
mode = away & next(out) = arrive: wait;
mode = bridge & next(out) = leave: away;
mode = wait & signal = green: bridge;
TRUE: mode;
esac;
MODULE controller(outE, outW)
VAR
signalE: {green, red};
signalW: {green, red};
west: {green, red};
east: {green, red};
nearE: boolean;
nearW: boolean;
ASSIGN
init(west):= red;
init(east):= red;
init(nearW):= FALSE;
init(nearE):= FALSE;
--Task A1
next(signalW):= west;
--Task A2
next(signalE):= east;
--Task A3
next(nearE):= case
outE = arrive: TRUE;
outE = leave: FALSE;
esac;
next(nearW):= case
outW = arrive: TRUE;
outW = leave: FALSE;
esac;
next(east):= case
next(nearE) = FALSE: red;
west = red: green;
esac;
next(west):= case
next(nearW) = FALSE: red;
east = red: green;
esac;

You actually have the same error in all case conditions:
file test.smv: line 68: case conditions are not exhaustive
file test.smv: line 64: case conditions are not exhaustive
file test.smv: line 60: case conditions are not exhaustive
file test.smv: line 56: case conditions are not exhaustive
Let's consider the error at line 56. You wrote the following cases:
next(nearE) := case
outE = arrive : TRUE;
outE = leave : FALSE;
esac;
Now, outE is an input connected to trainE.out. Inside module Train, out is declared as a variable that can have 3 possible values: {None, arrive, leave}. However, in your code, you specify the future value of nearE only for two possible current values of outE. Therefore, NuSMV rightfully complains because it doesn't know what value should be assigned to nearE in the next state when in the current state outE is equal to None.
Thus, in order to fix this error, you should think what you would like to happen when outE = None and add that specification to your model.
In the case in which you don't want the value of nearE to change, a common design practice is to add a catch all case condition as follows:
next(nearE) := case
outE = arrive : TRUE;
outE = leave : FALSE;
TRUE : nearE;
esac;

Related

NuSMV: Initialising range constant with parameter

I'm new to NuSMV. I'm trying to define a module, where each state has a duration variable than can range from 0 to the specified bound.
MODULE state(inc, bound)
VAR
duration : 0..bound;
ASSIGN
init(duration) := 0;
next(duration) := inc ? (duration + 1) mod (bound+1) : duration ;
DEFINE limit := duration = bound;
However, this yields the syntax error: A variable is expected in left-hand-side of assignment: init(duration) := 0. I'm able to fix this by declaring duration to duration : 0..1+bound.
In my main module, I wish to calculate the total_duration (or actually calculate all possible combinations of state's duration and make sure that no combination exceeds e.i. 3 as in the SPEC) of running my model and make sure that variable does not succeed a specific limit.
Here's my main module:
MODULE main
VAR
s0 : state(TRUE, 0);
s1 : state(s0.limit, 0);
s2 : state(s1.limit, 3);
state : {s0, s1, s2};
DEFINE
max_duration := s0.bound + s1.bound + s2.bound;
VAR
total_duration : 0..max_duration;
ASSIGN
init(state) := s0;
next(state) :=
case
state = s0 : s1;
state = s1 : s2;
state = s2 : s2;
esac;
total_duration := s0.duration + s1.duration + s2.duration;
SPEC
AG (state = s2 -> AF total_duration <= 3);
My problem is: When I run the model, NuSMV keeps adding to the total_duration variable and thus fails with the message "line 39: cannot assign value 5 to variable total_duration". This is due to the declaration of duration : 0..1+bound, because, in the particular example of
s0.duration = 0, s1.duration = 0 and s2.duration = 3, it will try to add 1 + 1 + 4 to total_duration, as that is the state's bound + 1.
However, if I check the trace there's no point where total_duration exceed 3. I have checked the followed specs:
-- specification AG total_duration < 4 is true
-- specification F total_duration = 4 is false
-- specification EF total_duration >= 4 is false
How can I fix this? Either by declaring duration in another way or changing anything else?
The software does something very simple. It takes the domain of each addend, and checks whether the result variable would be able to hold the result of every possible combination of value. In this case:
the domain of s0.duration is 0..1
the domain of s1.duration is 0..1
the domain of s2.duration is 0..4
so, in principle, the maximum total_duration could be 6 and its domain should thus be 0..6. Therefore:
DEFINE
max_duration := s0.bound + s1.bound + s2.bound + 3
You may want to run NuSMV with the following option:
-keep_single_value_vars
Does not convert variables that have only one
single possible value into constant DEFINEs
In this way, you'll be able to run the model without having to add +1 to the domain of bound.

Vending Machine in NuSMV

I am new to NuSMV, I am trying to create Vending Machine implementation from Kripke structure, I have three boolean (coin, selection, brewing) as well as three states.However, When I compile the code I receive "Line 25: at token ":": syntax error" If anyone sees any errors in my code I would appreciate the help.
Kripke structure
my attempt to write the code is as follow:
MODULE main
VAR
location : {s1,s2,s3};
coin : boolean;
selection: boolean;
brweing: boolean;
ASSIGN
init(location) := s1;
init(coin) := FALSE;
init(selection) := FALSE;
init(brweing) := FALSE;
next(location) :=
case
location = s1 : s2;
TRUE: coin;
esac;
next(location) :=
case
location = (s2 : s3 & (TRUE: selection));
location = (s2 : s1 & (FALSE: selection) & (FALSE: coin));
esac;
next(location) :=
case
location = (s3 : s3 & (TRUE: brewing));
location = (s3 : s1 & (FALSE: selection) & (FALSE: coin) & (FALSE: brewing));
esac;
-- specification
• AG [s ⇒ b] whenever a selection is made coffee is brewed for sure.
• E [(¬s) U (b)] the coffee will not be brewed as no selection were made.
• EF[b] there is a state where coffee is brewed.
The line (among others)
location = (s2 : s3 & (TRUE: selection));
doesn't make much sense. You need only one next statement to assign the next location from all possible values of location. Also, you don't need to declare coin, selection, and brewing as variables. Use DEFINE to define their values based on location:
MODULE main
VAR
location : {s1,s2,s3};
ASSIGN
init(location) := s1;
next(location) :=
case
location = s1 : s2;
location = s2 : {s1,s3};
location = s3 : {s1,s3};
esac;
DEFINE
coin := location = s2 | location = s3;
-- similarly for selection and brewing
What I understand from the model is that coin, selection and brew are not only labels but events that trigger the transition. If so, I would write the model like this:
MODULE main
VAR
location: {s1, s2, s3};
coin: boolean;
selection: boolean;
brew: boolean;
abort: boolean;
INIT
!coin & !selection & !brew;
ASSIGN
init(location) := s1;
next(location) := case
location = s1 & next(coin) : s2;
location = s2 & next(selection) : s3;
location = s2 & next(abort) : s1;
location = s3 : {s1, s3};
TRUE : location;
esac;
next(brew) := (next(location) = s3);
next(coin) := case
next(state) = s1 : FALSE;
state = s1 : {TRUE, FALSE};
TRUE : coin;
esac;
next(selection) := case
state = s2 : {TRUE, FALSE};
next(state) = s1 : FALSE;
esac;

Ada case statement with strings

I'm trying to use a string in a case statement, however it is giving me expected a discrete type. Found type Standard.String I understand that strings are not discrete. I'm wondering if there is a work around or not. Here is my code:
function Is_Valid_Direction(Direction_To_Go : in String) return Integer is
Room : Integer := 0;
begin
--if (Direction_To_Go = "NORTH" or Direction_To_Go = "N") then
-- Room := Building(currentRoom).exits(NORTH);
--elsif (Direction_To_Go = "SOUTH" or Direction_To_Go = "S") then
-- Room := Building(currentRoom).exits(SOUTH);
--elsif (Direction_To_Go = "EAST" or Direction_To_Go = "E") then
-- Room := Building(currentRoom).exits(EAST);
--elsif (Direction_To_Go = "WEST" or Direction_To_Go = "W") then
-- Room := Building(currentRoom).exits(WEST);
--elsif (Direction_To_Go = "UP" or Direction_To_Go = "U") then
-- Room := Building(currentRoom).exits(UP);
--elsif (Direction_To_Go = "DOWN" or Direction_To_Go = "D") then
-- Room := Building(currentRoom).exits(DOWN);
--end if;
case Direction_To_Go is
when "NORTH" | "N" => Room := Building(currentRoom).exits(NORTH);
when "SOUTH" | "S" => Room := Building(currentRoom).exits(SOUTH);
when "EAST" | "E" => Room := Building(currentRoom).exits(EAST);
when "WEST" | "W" => Room := Building(currentRoom).exits(WEST);
when "UP" | "U" => Room := Building(currentRoom).exits(UP);
when "DOWN" | "D" => Room := Building(currentRoom).exits(DOWN);
when others => Room := 0;
end case;
return Room;
end Is_Valid_Direction;
The commented section is doing exactly what I want, but with if statements. I'm just trying to see if it's possible with a case statement.
You could map your strings to a discrete type. The easiest being an enumerated type:
procedure Light (Colour : in String) is
type Colours is (Red, Green, Blue);
begin
case Colours'Value (Colour) is -- ' <- magic ;-)
when Red =>
Switch_Red_LED;
when Green =>
Switch_Green_LED;
when Blue =>
Switch_Blue_LED;
end case;
exception
when Constraint_Error =>
raise Constraint_Error with "There is no " & Colour & " LED.";
end Light;
I frequently use an actual map to do this kind of mapping, as it gives you more flexibility than enumerations. Your "names" don't have to conform to enumeration syntax, and you can easily provide variations that all map to a single value.
For the desired function definition, as provided in a package:
package Case_Map is
function Is_Valid_Direction(Direction_To_Go : in String) return Integer;
end Case_Map;
This (non-compiling due to missing game-specific declarations) implementation uses a mapping of strings to an enum that is in turn the case expression:
with Ada.Characters.Handling;
with Ada.Containers.Indefinite_Ordered_Maps;
package body Case_Map is
use Ada.Characters.Handling;
type Directions is (Go_North, Go_South, Go_East, Go_West, Go_Up, Go_Down);
package Direction_Management is new Ada.Containers.Indefinite_Ordered_Maps
(String, Directions);
Direction_Map : Direction_Management.Map;
function Is_Valid_Direction(Direction_To_Go : in String) return Integer is
Room : Integer := 0;
begin
case Direction_Map(To_Upper(Direction_To_Go)) is
when Go_North => Room := Building(CurrentRoom).Exits(NORTH);
when Go_South => Room := Building(CurrentRoom).Exits(SOUTH);
when Go_East => Room := Building(CurrentRoom).Exits(EAST);
when Go_West => Room := Building(CurrentRoom).Exits(WEST);
when Go_Up => Room := Building(CurrentRoom).Exits(UP);
when Go_Down => Room := Building(CurrentRoom).Exits(DOWN);
end case;
return Room;
exception
when Constraint_Error =>
return 0;
end Is_Valid_Direction;
begin
Direction_Map.Insert("NORTH", Go_North);
Direction_Map.Insert("N", Go_North);
Direction_Map.Insert("SOUTH", Go_South);
Direction_Map.Insert("S", Go_South);
Direction_Map.Insert("EAST", Go_East);
Direction_Map.Insert("E", Go_East);
Direction_Map.Insert("WEST", Go_West);
Direction_Map.Insert("W", Go_West);
Direction_Map.Insert("UP", Go_Up);
Direction_Map.Insert("U", Go_Up);
Direction_Map.Insert("DOWN", Go_Down);
Direction_Map.Insert("D", Go_Down);
end Case_Map;
The GNAT compiler itself uses a hash table that maps strings (identifiers, keywords,...) to integer. This is the package namet.ads, and GNATCOLL.Symbolic provides a similar API. This simplifies a number of things (string comparison for instance is much faster), and allow the use of case statements as in your example. So if you are using a limited (or at least slow-growing) list of strings, GNATCOLL.Symbolic might be a suitable approach

swift case falling through

Does swift have fall through statement? e.g if I do the following
var testVar = "hello"
var result = 0
switch(testVal)
{
case "one":
result = 1
case "two":
result = 1
default:
result = 3
}
is it possible to have the same code executed for case "one" and case "two"?
Yes. You can do so as follows:
var testVal = "hello"
var result = 0
switch testVal {
case "one", "two":
result = 1
default:
result = 3
}
Alternatively, you can use the fallthrough keyword:
var testVal = "hello"
var result = 0
switch testVal {
case "one":
fallthrough
case "two":
result = 1
default:
result = 3
}
var testVar = "hello"
switch(testVar) {
case "hello":
println("hello match number 1")
fallthrough
case "two":
println("two in not hello however the above fallthrough automatically always picks the case following whether there is a match or not! To me this is wrong")
default:
println("Default")
}
case "one", "two":
result = 1
There are no break statements, but cases are a lot more flexible.
Addendum: As Analog File points out, there actually are break statements in Swift. They're still available for use in loops, though unnecessary in switch statements, unless you need to fill an otherwise empty case, as empty cases are not allowed. For example: default: break.
Here is example for you easy to understand:
let value = 0
switch value
{
case 0:
print(0) // print 0
fallthrough
case 1:
print(1) // print 1
case 2:
print(2) // Doesn't print
default:
print("default")
}
Conclusion: Use fallthrough to execute next case (only one) when the previous one that have fallthrough is match or not.
The keyword fallthrough at the end of a case causes the fall-through behavior you're looking for, and multiple values can be checked in a single case.

Can I jump from one case to another in a switch statements?

For switch statements, is it possible to change the value of the switch inside the switch statement so that it can jump around to different cases?
Ex:
int w = 0;
switch(w)
{
case 1:
doSomething();
w = 3;
case 2:
doSomething();
break;
case 3:
doSomething();
break;
}
Basically what I'm asking is, if I do not place a break statement for a case and I change the value of the switch in the same case, will the code execute both cases?
Yes you can change the value inside switch but it will not execute case for new value until you break in the case where you changed the value.
In your case it will not go in any case as there is no case for 0. But if you change to w = 1 then it will go for case 1 and then for case 2 as you do not have break; but it will not go for case 3.
No, it will not change and will not execute new case statement.
Remember that, once appropriate match is found with the case statement corresponding to a value inside the switch statement, that particular case is executed and once that is executed ( if break is provided after each case to prevent falling through all cases) , then the control returns to the end of switch statement.
Sample Code :
public class A {
public static void main(String [] args) {
int i=1;
switch(i) {
case 1 :
System.out.println("Case 1");
i = 2;
break;
case 2 :
System.out.println("Changed to Case 2");
break;
default:
System.out.println("Default");
break;
}
System.out.println("Final value of i " + i);
}
}
Output :
Case 1
Final value of i 2
Note : Inserting proper breakpoints, try to debug. You will come to know yourself, what exactly is happening.
If we do not give break after each case then Java will start executing the statement from matching case and keep on executing statements for following cases as well, until either a break statement is found or switch statements end is encountered.
If case 1 happens to execute, it's just a fall through to the case 2. And since there is a break in case 2, further fall through doesn't happen. It doesn't jump to case 3 because of the statement w = 3 ; in case 1.
No the switch's case will not change when changing the value in a particular case it checks only once
let a = 1
switch (a) {
case 1:
console.log("Hello from 1")//only this will be printed
a = 2//value of a is changed
break
case 2:
console.log("hello from 2")//this will not execute
a = 3
break
case 3:
console.log("hello from 3")//this will not execute
a = 4
break
case 4:
console.log("hello from 4")//this will not execute
break
default:
console.log("default")
}
console.log(a)//value will be 2

Resources