Copyright ACM, 2000

A Coordination Language for Collective Agent Based Systems: GroupLog

Fernanda Barbosa and José C. Cunha
Dep. de Informática - Faculdade de Ciências e Tecnologia
Universidade Nova de Lisboa - Portugal
(fb,jcc)@di.fct.unl.pt

Abstract

We describe a language providing concepts for modeling autonomous entities (agents) and cooperating entities (groups). Agents are the execution units of a GroupLog program. Each agent possesses a hidden internal behavior and a well-defined communications interface and its behavior is defined by a set of logical rules. Groups are important to model agent cooperation in a flexible and well-structured manner and to hide low-level management of coordination activities. In the paper we give an informal presentation of the GroupLog language and illustrate its use through an example.

1  Introduction

In multi-agent systems several agents cooperate to achieve some task that might not otherwise be achieved by each individual agent. Group-oriented abstractions offer the possibility of joining related agents into logical units of cooperation that may help in the management of distributed computations. Nowadays, concurrent programming remains a complex task. This complexity could be reduced by a model supporting concepts for the structuring of multiple cooperating entities. Recently such abstractions appeared at the operating system or at the middleware levels [4], but only few proposals attempted their integration into programming languages [31,26,23,18,15,7]. GroupLog provides two main program structuring levels: agents (program entities) and groups (cooperating entities). Groups support the organization of the agent space into distinct sets, each set acting like a meta-agent with well-defined internal behavior and communications interface. GroupLog relies on logic programming abstractions aiming at providing transparency to the user. Furthermore, the logic based approach finds applications in multiple areas, where there is the need of some inference capability (modeled by agents in GroupLog), coupled with a requirement for an adequate model for specifying the interactions between autonomous agents (modeled by groups).

In the remainder of the paper, we first present a brief description of the GroupLog language. In 3 we give an example. In 4, we discuss GroupLog in relation to other languages and in 5 we present some conclusions.

2  The Language GroupLog

GroupLog defines extensions to the Extended Horn Clause language (EHC) [29], that are supported at two levels: L1, defines agents as program units and L2 defines groups of agents. A GroupLog system contains concurrently executing agents able to: (1) communicate through interface predicates, and (2) join groups to coordinate their activities. In the following, we first summarize EHC (see [29]), and then describe the two mentioned levels.

2.1  Extended Horn Clauses

Extended Horn Clause Logic (EHC) is an extension to Horn Clause Logic (HC) with mechanisms for concurrency and synchronous communication. EHC supports the parallel composition of goals and provides clauses for modeling an interaction between two parallel processes through a joint synchronization step.

Such EHC clauses allow an interpretation of a message based communication with an object, when some process invokes method ``mess(M)'' of an object instance obj(S). The execution of that object instance is modeled by a perpetual process and two cases are allowed to process message ``mess(M)'':
(i) obj(S) :: mess(M) :- method(M) | obj(NewS) :: true.

(ii) obj(S) :: mess(M) :- method(M) | obj(NewS) :: process(M).

This is achieved by activating one of these clauses and solving goal ``method(M)'', as explained below. In clause (i) the message is consumed. In clause (ii) the message is not consumed and is reduced to ``process(M)''. In both cases the object state changes from S to NewS.

EHC was used as the base language mainly because of this elegant interpretation of process interactions and because the language has rigorously defined semantics.

A EHC clause has the following form:
H1 :: ... :: Hn :- G | G1 :: ... :: Gn.

where Hi are atoms and G and Gi are goals. The goals are conjunctions of atoms built by using the following operators: ";" denotes sequential composition, "||" denotes parallel composition and "&" denotes simultaneous reduction of atoms.

A clause as follows can be used for the joint synchronization of two concurrent goals C1 and C2
(1) H1 :: H2 :- G | G1 :: G2.

On a concurrent execution, each goal invocation suspends and waits for the other and only then C1 and C2 may be simultaneously reduced to G1 and G2. This joint derivation step is only successful if there is a permutation of C1 and C2 that unifies with (H1,H2) with most general unifier q and if Gq is true. In that case, each ith element of the permutation is reduced to Giq (i = 1,2).

Parallel goal composition, G1||G2, may be achieved in two ways:
(a) Using two Horn Clauses
Hi :- Gi and Hj :- Gj where G1 unifies with Hi and G2 unifies with Hj
(b) Using one Extended Horn Clause
H1 :: H2 :- G | G1 :: G2, where a permutation of (G1,G2) unifies with (H1,H2), as explained above.

Use of Extended Horn Clauses in GroupLog In GroupLog we consider only Extended Horn Clauses with one or two atoms in the clause head corresponding, respectively, to Horn Clauses [25] and EHC clauses of form (1). Syntactically we use "," instead of ";" for sequential composition and the form below, where ":" stands for "::"
H1 : H2 :- G | G1 : G2.

2.2  L1 - Dynamic structuring units of program entities - Agents

The need for structuring the communication and synchronization in EHC motivated the definition of a dynamic entity, called agent. Syntactically, an agent is defined as follows:

agent <agent_name>{
    /* clause context */
  context(<list_modules>).
    /*communication context*/
  interface(<list_interface_pred_names>).
    /* agent behavior */
  <list of interface clauses>  
    /* agent creation */
  <creation clause>     
}

The following example defines a stack agent:

agent stack{
  context().                            (1)
  interface(push(X), pop(X), top(X)).   (2)
                        /* interface clauses*/
  stack(Id,L)    : push(X) :- | stack(Id,[X|L]).
  stack(Id,[X|L]) : pop(X) :- | stack(Id,L).
  stack(Id,[X|L]) : top(X) :- | stack(Id,[X|L]).
                       /* creation clause */
  stack(Id) : new :- | stack(Id,[]).     (3)
}

Agent name and instances Each agent has a name that defines its type. An instance of an agent has an unique identifier (e.g. stack(1) instance 1 of agent of type ``stack'') and is created when the predefined predicate
create_instance( < agent_instance > ) is invoked. Each agent type has an associated prototype that is responsible for the creation of its instances. The implicit definition of the agent prototype is given by an EHC clause, eg. for the stack agent:

(a) stack : create_instance(stack(Id)) :-
          | stack # stack(Id) : stack(Id)<<new.

where: stack is the prototype associated with the type of agent ``stack'', # is the operator for parallel composition of agent instances and << is the operator for communication with an agent instance.

When a program starts, the prototypes for all types of agents defined by the program are implicitely activated, namely for agent type stack, in the above example. When the create_instance(stack(1)) goal is invoked by another agent's instance, let us say b(2), the EHC resolution mechanism tries to unify the pair (stack,create_instance(stack(1))) with the head of clause (a). As a result of this successful unification:

The new instance stack(1) is represented by a perpetual process, successively evaluating calls to a recursively defined procedure with arguments representing the sucessive states (or configurations) of the agent. The creation clause of an agent is as follows:

    a(Id) : new :- <initial_conditions>
                         | <initial_configuration>.
When this clause is activated, the perpetual process a(Id) reduces to < initial_configuration > , if < initial_conditions > is true. At each point in a computation, the agent instance has a current configuration that is defined by its perpetual process. In the example of stack(1), the initial configuration is given by the empty list stack(1,[]) (see clause (3) in the stack agent).

Agent program The clause context of a given agent is a set of clauses, defined by:

   module <name_module>{
       clause 1
       ...
       clause n
   }
where clause i is an EHC with one or two atoms in the head of the clause, as explained.

The clause context is specified by the predefined predicate context( < list_modules > ) where < list_modules > is a list of module names. Its meaning is the union of the clauses defined in the listed modules, in their textual ordering. In the example of ßtack" agent, the clause context is empty (see clause (1) of stack agent).

Agent interactions The communication context defines the interaction of the agent with its environment and is specified by
interface( < list_interf_pred_names > )
where < list_interf_pred_names > is a list of interface predicate names and interface is a predefined predicate. The interface predicates define the visible ``entry points'' of an agent that can be invoked from the outside environment. In the example of ßtack" agent, these are: push(X), pop(X) and top(X) (see clause (2) of stack agent).

Communication forms The communication with an agent uses operator `` << '' and is synchronous. This can be one-to-one or one-to-many. In one-to-one communication, the destination agent and its interface predicate are explicitly cited. For example stack(1) << pop(X) denotes a communication with agent's instance stack(1) through interface predicate ``pop''. In one-to-many communication, we only need to specify the type of agent and the interface predicate, because this is a form of selective communication which addresses all instances of the specified type. For example stack(_) << pop(X) denotes a communication addressing all instances of an agent of type stack through interface predicate ``pop''. The agent exhibits a well defined behavior, depending on its current configuration and on the invoked interface predicate. There is a non empty set of Extended Horn Clauses associated with each interface predicate. Two forms are allowed, where (ii) is a simplified form of (i) when < process > is true:

(i)  <agent_config> : <interf_pred_name> :-
     <set_cond> | <new_agent_config> : <process>.
(ii) <agent_config> : <interf_pred_name> :-
         <set_cond> | <new_agent_config>.
The above clauses have the same interpretation as an EHC clause (see (1) in section on EHC) where:

  1. H1 corresponds to the < agent_config > of the addressed agent. This means that this agent instance must have a current configuration that unifies with < agent_config > This current configuration is modeled through the agent's perpetual process.
  2. H2 corresponds to the < interf_pred_name > in the interface predicate that must unify with the interface predicate that is cited by the invoker agent.
  3. G corresponds to < set_cond > that must be true so that the communication can be successful.
  4. G1 corresponds to the < new_agent_config > for the addressed agent.
  5. In form (i) G2 corresponds to < process > and has a similar interpretation as "process(M)" in the communication with an object in EHC (see section on EHC).

The evaluation of the first three conditions (1,2,3) as well as the transition to a new configuration (4) correspond to an atomic step in the invoked agent. This means any other invocation made to this agent remains suspended until this agent has completed such an atomic step, i.e. is available again for further interactions. If the first three conditions are satisfied, the agent changes to a new configuration, otherwise it keeps its current configuration and the communication fails in the invoker.

Given the actual configuration of an agent and an invoked interface predicate there is a (possibly empty) set of clauses which are enabled by that configuration. These are the clauses of that interface predicate such that < agent_config > unifies with the current agent configuration of the agent. All other clauses are disabled for that configuration. An example is given by the clause with head ßtack(Id,[X|L]):pop(X)" when stack agent is in its initial configuration (stack(1,[])). This means an invocation of ßtack(1) << pop(C)" will suspend the invoker agent until a matching configuration (triggered by a change to a nonempty stack) enables the cited clause. If there is a matching enabled interface clause, and if ßet_cond" is true, the communication is accepted by the invoked agent so it changes its current configuration to
< new_agent_config > . This state transition is non reversible and the agent becomes available for further interactions with other agents. This means that in clause (ii) the interaction is completed and the invoker proceeds with its computation. However in clauses like (i), the invoker agent must wait until this interaction is completed by the evaluation of goal < process > locally to the invoked agent i.e. within this agent context (this communication is said to be ongoing). The evaluation of < process > cannot involve communication with other agents and is performed concurrently with further interactions between the invoked agent and other invoker agents. This corresponds to an implicit spawning of a concurrent thread, internal to the invoked agent. If < process > fails, the communication fails for the invoker, although the invoked agent has already committed to a new configuration. Whenever an agent changes to a new configuration, there is a commitment. This decision relates to our view of an agent as a reactive entity that evolves to new configurations as a result of its interactions with the environment. The behavior of an agent is modeled in a logic framework given by EHC, except the meaning of the interactions2. Otherwise we would have to manage the complexity of distributed backtracking which would affect the practical feasibility of the model.

One-to-many communication, as in stack(_) << pop(X), proceeds in two steps:

  1. The communication suspends until there is an available instance of agent stack (i.e. that instance is currently waiting for interactions) with an enabled interface clause for this invocation of pop;
  2. If multiple instances are found in step 1, one is selected in a non-deterministic way and the communication with the selected instance proceeds as in one-to-one communication.

Communication fails when no such instances of ``stack'' are found, or there is no interface predicate ``pop/1'' in agent stack, or when the one-to-one communication fails in the selected instance of agent stack.

Agent termination An instance of an agent can be cancelled by the predefined interface predicate kill, or implicitely cancelled by an interface clause such as:

<current_config> : <interf_pred_name> :-
      <set_cond> | true : true.
This implies the forced failure of all communications involving this agent (both suspended and ongoing). If < set_cond > is true, this clause simplifies to:
  <current_config> : <interf_pred_name>.

2.3  L2 - Dynamic grouping of agents - Groups

The need for structuring the space of agents in L1 motivated the definition of groups as dynamic entities. Two forms of cooperation are allowed in L2: (1) access to a shared group state, based on the Linda model [20]; and (2) direct communication through interface predicates. The group, like a meta-agent, has well defined clause, communication and behavior contexts. Its creation is done by the predicate create_instance and there is a perpetual process, called the group representative, that models the successive configurations of the group and the associated transitions. Syntactically, a group is defined as follows:

group <name_group>{
     context(<list_modules>).
     interface(<list_interface_pred_names>).
     <list of interface clauses>
     <the creation clause>
}
The following example defines a group ``meet_sch'', which has an interface predicate (begin), to simulate the beginning of the Meeting Scheduling (in section 4):
group meet_sch{
   context().
   interface(begin).
   meet_sch(Id) : begin :-
         members(meet_sch(Id),[H,I]),
         rd(meet_sch(Id),meet(MeetId)),
         H<<begin(I,MeetId) || I<<begin(H,MeetId)
                         | meet_sch(Id).
   meet_sch(Id) : new :- | meet_sch(Id).
}

Group membership A group is a composition of agents, called its members. The group membership changes dynamically as a result of predefined interface predicates ``add'' and ``delete''. For example
friends(1) << add(F) adds agent F to an instance of group friends(1) and
friends(1) << delete(F) removes agent F from that instance friends(1). A group hides its members from the outside but allows the redirection of communication to them through the group interface predicates. The internal concurrency to a group is explicitely defined by its members that have access to a shared group state, for internal coordination. An agent can belong to one or more groups and inspect their membership through the following predefined predicates:

Structuring the space of agents In L1, all agents belong to the universe of agents (U) that models a flat space. In L2, an agent only belongs to U if it is not a member of any group. All agents in U can directly communicate with one another using one-to-one or one-to-many communication. When an agent in U joins a group, it is removed from U so it becomes inaccessible to all other agents in U. An agent A can only be accessed by the following classes of agents: (1) directly by members of the same group as A, through the interface predicates of A, and (2) indirectly, by other agents, if they have access to the group interface predicates of one of the groups containing A. An agent is put back in U only when it leaves all the groups it had previously joined. In L2, the termination of an agent implies its removal from all its groups as well as from U.

Group communication The interface clauses have the following form:

(i)  <group_config> : <interf_pred_name> :-
     <set_cond> | <new_group_config> : <process>.
(ii) <group_config> : <interf_pred_name> :-
         <set_cond> | <new_group_config>.

In these clauses the ``set_cond'' and ``process'' goals are evaluated by a thread of the group representative in the group clause context. In these goals we allow the invocation of: (1) predicates defined by the group clause context, (2) predicates to access the shared group state or (3) interface predicates of group members or other agents. Unlike an agent, communication is allowed in goal < process > . Communication within the group may involve only group members, or the group representative and the group members.

Shared group state The shared group state is a multi-set of atoms, defined in a module by the predefined interface predicate ``state''. For example, given an instance of group friends(1), the goal friends(1) << state(m1) creates the shared group state, based on the contents of module m1. The members of the group may interact by accessing the shared group state, i.e. by reading and writing state elements. The predefined predicates - rd, ts, in e out allow access to the state of a group G:

  1.  ts(G,State_group) : is true if there is a subset of the shared state that matches ``State_group'';
  2.  rd(G,State_group) : reads a subset from the shared state that matches ``State_group'';
  3.  in(G,State_group): reads a subset from the shared state matching ``State_group'' and removes it;
  4. out(G,State_group): puts the subset ``State_group'' in the shared state.

In 2 and 3 above, the invocations suspend until there is a subset of the shared state matching ``State_group''. The predicates ts and out are non-blocking. Namely, ts fails if no matching is possible. The modifications made to the shared state, due to these predicates, are not reversible.

Group termination The elimination of a group is achieved through the interface predicate ``kill'', or implicitly through the activation of a clause like in L1. As soon as the termination of a group is activated, its interface predicates disappear except for the ``delete'' predicate. This is so that the current group members may leave the group. When there are no more members, all pending and ongoing communications are forced to fail, and the group is removed from all its enclosing groups, and from the universe U.

3  Two-Agent Meeting Scheduling

The Meeting Scheduling is a complex problem which consists of finding a time schedule for a meeting of N agents. This meeting time must be accepted by all agents. The basic idea is to allow agents to coordinate themselves in order to reach an agreement. The version below (see also in [22]), for simplicity, considers the meeting of two agents only - Two-Agents Meeting Scheduling. In this version, one of the agents acts as the host (it is the agent who is trying to arrange the meeting) and the other agent is the guest. To guarantee that the cooperation will reach a conclusion, we assume that the agents always share a free slot of the appropriate lenght in their agenda where the meeting can be scheduled. The group ``meet_sch'', as defined in section 2.3, is used to join the agents in such way that they can cooperate through the shared group state. In our example, the two agents have some common knowledge related to: (1) finding a possible time for the meeting in accordance with his agenda and (2) telling a possible time to the cooperative agents. This knowledge is defined as:
module schedule{
   found_time(S,meet(MeetId,T,L,Att)) :-
   /* returns in T a possible time to meet MeetId
      in accordance with the schedule S */
   tell_time(I,S,meet(MeetId,L,Att)) :-
         found_time(S,meet(MeetId,T,L,Att)),
         out(meet_sch(1),tell(I,meet(MeetId,T))),
         ts(meet_sch(1),stop_sch(I)).
  tell_time(I,_,_) :- in(meet_sch(1),stop_sch(I)).
}
The cooperative agents are modeled by two concurrent goals: (1) find and inform about the possible times and (2) find a common time (in case of the host) or wait for the confirmation of the time (in case of the guest). This knowledge is defined in the following modules:
module schd_host{
      ex_host(I,Guest,S,meet(MeetId,T,L,Att)) :-
         rd(game(1),inf_meet(MeetId,T,L,Att)),
         tell_time(I,S,meet(MeetId,L,Att))
                  || match_time(I,Guest,MeetId,T).
      match_time(I,Guest,MeetId,T) :-
         in(game(1),[tell(I,meet(MeetId,T)),
                     tell(Guest,meet(MeetId,T))]),
          out(game(1),[stop_sch(I),
                       confirm(I,meet(MeetId,T))]).
}
module schd_guest{
    ex_guest(I,Host,S,meet(MeetId,T,L,Att)) :-
           rd(game(1),inf_meet(MeetId,T,L,Att)),
           tell_time(I,S,meet(MeetId,L,Att))
                  || conf_inv(I,Host,MeetId,T).
    conf_inv(I,Host,MeetId,T) :-
        in(game(1),confirm(Host,meet(MeetId,T))),
        out(game(1),stop_sch(I)).
}
The host and guest are defined as agents in the following way:
agent host{
   context(schedule,schd_host).
   interface(begin(MeetId,Guest)).

   host(Id,S) : begin(MeetId,Guest) :-
       ex_host(I, Guest,S,meet(MeetId,T,L,Att))
            | host(Id,[meet(MeetId,T,L,Att)|S]).
   host(Id) : new :- game(1)<<add(host(Id))
            | host(Id,[]).
}
agent guest{
   context(schedule,schd_guest).
   interface(begin(MeetId,Host)).

   guest(Id,S) : begin(MeetId,Host) :-
         ex_guest(I,Host,S,meet(MeetId,T,L,Att))
             | guest(Id,[meet(MeetId,T,L,Att)|S]).
   guest(Id) : new :- game(1)<<add(guest(Id))
             | guest(Id,[]).
}
In this example, we can see how GroupLog concepts are used to coordinate a set of related agents. Other typical example of a Philosophers' Restaurant can be seen in [3], where the group notion is used to model the dynamic evolution of the system.

4  Related Work

Recently, models have been proposed based on coordination concepts aiming at integrating a number of components together such that the collective set forms a single application that can take advantage of distributed systems.

Many proposals extend a base logic language for concurrency, communication and non-determinism. The base language may be Horn Clause Logic [25], Temporal Logic, Linear Logic [21] or Situation Calculus. In the first case, we have Rose [6], DeltaProlog [32,16], MultiProlog [5]. In the second, MetaTem [18]. In the third, COOL [8] and IAM [2] and in the last case ConGolog [24]. Specification of concurrency has also been introduced jointly with an object-oriented model such as in DLP [17], CSO-Prolog [35], ShaDE [9], IAM [2] and COOL [8].

The motivation to use EHC as the base language for GroupLog is due to its elegant interpretation of a process interaction and its rigorously defined semantics.

The dynamic entities of a program can be modeled by:
Processes, as April [27] and MultiProlog [5];
Objects, as ShaDe [9], Law Governed Linda [28], IAM [2], ColaS [15], Electra [26] and Emerald [31];
Agents, as ConGolog [24], COOL [8], MetaTem [18], Agentspeak [34], 3APL [1] and Placa [33];
Actors, as Concurrent Agregate [10] and Synchronizers [30].

The interation between dynamic entities can be modeled by:
Sending messages, as ShaDe [9], ConGolog [24], Concurrent Agregate [10], IAM [2], AgentSpeak [34], COOL [8], MetaTem [18], April [27], Placa [33] and Electra [26];
Shared tuples, as GammaLog [13], PoliS [14], Law-Governed Linda [28], MultiProlog [5] and ESP [12].

L1 vs others models In L1, we structured the concurrency and communication with the agent notion, but this language does not aim to provide a theory to model the mental state of an agent, as in MetaTem, ConGolog, AgentSpeak, 3APL and Placa. The agent behavior is only dependent on the interface predicates and its configuration, i.e. the entities are reactive and act in accordance with the interaction and its configuration, like in the actor model. This behavior is modeled by EHC clauses, with a very similar interpretation to the rule based one in AgentSpeak and 3APL. In L1, one simple form of communication is allowed: the explicit invocation of interface predicates. The notion of agent in L1 integrates the logic aspect with the object-oriented model, as in [11]. In this model it is possible to model blackboard-based systems, which is only allowed in GroupLog in L2.

L2 vs others models The definition of groups in GroupLog was the result of an incremental development process which started with our early experimentation with the ISIS system [4]. Groups allow the modeling of a cooperative entity and the dynamic evolution of a system. A group can be created or destroyed, as its members can join or leave the group at any time. The group members are hidden from the outside environment. Because a group is a meta-agent, it is possible to have a group as a member of another group, so this allows the composition of the group notion, as the context notion defined in [7]. In a group we allow two forms of communication: by invocation of interface predicates or through the shared group state. So, L2 is also an experiment towards unifying distributed-memory (remote predicate call) and shared-memory models (shared data). In some of programming languages, like MetaTem [18], COOL [8] and Concurrent Aggregates [10], the group notion is used to restrict the communication to a certain group of agents, which may alleviate some of the inefficiencies that occur in full broadcasting. In other languages, like Electra [26], Emerald [31], Synchronizers [30] and ColaS [15], the group is seen as a logical unit that manipulates and restricts the invocation of the members group interface. In Syncronisers, the notion of coordination is modeled by a special object (synchroniser) that restricts the invocation of the group of objects using constraints. In most of these programming languages, as in GroupLog, the group is a dynamic entity. But in Synchronizers and ColaS it is possible to dynamically change the coordination behavior, which is not possible in GroupLog. In GroupLog, as in Electra and Emerald, the members of the group perceive a consistent view of: (1) the other agents who are also part of the group and (2) the shared state. The main difference between GroupLog and these languages is the group interface predicates, that may be distinct from the group members individual interface. In languages where the communication is modeled by shared-memory, like ESP [12] and PoliS [14], the communication structuring is done by allowing multi-tuple spaces. In case of PoliS there are hierarchical tuple spaces. The L2 level of GroupLog supports the structuring of the tuples space into multiple parts, as each is naturally encapsulated within a specific group such that only its members are allowed to access the group state. This is a good approach to address both modularity, information-hiding, and scalability concerns in large-scale real applications.

5  Conclusions and Future Work

GroupLog is a programming language allowing clear specification of systems supporting the concept of multiple cooperating entities. It can be used to implement multi-agent and open systems, as it allows: (1) the logical specification of the agent rules, (2) communication and coordination among agents and (3) a system to be completely dynamic and open, in that new groups and agents may appear/disappear at any time. Ongoing work is related to the formal definition of the semantics and a distributed implementation of GroupLog on top of the PVM system [19].

References

[1]
3APL - An Abstract Agent Programming Language. In http://www.students.cs.uu.nl/swp/1997/robo/3apl/, Robolab Software Project, University of Utrecht, The Netherlands.

[2]
Andreoli, J. M., Ciancarini, P., and Pareschi, R. Interaction Abstract Machines (IAM). Research Directions in Concurrent Object-Oriented Programming .

[3]
Barbosa, F., and Cunha, J. A Language Framework for Group Based Multi-Agent Systems: GroupLog. In Workshop Foundations and Applications of Collective Agent Based Systems of 11th ESSLLI99 Proceedings (1999).

[4]
Birman, K., and Joseph., T. Exploiting Virtual Synchrony in Distributed Systems. In 11th ACM Symposium on Operating Systems Principles Proceedings (1987), ACM Press.

[5]
Bosschere, K. D., and Jacquet, J.-M. Multi-Prolog: a Blackboard-based Parallel Logic Programming Language. Technical report, 1992.

[6]
Brogi, A. AND-Parallelism without Shared Variables. In 7th International Conference on Logic Programming Proceedings (1990).

[7]
Buffo, M., and Buchs, D. Context Coordination for the Mapping of Distributed Systems on Object-Oriented Systems. In Computers and Artificial Inteligence Proccedings (1997).

[8]
Castellani, S., and Ciancarini, P. Exploring the Coordination Space with LO. Technical report ublcs-94-6, Department of Computer Science, Bologna, 1994.

[9]
Castellani, S., Ciancarini, P., and Rossi, D. The ShaPE of ShaDE: a coordination system. Technical report ublcs-96-5, Department of Computer Science, Bologna, 1996.

[10]
Chien, A. A. Support Modularity in Highly-Parallel Programs. Research Directions in Concurrent Object-Oriented Programming .

[11]
Ciampolini, A., Lamma, E., Stefanelli, C., and Mello, P. Blackboard- and Object-based Systems via Multi-heads Clauses. In Computers and Artificial Inteligence Proccedings (1997).

[12]
Ciancarini, P. Distributed Programming with Logic Tuple Spaces. Technical report ublcs-93-7, Lab of Computer Science, University of Bologna, 1993.

[13]
Ciancarini, P., Fogli, D., and Gaspari, M. A Logic Coordination Language based on the Chemical Metaphor. Technical report ublcs-96-12, Department of Computer Science, Bologna, 1996.

[14]
Ciancarini, P., and Mascolo, C. Using a Coordination Language to Specify the Invoicing System. Technical report, Department of Computer Science, Bologna, 1996.

[15]
Cruz, J., and Ducasse, S. A Group Based Approach for Coordinating Active Objects. In Proccedings Third International Conference, Coordination 99 (1999).

[16]
Cunha, J., Ferreira, M. C., and Pereira, L. M. Programming in Delta Prolog. In 6th International Conference on Logic Programming Proccedings (1989).

[17]
Eliens, A. DLP: a Language for Distributed Logic Programming - design, semantics and implementation. PhD thesis, 1992.

[18]
Fisher, M. Representing and Executing Agent-Based Systems. In Intelligent Agents - Proceeding of the 1994 Workshop on Agent Theories, Architectures and Languages (1995), M. Wooldridge and N. R. Jennings, editors.

[19]
Geist, A., and et al. PVM 3 User's Guide and Reference Manual. Technical report ornl/tm-12187, Oak Ridge National Laboratory, USA, 1994.

[20]
Gelernter, D. Generative Communication in Linda. In ACM Transactions on Programming Languages and Systems Proceedings (1985).

[21]
Girard, J. Y. Linear Logic. In Theorical Computer Science (1987).

[22]
Hindriks, K. V., Boer, F., van der Hoek, W., and Meyer, J.-J. Semantics of Communicating Agents Based on Deduction and Abduction. In Workshop Foundations and Applications of Collective Agent Based Systems of 11th ESSLLI99 Proceedings (1999).

[23]
Holzbacher, A. A. A Software Environment for Concurrent Coordinated Programming. In Coordination Languages and Models, First Int. Conf. COORDINATION96 Proceedings (1996).

[24]
Lespérance, Y., Levesque, H. J., Lin, F., Marcu, D., Reiter, R., and Scherl, R. Foundations of a Logical Approach to Agent Programming. In Intelligent Agents II - Proceeding of the 1995 Workshop on Agent Theories, Architectures and Languages (1996), M. Wooldridge and N. R. Jennings, editors.

[25]
Lloyd, J. Foundations of Logic Programming. Springer-Verlag, editors, 1987.

[26]
Maffeis, S. The Object Group Design Pattern. In Proceedings of the USENIX Conference on Object-Oriented Technologies (1996).

[27]
MCabe, F., and Clark, K. April - Agent PRocess Interation Language. In Intelligent Agents - Proceeding of the Workshop on Agent Theories, Architectures and Languages (1994), M. Wooldridge and N. R. Jennings editors.

[28]
Minsky, N. H., and Leichter, J. Law-Governed Linda as a Coordination Model. Technical report, 1992.

[29]
M.Jacquet, J., and Monteiro, L. Extended Horn Clauses: The Framework and its Semantics. In 2d International Conference on Concurrency Theory Proceedings (1991), J.C.M. Baeten and J.F. Groote (ed.), pp. 281-297.

[30]
Papadopoulos, G. A., and Arbeb, F. Coordination Models and Languages. Technical report sen-r9834, 1998.

[31]
Pardyak, P., and Bershad, B. N. A Group Structuring Mechanism for a Distributed Object-Oriented Language. In Proceedings of 14th International Conference on Distributed Computing Systems (1994).

[32]
Pereira, L. M. Delta Prolog: A Distributed Logic Programming Language. In Proccedings of FGCS, ICOT (1984).

[33]
Thomas, S. R. PLACA, An Agent Oriented Programming Language. Technical report stan-cs-93-1487, Computer Science Department, Stanford University, Stanford, 1993.

[34]
Weerasooriya, D., and A. Rao, K. R. Design of a Concurrent Agent-Oriented Language. In Intelligent Agents - Proceeding of the 1994 Workshop on Agent Theories, Architectures and Languages (1995), M. Wooldridge and N. R. Jennings, editors.

[35]
Wiederanders, K. CSO-Prolog: A language for knowledge based object-oriented programming, distributed execution and simulation. Tech. rep., 1992.


Footnotes:

1 In this way, we are able to model the creation and activation of agent instances in the framework of the EHC model.

2 The formal semantics of level L1 of GroupLog is already defined, but its presentation is beyond the scope of this paper.

Copyright 2000 ACM

Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. To copy otherwise, to republish, to post on servers or to redistribute to lists, requires prior specific permission and or fee.
SAC 2000 March 19-21 Como, Italy
(c) 2000 ACM 1-58113-239-5/00/003>...>$5.00