================================================================= 22c:181 Formal Methods in Software Engineering, Spring 2012 Elevator II Solutions ================================================================= 1. node Requirements( Floor_1, Floor_2, Door_Closed, Call_1, Call_2, Stop : bool ) returns ( R1, R2, R3, R4, R5 : bool ); var Motor_Up, Motor_Down, Moving, Halts : bool; let (Motor_Up, Motor_Down) = Control(Floor_1, Floor_2, Door_Closed, Call_1, Call_2, Stop); -- Moving is true iff the elevator is moving now Moving = Motor_Up or Motor_Down; -- Halts is true iff the elevator has come to a stop Halts = not Moving and (false -> pre Moving); -- The elevator moves only when the door is closed and -- the Stop button is not pressed. R1 = Moving => (Door_Closed and not Stop); -- The elevator will not pass the end positions, that is, -- go through the roof or the floor. R2 = (Floor_1 => not Motor_Down) and (Floor_2 => not Motor_Up); -- A moving elevator halts only if -- the Stop button is pressed, or the door is opened, -- or the elevator has arrived at the destination floor. R3 = Halts => (Stop or not Door_Closed or ((true -> pre Motor_Down) and Floor_1) or ((true -> pre Motor_up) and Floor_2) ); -- The elevator halts before changing direction. R4 = true -> (Motor_Up => (not pre Motor_Down)) and (Motor_Down => (not pre Motor_Up)); -- The signals sent to the motor are not contradictory R5 = not (Motor_Up and Motor_Down); tel The implementation of the Control node in the posted solution of the Elevator does not satisfy Requirement R5. If the elevator is stopped in between floors and Call_1 and Call_2 are simultaneously true, both Motor_Up and Motor_Down will be true. One way to fix the problem is to give preference to one direction, down say, and modify the definition of Motor_Up accordingly. node Control( Floor_1, Floor_2, Door_Open, Call_1, Call_2, Stop : bool ) returns ( Motor_Up, Motor_Down : bool); var CanMove : bool; let CanMove = not Stop and not Door_Open ; Motor_Up = not Motor_Down and --- this restriction is new CanMove and not Floor_2 and ((false -> pre Motor_Up) or Call_2) and not (false -> pre Motor_Down); Motor_Down = CanMove and not Floor_1 and ((false -> pre Motor_Down) or Call_1) and not (false -> pre Motor_Up); tel The new restriction in the definition of Motor_Up guarantees that Motor_Up is false in all cases in which Motor_Down is true. When the elevator is stopped in between floors and Call_1 and Call_2 are simultaneously true, the elevator will now go down. 2. The original requirement was: If the elevator is at a floor, someone presses the Call button on the other floor, no one presses the Stop button at the same time, and the door is closed, then the elevator will move. This requirement is simply not satisfied by the system. Depending on your definition of Control, more things have to hold for the elevator to move. For the definition above: - The other call button must not be pressed at the same time - The call signal might be ignored if the elevator has arrived at the floor at this very moment (due to R4) With these additional assumptions the requirement is: R6 = (((Floor_1 and Call_2) or (Floor_2 and Call_1)) and not Stop and Door_Closed and not(Call_1 and Call_2) and not (false -> pre Moving) ) => (Motor_Up or Motor_Down); Unfortunately, this requirement is not satisfied either! A counter-example can be found by setting the initial values of Floor_1 and Floor_2 both to true. Since it is not in the controller's power to rule out that possibility (Floor_1 and Floor_2 are inputs), we must exclude it in the requirement itself, by adding as a precondition also that the elevator is not at both floors of the same time: R6 = (((Floor_1 and Call_2) or (Floor_2 and Call_1)) and not Stop and Door_Closed and not(Call_1 and Call_2) and not (false -> pre Moving) and not (Floor_1 and Floor_2) --- new precondition ) => (Motor_Up or Motor_Down);