EL LENGUAJE ADL

Ramón M. Gómez Labrador
Departamento de Lenguajes y Sistemas Informáticos
Junio 1.997.

 

MODELO DE AGENTE MIX.

La figura siguiente muestra esquemáticamente la estructura de un agente MIX.

Este modelo ha sido ampliado desde varios puntos de vista:

Otro aspecto importante del modelo es el ciclo de control básico, que muestra el comportamiento de un agente MIX. El siguiente pseudocódigo presenta dicho ciclo de control.

Enviar un mensaje CheckIn al agente servidor de nombre.
Esperar la respuesta.
Actualizar la base de datos interna.
Iniciar las funciones de objetivos, si existen.
REPETIR SIEMPRE:
   Buscar un mensaje nuevo en el buzón (escucha).
   SI hay mensajes pendientes:
      Seleccionar uno según la política de gestión del buzón.
      SEGÚN el tipo de mensaje
         Petición de servicio (AskForService):
            SI va a procesarse (de acuerdo con serv_policy):
               Ejecutar el método de servicio asociado.
            FIN-SI
         Petic. de servicio con coste (AskForServiceWithCost):
            SI va a procesarse (de acuerdo con serv_policy):
               Ejecutar el método de coste asociado.
            FIN-SI
         Respuesta (Answer):
            Ejecutar el método asociado.
         Objetivo o servicio no alcanzado (ErrorReport):
            Ejecutar el método asociado.
         EN-OTRO-CASO:
            Error.
      FIN-SEGÚN
   FIN-SI
FIN-REPETIR

Cada una de las 2 clases predefinidas del modelo tiene una serie de servicios fundamentales, que permiten realizar las funciones más básicas de cada agente.

Ambas clases heredan funciones de más bajo nivel de la clase Agent, como el servicio Suicide, que cierra las comunicaciones y finaliza la ejecución de un agente.

 

LA PLATAFORMA MIX.

El siguiente gráfico muestra esquemáticamente la estructura de programación de la plataforma MIX.

Para la obtención de los procesos (agentes), el traductor ADL utiliza:

 

EL LENGUAJE ADL.

Un programa ADL consta de 2 partes principales: la cabecera y la zona de definición de clases y agentes.

La cabecera de un programa ADL tiene el siguiente formato:

El cuerpo de un programa ADL consta de las definiciones de agentes, de clases de agentes y de sociedades de agentes.

El cuerpo de la declaración de agentes y de clases de agentes consta de 5 secciones:

  1. Recursos:
  2. Los recursos engloban al conocimiento estático que el programador tiene sobre las necesidades del agente. Por otro lado, el entorno engloba al conocimiento dinámico sobre los servicios que ofrecen los agentes en un momento determinado.

    Estos recursos puede ser:

        RESOURCES
           [ REQ_LIBRARIES: biblioteca1, biblioteca2, ... ]
           [ REQ_SERVICES: serv1 [ CONTRACT_POLICY método ]
                                 [ TIMEOUT real ]
                                 [ RETRIES entero ] ;
                           serv2 ... ]
           [ SUBSCRIBE_TO: grupo1, grupo2, ... ]
           [ REQ_PUBLIC_GORUPS: grupo1, grupo2, ... ]
           [ REQ_PRIVATE_GROUPS: grupo1: ag11, ag12, ... ;
                                 grupo2: ag21, ag22, ... ; ... ]
           [ REQ_ONTOLOGIES: fichero1, fichero2, ... ]
    

  3. Objetos internos:
  4. Cada agente puede tener sus objetos propios, instancias de clases C++ o de conceptos de una ontología.

        INTERNAL_OBJECTS
           obj11, obj12, ... -> clase1 | ontología1::entidad1 ;
           obj21, obj22, ... -> clase2 | ontología2::entidad2 ; ...
    

  5. Control:
  6. ADL permite modificar el bucle de control básico del agente.

        CONTROL
           [ MBOX_MANAGER: función ]
           [ SERV_POLICY : función ]
           [ DEST_POLICY : función ]
    

  7. Objetivos:
  8. Un objetivo puede definirse como una función que el agente inicia en su nacimiento. Al menos un agente de la comunidad debe tener algún objetivo.

    Atendiendo a este criterio los agentes pueden ser:
        GOALS
           objetivo1 : CONCURRENT método
                       [ IF_SUCCESS función ]
                       [ IF_FAIL función    ] ;  ...
    

  9. Servicios:
  10. Los servicios son funciones C++ que ofrece un agente a otro y que pueden ejecutarse en modo concurrente o no concurrente.

    La petición de servicio y la respuesta se realiza mediante un protocolo de paso de mensajes transparente para el usuario final. Uno de estos protocolos es el Contract Net, que requiere una función de estimación de coste para el servicio. El agente emisor elegirá la petición de menor coste.

        SERVICES
           servicio1 : [ CONCURRENT ] método
                       [ COST método ] ; ...
    

    Un método es una función que puede tomar como parámetros -tanto de entrada como de salida- mensajes con estructuras ontológicas. Su sintaxis en ADL es:

        función
           [ REQ_MSG_STRUCT ontología1 :: entidad1, ... ]
           [ ANS_MSG_STRUCT ontología1 :: entidad1, ... ]
    

 

EL LENGUAJE MIX-CKRL.

El MIX-CKRL es un subconjunto del Lenguaje para la Representación de Conocimientos Comunes CKRL 2.0. Un programa en MIX-CKRL consta de un conjunto de declaraciones de entidades. Estas entidades pueden ser:

La sintaxis del lenguaje resulta algo incómoda de expresar y es preferible estudiarla en el apartado de ejemplos.

 

NOTAS PARA PROGRAMAR SERVICIOS.

Un servicio es una rutina en C++ que toma 2 parámetros -uno de la clase servicio y otro de la clase mensaje- y que tiene el siguiente formato:

// Ficheros de inclusión.
#include <service.H>
#include <message.H>

// Formato de la función.
void nombre_servicio (Service &s, Message &m)
     {

     }

Un mensaje consta de los siguientes campos:

Para declarar en la rutina mensajes y listas de mensajes se usa el formato:

    Message m;        // m es un mensaje
    List<Message> l;  // l es una lista de mensajes

Las funciones que permiten enviar una petición son:

Para enviar una respuesta se utiliza el método SendAnswer de la clase Service:

    s.SendAnswer (m);

Para obtener la respuesta en diferido, se utiliza la función:

    int GetDeferredAnswers (List<Message> &resp, int id_resp);

MIX permite la traducción entre CKRL y C++. Una vez definida la ontología necesaria, un servicio puede tratar la estructura de datos creada.

La recepción de objetos C++ se realiza en 2 pasos:

 

EJEMPLOS.

Los siguientes ejemplos permitirán ilustrar todos los conceptos fundamentales para la programación de agentes utilizando ADL, MIX-CKRL y C++.

  1. Foo.
  2. Este es el ejemplo más sencillo. El sistema consta de un agente de páginas amarillas (servidor de nombre), un agente que gestiona el servicio foo y un agente cliente de dicho servicio y que no espera respuesta (comunicación asíncrona).

    La siguiente tabla muestra los agentes del dominio, el tipo de cada agente, los servicios que presta, los servicios que necesita de otros agentes y sus objetivos.

    Agente

    Clase de agente

    Servicio prestado

    Servicio requerido

    Objetivos

    YP_Agent

    YPAgent

         

    Foo_Agent

    BaseAgent

    Foo

       

    Client_Foo

    BaseAgent

     

    Foo

    AskForFoo

    Por último los programas.

    // foo.adl
    #DOMAIN "foo_domain"
    #YP_SERVER "arturo.lsi.us.es:6050"
    #MIX_LIBRARY "/home/ramon/tesis/mix/MIXWP1.4"
    
    AGENT YP_Agent -> YPAgent
    END YP_Agent
    
    AGENT Foo_Agent -> BaseAgent
      RESOURCES
        REQ_LIBRARIES: "foo-functions.C"
      SERVICES
        Foo: CONCURRENT foo_service
    END Foo_Agent
    
    AGENT Client_Foo -> BaseAgent
      RESOURCES
        REQ_LIBRARIES: "foo-functions.C"
        REQ_SERVICES: Foo
      GOALS
        AskForFoo: CONCURRENT AskForFoo
    END Client_Foo
    
    
    // foo-functions.C
    #include <service.H>
    #include <message.H>
    #include <MASError.H>
    
    void foo_service (Service &srv, Message &msg){
         cout << "I am the foo service" << endl;
    }
    
    

    void AskForFoo (Service &s, Message &msg){ Message m; //msg is the message requesting the service ask-for-foo received //by the agent //m is the message we send to request the foo service m.To = "Foo_Agent"; m.ServName = "Foo"; m.Body = ""; //This line is not necessary cout << "I request the foo service" << endl; if (s.AskForAsyncService(m) != SMA_SUCCESS) Error(); }

  3. Echo.
  4. Este ejemplo trata las peticiones síncronas y en diferido. Aparte del agente servidor de nombre, el sistema consta de un agente servidor -la montaña que repite el eco- y 2 agentes clientes, que permitirán observar las diferencias entre los dos métodos de petición de servicio.

    Los archivos utilizados son:

    // echo.adl
    #DOMAIN "echo_domain"
    #YP_SERVER "arturo.lsi.us.es:6050"
    #MIX_LIBRARY  "/home/ramon/tesis/mix/MIXWP1.4"
    
    AGENT YP_Agent -> YPAgent
    END YP_Agent
    
    AGENT Mountain -> BaseAgent
      RESOURCES
         REQ_LIBRARIES: "echo-functions.C"
      SERVICES
         echo: CONCURRENT Echo
    

    END Mountain AGENT Mixy -> BaseAgent RESOURCES REQ_LIBRARIES: "echo-functions.C" REQ_SERVICES : echo GOALS user_echo: CONCURRENT user_echo END Mixy AGENT Mixie -> BaseAgent RESOURCES REQ_LIBRARIES: "echo-functions.C" REQ_SERVICES : echo GOALS user_echo2: CONCURRENT user_echo_2 END Mixie // echo-functions.C #include <service.H> #include <message.H> #include <MASError.H> void Echo(Service &s, Message &msg) { Message m; cout << "ECHOOOOO: " << msg.Body << endl; m.Body = msg.Body; //Returns the input message s.SendAnswer(m); //Sends the msg to the caller }; void user_echo(Service &s, Message &msg) { Message m, m_aux; List<Message> answers; //Gets the user name cout << "Type your name and the Mountain will make an echo "; cin >> m.Body; //Asks Mountain for the echo service m.To = "Mountain"; m.ServName = "echo"; if (s.AskForSyncService(m, answers) == SMA_SUCCESS) { do { m_aux = answers.GiveCursor(); //each answer //Process the message m_aux.Show(); //Show is a method of the message class //to display the message structure } while(answers.GoNext()); } else Error(); //Invoke the standard error function }; void user_echo_2(Service &s, Message &msg) { Message m, m_aux; List<Message> answers; int ServReq_id; //Gets the user name cout << "Type your name and the Mountain will make an echo "; cin >> m.Body; //Asks Mountain for the echo service m.To = "Mountain"; m.ServName = "echo"; if (s.AskForDeferredService(m, ServReq_id)== SMA_SUCCESS) { //Now execute some actions before getting answers cout << "Service echo just requested" << endl; //Getting answers if (s.GetDeferredAnswers(answers, ServReq_id)== SMA_SUCCESS) { do { m_aux = answers.GiveCursor(); //each answer //Process the message m_aux.Show(); } while(answers.GoNext()); } else Error(); } else Error(); //Invoke the standard error function };

  5. Santa.
  6. Por último, el ejemplo que permite comprobar la traducción de CKRL a C++. El agente Santa es el encargado de repartir los juguetes a los niños. Si el niño ha sido bueno durante el año (agente Mixy), recibirá un regalo extra además del que ha pedido. Si el niño a sido malo (agente BadMixy), obtendrá carbón.

    Para representar los comportamientos se definen 2 conceptos CKRL: la carta de Navidad (Christmas_letter) y el juguete (Toy). La tabla muestra las propiedades de cada concepto.

    Concepto

    Propiedad

    Tipo

    Restricciones

    Christmas_letter

    child_name

    string

     

    age

    integer

    0-99

    good_behaviour

    Boolean

    Por defecto: true

    toy_name

    string

    Por defecto: ball

    Toy

    toy_name

    string

    Por defecto: ball

    toy_kind

    string

     

    Los ficheros utilizados son:

    // santa.ckrl
    defproperty boy_name
        range (string);
    defproperty age
        range (integer (0:99));
    defproperty good_behaviour
        range (boolean)
        default (true);
    defproperty toy_name
        range (string)
        default ("ball");
    
    defproperty toy_kind
        range(nominal(good,bad))
        default(good);
    
    defconcept Christmas_letter
        relevant boy_name, age, good_behaviour, toy_kind, toy_name;
    
    defconcept Toy
        relevant toy_kind, toy_name;
    
    
    // santa.adl
    #DOMAIN "santa_domain"
    #YP_SERVER "arturo.lsi.us.es:6050"
    #COMM_LANGUAGE ckrl
    #MIX_LIBRARY  "/home/ramon/tesis/mix/MIXWP1.4"
    #ONTOLOGY "santa.ckrl"
    
    AGENT YP_Agent -> YPAgent
    END YP_Agent
    
    AGENT Santa -> BaseAgent
      RESOURCES
        REQ_LIBRARIES: "santa-functions.C"
      SERVICES

    dispenser_gift: CONCURRENT disp_gift REQ_MSG_STRUCT SANTA::Chritsmas_letter ANS_MSG_STRUCT SANTA::Toy END Santa AGENT Mixy -> BaseAgent RESOURCES REQ_LIBRARIES: "santa-functions.C" REQ_SERVICES: dispenser_gift GOALS send_letter: CONCURRENT send_letter ANS_MSG_STRUCT SANTA::Toy END Mixy AGENT BadMixy -> BaseAgent RESOURCES REQ_LIBRARIES: "santa-functions.C" REQ_SERVICES: dispenser_gift GOALS send_letter: CONCURRENT send_letter ANS_MSG_STRUCT SANTA::Toy END BadMixy // santa-services.C #include <service.H> #include <message.H> #include <MASError.H> void disp_gift(Service &s, Message &msg) { Message m; char buffer[2000]; Christmas_letter *letterptr; Toy coal("bad","`coal`"); // coal for bad boys Toy gift, gift_extra; cout << endl << "Ho, ho, ho!! NEW LETTER" <<endl; ReceiveCKRL(msg.Body.GetString()); cout << "Ho, ho, ho!! I have received " << total_instances << " letters " << " in this message!!" << endl; if (!(strcmp(messCKRL[0].concept, "Christmas_letter"))) { letterptr = CKRL2Obj(messCKRL[0]); //messCKRL global variable if (!(letterptr->good_behaviour.GetValue())) // a letter from a bad boy { coal.SetID("COAL"); m.Body = coal.PrintCKRL(); cout << "No, no, A bad boy!! This is my answer !!" << endl; cout << m.Body << endl; s.SendAnswer(m); //Sends the msg to the caller } else // a letter from a good boy { gift.SetID("gift"); gift.toy_kind = letterptr->toy_kind; gift.toy_name = letterptr->toy_name; m.Body = gift.PrintCKRL();//Returns the input message //Another gift for all the children gift_extra.SetID("gift_extra"); m.Body += gift_extra.PrintCKRL(); cout << "Ho, ho, ho!! This is my answer (plus a bonus toy :-)!!" << endl; cout << m.Body << endl; s.SendAnswer(m); //Sends the msg to the caller } } }; void send_letter(Service &s, Message &msg) { Message m, m_aux; List<Message> answers; Toy *toyptr; Chain myname; myname = s.GetFatherName(); myname = "`"+s.GetFatherName()+"`"; // CRKL strings format "`xxxx`" Christmas_letter myletter(myname.GetString(), 1, SMA_TRUE, "good", "`Teddy_bear`"); myletter.SetID("MixyLetter"); if (myname=="`BadMixy@santa_domain`") { myletter.SetValue("good_behaviour","false"); myletter.SetID("BadMixyLetter"); } //Asks Santa for the dispenser_gif service m.To = "Santa"; m.ServName = "dispenser_gift"; m.Body = myletter.PrintCKRL(); cout << "I send my christmas letter to Santa: " << endl; m.Show(); cout << endl; if (s.AskForSyncService(m, answers)== SMA_SUCCESS){ do { m_aux = answers.GiveCursor(); //each answer //Process the message

    m_aux.Show(); //Show is a method of the message class //to display the message structure (here, the ckrl description) ReceiveCKRL(m_aux.Body.GetString()); cout << "Wow! I have received " << total_instances << " gifts from Santa!!" << endl; for (int i=0;i < total_instances; i++) { //total_instances global variable if (!(strcmp(messCKRL[i].concept,"Toy"))) { toyptr = CKRL2Obj(messCKRL[i]); cout << "the GIFT : " << toyptr->toy_name << "is " << toyptr->toy_kind.GetValue() << endl; } } } while(answers.GoNext()); } else Error(); //Invoke the standard error function };

-> Otros ejemplos.
<- Volver a estudio del MIX.