I'm learning Constraint Handling Rules (in SWI-Prolog) and trying to (faithfully) program the "Example 5 (Petri Nets - Barber Shop)" from https://www.informatik.uni-ulm.de/pm/fileadmin/pm/home/fruehwirth/rule-based-summer-2013.pdf (page 10).
Exercise 5 (Petri Nets - Barber Shop). A typical scenario at a Barber shop is as follows:
Customers enter a Barber shop and wait till a barber is idle and ready to serve them. Then
the barber cuts the hair of a customer. When the hair cut is done, the customer leaves and the
barber becomes idle once again. This can be represented using the Petri net given below:
customers waiting cut
O -------------> ___ ____
| | --> O --> | | ---> customers done
O ------------->|___| customers |___| ----
idle barbers cutting leave |
^---------------------------------------------<
Translate the Barber shop Petri net into CHR by adding the constraints customers_waiting/0,
idle_barbers/0, customers_cutting/0, and customers_done/0 for each of the places. Add
an observer/0 constraint to print the interesting states of the problem. A typical test
query would be ?-observer,customers_waiting,customers_waiting,idle_barbers.
What I wonder is how to program the observer/0
constraint in CHR. I've tried to figure out if observer has a special meaning in Petri Nets, but haven't found any indication of that. If observer refers to the Observer Pattern then I would expect that it should be observer/1
instead, but perhaps there's a CHR trick that one can use?
Here's the code I've done. Using the state/1
is probably considered cheating, but it's a way to collect the states of the flow. (For debugging purposes, I also added the constraints with writeln/1
).
:- use_module(library(chr)).
:- chr_constraint customers_waiting/0, idle_barbers/0, customers_cutting/0,
customers_done/0, observer/0, states/1.
go :-
observer,customers_waiting,customers_waiting,idle_barbers,nl.
% This is probably not the intended idea of using the observer/0.
observer <=> states([]).
idle_barbers ==> writeln(idle_barbers) .
customers_waiting ==> writeln(customers_waiting).
customers_cutting ==> writeln(customers_cutting).
customers_done ==> writeln(customers_done).
customers_waiting, idle_barbers, states(States) <=>
append(States,[customers_waiting,idle_barbers],NewStates) | customers_cutting, states(NewStates).
customers_cutting, states(States) <=>
append(States,[customers_cutting],NewStates)| states(NewStates), customers_done.
customers_done, states(States) <=>
append(States,[customers_done],NewStates) | states(NewStates), idle_barbers.
Running the program:
$ swipl petri_nets_barber_shop.pl
?- go.
customers_waiting
customers_waiting
idle_barbers
customers_cutting
customers_done
idle_barbers
customers_cutting
customers_done
idle_barbers
idle_barbers,
states([customers_waiting, idle_barbers, customers_cutting, customers_done, customers_waiting, idle_barbers, customers_cutting, customers_done]).
The output before the newline is from writeln/1
, and the two lines after are from CHR's constraint store.