{"id":982,"date":"2020-08-13T08:36:39","date_gmt":"2020-08-13T11:36:39","guid":{"rendered":"http:\/\/www.galirows.com.br\/meublog\/?p=982"},"modified":"2023-10-30T15:08:46","modified_gmt":"2023-10-30T18:08:46","slug":"sma-com-spade-parte-da-solucao-do-agente-gerador","status":"publish","type":"post","link":"http:\/\/www.galirows.com.br\/meublog\/blog\/sma-com-spade-parte-da-solucao-do-agente-gerador\/","title":{"rendered":"SMA com SPADE &#8211; parte da solu\u00e7\u00e3o do agente &#8220;Gerador&#8221;"},"content":{"rendered":"\n<p>Esse post \u00e9 uma continua\u00e7\u00e3o do <a href=\"http:\/\/www.galirows.com.br\/meublog\/blog\/implementacao-sma-python-spade1\/\" data-type=\"post\" data-id=\"946\">Implementa\u00e7\u00e3o de SMA no Python e utilizando SPADE<\/a>. Aqui eu apresento uma parte da solu\u00e7\u00e3o do agente &#8220;Gerador&#8221; (ela cria apenas uma equa\u00e7\u00e3o do primeiro grau).<\/p>\n\n\n\n<p>Um primeiro detalhe \u00e9 que os agentes SPADE precisam ser registrados em um servidor XMPP. Voc\u00ea pode rodar um servidor na sua pr\u00f3pria m\u00e1quina, mas eu recomendo usar um servidor p\u00fablico online. Nem todo servidor p\u00fablico ir\u00e1 aceitar o registro dos agentes (n\u00e3o sei o motivo). Um que eu uso \u00e9 o <a rel=\"noreferrer noopener\" href=\"https:\/\/jix.im\/en\/\" target=\"_blank\">jix.IM<\/a>. O jix.IM \u00e9 um servidor gratuito e voc\u00ea precisa criar uma conta para cada agente executando (se for criar um agente Gerador e um Resolvedor, voc\u00ea precisar\u00e1 criar duas contas).<\/p>\n\n\n\n<p>Na linha 7 eu criei meu agente estendendo a classe Agent do SPADE. Essa classe abstrai toda a conex\u00e3o com o servidor XMPP (login, troca de mensagens, etc.). Em seguida eu determino valores para <em>a<\/em> e <em>y<\/em> para a equa\u00e7\u00e3o <em>a*x + y<\/em>, que \u00e9 a equa\u00e7\u00e3o de primeiro grau da qual o agente &#8220;Resolvedor&#8221; deve acertar o valor de <em>x<\/em>, de forma que o resultado da equa\u00e7\u00e3o seja zero.<\/p>\n\n\n\n<p>Esse agente tem dois comportamentos c\u00edclicos, representados pelas fun\u00e7\u00f5es <em>funcao_1grau() <\/em>e <em>tipo_funcao()<\/em>. Isso quer dizer que as fun\u00e7\u00f5es ficam sempre executando. Ambas funcionam de forma parecida, onde elas ficam esperando uma mensagem e, quando recebem a mensagem, respondem. A <em>funcao_1grau()<\/em> espera como conte\u00fado um n\u00famero e responde com o valor calculado pela equa\u00e7\u00e3o e a <em>tipo_funcao()<\/em> responde com o tipo de fun\u00e7\u00e3o do agente Gerador (no caso, apenas a mensagem &#8220;1grau&#8221; para dizer que o agente gerou uma equa\u00e7\u00e3o do primeiro grau). <\/p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<pre class=\"wp-block-code\"><code lang=\"python\" class=\"language-python line-numbers\">import spade\nfrom spade.agent import Agent\nfrom spade.behaviour import CyclicBehaviour\nfrom spade.template import Template\nfrom spade.message import Message\nimport random\n\nclass Gerador(Agent):\n    x = random.randint(-1000,1000)\n    a=0\n    while a == 0:\n        a = random.randint(-100,100)\n    y = -1 * (a*x)\n\n    class funcao_1grau(CyclicBehaviour):\n        async def run(self):\n            res = await self.receive(timeout=5)\n            if res:\n                x = float(res.body)\n                x = float( Gerador.a*x + Gerador.y )\n                print(\"Enviou para \" + str(res.sender) + \" f(\",res.body,\")= \",x,\"=>\",int(x))\n                msg = Message(to=str(res.sender)) \n                msg.set_metadata(\"performative\", \"inform\")  \n                msg.body = str(int(x))\n                await self.send(msg)\n\n    class tipo_funcao(CyclicBehaviour):\n        async def run(self):\n            msg = await self.receive(timeout=5)\n            if msg:\n                msg = Message(to=str(msg.sender))\n                msg.set_metadata(\"performative\", \"inform\")\n                msg.body = \"1grau\" \n                await self.send(msg)\n                print(\"Respondeu para\" + str(msg.sender) + \" com \" + msg.body)\n\n\n    async def setup(self):\n        t = Template()\n        t.set_metadata(\"performative\",\"subscribe\")\n\n        tf = self.funcao_1grau()\n        print(\"Funcao de 1o grau: \", Gerador.x)\n        print(\"Funcao: \", Gerador.a, \"x + (\", Gerador.y, \")\")\n\n        self.add_behaviour(tf,t)\n\n        ft = self.tipo_funcao()\n        template = Template()\n        template.set_metadata(\"performative\", \"request\")\n        self.add_behaviour(ft, template)\n\nasync def main():\n  gerador = Gerador(\"aulaufsc@jix.im\", \"senhaAqui\")\n  await gerador.start()\n\nif __name__ == \"__main__\":\n  spade.run(main())\n  \n<\/code><\/pre>\n<\/div><\/div>\n\n\n\n<p>No <em>setup()<\/em> s\u00e3o colocados os dois comportamentos para rodar os dois comportamentos logo que o agente \u00e9 criado. O comportamento da fun\u00e7\u00e3o <em>funcao_1grau()<\/em> \u00e9 configurado para responder somente com mensagens que s\u00e3o com a performativa <em>subscribe <\/em>e a fun\u00e7\u00e3o <em>tipo_funcao() <\/em>responde apenas performativas <em>request<\/em>. Sendo assim, o agente n\u00e3o responde a qualquer outro tipo de performativa de mensagem e filtra qual comportamento ir\u00e1 executar pela performativa.<\/p>\n\n\n\n<p>A instancia\u00e7\u00e3o do agente \u00e9 feita no servidor jix.IM e tamb\u00e9m instancia um servidor local. \u00c9 uma alternativa para acompanhar a execu\u00e7\u00e3o do agente. O hostname \u00e9 o endere\u00e7o do IP do computador que est\u00e1 executando o agente. Considerando a configura\u00e7\u00e3o apresentada, se acessar o endere\u00e7o http:\/\/127.0.0.1:10000\/spade voc\u00ea ter\u00e1 acesso aos estados do agente.<\/p>\n\n\n\n<p>A \u00faltima linha \u00e9 a linha que efetivamente faz o agente come\u00e7ar a executar.<\/p>\n\n\n\n<p>Veja que o agente Gerador ainda n\u00e3o est\u00e1 completo, mas ele \u00e9 um in\u00edcio para o testar o agente Resolvedor. Eu recomendo fazer o agente Resolvedor inicialmente chutando valores. Veja que eu rodar o script do agente Gerador \u00e9 mostrada qual a equa\u00e7\u00e3o gerada, mas essa informa\u00e7\u00e3o n\u00e3o \u00e9 compartilhada com o agente Resolvedor, mas voc\u00ea pode usar para testar seu agente.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>Pode ser que ao executar o c\u00f3digo do meu script nada apare\u00e7a 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\u00e3o sem bem porque isso ocorre e que configura\u00e7\u00e3o do Python gera isso, mas nesse caso, deve ser adicionado o seguinte c\u00f3digo ap\u00f3s a instru\u00e7\u00e3o gerador.start() (\u00faltima linha do c\u00f3digo do script acima).<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"python\" class=\"language-python\">await gerador.start()\n\n<strong>while<\/strong> gerador.is_alive():\n    <strong>try<\/strong>:\n        time.sleep(1)\n    <strong>except<\/strong> KeyboardInterrupt:\n        gerador.stop()\n        <strong>break<\/strong>\nprint(\"Agente encerrou!\")<\/code><\/pre>\n\n\n\n<p>Logicamente que a inclus\u00e3o desse novo trecho de c\u00f3digo tamb\u00e9m exige a inclus\u00e3o da biblioteca <em>time <\/em>para utilizar a instru\u00e7\u00e3o <em>time.sleep(1)<\/em>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Esse post \u00e9 uma continua\u00e7\u00e3o do Implementa\u00e7\u00e3o de SMA no Python e utilizando SPADE. Aqui eu apresento uma parte da solu\u00e7\u00e3o do agente &#8220;Gerador&#8221; (ela cria apenas uma equa\u00e7\u00e3o do primeiro grau). Um primeiro detalhe \u00e9 que os agentes SPADE precisam ser registrados em um servidor XMPP. Voc\u00ea pode rodar um servidor na sua pr\u00f3pria [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-982","post","type-post","status-publish","format-standard","hentry","category-offtopic"],"aioseo_notices":[],"amp_enabled":true,"_links":{"self":[{"href":"http:\/\/www.galirows.com.br\/meublog\/wp-json\/wp\/v2\/posts\/982","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.galirows.com.br\/meublog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.galirows.com.br\/meublog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.galirows.com.br\/meublog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.galirows.com.br\/meublog\/wp-json\/wp\/v2\/comments?post=982"}],"version-history":[{"count":9,"href":"http:\/\/www.galirows.com.br\/meublog\/wp-json\/wp\/v2\/posts\/982\/revisions"}],"predecessor-version":[{"id":1187,"href":"http:\/\/www.galirows.com.br\/meublog\/wp-json\/wp\/v2\/posts\/982\/revisions\/1187"}],"wp:attachment":[{"href":"http:\/\/www.galirows.com.br\/meublog\/wp-json\/wp\/v2\/media?parent=982"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.galirows.com.br\/meublog\/wp-json\/wp\/v2\/categories?post=982"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.galirows.com.br\/meublog\/wp-json\/wp\/v2\/tags?post=982"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}