Oz-world simulation
This example is taken from an example in the paper Research on Procedural Reasoning Systems, Georgeff M. and Ingrand F., March 1990. In this paper, several examples are given of PRS in action, one of which has a robot moving across several lanes of oncoming traffic to pick up trash (while avoiding onrushing cars!). In the paper this example is occasionally referred to as Oz world, so we have adopted that moniker for this Nuin example program. The Nuin version is not a direct clone of the PRS scenario however.
Caution at the time of writing (Nuin 0.2 release), this example is not yet complete. In particular, the use of truly concurrent threads means that the behaviour of the agents is somewhat non-deterministic as different agent actions get scheduled at different times. Work is ongoing to improve and update the example, to include, if necessary, adding extra features to Nuin.
The example is structured as four agents. The first is a simulator, that runs the example as a series of discrete steps. The simulator knows how many clock ticks to run the simulation for. It sends a clock tick message to each agent at the start of the tick, and waits for each agent to respond saying that the tick is completed before moving on to the next clock tick. At the end of the simulation, the simulator sends out messages to shut downt the agents and terminate the run. The remaining agents correspond to actors in the Oz world domain: the robot itself, a car agent and a trash agent. The car and trash are very similar: they send messages to the robot at certain points in the simulation (determined by their starting beliefs), saying that a car or trash respectively have appeared in a certain lane. The robot agent is the only really complex agent. Some of the features of the robot's script are outlined below.
Running the example
The easiest way to run this example is using the Nuin command line tool
cmd.Run. This takes as an argument the URL of the config
file describing the agents to run:
cd $NUIN_ROOT/examples/oz-world
java cmd.Run file:etc/config.rdf
See the separate note on setting the classpath appropriately.
Simulator script - notable features
These notes do not attempt to analyse the example scripts in detail, but just to
point out some highlights. The tick plan is the main driver:
plan ozs:tick
do
holds oz:currentTick( ?n );
invoke ozs:sendTick( ?n, ex:oz-robot ) ;
invoke ozs:sendTick( ?n, ex:oz-car ) ;
invoke ozs:sendTick( ?n, ex:oz-trash ) ;
resume on event( ozs:doneTick( ?n ) ) ;
retract oz:currentTick( ?n );
?n1 is ?n + 1 ;
(
holds oz:ticks( ?n );
commit
|
println( "New tick ", ?n1 );
assert oz:currentTick( ?n1 );
invoke ozs:tick
)
end.
The current tick number is stored in the default KS (the agent's beliefs, in fact, though
this isn't explicit in this code fragment). The sendTick plan is invoked 3 times
to notify the other agents that a tick of the simulation clock has occurred. The plan then
suspends until the event doneTick is seen (and which matches the current tick number).
The tick number is retracted, and the plan recurses until all the ticks of the clock have
been completed. Note that this use of a recursive plan does mean that long simulations will
use more and more memory, as each parent intention will wait until the child has completed
before terminating. This is not, therefore, a good technique for serious discrete event
simulators. Once the number of ticks corresponding to the length of the simulation has
been reached, the recursion stops.
The plan waitForTick illustrates the use of a compound event expression to trigger
the plan only when all three agents have responded. Furthermore, the library action
lib:clearEventHistory removes all events from the scheduler agent's event
history, so that the trigger expression will correctly match the next round of messages
from the other agents.
plan ozs:waitForTick
trigger
after message {acl:content = oz:tickDone, acl:sender = ex:oz-robot} &&
after message {acl:content = oz:tickDone, acl:sender = ex:oz-trash} &&
after message {acl:content = oz:tickDone, acl:sender = ex:oz-car}
do
println( "Scheduler has seen all replies for end of tick" );
@lib:clearEventHistory;
holds oz:currentTick( ?n );
post event( ozs:doneTick( ?n ) )
end.
Robot script - notable features
The (anonymous) plan that responds to the tick event from the simulator shows a
current difficulty with Nuin: how to know when all activity is complete (given
that messages from other agents may not have arrived yet). For the time being,
the script allows enough time before replying for all of the other actions to have
occurred. Obviously this is only an approximate solution, and a better one
will be sought. The suspend for action takes a duration argument,
which can be specified in a number of time formats including hours, minutes,
second and ms.
plan
trigger
on ?msg as message {acl:content = oz:tick(?n)}
do
holds oz:currentTick( ?t );
retract oz:currentTick( ?t );
assert oz:currentTick( ?n );
suspend for 2s ;
println( "robot sending reply for tick =", ?n );
send message {acl:receiver = ex:oz-scheduler, acl:content = oz:tickDone }
end.