Exercises



Exercise 1 (Solution)

This exercise has two parts:

A. Some basic exercises to remind you of propositional logic

Recall that a truth assignment for a propositional (or Boolean) formula F is an assignment of the values {true, false} to the variables of F.
An assignment satisfies, or is a model of, F if F evaluates to true under that assignment.
An assignment falsifies, or is a counter-model of, F if F evaluates to false under that assignment.
A propositional formula F is satisfiable if it has a model. It is unsatisfiable if has no models. It is valid if every assignment is a model of F.

Examples: Questions:
  1. List all the models of the propositional formula (a and (not b or not c)).

  2. List all the counter-models of the propositional formula (a and (not b or not c)).

  3. Given a formula of the form P => Q. Suppose we know that the formula is false, what do we then know about the subformulas P and Q?

  4. Suppose we know that the above formula is true, what do we then know about P and Q?

  5. Given variables a, b, and c, write a propositional formula, using only the connectives and, or and not, that is true precisely if exactly one of a, b, c is true.

  6. Reflect on what it means for a formula F
    • to be unsatisfiable
    • to be valid.
    Can one of the two notions be defined in terms of the other?

B. Some Lustre exercises

  1. Implement a node Sum, with one input stream X and one output stream S. At each instant, S contains the sum of all X's that the node has seen so far.

  2. Now implement SumReset, a version of Sum above with an additional Boolean input Reset that makes Sum start over from 0.

  3. Implement a node Average with one integer input X and one Boolean input Reset, and that outputs the average of the stream X since the last Reset.

  4. Define a Lustre node called HasHappened, with one Boolean input X and one Boolean output Y. Y should be true precisely when X has been true at least once since the first instant.
Simulate your nodes using Luke to see how they behave!


Exercise 2 (Solution)

Some exercises about synchronous observers:

  1. Define a temporal combinator MaxDistance3 that gets one Boolean input X, and checks that the distance between two instants in which X is true is no more than 3.

  2. Define a temporal combinator MaxDistance that gets one Boolean input X and one integer input N, and checks that the distance between two instants in which X is true is no more than N.

  3. Critize the description of the node MaxDistance above. Can you find ambiguous statements in the text? How would you try to be more precise?

  4. Does the expression "Sofar(X) and Sofar(Y)" behave the same as "Sofar(X and Y)"? And does the expression "Sofar(X) or Sofar(Y)" behave the same as "Sofar(X or Y)"? Justify your answer.

  5. There are two possibilities of interpreting Since(X,Y): Non-overlapping since (where Y has to happen after X has happened), and overlapping since (where Y also has to happen at the same time as X). Implement both versions, and make an observer that expresses exactly when they give the same answer.

  6. Define an observer Positive for the node Average from Exercise 1. It checks that if the input to the Average node is always positive, then the output should be positive too.

  7. Adapt the observer Positive above, so that it checks that if the input since the last time we reset the node has been positive, then the output is positive too.

  8. Write an observer that checks the following for a node F with integer output: Whenever F outputs a positive number x, its negation -x has occurred as an earlier output

Where appropriate, try to verify using Luke that your observers behave correctly.



Exercise 3 (Solution)

Acknowledgements: This exercise is inspired by a similar assignment first made by Prover Technology AB, then adapted for previous versions of a similar course at Chalmers University by Carl Johan Lillieroth, K.V.S. Prasad, Mary Sheeran, Angela Wallenburg, and Jan-Willem Roorda. The current version is our adaptation to the Luke tool, and focuses more on simulation than some of the previous versions.

The Elevator

Consider a simple elevator, moving people up and down between two floors. A picture of the situation is shown on the right.

In the elevator, there are three buttons: a First button for going to the first floor, one Second button for going to the second floor, and a Stop button to stop the elevator. On each floor, there is a Call button. Furthermore, each floor has a sensor, indicating if the elevator is on that floor or not. There is also a sensor in the elevator, checking if the door to the elevator is closed or not.

The elevator is moved up and down by a motor that is on the roof of the building. The motor is controlled by two signals, Motor_Up and Motor_Down.

The idea is that you will implement the control system for this elevator. The control system looks at the buttons that are being pressed and the sensors that say where the elevator is and if the door is open, and then decides if the motor should move the elevator up or down, or do nothing.

For simplicity, we do not distinguish between the case of someone on floor 2 pressing the Call button and someone in the elevator pressing the Second button. Similarly for the Call button on floor 1 and the First button in the elevator.

Safety Requirements

To understand better what the control system of the elevator is supposed to do, here is a list of safety requirements that any decent control system should satisfy.

R1 The elevator may only move when the door is closed and the Stop button is not pressed.
R2 The elevator may not pass the end positions, that is, go through the roof or the floor.
R3 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.
R4 The elevator must halt before changing direction.
R5 The signals sent to the motor may not be contradictory.

If, during your implementation, you are ever in doubt about any issue not mentioned in the list above, you can make a reasonable assumption yourself.

Problems

  1. Implement the control system as a Lustre node with (exactly!) the following interface:

      node Control( Floor_1, Floor_2, Door_Closed, Call_1, Call_2, Stop : bool )
      returns ( Motor_Up, Motor_Down : bool );
    
    The Boolean streams Floor_1 and Floor_2 represent the output of the floor sensors. The stream Door_Closed is the output of the door sensor. The value of stream Call_1 is true at time n if and only if someone has pressed the Call button on floor 1 or the First button in the elevator. Similarly for Call_2. The output streams Motor_Up and Motor_Down represent the signals Motor_Up and Motor_Down, respectively.

  2. To ease the simulation of the system implemented by the Control node, we can introduce an auxiliary node that produces reasonable values for the sensors Floor_1 and Floor_2.

    One possibility is to use a "environment" node like the following:

    node Environment( Motor_Up, Motor_Down : bool )
    returns ( Floor_1, Floor_2 : bool );
    var L : int;
    let
      L = 0 -> if pre(Motor_Up) then pre(L) + 1
               else if pre(Motor_Down) then pre(L) - 1
               else pre(L);
      Floor_1 =  L = 0;
      Floor_2 =  L = 6;
    tel
    
    In the code above we make the assumptions at each clock tick in the system lasts one second, and that it takes the elevator 6 seconds to reach one floor from the other. So we can see it as going through 6 intermediate "levels" L when moving from one floor to the other.

    Put together the two nodes Control and Environment, in a new node with (exactly) the following interface:

      node Simulate( Door_Closed, Call_1, Call_2, Stop : bool )
      returns ( Motor_Up, Motor_Down : bool );
    
    Simulate your system, and try to see if the safety requirements above hold for it. Look at the values returned by Environment to see where the elevator is actually going.



Exercise 4 (Solution)

A. More Elevator problems

Consider again the elevator problem in the previous exercise.

  1. Define a synchronous observer node that expresses each of the safety requirements listed in Exercise 3. Your observer should have (exactly) the following interface:

      node Requirements( Floor_1, Floor_2, Door_Closed, Call_1, Call_2, Stop : bool )
      returns ( R1, R2, R3, R4, R5 : bool );
    
    
    Use the Luke tool to verify that the requirements hold! If necessary, you can fix bugs in your Control node.
    NB: The Environment and Simulate nodes are not to be used in this assignment.

  2. Define a synchronous observer that formalizes the following requirement: "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."

    What changes did you have to make to this requirement for it to go through?

B. k-induction questions

  1. Looking at the simple ReqSwitch observer seen in class, what is the induction depth required for each of the three requirements R1, R2, and R3? Why?

  2. Suppose we have a property that does not hold. When we run the basic k-induction procedure seen in class, it terminates for some value of k. What can we say about the lengths of traces starting in the initial state, going through states where the property holds and ending in a state where the property does not hold?

  3. Suppose we have a property that does hold. When we run the basic k-induction procedure, it terminates for some value of k. What can we say about the lengths of traces anywhere in the state space, going through states where the property holds, and ending in a state where the property does not hold?



Exercise 5 (Partial solution as a zipped Together project)

Consider the class diagram seen in class, for the university domain.

Express the following domain constraints in OCL.

  1. Instructors are graduate students or faculty members.
  2. Graduate student do not teach courses they are enrolled in.
  3. No one is waiting for a course unless someone is enrolled.
  4. No one is taking or waiting for a course unless they have already taken all the prerequisite courses.
  5. No course has itself as a prerequisite.

Add the following operations to the diagram, and write their specified preconditions and postconditions in OCL.

Student::newId(n : Integer)
preconditions: n is greater than 1000
postconditions: Id object is new and its number equals n

Student::dropCourse(c: Course)
preconditions: the student is currently taking course c
postconditions: the student is no longer taking course c

Student::addCourse(c: Course)
preconditions: the student is not currently taking course c and has already takes all its prerequisite courses
postconditions: the student is now taking course c

Student::completeCourse(c: Course, g: Grade)
preconditions: the student is currently taking course c
postconditions: the student is no longer taking course c and the course appears on the student's transcript with grade g


Exercise 6

Domain Models (Partial solution as a zipped Together project)

Develop a domain model (class diagram) for the following domain:

Our university library has a collection of books and journals. These can be lent to its patrons, among them undergraduate students, graduate students, and faculty. These groups of people have different maximal lending periods. When a person checks out an item from the library, the start date of loan is recorded.

Create a UML class diagram with the following classes

Add attributes and associations between the classes above, as appropriate to adequately model the problem domain.

OCL Specification

For each of the following questions, you first have to select an appropriate context in the domain model (a concept). Then, you can add the formalised specification as an OCL constraint for the chosen concept.

  1. The length of the maximum loan period for a patron is the following: 7 days for undergraduates, 21 dayes for graduates, and 30 days for faculty.

  2. Students are not allowed to check out more than 5 books at the same time.

  3. Create an operation
        Loan::pastDueDate() : Boolean
    
    and specify that the operation returns true if and only if the due date for that item item has passed. To query the current date, assume the existence of a class operation Library::today() that returns the current date as an integer value.

  4. Create an operation
      Library::newLoan(item: Item, pat: Patron): Integer
    
    and specify that the operation
    • assumes that item is not already checked out,
    • creates a new instance of Loan for item and pat,
    • sets the starting date of the new loan to the current date, and
    • sets the due date of the new loan, as an integer, according to the kind of patron, and
    • returns the due date.



Course Info

  Announcements

  Syllabus

  Lectures

Course Work

  Exercises

  Mini Projects

  Exams

  Readings

  Tools

Misc

  Resources

  Credits