SMA com SPADE – parte da solução do agente “Gerador”

Esse post é uma continuação do Implementação de SMA no Python e utilizando SPADE. Aqui eu apresento uma parte da solução do agente “Gerador” (ela cria apenas uma equação do primeiro grau).

Um primeiro detalhe é que os agentes SPADE precisam ser registrados em um servidor XMPP. Você pode rodar um servidor na sua própria máquina, mas eu recomendo usar um servidor público online. Nem todo servidor público irá aceitar o registro dos agentes (não sei o motivo). Um que eu uso é o jix.IM. O jix.IM é um servidor gratuito e você precisa criar uma conta para cada agente executando (se for criar um agente Gerador e um Resolvedor, você precisará criar duas contas).

Na linha 7 eu criei meu agente estendendo a classe Agent do SPADE. Essa classe abstrai toda a conexão com o servidor XMPP (login, troca de mensagens, etc.). Em seguida eu determino valores para a e y para a equação a*x + y, que é a equação de primeiro grau da qual o agente “Resolvedor” deve acertar o valor de x, de forma que o resultado da equação seja zero.

Esse agente tem dois comportamentos cíclicos, representados pelas funções funcao_1grau() e tipo_funcao(). Isso quer dizer que as funções ficam sempre executando. Ambas funcionam de forma parecida, onde elas ficam esperando uma mensagem e, quando recebem a mensagem, respondem. A funcao_1grau() espera como conteúdo um número e responde com o valor calculado pela equação e a tipo_funcao() responde com o tipo de função do agente Gerador (no caso, apenas a mensagem “1grau” para dizer que o agente gerou uma equação do primeiro grau).

import spade
from spade.agent import Agent
from spade.behaviour import CyclicBehaviour
from spade.template import Template
from spade.message import Message
import random

class Gerador(Agent):
    x = random.randint(-1000,1000)
    a=0
    while a == 0:
        a = random.randint(-100,100)
    y = -1 * (a*x)

    class funcao_1grau(CyclicBehaviour):
        async def run(self):
            res = await self.receive(timeout=5)
            if res:
                x = float(res.body)
                x = float( Gerador.a*x + Gerador.y )
                print("Enviou para " + str(res.sender) + " f(",res.body,")= ",x,"=>",int(x))
                msg = Message(to=str(res.sender)) 
                msg.set_metadata("performative", "inform")  
                msg.body = str(int(x))
                await self.send(msg)

    class tipo_funcao(CyclicBehaviour):
        async def run(self):
            msg = await self.receive(timeout=5)
            if msg:
                msg = Message(to=str(msg.sender))
                msg.set_metadata("performative", "inform")
                msg.body = "1grau" 
                await self.send(msg)
                print("Respondeu para" + str(msg.sender) + " com " + msg.body)


    async def setup(self):
        t = Template()
        t.set_metadata("performative","subscribe")

        tf = self.funcao_1grau()
        print("Funcao de 1o grau: ", Gerador.x)
        print("Funcao: ", Gerador.a, "x + (", Gerador.y, ")")

        self.add_behaviour(tf,t)

        ft = self.tipo_funcao()
        template = Template()
        template.set_metadata("performative", "request")
        self.add_behaviour(ft, template)

async def main():
  gerador = Gerador("aulaufsc@jix.im", "senhaAqui")
  await gerador.start()

if __name__ == "__main__":
  spade.run(main())
  

No setup() são colocados os dois comportamentos para rodar os dois comportamentos logo que o agente é criado. O comportamento da função funcao_1grau() é configurado para responder somente com mensagens que são com a performativa subscribe e a função tipo_funcao() responde apenas performativas request. Sendo assim, o agente não responde a qualquer outro tipo de performativa de mensagem e filtra qual comportamento irá executar pela performativa.

A instanciação do agente é feita no servidor jix.IM e também instancia um servidor local. É uma alternativa para acompanhar a execução do agente. O hostname é o endereço do IP do computador que está executando o agente. Considerando a configuração apresentada, se acessar o endereço http://127.0.0.1:10000/spade você terá acesso aos estados do agente.

A última linha é a linha que efetivamente faz o agente começar a executar.

Veja que o agente Gerador ainda não está completo, mas ele é um início para o testar o agente Resolvedor. Eu recomendo fazer o agente Resolvedor inicialmente chutando valores. Veja que eu rodar o script do agente Gerador é mostrada qual a equação gerada, mas essa informação não é compartilhada com o agente Resolvedor, mas você pode usar para testar seu agente.


Pode ser que ao executar o código do meu script nada apareça no prompt, nem mesmo uma mensagem de erro. Isso ocorre porque o Python encerrou o script logo depois do start(), sem dar chance de nada acontecer. Não sem bem porque isso ocorre e que configuração do Python gera isso, mas nesse caso, deve ser adicionado o seguinte código após a instrução gerador.start() (última linha do código do script acima).

await gerador.start()

while gerador.is_alive():
    try:
        time.sleep(1)
    except KeyboardInterrupt:
        gerador.stop()
        break
print("Agente encerrou!")

Logicamente que a inclusão desse novo trecho de código também exige a inclusão da biblioteca time para utilizar a instrução time.sleep(1).

Share

Uma opinião sobre “SMA com SPADE – parte da solução do agente “Gerador”

  1. Pingback: Implementação de SMA no Python e utilizando SPADE – Professor Benjamin

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.