Specification of a car rental company
SPECIFICATION Company
TEMPLATE Customer
DATA TYPES
String;
ATTRIBUTES
Name : string;
Address : string;
EVENTS
BIRTH createCustomer(aName : string, anAddress : string);
updateAddress(anAddress : string);
VALUATION
[ createCustomer ] Name = aName, Address = anAddress;
[ updateAddress ] Address = anAddress;
BEHAVIOR
PROCESS Customer =
( createCustomer -> CustomerUpdate );
PROCESS CustomerUpdate =
( { Address <> anAddress : "new address `" + anAddress +
"' must not be equal to old one" }
updateAddress -> CustomerUpdate );
END TEMPLATE
// ---------------------
TEMPLATE Car
DATA TYPES
String, Int, Bool;
ATTRIBUTES
CarNo : string;
CarCat : int; // 1..5
Brand : string;
Available : bool;
EVENTS
BIRTH createCar(aCarNo : string, aCarCat : int, aBrand : string);
pickUp;
return;
CONSTRAINTS
1 <= CarCat AND CarCat <= 5;
VALUATION
[ createCar ]
CarNo = aCarNo, CarCat = aCarCat, Brand = aBrand, Available = TRUE;
[ pickUp ] Available = FALSE;
[ return ] Available = TRUE;
BEHAVIOR
PROCESS Car =
( createCar -> CarAvailable );
PROCESS CarAvailable =
( { Available : "car is not available for pickUp" }
pickUp -> CarAway );
PROCESS CarAway =
( { NOT Available : "car is not away" }
return -> CarAvailable );
END TEMPLATE
// ---------------------
TEMPLATE Booking
DATA TYPES
String, Int, Bool;
TEMPLATES
Customer, Car;
ATTRIBUTES
TheCustomer : customer;
TheCar : car;
BookingCat : int; // 1..5
StartDay : int; // YYYYMMDD
EndDay : int; // YYYYMMDD
IsClosed : bool;
DERIVED IsOpen : bool;
DERIVED IsCurrent : bool;
EVENTS
BIRTH createBooking(aCustomer : customer, aCat : int,
aStartDay : int, anEndDay : int);
makeCurrent(aCar : car);
close;
CONSTRAINTS
1 <= BookingCat AND BookingCat <= 5;
19900101 <= StartDay AND StartDay <= EndDay AND EndDay <= 20001231;
VALUATION
[ createBooking ]
TheCustomer = aCustomer, BookingCat = aCat,
StartDay = aStartDay, EndDay = anEndDay,
IsClosed = FALSE;
[ makeCurrent ] TheCar = aCar;
[ close ] TheCar = NIL(car), IsClosed = TRUE;
DERIVATION
IsOpen = UNDEF(TheCar) AND NOT(IsClosed);
IsCurrent = DEF(TheCar) AND NOT(IsClosed);
BEHAVIOR
PROCESS Booking =
( createBooking -> BookingOpen );
PROCESS BookingOpen =
( { BookingCat <= CarCat(aCar) : "category of car is too low" }
makeCurrent -> BookingCurrent );
PROCESS BookingCurrent =
( close -> BookingClosed );
PROCESS BookingClosed = ( );
END TEMPLATE
// ---------------------
TEMPLATE Company
DATA TYPES
String, Int;
TEMPLATES
Customer, Car, Booking;
SUBOBJECTS
Customers : MAP(CustomerNo : int, Customer : customer);
Cars : MAP(CarNo : string, Car : car);
Bookings : MAP(BookingNo : int, Booking : booking);
ATTRIBUTES
Today : int; // YYYYMMDD
NextCustomerNo, NextBookingNo : int;
DERIVED CurrentCustomersAndCars : BAG(TUPLE(Name : string, CarNo : string));
DERIVED ReturnCarsMenu : BAG(string);
DERIVED DeliverCarsMenu :
BAG(TUPLE(BookingNo : int, BookingCat : int,
PossibleCars : BAG(TUPLE(CarNo : string, CarCat : int))));
EVENTS
BIRTH create;
addCustomer(aName : string, anAddress : string);
addBooking(aCustomer : customer, aCat : int,
aStartDay : int, anEndDay : int);
incTime(aDay : int);
returnCar(aCarNo : string);
closeReturnCars;
addCar(aCarNo : string, aCarCat : int, aBrand : string);
deliverCar(aBookingNo : int, aCarNo : string);
closeDeliverCars;
CONSTRAINTS
NextCustomerNo >= 0;
NextBookingNo >= 0;
// make sure that each car is assigned to at most one booking
FORALL (C IN Cars)
(CNT(SELECT B
FROM B IN Bookings
WHERE TheCar(Booking(B)) = Car(C)) <= 1);
VALUATION
[ create ]
NextCustomerNo = 0, NextBookingNo = 0;
[ addCustomer ]
NextCustomerNo = NextCustomerNo + 1;
[ addBooking ]
NextBookingNo = NextBookingNo + 1;
{ aDay > 19000000 : "invalid date `" + STR(aDay) + "'" }
[ incTime ]
Today = aDay;
DERIVATION
CurrentCustomersAndCars =
SELECT Name(Customer(CUS)), CarNo(Car(CAR))
FROM CUS IN Customers, CAR IN Cars
WHERE EXISTS ( B IN Bookings )
( TheCustomer(Booking(B)) = Customer(CUS) AND
TheCar(Booking(B)) = Car(CAR) );
ReturnCarsMenu =
SELECT CarNo(TheCar(Booking(B)))
FROM B IN Bookings
WHERE EndDay(Booking(B)) <= Today AND IsCurrent(Booking(B));
DeliverCarsMenu =
SELECT BookingNo(B), BookingCat(Booking(B)),
( SELECT CarNo(Car(C)), CarCat(Car(C))
FROM C IN Cars
WHERE Available(Car(C)) AND
CarCat(Car(C)) >= BookingCat(Booking(B)) )
FROM B IN Bookings
WHERE StartDay(Booking(B)) = Today AND IsOpen(Booking(B));
INTERACTION
addCustomer >>
createCustomer(aName, anAddress) IN Customers(NextCustomerNo);
// shortcut for: MAP_SEL(Customers(SELF), NextCustomerNo);
addBooking >>
createBooking(aCustomer, aCat, aStartDay, anEndDay) IN
Bookings(NextBookingNo);
// return car and close booking for this car
returnCar >> return IN Cars(aCarNo),
close IN SINGLE(SELECT Booking(B)
FROM B IN Bookings
WHERE CarNo(TheCar(Booking(B))) = aCarNo);
addCar >> createCar(aCarNo, aCarCat, aBrand) IN Cars(aCarNo);
// deliver car and mark booking as current for this car
deliverCar >> pickUp IN Cars(aCarNo),
makeCurrent(Cars(aCarNo)) IN Bookings(aBookingNo);
BEHAVIOR
PROCESS Company =
( create -> SetTime );
PROCESS SetTime =
( incTime -> AddCustomerOrBooking );
PROCESS AddCustomerOrBooking =
( addCustomer -> AddCustomerOrBooking
| { Today < aStartDay : "start day must be after today" }
addBooking -> AddCustomerOrBooking
| { Today < aDay AND
FORALL (B IN Bookings)
// don't skip start day of open bookings
(IsOpen(Booking(B)) IMPLIES aDay <= StartDay(Booking(B)) AND
// don't skip past end day of current bookings
IsCurrent(Booking(B)) IMPLIES aDay <= EndDay(Booking(B))) }
incTime -> ReturnCars );
PROCESS ReturnCars =
( { aCarNo IN ReturnCarsMenu :
"car `" + STR(aCarNo) + "' not in ReturnCarsMenu" }
returnCar -> ReturnCars
| { EMPTY(ReturnCarsMenu) : "there are still cars to return" }
closeReturnCars -> DeliverCars );
PROCESS DeliverCars =
( addCar -> DeliverCars
| { aBookingNo IN ( SELECT BookingNo(B)
FROM B IN Bookings
WHERE StartDay(Booking(B)) = Today )
AND Available(Cars(aCarNo))
: "no booking number `" + STR(aBookingNo) + "' or car not available" }
// category is checked in Booking behavior
deliverCar -> DeliverCars
| { FORALL (B IN Bookings)
( StartDay(Booking(B)) = Today IMPLIES
IsCurrent(Booking(B)) ) }
closeDeliverCars -> AddCustomerOrBooking );
END TEMPLATE
Home|People|Teaching|Publications
Last change: 11/14/97