Everyone get sad when we are using ssh connection and we receive a "broken pipe" message. Multiplexing shell apps may mitigate this problem, the idea is after connect to attach to a shell resuming where exactly it stopped.
On the first connection the command, as following, will create and attach to the created shell:
$ tmux
After disconnected to get back to the earlier created shell:
$ tmux attach -t 0
To list all existing sessions:
$ tmux ls
Multi-agent Systems Programming using Jason
Blog da programação de Sistemas Multiagentes (SMA), paradigma que permite desenvolvimento de sistemas mais autônomos e flexíveis.
07 maio 2018
20 fevereiro 2018
Testando o Jason em um Sistema Operacional de Tempo Real
Para este teste foi utilizada uma Raspberry Pi3, primeiramente instalado o Raspian de forma padrão que pode ser obtido em https://www.raspberrypi.org/downloads/raspbian/. O SO será adaptado para operar em tempo real utilizando o Linux RT disponível em https://rt.wiki.kernel.org/.
Antes de habilitar o pacote de tempo real foram realizados testes usando cyclictest e uma aplicação multiagentes em JaCaMo.
pi@raspberry ~$ uname -v#1023 SMP Tue Aug 8 16:00:15 BST 2017
Foi obtido e executado o cyclictest conforme comandos e respostas a seguir (*1):
Rodando 3 vezes, obtive-se as respostas:
T: 0 ( 981) P:80 I:500 C: 100000 Min: 4 Act: 16 Avg: 14 Max: 149
T: 0 ( 1004) P:80 I:500 C: 100000 Min: 9 Act: 13 Avg: 13 Max: 43
T: 0 ( 1015) P:80 I:500 C: 100000 Min: 4 Act: 14 Avg: 14 Max: 114
A aplicação multiagentes utilizada nestes testes é baseada no desafio Goldminers onde na Raspberry é instanciado um agente que se junta a um sistema remoto e controla um robô minerador. Quando este robô encontra ouro é acionado um pino da placa que está em curto com uma entrada para leitura. O tempo entre o acionamento e a percepção através do pino é calculado através de temporizadores. A biblioteca utilizada para uso de pinos é a PI4J. Neste teste a placa estava com sistema original, inclusive com interface gráfica habilitada. Neste teste foram tomadas 70 leituras de pino. Em média o tempo entre o acionamento e a percepção foi de 754 us. O tempo mínimo foi de 147 us e o máximo de 5104 us, com desvio padrão de 1095 us.
Antes de habilitar o pacote de tempo real foram realizados testes usando cyclictest e uma aplicação multiagentes em JaCaMo.
Testes com sistema Raspbian original
Primeiramente o sistema operacional original era:pi@raspberry ~$ uname -v#1023 SMP Tue Aug 8 16:00:15 BST 2017
Foi obtido e executado o cyclictest conforme comandos e respostas a seguir (*1):
- pi@raspberry ~$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/clrkwllms/rt-tests.git
- pi@raspberry ~$ cd rt-tests/
- pi@raspberry ~/rt-test$ make all
- pi@raspberry ~/rt-test$ sudo ./cyclictest -m -t1 -p 80 -n -i 500 -l 100000
T: 0 ( 981) P:80 I:500 C: 100000 Min: 4 Act: 16 Avg: 14 Max: 149
T: 0 ( 1004) P:80 I:500 C: 100000 Min: 9 Act: 13 Avg: 13 Max: 43
T: 0 ( 1015) P:80 I:500 C: 100000 Min: 4 Act: 14 Avg: 14 Max: 114
A aplicação multiagentes utilizada nestes testes é baseada no desafio Goldminers onde na Raspberry é instanciado um agente que se junta a um sistema remoto e controla um robô minerador. Quando este robô encontra ouro é acionado um pino da placa que está em curto com uma entrada para leitura. O tempo entre o acionamento e a percepção através do pino é calculado através de temporizadores. A biblioteca utilizada para uso de pinos é a PI4J. Neste teste a placa estava com sistema original, inclusive com interface gráfica habilitada. Neste teste foram tomadas 70 leituras de pino. Em média o tempo entre o acionamento e a percepção foi de 754 us. O tempo mínimo foi de 147 us e o máximo de 5104 us, com desvio padrão de 1095 us.
Instalação do pacote Linux RT
Para facilitar, o pacote RT utilizado aqui já vem pré-compilado para o Raspbian. Portanto, para realizar a adaptação foram seguidos os seguintes passos (*1):- Na Raspberry, abrir um terminal para baixar e descompactar o kernel do Linux RT já pré-compilado:
- pi@raspberry ~$ cd /tmp
- pi@raspberry ~$ wget http://download.frank-durr.de/kernel-4.4.9-rt17.tgz
- pi@raspberry ~$ tar xzf kernel-4.4.9-rt17.tgz
- Instalar o novo kernel:
- pi@raspberry ~$ sudo rm -r /boot/overlays/
- pi@raspberry ~$ sudo rm -r /lib/firmware/
- pi@raspberry ~$ cd boot
- pi@raspberry ~$ sudo cp -rd * /boot/
- pi@raspberry ~$ cd ../lib
- pi@raspberry ~$ sudo cp -rd * /lib/
- Reiniciar o sistema e pronto!
- pi@raspberry ~$ sudo shutdown -r now
Testes com sistema Raspbian modificado para RT
O sistema passa a ser identificado como PREEMPT RT:
pi@raspberrypi:~ $ uname -v
#1 SMP PREEMPT RT Wed May 11 22:46:14 CEST 2016
Rodando pi@raspberry ~/rt-test$ sudo ./cyclictest -m -t1 -p 80 -n -i 500 -l 100000 obteve-se as seguintes respostas:
T: 0 ( 1184) P:80 I:500 C: 100000 Min: 6 Act: 14 Avg: 13 Max: 59
T: 0 ( 1212) P:80 I:500 C: 100000 Min: 6 Act: 13 Avg: 13 Max: 63
T: 0 ( 1235) P:80 I:500 C: 100000 Min: 6 Act: 14 Avg: 13 Max: 55
A mesma aplicação multiagentes baseada no desafio Goldminers foi utilizada aqui. Novamente foram tomadas 70 leituras de pino. Em média o tempo entre o acionamento e a percepção foi de 772 us. O tempo mínimo foi de 154 us e o máximo de 9729 us, com desvio padrão de 1471 us.
Conclusão
Desconsiderando que os testes realizados podem conter viés uma vez que havia muitos serviços habilitados, inclusive interface gráfica, pode-se dizer que rodando via cyclictest houve menor variação nos ciclos, mas precisaria-se estudar mais a ferramenta para concluir melhor sobre. Já nos testes com o MAS, não houve ganho de tempo de resposta com o pacote Linux RT nem tampouco maior acuracidade. Uma hipótese para esta ocorrência está no fato de que o framework JaCaMo se baseia em Java que possui processos internos, como o garbage collector, que podem anular tentativas de estabelecer precisão nos ciclos de processamento. Conforme sugerido por Bogdan, a biblioteca original pigpio escrita em C pode ser uma alternativa para melhorar estas respostas, neste caso a leitura de pinos poderia rodar em uma aplicação em C que teria característica de tempo real e uma segunda aplicação em Java, em nosso caso o Sistema Multiagente, rodar sem este compromisso.
(*1) Estes comandos se baseiam no tutorial de Frank Duerr mantendo a licença Attribution-ShareAlike 4.0 International License (CC BY-SA 4.0).
04 dezembro 2017
Rodando o Jason em uma Raspberry Pi
O Jason (ou JaCaMo) está apto a rodar na Raspberry Pi (usando o sistema operacional Raspbian) por padrão uma vez que a distribuição já traz o JRE (Java Runtime Engine). A distribuição traz também o JDK (Java Development Kit) e é possível instalar a IDE Eclipse ou mesmo rodar o JEdit (Interface que acompanha o Jason).
19 outubro 2017
Implementando Contract Net Protocol em Jason e JADE - uma comparação
Objetivo
O objetivo deste trabalho é avaliar o uso de agentes e suas linguagens para implementar o Contract Net Protocol (desafio descrito em: http://jomi.das.ufsc.br/mas/tp/tp-cnp.pdf e o protocolo em: http://www.fipa.org/specs/fipa00029/SC00029H.pdf). Este protocolo foi implementado em duas plataformas diferentes, JADE e Jason (sites oficiais: http://jason.sourceforge.net/ e http://jade.tilab.com/), onde foram criados agentes iniciadores de operações comerciais de compra de produtos, outros agentes são participantes do processo comercial que realizam propostas de venda. Há ainda um terceiro tipo de agente criado para testar a operação de recusa a um pedido de oferta. A quantidade destes agentes foi variada, criando-se diferentes cenários de testes. Estes cenários foram ensaiados utilizando projetos escritos para as plataformas mencionadas. Parâmetros quantitativos como tempo de processamento, uso de memória e tamanho do código foram obtidos. Parâmetros qualitativos como a curva de aprendizagem na implementação também foram gerados para realização de análise comparativa entre estas tecnologias. Os dados gerados e resultados destas análises serão apresentados neste relatório.Implementação em Jason
A implementação em Jason foi realizada utilizando as IDEs jEdit (que acompanha a API Jason) e eclipse (utilizando o plugin para Jason - aqui foi utilizado Jason versao 2.1 e JADE versao 4.3.3). Códigos da implementações em Jason e JADE disponíveis no apêndice deste relatório bem como no github: https://github.com/cleberjamaral/tp_cnp/). Grande parte do projeto foi feito baseando-se em um exemplo dado no livro "Programming Multi-Agent Systems in AgentSpeak Using Jason".
Foi criado um projeto simples que instancia os agentes "initiator", "participant", "rejector" e "controller". O arquivo, do tipo mas2j, especifica a insfraestrutura em que os agentes rodarão, neste caso foi utilizada a infraestrutura padrão chamada de centralizada, que trabalha com agentes rodando numa mesma máquina e mesmo espaço, o que é bastante adequado para os ensaios deste trabalho. O referido arquivo contém também a lista de agentes que serão instanciados bem como a quantidade de instâncias, desta forma pode-se criar vários agentes que compartilham o mesmo esqueleto de código porém com contextos próprios em processamentos paralelos. Além da cardinalidade, via arquivo de projeto foram geradas algumas crenças que são necessárias para os testes conforme será descrito a seguir:
- Agente initiator: Recebe do arquivo de projeto a crença de quantos participantes tem no sistema, o que será necessário para saber quantas propostas deve aguardar. Este agente possui uma lista de 4 produtos que deseja comprar, 1 deles nenhum participante tem para vender, espera-se a rejeição de todos. O agente começa enviando o pedido de "call for proposals", ou cfp, para todos os agentes e armazena através de novas crenças as propostas recebidas. Ao receber uma proposta este agente invoca um método que analiza se já recebeu todas as propostas que espera para aquele produto, em caso positivo, envia um aceite para a melhor proposta e rejeição para todas as demais. Casos de recusa de proposta também dispararam este método de deliberação. Por fim, este agente aguarda que os contratados informem que forneceram o produto em questão, se isto ocorrer para os três produtos que possuem fornecedores disponíveis (no caso 3 dos 4 que deseja), este agente informa ao agente "controlador" que finalizou suas atividades.
- Agente participant: Possui uma base com 3 produtos dos quais o initiator deseja comprar. Ao receber a mensagem "cfp" calcula um valor aleatório sobre o valor base de cada produto e envia ao solicitante (initiator). Caso não tenha o produto desejado recusa o "cfp". Por fim, possui planos para respostas a rejeição de oferta que não geram atividades extra, bem como para o aceite, que fazem disparar uma mensagem de retorno dizendo que forneceu o produto.
- Agente rejector: Envia mensagens de recusa todas as mensagens de "cfp" que recebe.
- Agente controller: agente adicional criado para controlar a quantidade de agentes ativos. Este agente recebe do projeto a quantidade de initiators instanciada esperando que a quantidade de initiators que finalizaram suas atividades seja igual a essa, desta forma invocando o método de encerramento do sistema multi agentes.
Implementação em JADE
A implementação em JADE foi realizada utilizando a IDE eclipse, foi necessário apenas adicionar a API JADE (utilizada a API JADE disponibilidade pelo pacote Jason). Foi utilizada uma classe principal chamada "StartJade" que possui um método "main" responsável por criar o container JADE e os agentes. O esqueleto deste código foi baseado em um exemplo disponibilizado para este trabalho. Cada agente foi descrito em uma classe própria que extende Agent (da API JADE). Foram criados os agentes "initiator", "participant" e "rejector". A classe principal instancia agentes através da criação destes no container principal e posterior comando de inicialização. Laços de repetição utilizando as classes originais dos agentes foram utilizados para instanciar vários agentes de mesmo tipo variando apenas seus nomes. A instanciação dos agentes dos tipos participant e rejector foram feitas antes dos agentes do tipo initiator para que quando estes enviarem o "cfp" já hajam agentes para responder. Os agentes initiators recebem na forma de argumento as quantidades de iniciadores, participantes e rejeitores que serão utilizados nas lógicas deste código.
- Agente initiator: Recebe as quantidades de agentes e possui também uma propriedade que marca a quantidade de comportamentos ativos, que representam quantos produtos ainda não foram comprados (finalizados). Na inicialização um comportamento do tipo "One Shot" é descrito na forma "inline". Este comportamento utiliza um laço verificando o Diretório de Facilidades do JADE e aguardando que todos os participantes esperados já estejam ativos (incluindo rejeitores). Quando isso ocorre os comportamentos cíclicos de comprar cada produto são criados. Dentro dos comportamentos de compra, um "cfp" é enviado a cada participante e rejeitor. Com um funcionamento de máquina de estados, após o "cfp", fica aguardando respostas. Ao receber uma proposta, inclui esta em uma lista que será analisada quando todas as propostas esperadas forem recebidas o que dá início ao processo de responder com uma aprovação e demais rejeições. Também aguarda recebimento de recusas e de informes de que o serviço foi realizado. Estes informes alteram o estado do comportamento para "feito" e atualizam a propriedade de comportamentos ativos. Um último comportamento cíclico analisa se o agente corrente já finalizou todos so comportamentos de compra, verificando também seus pares (outros agentes iniciadores). Se este agente não é o último a se encerrar, simplesmente invoca o processo de sustensão própria. Se for o último o initiator ativo, envia ao agente AMS (controlador geral do sistema JADE) uma mensagem de shutdown do sistema.
- Agente participant: Possui um catálogo de 3 produtos dos quais o initiator deseja comprar. Instancia os comportamentos de "cfp", "Aceite de proposta" e "Rejeição de proposta". Ao receber a mensagem "cfp" calcula um valor aleatório sobre o valor base de cada produto e envia ao solicitante (initiator). Caso não tenha o produto desejado recusa o "cfp". Por fim, ao receber o aceite responde que concluiu o serviço.
- Agente rejector: Recusa todas as mensagens de "cfp", neste caso, implementa os comportamentos de "cfp" e "Rejeição de proposta".
Comparação entre Jason e Jade para implementação do problema
Tempo de execução / Performance
Para análise do tempo de execução, os projetos foram implementados de forma que ao finalizarem as transações comerciais os agentes iniciadores paravam sua execução. Em jason isso foi feito através de uma mensagem enviada ao agente controlador que contou quantos agentes finalizaram, ao alcançar a quantidade definida parou o sistema. Em jade, os agentes ao concluirem as transações se auto-destruiram, cabendo ao último enviar ao AMS o comando de finalização do sistema.
O tempo foi obtido através do comando "time" em uma máquina linux\footnote{A máquina utilizada tem SO Debian GNU/Linux 8 - 64bits, com Duplo processador virtual, 2 GB de RAM rodando em infraestrutura VMWare ESXi 6} com condições de execução similares nos diferentes ensaios. Apenas uma tomada de tempo foi obtida para cada ensaio. O tempo utilizado foi o tempo "user" que representa o esforço real de processamento da tarefa, ou seja, o tempo em que o processor efetivamente ficou ocupado com aquele processo.
A coluna "nMsgs" representa a quantidade de mensagens trocadas. No caso de 60 mensagens, há uma quantidade total de 5 agentes, 2 agentes "initiators", 2 "participants" e 1 "rejector". Cada initiator realiza 4 cfp, que são respondidas por cada participant e rejector (seja para propor ou para recusar). Para cada cfp haverá um aceite que será notificado e responderá com a informação de "feito". As quantidades de agentes foram sendo dobradas até o cenário de 80 agentes. Nos cenários de 125, 175 e 275 agentes a quantidade de "participants" foi sempre de 50 e de "rejectors" sempre de 25, os demais são "initiators".
Observa-se que a plataforma Jason apresenta linearidade no aumento de tempo em relação a complexidade do sistema. Já os testes em jade apresentaram aumento no tempo de processamento mais acentuado. Ambos os sistemas estavam com a opção de imprimir mensagens das transações em tela, no caso do Jason na janela própria de depuração e no caso do JADE no console do sistema operacional. O sistema JADE foi testado também na configuração de não escrever mensagens na saída de tela, afim de verificar o impacto deste recurso. A melhora de performance foi baixa, impactando em menos de 3% do tempo final.
Ainda sobre os dados obtidos de tempo, foi feita uma análise baseada no aumento da complexidade contra o aumento de tempo que cada abordagem apresentou (Taxa de aumento - T ). As taxas foram obtidas dividindo o valor do parâmetro do cenário em questão sobre o parâmetro do cenário anterior. Neste caso, mantêm-se aqui o entendimento que o aumento de complexidade refere-se ao aumento da quantidade de mensagens trocadas. Vale ressaltar que este é apenas um dos processos importantes. Outro processo relativamente custoso é o de verificação da melhor proposta, que ocorre após se receber todas as ofertas, neste caso este processo bem como outros menores não estão sendo ponderados como elevadores de complexidade nesta análise. O que se observa é que o projeto Jason é menos sensível a elevação da quantidade de mensagens trocadas, mostrando que o esforço requerido neste processo fica mais próximo de outros esforços, o que faz com que a elevação do tempo com o aumento do número de mensagens trocadas não seja tão alta. No Jason, em média cada ponto de aumento no número de mensagens representa um fator de aumento de 0.6 no tempo de processamento (Relação - R). A relação é obtida devidindo a Taxa de complexidade geral pela taxa de elevação do tempo da tecnologia naquele cenário. No JADE, percebe-se que a troca de mensagens é uma tarefa mais custosa. Em média para cada ponto de elevação na quantidade de mensagens há um aumento de 0.8 no tempo de processamento.
Licenciamento
Tanto o Jade quanto o Jason são gratuítos e de código aberto, os frameworks estão disponiveis em https://sourceforge.net/projects/jason/files/jason/ e http://jade.tilab.com/download/jade/. Ambos são distribuídos sob licença GNU Library or Lesser General Public License version 2.0 (LGPLv2), considerada bastante permissiva pelo fato de liberar o uso inclusive para uso comercial.
Tamanho do código
Para análise do tamanho do código, foram obtidos os arquivos de código fonte que compreendem cada projeto Jason e JADE, estes arquivos foram comprimidos utilizando um compactador ZIP. O resultado em tamanho dos arquivos representa uma forma mais fiel de se analisar q quantidade de código gerado que indica esforço de programação. Obteve-se 3,1 KBytes de tamanho para o Jason e 5,9 KByes para o Jade, resultando que o código fonte Jason é 48\% menor que o JADE. Nesta comparação está se incluindo no código Jason a classe Java criada para realização da ação interna de formatação de números com duas casas decimais.
Curva de aprendizagem
- Quanto a sintaxe: Tanto Jason quanto JADE rodam em java, porém o Jason propõe uma linguagem própria para desenvolvimento do código dos agentes, a linguagem é uma extensão de AgentSpeak que usa o paradigma de programação lógica herdado do Prolog\footnote{Prolog acrônimo de Programação Lógica é uma linguagem de programação cujo paradigma é de Programação em Lógica Matemática em contraponto a outros paradigmas mais conhecidos como de Imperativo e de Orientação a Objetos.}. Este paradigma não é trivial e requer um esforço grande para adaptação. Apesar do tema ser bastante discutido na internet e explorado em livros há diferentes "dialetos" o que faz com que as soluções encontradas não sejam "plug-and-play". Ainda apesar desta certa fartura na disponibilidade de informação em linguagens baseadas em Prolog, se comparado com Java, esta disponibilidade é muito baixa. O JADE, por sua vez, utiliza a mesma sintaxe Java, requer apenas a compreensão quanto aos recursos de sua API e da abordagem AOP sobre este plataforma. Além disso, o JADE se apropria de abordagens e soluções que são cabíveis a qualquer API Java, desta forma grande parte dos problemas podem ser resolvidos sem que a solução se refira exatamente a API JADE.
- Quanto a bibliografia: Ambos tem API documentada publicamente, contam com exemplos implementados e tutoriais referenciados em seus portais (Portal Jason: http://jason.sourceforge.net/wp/ e portal JADE http://jade.tilab.com/) que são normalmente atualizados algumas vezes por ano. Ambos também possuem livros específicos (livro Jason http://jason.sourceforge.net/jBook/jBook/Home.html e livro JADE http://www.wiley.com/WileyCDA/WileyTitle/productCd-0470057475.html).
- Disponibilidade de recursos de programação: Jason e JADE podem ser invocados via linha de comando utilizando "Apache ant (http://ant.apache.org/). Na experiência deste trabalho a compilação do programa em Jason foi via ant já que o Jason cria o arquivo build.xml, facilitando este processo. No caso do JADE a bibliografia refere-se a programas exemplo onde se pode obter tal arquivo, esta abordagem não foi empregada por necessitar desta pesquisa extra. Para o JADE a compilação e testes via linha de comando ocorreram nativamente via javac e java. Importante ressaltar também que Jason por ter sintaxe própria disponibiliza a IDE jEdit que traz facilidades de desenvolvimento como o destaque em relação comandos e apontamento de falhas em código bem como dispõe de plugin para Eclipse como recursos similares. Quanto ao uso do compilador Maven (https://maven.apache.org/), apenas a plataforma JADE utiliza este recurso.
Memória utilizada
Houve dificuldade em rastrear este parâmetro pois o uso de memória forma uma curva de alocação e posterior liberação até a finalização da aplicação. A informação mais interessante seria o pico desta curva, algo que não é simples de obter via ferramentas de monitoramento de uso de memória como "ps" e "top". Foi então utilizado o framework "valgrind" que é próprio para depuração de programas (uma amostra de resposta deste comando está como apêndice deste trabalho). Dentre os recursos do pacote há a ferramenta "memcheck" que avalia o uso em blocos exibindo relatórios parciais até a finalização do programa quando exibe quanto de memória estava sendo utilizado naquele momento.
Ambos os sistemas utilizaram entre 14 e 20 MBytes de memória para os diferentes cenários (neste caso foram testados cenários com entre 5 e 40 agentes, não chegando aos 275 agentes pois estourava o buffer do valgrind). As respostas especialmente no caso do Jason apresentaram baixa variação (da ordem de KBytes) ficando sempre em torno de 15 MBytes e o JADE apresentou uma variação maior (da ordem de poucos MBytes), variando entre 14 e 20 MBytes. A pouca variação no uso de memória apesar dos diferentes cenários se deve ao fato de que o que está sendo lido é a alocação de memória que a máquina virtual (VM) Java realizou para o processo, neste caso este parâmetro é mascarado pela VM que também traz consigo todo o aparato desta estrutura. Portanto, não é seguro afirmar se um sistema ocupa mais que o outro ou tampouco se há comportamentos diferentes apenas analisando esta amostra.
Conclusão
O problema em questão trata da interação de múltiplos softwares com propósitos distintos, como o de comprador e de vendedor de produtos. Este problema poderia ser modelado utilizando Programação Orientada a Objetos (OOP), por exemplo, talvez o mais desafiador seria implementar os recursos de comunicação uma vez que estes softwares teriam que abrir canais para se comunicarem mutuamente. Utilizando o paradigma de Programação Orientada a Agentes (AOP), a questão da comunicação é parte integrante da abordagem, algo normalmente nativo, fato constatado tanto com Jason quanto JADE. O paradigma AOP, por outro lado, propõe uma visão que traz barreiras aos iniciantes nesta abordagem, como a visão de um projeto baseado em objetivos e comportamentos ou planos. Desta forma, mesmo com as dificuldades relativas a comunicação, um iniciado em OOP provavelmente não se sentiria estimulado a explorar o paradigma AOP em um projeto desta complexidade, que é baixa. Talvez em projetos de mais alta complexidade, que se apropriam de mais vantagens de AOP, se pondere mais sobre esta questão.
Em relação ao tempo total desprendido para desenvolvimento de cada projeto, acredita-se que foram equivalentes. A implementação em Jason foi a primeira a ser experimentada, apesar de ter ocorrido esforço maior deve-se desconsiderar o tempo empregado para compreender a natureza do problema, algo que não tinha relação com a ferramenta em si. Por outro lado, as implementações em Jason foram aceleradas por contarmos com suporte especializado. Em JADE não temos suporte tão acessível porém recebemos um projeto exemplo e informações básicas. Portanto, não há como dizer se uma abordagem requer menos esforço que outra, mas pode-se dizer que Jason tem uma grande barreira inicial relacionado a sua sintaxe e lógica de programar e o JADE traz os desafios de compreender esta API utilizando uma linguagem OOP (Java) para programar um sistema AOP. JADE também tem um aparato complexo, requer a criação de um container, são criados agentes sem que o programador tenha programado (como SMA e RMA), enfim, características e recursos não triviais.
Sobre as linguagens, o projeto é pequeno para se avaliar conclusivamente, porém nesta experiência pode-se observar que a abordagem de paradigma lógico pode ser mais expressivo, permitindo codificação compacta e eficaz. Porém, o Java por seu alto nível de maturidade traz inúmeras vantagens e recursos. Um exemplo foi na exibição de valores monetários em tela, recurso que se viu necessário para depuração do código. No caso do JADE bastou a utilização de método Java que permite este tipo de formatação. No caso do Jason, foi bem mais trabalhoso uma vez que foi necessário a criação de uma ação interna, que na prática é uma classe Java que foi chamada "formatCurrency.java".
Como conclusão final, ficou evidente que a utilização de Jason trouxe mais vantagens para este projeto em relação a JADE. O projeto apresentou melhor performance, ficou mais compacto e coeso. Aparentemente a manutenção e expansão do projeto Jason é também mais facilitada bem como, devido a melhor performance, tem maior escalabilidade neste contexto. O projeto JADE ainda ficou com um bug a ser resolvido relativo ao paralelismo, onde ocorre por vezes dos últimos agentes iniciadores acabaram lendo a mesma quantidade de iniciadores ativos, fazendo com que ambos se auto-destruam sem que finalizem o sistema. Este recurso é um exemplo de atividade não trivial em especial ao JADE, algo que em Jason foi resolvido de maneira mais simples, com a criação do agente Controller. No caso do JADE como há o agente SMA, tentou-se pesquisar solução neste sentido mas que não foi encontrada na pesquisa prévia, optando-se pela abordagem atual que é sensível a concorrência de dados.
Notas finais
Este estudo foi desenvolvido como um trabalho da disciplina Sistemas Multiagentes (UFSC - DAS - PPGEAS - http://pgeas.ufsc.br/) pelos alunos Cleber Jorge Amaral e Carolina Rutili de Lima em Setembro de 2017.06 setembro 2017
Creating an internal action to format number with two decimals (currency format)
This need is about how to write and show numbers in currency format and also how to create and invoke internal actions. In the case of this format, it is interesting because the method must receive a param and also return the formatted number, so it also uses unification as we will see.
Firstly, to create an internal action the easier way is by jedit where there is a button for it. It is near the buttons to create project, agent and environment. In the case of internal action a window ask for a package name, where we can give a group of actions meaning, like "format", and another field asks for an action name, I chose "formatCurrency".
After this, JEdit will create a folder called "format" with a java file called "formatCurrency.java" with a template content. Bellow the final code of the format method and some comments:
package format;
import jason.asSemantics.*;
import jason.asSyntax.*;
public class formatCurrency extends DefaultInternalAction {
private static final long serialVersionUID = 1L;
@Override
public Object execute(TransitionSystem ts, Unifier un,
Term[] args) throws Exception {
StringTerm str = new StringTermImpl(
String.format("%.2f", Float.valueOf(args[0].toString()))
);
un.unifies(str, args[1]);
return true;
}
}
As we can see, this class extends "DefaultInternalAction" overriding execute method which run when the internal action "formatCurrency" is invoked in an AgentSpeak code (a sample invoke code is shown bellow). For this example we are using the params Term[] and Unifier which represents the list o terms that the function accepts, which is here the original float number in args[0] and the result formatted string of input number with only two decimals in args[1]. The way to "write" this output is by unification as shown in the code "un.unifies(str, args[1])".
Firstly, to create an internal action the easier way is by jedit where there is a button for it. It is near the buttons to create project, agent and environment. In the case of internal action a window ask for a package name, where we can give a group of actions meaning, like "format", and another field asks for an action name, I chose "formatCurrency".
After this, JEdit will create a folder called "format" with a java file called "formatCurrency.java" with a template content. Bellow the final code of the format method and some comments:
package format;
import jason.asSemantics.*;
import jason.asSyntax.*;
public class formatCurrency extends DefaultInternalAction {
private static final long serialVersionUID = 1L;
@Override
public Object execute(TransitionSystem ts, Unifier un,
Term[] args) throws Exception {
StringTerm str = new StringTermImpl(
String.format("%.2f", Float.valueOf(args[0].toString()))
);
un.unifies(str, args[1]);
return true;
}
}
As we can see, this class extends "DefaultInternalAction" overriding execute method which run when the internal action "formatCurrency" is invoked in an AgentSpeak code (a sample invoke code is shown bellow). For this example we are using the params Term[] and Unifier which represents the list o terms that the function accepts, which is here the original float number in args[0] and the result formatted string of input number with only two decimals in args[1]. The way to "write" this output is by unification as shown in the code "un.unifies(str, args[1])".
In the code bellow, the new internal action formatCurrency is being invoked. The input valuw in this example is a constant and output variable is "Price", the one that is being unified.
!test.
+!test : true <-
format.formatCurrency(3.66667,Price);
.print("$",Price).
25 agosto 2017
A simple example using 2 agents one of them with a Java class
This examples shows 2 Jason agents interacting by internal messages and one of them has a Java class where an interface is shown. The user can interact with the agents by a button.
This project can run in Eclipse using JasonIDE plugin of by JEdit.
Project code (project.mas2j file):
MAS jasonEmbedded {
infrastructure: Centralised
agents:
a1;
a2 agentArchClass agent2;
aslSourcePath:
"src/asl";
}
Agent1 code (a1.asl file):
!start.
+!start : true
<- .print("Hello, I am here!").
+!goalPerformed[source(X)] : true
<- .send(X, achieve, beReady).
This project can run in Eclipse using JasonIDE plugin of by JEdit.
Project code (project.mas2j file):
MAS jasonEmbedded {
infrastructure: Centralised
agents:
a1;
a2 agentArchClass agent2;
aslSourcePath:
"src/asl";
}
Agent1 code (a1.asl file):
!start.
+!start : true
<- .print("Hello, I am here!").
+!goalPerformed[source(X)] : true
<- .send(X, achieve, beReady).
Agent2 code (a2.asl file):
!start.
+!start : true
<- .print("Hello, I am here!").
@doSomething
+!doSomething : true // this goal is created by the GUI of the agent
<- .print("Agent 2 is performing something.");
.send(a1, achieve, goalPerformed).
@beReady
+!beReady : true
<- .print("I am ready for the next task!").
Agen2 java class (agent2.java file):
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import jason.architecture.*;
import jason.asSyntax.ASSyntax;
import jason.asSyntax.Literal;
import javax.swing.*;
/** example of agent architecture's functions overriding */
public class agent2 extends AgArch {
JTextArea jt;
JFrame f;
JButton button;
public agent2() {
jt = new JTextArea(10, 30);
button = new JButton("Perform goal 1");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Literal goal = ASSyntax.createLiteral("doSomething");
jt.append("\n\rPerforming goal 1...");
getTS().getC().addAchvGoal(goal, null);
}
});
f = new JFrame("Agent2");
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(BorderLayout.CENTER, new JScrollPane(jt));
f.getContentPane().add(BorderLayout.SOUTH, button);
f.pack();
f.setVisible(true);
}
@Override
public void stop() {
f.dispose();
super.stop();
}
}
11 maio 2017
Listing items when these items are also lists
A way to list items which also are lists is by "nth" internal action asking for each register. Having the register another "nth" call may get the fields of the register like this:
products([
["Banana",1],
["Apple",2],
["Pinapple",2.5]
]).
!start.
+!start : products(List) <-
.length(List,LLenght);
-+listSize(0);
while(listSize(Sz) & Sz < LLenght)
{
.random(Y);
.nth(Sz,List,Item);
.nth(0,Item,Name);
.nth(1,Item,Price);
.print("Product(",Sz,"): ",Name," $",Price);
-+listSize(Sz+1);
}.
Another way is using "member" internal action which returns with each item of a list (which can be seen as a register if it is a two dimensions array):
products([
["Banana",1],
["Apple",2],
["Pinapple",2.5]
]).
!start.
+!start : products(List) <-
for (.member(Item,List)){
.random(Y);
.nth(0,Item,Name);
.nth(1,Item,Price);
.print("Product: ",Name," $",Price);
}.
Assinar:
Postagens (Atom)