Copyright 2011,
Ralph Rönnquist.
Teams, performers and roles are attributed with plans of how to achieve goals. These are expressed as goal hierarchies that define how goals are composed of sub goals, and a typical design combines goal hierarchies into capabilities as a way of structuring the software. In GORITE, a team is a performer, and there is a common execution machinery for goal processing regardless of whether goals are team goals or performer goals. A role is a capability that augments a team with protocol plans that are focused on a particular role filling.
The process modelling of GORITE is Goal Oriented, which means that processing is casted in terms of achieving goals. Thus, the process models for a team are like statements or paragraphs that explain how the team achieves its goals by means of achieving sub goals and performing tasks. At some points in the goal hierarchy, sub goals are deferred to team members, which deploy their own processes to achieve these goals. The team level process is primarily concerned with the coordination of member activity rather than how the detailed tasks are performed.
In practise, a goal hierarchy is created by instantiating Goals, and then for each goal tell its name and sub-goals. The goal name is that which identifies the goal. The names of the inner nodes of a goal hierarchy are not semantically significant, whereas the top level name identifies which goal a hierarchy achieves, and the leaf goal names of BDI type goals identify which goals to look up methods for. The type of goal defines how a goal is processed, and it ties a particular execution semantics to the goal. Inner nodes of a goal hierarchy would be SequenceGoal, ParallelGoal, ConditionGoal, LoopGoal, RepeatGoal, EndGoal, ControlGoal or FailGoal objects, and leaf nodes would be TeamGoal, BDIGoal or plain Goal objects. By combining the different types of goals, one can express any kind of procedural semantics in a goal hierarchy, which thus constitutes a plan for reasoned behaviour.
The detailed execution semantics for the various types of goals are as follows.
The goal hierarchies that represent process models for achieving a BDIGoal goal are also called plans, and a BDIGoal goal is achieved by means of trying all the alternative plans one by one until one succeeds. The GORITE Plan class extends the SequenceGoal class to allow a context predicate that identifies instantiation variants of a plan relating to the situation at hand, and a precedence value that guides the selection of which alternative to try next. The instantiation variants arise by the context predicate being true for different combinations of bindings for the variables involved, and each such combination of bindings defines an applicable variant of the plan. The precedence value is then used to partially order alternatives, and allow programmed control of the order to try the alternatives in. This is discussed further below.
The choice of which plan option to pursue can be modified either
towards making a random choice among highest precedence plan options,
or towards using a plan choice goal and an associated BDIGoal
execution of meta level plans for making the choice more deliberately.
Coordination Goals
Team plans involve coordination goals, which are TeamGoal goals that refer to roles. An ordinary BDIGoal goal is a goal for the current performer, whereas a TeamGoal goal is a BDI goal for the fillers of that role. The "visit a planet" plan in the example is a team plan with such coordination goals. The GORITE role filling concept includes a protocol layer where plans are attributed to roles. Such plans are used to handle coordination goals, and are performed by the team with a focus on a particular role filling. These plans typically define meta-level team activity related to a role filler activity such as monitoring the performer progress relative to other performers, and perhaps make amendment notes to the performer. The following is a code example where the "crew" role filling is changed so that the performer goal merely means to look out for the next planet, while the decision step to determine whether that planet is the destination, is attributed to the Role object:
new Role( "crew", new String [] { "look for next planet" } ) {{
addGoal( new LoopGoal( "look out", new Goal [] {
new TeamGoal( "crew", "look for next planet" ),
new EndGoal( "end if destination", new Goal [] {
new Goal( "is destination?" ) {
public States execute(Data d) {
if ( d.getValue( "planet" ).equals( d.getValue( "destination") ) )
return PASSED;
return FAILED;
}
}
} )
} ) );
}}
By the revised code, the "crew" filler is unaware about the longer term role objective of finding a particular planet, and it merely keeps achieving the simpler goal to be on look-out for the next planet. The simpler goal involves naming the planet in the data element "planet", before succeeding. However by the role protocol, the team keeps asking the "crew" to "look for next planet" until the destination is reached.
The snippet above illustrates a plan attributed to a role as way of augmenting a performer ability into a compound activity, and lift out the decision making step to be a team level reasoning step; it's not for the "crew" to decide that the destination is reached.
A semantically more complex variation would be to make the decision step a responsibility of the "greeter" role, in which case the "crew" plan would refer to the "greeter" role to achieve the "is destination?" goal. The notion might be extended further into a design where we embed all the "visit a planet" coordination within role plans. For instance, we might say that "visit a planet" is something a "greeter" does, within the context of the task team. It then will ask the "pilot" role to "fly to destination", and this, as before, requires a "crew" to "look out". We might end up with the following definition of the "flight staff" TaskTeam:
setTaskTeam( "flight staff", new TaskTeam() {{
addRole( new Role( "greeter", new String [] { "greet", "is destination?" } ) {{
addGoal( new SequenceGoal( "visit a planet", new Goal [] {
new TeamGoal( "pilot", "fly to destination" ),
new TeamGoal( "greeter", "greet" )
} ) );
}} );
addRole( new Role( "pilot", new String [] { "fly spacecraft" } ) {{
addGoal( new ParallelGoal( "fly to destination", new Goal [] {
new TeamGoal( "pilot", "fly spacecraft" ),
new ControlGoal( "arrive", new Goal [] {
new TeamGoal( "crew", "look out" )
} )
} ) );
}} );
addRole( new Role( "crew", new String [] { "look for next planet" } ) {{
addGoal( new ControlGoal( "look out", new Goal [] {
new LoopGoal( "look for destination", new Goal [] {
new TeamGoal( "crew", "look for next planet" ),
new EndGoal( "end if destination", new Goal [] {
new TeamGoal( "greeter", "is destination?" )
} )
} )
} ) );
}} );
}} );
For the sake of example, we have made an additional ControlGoal goal wrapping in the "crew" "look out" goal. This is done in order to cater for multiple "crew" fillers, where any one of them will make the "look out" goal to succeed. If there are multiple "crew", then the "look out" goal is instantiated for each "crew" filler in parallel, and unless there is a ControlGoal goal that force this parallel execution to succeed, it will be waiting for all the fillers to succeed before "look out" succeeds.
With that task team, the team's "visit a planet" goal would simply be to defer the goal to the "greeter" role.
The alternative design solutions provide very similar dynamic
behaviour, except in light of multi-filled roles. If, for instance,
there would be multiple fillers of the "greeter" role, then the second
alternative would have a possibly unwanted effect of directing the
"pilot" role to "fly to destination" many times in parallel.
Dynamic Data Context
Goals are performed with respect to both a lexical belief context and a dynamic data context, where the latter is a data structure created specifically for the individual goal execution. The dynamic data context is provided to support a business process modelling perspective, where in particular the task goals are seen to use and produce dynamic data. The lexical belief context supports the agent perspective of goal processing, allowing goals to use and update beliefs of more long-term persistence.
The dynamic data context is a collection of named data elements, where a data element carries a single value or multiple values. The data context is shared along an intention, but is split up to provide local data contexts for parallel intentions. When parallel intentions join, their local data contexts are joined into the parent context.
For example, consider the following goal hierarchy, which implements a contract net auction:
// In: RFQ, bidder*, Out: winner
addGoal( new SequenceGoal( "hold auction", new Goal [] {
// In: RFQ, bidder*, Out: bid*
new TeamGoal( "bidder", "request bid" ),
// In: bid*, Out: winner
new BDIGoal( "select winner" ),
// In: bidder*, winner, Out:
new TeamGoal( "bidder", "tell winner" )
} ) );
The code snippet includes comments with details about the data used and produced by goals. These note that the incoming data context for the "hold action" goal has an "RFQ" data element with a value describing what is auctioned, and role "bidder" established with multiple fillers. The asterisk, "*", is used to indicate a multi-valued data item.
With multiple fillers for the "bidder" role, the first goal, "request bid", causes parallel intentions for each "bidder" to perform the "request bid" goal, each in their own way. A "bidder" eventually makes a response by means of defining a "bid" data element in the dynamic context. When all "bidder" intentions have completed, the parallel "bid" values are aggregated into a multi-valued "bid" data element, which is available to the next goal, "select winner". The "select winner" goal is a BDIGoal goal for the team itself, and its outcome is a setting of the "winner" data element. This is followed by the third goal, "tell winner", which is directed to the "bidder" role and again gets repeated for each "bidder" role filler in parallel.
The dynamic data context prior to an intention split is shared
between the parallel intentions, and the updates made on any one of
the parallel branches only affects its own local data
context. However, parallel intentions can interact by referring to,
and update, values of the shared part.
Belief Structures and Context Predicates
Plans in GORITE have context predicates by which plan applicability is determined. In code, a context predicate is a data structure that represents the logical predicate as a relational query that provides a succession of bindings to the logical variables involved. This part of the framework includes a Ref class to represent logical variables, and a Query interface representing the abstract predicate. The Query interface is implemented by classes that represent expression forms, in particular the conjunctive and disjunctive forms, And and Or, and variable distinction, Distinct. Further, there is a Relation class that can be used for representing primitive terms, where a relation may include consistency rules in the form of "key constraints".
Conceptually a context predicate defines the required situation or situations in which a plan is applicable. Each way in which the predicate is true in terms of the bindings to the logical variables, defines a dynamic context variant for plan execution. The following code outline is an illustration:
Relation lamps = new Relation( "lamps", String.class, Boolean.class ).
addConstraint( true, false );
...
addGoal( new Plan( "more light", new Goal [] {
// The Data for the sub goals will include a "lamp" data element
new Goal( ..........
} ) {
public Query context(Data d) {
Ref $lamp = new Ref( "lamp" );
return lamps.get( $lamp, false ); // Some lamp being off
}
}
The first two code lines in the outline above defines a relation called "lamps", which would be a belief structure that holds the performer's beliefs about lamps being on or off. The relation is set up with a key constraint where the first column is a key field and the second a value field; i.e., the relation is designed to hold a single on/off state value for any lamp. Key constraints are applied when tuples are added to the relation, such that when the added tuple is in conflict with an old tuple by any key constraint, then the old tuple is removed.
The "more light" plan is supposed to achieve its goal by turning on a lamp that is off. To this end it includes a context predicate to recognise lamps being off, and consequently the plan has an instantiation variant for each such lamp. If all lamps are on already, then the plan is not applicable at all, and otherwise there is a variant for each lamp being off. The variants are all the same in terms of goal instantiation, but their executions differ in their dynamic context, where each variant has its own value for the "lamp" data element.
The BDIGoal goal processing will select one of the variants to achieve, and succeeds if that variant succeeds. Otherwise, a new set of alternative plans is formed, which excludes the variants already attempted, and another plan variant is tried, until either one succeeds, or all variants have failed, in which case the BDIGoal goal fails.
The diagram below is an expanded GORITE concept map, including the Plan concept of the process modelling perspective. As noted above, a GORITE Plan is a Goal augmented with a context predicate, which defines the plan's applicability with respect to the performer's situated beliefs. Technically a belief structure is a data structure of some kind; perhaps a Relation or perhaps some other Java structure. The context predicate is a Query that defines a predicate abstraction for accessing individual beliefs regardless of the underlying representation.