martes, 27 de noviembre de 2007

PFC: proceso con estados

El ciclo de vida de un agente se pude entender como una sucesión de estados. El comportamiento de un agente se puede programar con varios comportamientos o con un comportamiento compuesto continente de otros.
FSMBehaviour es uno de estos comportamientos compuestos. De manera secuencial, y definiendo transiciones entre estados, se implementa la acción que debe realizar el comportamiento. Pero FSMBehaviour carece de método action(), con lo que la implementación de estados y transiciones debe realizarse en el constructor o en su método onStart() o justo después de añadir el comportamiento en el nacimiento del agente.

public class MaquinaEstados extends FSMBehaviour
{
private static final String STATE_1 = "1";
private static final String STATE_2 = "2";
private static final String STATE_3 = "3";

public MaquinaEstados(Agent _agente)
{
super(_agente);
}

public void onStart()
{
registerFirstState(new OneShotBehaviour1(agente));
registerState(new OneShotBehaviour2(agente));
registerLastState(new OneShotBehaviour3(agente));

Los estados de un agente, con FSMBehaviour, son los distintos comportamientos que forman parte de este comportamiento compuesto.
Se definen unas constantes cómo etiquetas para identificar los estados. Hay que registrar los distintos comportamientos que componen FSMBehaviour a modo de estados, registrando cada cual cómo primer estado, último estado y estado intermedio.

registerDefaultTransition(STATE_1, STATE_2);
registerTransition(STATE_2, STATE_1, 0);
registerTransition(STATE_2, STATE_3, 1);
}
}

Para controlar el flujo de ejecución, basta con definir varias transiciones entre los estados registrados. Las transiciones puede ser por defecto - el flujo de ejecución siempre va del estado/comportamiento origen al estado/comportamiento destino - o teniendo en cuenta un valor de salida del comportamiento origen, que será devuelto por el método onEnd() de cada comportamiento. Este valor va a depender de las condiciones de ejecución que se implementen en cada estado/comportamiento.

public class OneShotBehaviour2 extends OneShotBehaviour
{
private int exitValue;
...
public void action()
{
if (true)
exitValue= 1;
else
exitValue= 0;
}
...
public int onEnd()
{
return exitValue;
}
}

sábado, 17 de noviembre de 2007

PFC: nacer y morir

En la POA con JADE, existe un agente llamado DF (Directory Facilitator) . Dicho agente se encarga de guardar la descripción y dirección de los agentes que viven en un mismo sistema. Proporciona un servicio de páginas amarillas al cual los demás agentes acceden para saber la dirección de otros y poder comunicarse entre ellos.

Cuando se crea un agente, la primera tarea que debe hacerse en su nacimiento, en su método setup(), es la de registrarse en el DF.

public class Jane extends Agent
{
...
public void setup()
{
DFAgentDescription dfd = new DFAgentDescription();
dfd.setName(this.getAID()); //una descripción con su identificador
ServiceDescription sd = new ServiceDescription();
sd.setType("agente_recomendador");
sd.setName(this.getName());
dfd.addServices(sd);
DFService.register(this, dfd);
...
}

Para registrarlo, utilizamos el método estático register(Agent, DFAgentDescription) del DF, pasándole por parámetros el tipo de agente que es (instancia de la clase que implementa) y su descripción. Y aquí ya tenemos listo al agente para ser localizado dentro del sistema.
Al terminar la aplicación, todos los agentes mueren al mismo tiempo que se cierra la JVM dónde residen todos los agentes. Pero ¿si queremos dar por terminado un agente sin tener que cerrar la JVM?
Cuando un agente termina su actividad, pasa de estado ACTIVE a DELETED, ejecuta su método interno takeDown(). En este método tenemos que quitar el agente del DF para que ningún otro se pueda comunicar con él.

...
public void takeDown()
{
...
DFAgentDescription dfd = new DFAgentDescription();
dfd.setName(this.getAID());
ServiceDescription sd = new ServiceDescription();
sd.setType("agente_recomendador");
sd.setName(this.getName());
dfd.addServices(sd);
DFService.deregister(this, dfd);
}
}

Basta con llamar al método estático deregister(Agent, DFAgentDescription) para acabar con él. La API de este método permite varias maneras de quitar del DF a un agente. Fijaros que he incluido la misma descripción para registrarlo que para quitarlo del registro. Así me aseguro que sólo ese agente va a ser eliminado.
Pero, ¿porqué no llamar a DFService.deregister(), sin parámetros? Con esta última solución eliminaría a todos los agentes que implementan la misma clase, cosa que para mi proyecto no me interesa, porque en el sistema tengo varios agentes de la misma clase y se puede dar el caso que un agente recomendador tenga que hacer cálculos mientras que otro ya ha acabado.

sábado, 10 de noviembre de 2007

PFC: entender un mensaje

Cómo un agente puede tener varios comportamientos, cada uno de ellos va a actuar según el tipo de mensajes que reciba.
Habéis leído ( o decido de la lectura) que un mensaje se lo identifica por un tipo o performativa. Con el envío y recepción de mensajes de performativas relacionadas se puede identificar una conversación entre agentes, con la cual se maneja el flujo de datos y la ejecución de algoritmos entre ellos. Por ejemplo,

CFP (Call For Proposal)
ACCEPT-PROPOSAL
REJECT-PROPOSAL
PROPOSE

son performativas que pueden ayudarnos a crear una comunicación de negociación entre agentes. Pero, ¿cómo se sabe que mensaje ha de recibir un comportamiento? Basta con declarar una variable de tipo jade.lang.acl.MessageTemplate e indicarle que patrón debe tener el mensaje que tiene que recibir. Siguiendo el ejemplo visto en el mini artículo anterior:

template= MessageTemplate.and(
MessageTemplate
.MatchConversationId("consulta_bd"),
MessageTemplate.MatchInReplyTo(mensaje.getReplyWith()));

indico al agente que el mensaje que tiene que identificar y tratar debe contener un conversationId = "consulta_bd" y que debe ser una respuesta o réplica del mensaje que le he enviado. Mirad la documentación de jade.lang.acl.MessageTemplate para más detalles.

PFC: comunicacion interagente

Uno de los puntos fuertes de la POA es la programación de mensajes. Con éstos, se establece comunicación entre agentes que estan en ejecución. A modo de conversación entre ellos, en una POA tiene que haber mensajes que se envian o se reciben por uno u otro agente, a modo de ejecución de órdenes y devolver respuestas.

Un primer agente crea un mensaje :
ACLMessage mensaje = new ACLMessage(ACLMessage.REQUEST);
mensaje.addReceiver(agente); //destinatario del mensaje
mensaje.setConversationId("consulta_bd"); //un identificador de la conversación
mensaje.setReplyWith("consulta_bd"+System.currentTimeMillis());
mensaje.setContent("te envio un mensaje"); //contenido del mensaje
myAgent.send(mensaje);

El mensaje es de tipo jade.lang.acl.ACLMessage. El destinatario de éste se define mediante la variable jade.core.AID agente, y con setContent(String msg) se indica el qué va a contener el mensaje. Los otros métodos sirven para identificar el mensaje, para quién hay que responderlo, etc.

Y para contestar a este mensaje, otro agente crea una réplica del mensaje recibido por el primer agente:
ACLMessage recibido = myAgent.receive(template); //recibe un tipo de mensaje
ACLMessage replica= recibido.createReply();
replica.setPerformative(ACLMessage.INFORM); //tipo de mensaje
replica.setContent("te envio una respuesta");
myAgent.send(replica);

Un punto a destacar de la comunicación es cómo definir el tipo de mensaje empleado. Existen varios actos comunicativos que permiten distinguir una comunicación de otra, pudiendo ser procesados, en paralelo, por varios comportamientos de un agente.