You are here

Aula 10 - CLARION e WS3D

Introdução ao CLARION [The CLARION Project]

CLARION (Connectionist Learning with Adaptive Rule Induction ON-line) is a project investigating fundamental structures of the human mind.



 

Neste experimento utilizamos o CLARION para controlar uma criatura artificial no WorldServer3D, esta atividade é um complemento das Aulas 8 e 9.

 


Atividades

O experimento consiste em desenvolver um sistema de controle (mente artificial) para a criatura do WorldServer3D utilizando o CLARION, de modo análogo ao experimento (vide Aula 7) utilizando o SOAR. Nosso desafio será semelhante ao desafio que foi proposto na implementação com o Soar.

  • Teste 1

A criatura deve obter sua meta de aquisição de jóias a partir de seu leaflet, e buscar de maneira mais rápida todas as pedras designadas e parar ao fim da tarefa. Disponibilizamos um arquivo compactado dos executaiveis [ aqui ] e outro dos fontes [ aqui ]. Para a execução via java-webstart acione ws3d e em seguida demo-clarion.  

  • Teste 2

Duas criaturas devem competir para buscar as jóias que lhes foram delegadas. Uma deverá ser controlado pelo Soar e outra pelo CLARION. Não realizamos esta parte da atividade.

O detalhamento do desenvolvimento dos dois testes segue nas seções abaixo. Porém, antes de iniciarmos a resolução propriamente dita apresentamos rapidamente o esquema do pacote Demo-CLARION (WS3D e Demo) disponibilizado no enunciado.

 


Apresentação do Demo-CLARION

A simulação Demo-CLARION utiliza o WorldServer3D (WS3D) como arena para o agente CLARION. O agente percorre a arena (anda em linha reta, orientado pela direção da visão frontal: GO_AHEAD) evitando colidir com as paredes (faz uma rotação, sempre no sentido horário: ROTATE_CLOCKWISE). A Figura 1 mostra o cenário da simulação do Demo-CLARION (Demo). Do lado esquerdo da arena do WS3D temos na parte superior: o terminal exibindo a conexão com o WS3D e na parte inferior:  os projetos associados ao DemoCLARION:

Figura 1. Cenário do Demo CLARION

 

Na Aula 7, apresentamos a estrutura e funcionalidades do WS3D. Desse modo, nesta apresentação sobre o Demo-CLARION a parte referente ao WS3D será menos detalhada. Por outro lado, a apresentação da estrutura e funcionalidades do projeto principal Demo-CLARION, vide estrutura da solução (lista dos projetos na Figura 2, destaque em vermelho, lado esquerdo da figura), será um pouco mais detalhada (o suficiente para realizar esta atividade). Comentários adicionais serão feitos ao longo do desenvolvimento dos testes propostos.

Figura 2. Projetos do Demo-CLARION

 

  • O ClarionDEMO contém a classe raiz, usa os outros dois projetos para estabelecer a comunicação entre o WS3D e o agente CLARION.
  • O WorldServerLibrary mantém as classes de comunicação (p.ex., envio de comandos) caracteriza a interface do WS3D.
  • O WorldServerAgent contém a thread do agente CLARION que atua no mundo WS3D via CLARION. O laço de execução da simulação é mantida neste projeto.

Iniciamos a apresentação comentando o Main.cs, a codificação abaixo mostra apenas o esquema: 

                          
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
using ClarionSimulation;
using WorldServerLibrary;
using WorldServerLibrary.Model;
using WorldServerLibrary.Exceptions;

namespace ClarionDEMO {

  class MainClass {

     #region properties
     private WorldServer worldServer = null;
     private ClarionAgent agent;
     String creatureId = String.Empty;
     String creatureName = String.Empty;
     double prad = 0;
     #endregion

     #region constructor
     public MainClass() {

       Console.WriteLine ("Clarion Demo V0.4");

       agent = new ClarionAgent();

       agent.OnNewVisualSensorialInformation += 
                      new InputVisualSensorialInformationEventHandler(agent_OnNewVisualSensorialInformation);
       agent.OnNewExternalActionSelected += 
                      new OutputActionChunkEventHandler(agent_OnNewExternalActionSelected);

       try {
          worldServer = new WorldServer("localhost", 4011);     
          String message = worldServer.Connect();

          if (worldServer != null && worldServer.IsConnected) {
          . . .                                                  // Veja continuação no bloco abaixo [ aqui ]

          }
       }
       . . . tratamento de exceções

     }
     #endregion

     #region Methods
     public static void Main (string[] args) {

          new MainClass();
     }

     IList<Thing> agent_OnNewVisualSensorialInformation() {

        IList<Thing> response = null;

        if (worldServer != null && worldServer.IsConnected) {
          . . . 

        }
        return response;
     }

     void agent_OnNewExternalActionSelected(ClarionAgentActionType externalAction) { 
        
        Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); // Fixa o separador decimal: "." 
        if (worldServer != null && worldServer.IsConnected) {

           switch (externalAction) {

           . . .           

           }
        }
     }
     #endregion
  }
}

               

 

No esquema acima vemos o conjunto de bibliotecas utilizadas, as duas últimas (ClarionSimulation e o WorldServerLibrary) são as que servem de base para essa atividade. Após a declaração dos elementos principais da simulação (worldServer e agent) é atribuído ao agente CLARION um sensor visual e um modo de atuar no mundo.  Com isso o agente pode ser conectado ao WS3D (com o devido tratamento de exceção, caso ocorra alguma falha na tentativa de conexão). Estabelecida a coneção o agente CLARION pode atuar no mundo. O trecho de código abaixo mostra a inicialização do mundo (com quatro paredes) e a ativação do agente (agent.Run()).

 

                     
. . . 

namespace ClarionDEMO {

  class MainClass {

       . . . 

     #region constructor
       . . . 

       try {                                             // Parte da codificação do bloco acima [ aqui ]
          worldServer = new WorldServer("localhost", 4011);
          String message = worldServer.Connect();

          if (worldServer != null && worldServer.IsConnected) {

             Console.Out.WriteLine ("[SUCCESS] " + message + "\n");
             worldServer.NewCreature(400, 200, 0, out creatureId, out creatureName);
             worldServer.NewBrick(4, 747, 2, 800, 567);
             worldServer.NewBrick(4, 50, -4, 747, 47);
             worldServer.NewBrick(4, 49, 562, 796, 599);
             worldServer.NewBrick(4, -2, 6, 50, 599);

             if (!String.IsNullOrWhiteSpace(creatureId)) {

                worldServer.SendStartCamera(creatureId);
                worldServer.SendStartCreature(creatureId);
             }
             Console.Out.WriteLine("Creature created with name: " + creatureId + "\n");
             agent.Run();
             Console.Out.WriteLine("Running Simulation ...\n");
          }
       }
       catch (WorldServerInvalidArgument invalidArtgument) {

          Console.Out.WriteLine(String.Format("[ERROR] Invalid Argument: {0}\n", 
                                              invalidArtgument.Message));
       }
       catch (WorldServerConnectionError serverError) {

          Console.Out.WriteLine(String.Format("[ERROR] Is is not possible to connect to server: {0}\n", 
                                              serverError.Message));
       }
       catch (Exception ex) {

          Console.Out.WriteLine(String.Format("[ERROR] Unknown Error: {0}\n", ex.Message));
       }
     }
     #endregion

     . . . 

}             
                                               

 

O trecho de codificação abaixo mostra que as ações do agente (ações visíveis no mundo) se restringem a mover-se para a frente ou rotacionar de acordo com a informação que recebe do sensor visual.  

                                         
  . . . 

namespace ClarionDEMO {

  class MainClass {

     . . . 

     #region Methods                                // Parte da codificação do bloco acima [ aqui ]
     public static void Main (string[] args) {

          new MainClass();
     }

     IList<Thing> agent_OnNewVisualSensorialInformation() {

        IList<Thing> response = null;

        if (worldServer != null && worldServer.IsConnected) {

           response = worldServer.SendGetCreatureState(creatureName); // Veja em WorldServerLibrary
           prad = (Math.PI / 180) * response.First().Pitch;
           while (prad > Math.PI) prad -= 2 * Math.PI;
           while (prad < - Math.PI) prad += 2 * Math.PI;
        }
        return response;
     }

     void agent_OnNewExternalActionSelected(ClarionAgentActionType externalAction) { 
        
        Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
        if (worldServer != null && worldServer.IsConnected) {

           switch (externalAction) {

              case ClarionAgentActionType.DO_NOTHING:
                 // Do nothing as the own value says
                 break;
 
              case ClarionAgentActionType.ROTATE_CLOCKWISE:             // Rotaciona para evitar colisão
                 double newprad = prad + Math.PI/1000;                  // está associada a 
                 while (newprad > Math.PI) newprad -= 2 * Math.PI;      // NewExternalActionChunk
                 while (newprad < - Math.PI) newprad += 2 * Math.PI;    // declarada no ClarionAgent.cs 
                 worldServer.SendSetAngle(creatureId, 0, 0, newprad);   
                 break;

              case ClarionAgentActionType.GO_AHEAD::                    // Move para frente ... 
                 worldServer.SendSetAngle(creatureId, 1, 1, prad);      // também está ssociada a 
                 break;                                                 // NewExternalActionChunk
   
              default:
                 break;
           }
        }
     }
     #endregion
  . . . 

}          
                              

 

A informações do sensor visual são tratas pela classe ClarionAgent, no namespace ClarionSimulation (veja em ClarionAgent.cs no projeto WorldServerAgent.  Isto é, as ações rotacionar e mover para frente são tratadas na classe ClarionAgent. O trecho de código abaixo mostra como ocorre parte do tratamento: estabelece a forma da representação das informações sensoriais capturadas, define quais as ações do agente, as informações iniciais, descreve as ocorrências inicial e final do ciclo cognitivo e, por fim, fornece as ExternalActionChunks associadas às ações do agente. 

             
namespace ClarionSimulation {

    // As informações visuais (na forma de lista) são fornecidas no início de cada ciclo cognitivo. 
    // Este delegate está associado ao SendGetCreatureState (veja em WorldServerLibrary). 
    // Armazena (recebe) o estado atual do agente CLARION
    public delegate IList<Thing> InputVisualSensorialInformationEventHandler();

    // As ações externas escolhidas são disparadas ao fim de cada ciclo cognitivo 
    // Este delegate está associado ao envio de comandos: o agete o cria para envio de comandos
    // Veja um exrmplo do esquema de um comando em WorldServerLibrary. 
    public delegate void OutputActionChunkEventHandler(ClarionAgentActionType externalAction);

    // Abaixo estão todas as ações que o agente pode executar (similar ao tratamento feito no Soar).
    public enum ClarionAgentActionType {
        DO_NOTHING,                             
        ROTATE_CLOCKWISE,
        GO_AHEAD
    }
    public class ClarionAgent {

        #region Constants
        // Captura informação do sensor visual
        private String SENSOR_VISUAL_DIMENSION = "VisualSensor";

        // Captura uma das paredes (a frontal)
        private String DIMENSION_WALL_AHEAD = "WallAhead";
        #endregion

        . . .  

        #region Agent
        // O agente CLARION 
        private Clarion.Framework.Agent CurrentAgent;

        // Para cada ciclo cognitivo, o agente atualiza as informações sensoriais correntes
        public event InputVisualSensorialInformationEventHandler OnNewVisualSensorialInformation;

        // Para cada ciclo cognitivo, o agente seleciona uma ação
        public event OutputActionChunkEventHandler OnNewExternalActionSelected;
        #endregion

        #region Perception Input
        /// Perception input to indicates a wall ahead
        private DimensionValuePair InputWallAhead;
        #endregion

        #region Action Output
        /// Ações externas: rotação e mover para frente
        private ExternalActionChunk OutputRotateClockwise;
        private ExternalActionChunk OutputGoAhead;
        #endregion
 
        #region Constructor
        public ClarionAgent()  {
          // Inicializa: o agente, as informações capturadas e as ações (rotação e mover p/ frente)
          CurrentAgent = World.NewAgent("Current Agent");
          InputWallAhead = World.NewDimensionValuePair(SENSOR_VISUAL_DIMENSION, DIMENSION_WALL_AHEAD);
          OutputRotateClockwise = 
                       World.NewExternalActionChunk(ClarionAgentActionType.ROTATE_CLOCKWISE.ToString());
          OutputGoAhead = World.NewExternalActionChunk(ClarionAgentActionType.GO_AHEAD.ToString());

          // Cria a thread para a simulação
          runThread = new Thread(RunThread);
          Console.WriteLine("Agent started");
        }
        #endregion

        . . .  

}          
                               

 

O último trecho do código acima cria a thread para a simulação, o laço principal está descrito na codificação abaixo: 

                 
namespace ClarionSimulation {

        . . .  

        #region Public Methods
        // Executa a simulação no WS3D
        public void Run() {                
            Console.WriteLine ("Running ...");

            // Ativa o agente CLARION
            if (runThread != null && !runThread.IsAlive) {

                SetupAgentInfraStructure();

                if (OnNewVisualSensorialInformation != null) {

                    // Dispara a thread da simulação                
                    runThread.Start(null);
                }
            }
        }
        #endregion

        . . .  

}
                            

 

O ciclo cognitivo é descrito na codificação abaixo, antes do laço do ciclo são declaradas as Fixed Rules (ruleGoAhead e ruleAvoidCollisionWall), veja maiores comentários no tópico ACS da Aula 8.  

                       
namespace ClarionSimulation {

        . . .  

        #region Delegate Methods
        #region Fixed Rules
        private double FixedRuleDelegateToAvoidColissionWall(ActivationCollection currentInput, 
                                                             Rule target)  {

          // Estabelece a lógica para o avoid_collision, a ativação ocorre sempre que houver um  
          // obstáculo num perímetro mínimo
           return ((currentInput.Contains(InputWallAhead, CurrentAgent.Parameters.MAX_ACTIVATION))) ? 1.0 : 0.0;
        }

        private double FixedRuleDelegateToGoAhead(ActivationCollection currentInput, Rule target) {

          // Estabelece a lógica do go_ahead. Note que o valor de ativação é o contrário da fixed
          // rule acima. Estas duas funções são reguladas pela SupportCalculator (vide bloco abaixo).  
           return ((currentInput.Contains(InputWallAhead, CurrentAgent.Parameters.MIN_ACTIVATION))) ? 1.0 : 0.0;
        }
        #endregion

        #region Run Thread Method
        private void RunThread(object obj) {

            Console.WriteLine("Starting Cognitive Cycle ... press CTRL-C to finish !");

            // Ciclo cognitivo:  grosso modo, mantém a seqüência Agent.Perceive(si), 
            // ExternalActionChunk chosen = Agent.GetChosenExternalAction(si). 
            // O ciclo tem início com a captura das informações sensoriais
            while (CurrentCognitiveCycle != MaxNumberOfCognitiveCycles) {
   
                // Captura os dados sensoriais corrente, interpreta-os e os torna informação perceptual
                IList<Thing> sensorialInformation = OnNewVisualSensorialInformation();
                SensoryInformation si = MakePerceptionFromSensorialInput(sensorialInformation);
                CurrentAgent.Perceive(si); // si é objeto do tipo SensoryInput com informação sensorial.

                // (1) escolhe uma ação, (2) pega a ção selecionada e (3) executa
                ExternalActionChunk chosen = CurrentAgent.GetChosenExternalAction(si);

                String actionLabel = chosen.LabelAsIComparable.ToString();
                ClarionAgentActionType actionType = 
                   (ClarionAgentActionType)Enum.Parse(typeof(ClarionAgentActionType), actionLabel, true);

                if (OnNewExternalActionSelected != null)  {

                    OnNewExternalActionSelected(actionType);
                }

                // incremento do número de ciclos cognitivos e tempo para o agente terminar sua tarefa
                CurrentCognitiveCycle++;
                if (TimeBetweenCognitiveCycles > 0) { 

                    Thread.Sleep(TimeBetweenCognitiveCycles);
                }
            }
        }
        #endregion
        #endregion
        . . .  

}          
                   

 

Finalmente, no trecho de código abaixo temos a configuração da infra-estrutura do agente CLARION. Evidentemente, a base é o subsistema  ACS (vide Aula 8).

                  
namespace ClarionSimulation {

        . . .  

        #region Setup Agent Methods
        //Configura a infra-estrutura (ACS, NACS, MS e MCS) do agente. Abaixo temos o subsistema ACS
        private void SetupAgentInfraStructure() {

            SetupACS();                    
        }

        private void SetupMS() {
            
            //RichDrive
        }

        // Configuração do ACS
        private void SetupACS() {

          // Cria as regras para "Colission-Wall" e "Go Ahead"
          SupportCalculator avoidCollisionWallSupportCalculator = FixedRuleDelegateToAvoidColissionWall;
          SupportCalculator goAheadSupportCalculator = FixedRuleDelegateToGoAhead;
          FixedRule ruleAvoidCollisionWall = AgentInitializer.InitializeActionRule(CurrentAgent, 
                                                               FixedRule.Factory, 
                                                               OutputRotateClockwise, 
                                                               avoidCollisionWallSupportCalculator);
          FixedRule ruleGoAhead = AgentInitializer.InitializeActionRule(CurrentAgent, FixedRule.Factory, 
                                                                        OutputGoAhead, 
                                                                        goAheadSupportCalculator);

          // Agrega as regras ao agente (no ACS)
          CurrentAgent.Commit(ruleAvoidCollisionWall);             
          CurrentAgent.Commit(ruleGoAhead);

          // Desativa a regras de refinamento 
          CurrentAgent.ACS.Parameters.PERFORM_RER_REFINEMENT = false;

          // Estabelece a forma de seleção: probabilística
          CurrentAgent.ACS.Parameters.LEVEL_SELECTION_METHOD = 
                                            ActionCenteredSubsystem.LevelSelectionMethods.STOCHASTIC;

          // A seleção da ação é fixa, definida acima.
          CurrentAgent.ACS.Parameters.LEVEL_SELECTION_OPTION = 
                                            ActionCenteredSubsystem.LevelSelectionOptions.FIXED;

          // Estabelece os valores probabilísticos
          CurrentAgent.ACS.Parameters.FIXED_FR_LEVEL_SELECTION_MEASURE = 1;
          CurrentAgent.ACS.Parameters.FIXED_IRL_LEVEL_SELECTION_MEASURE = 0;
          CurrentAgent.ACS.Parameters.FIXED_BL_LEVEL_SELECTION_MEASURE = 0;
          CurrentAgent.ACS.Parameters.FIXED_RER_LEVEL_SELECTION_MEASURE = 0;
        }

        // O agente interpreta os dados sensoriais em informação (conhecimento)
        // <param name="sensorialInformation"> Informação fornecida pelo mundo 
        /// <returns> Informação sensória 
        private SensoryInformation MakePerceptionFromSensorialInput(IList<Thing> sensorialInformation) {

            // Informação sensorial corrente 
            SensoryInformation si = World.NewSensoryInformation(CurrentAgent);

            // Detecta se há uma parede à frente
            Boolean wallAhead = 
                    sensorialInformation.Where(item => (item.CategoryId == Thing.CATEGORY_BRICK && 
                                               item.DistanceToCreature <= 61)).Any();
            double wallAheadActivationValue = 
                         wallAhead ? CurrentAgent.Parameters.MAX_ACTIVATION : CurrentAgent.Parameters.MIN_ACTIVATION;
            si.Add(InputWallAhead, wallAheadActivationValue);

            return si;
        }
        #endregion

        . . .  

}
                    

 

Grosso modo, é esse o esquema do agente CLARION: começa na classe SensoryInput (pega o estado do mundo via OnNewVisualSensorialInformation()) e cria objetos que funcionam como sensory input (a SensoryInformation: entrada do ciclo cognitivo via MakePerceptionFromSensorialInput()). Os objetos correspondem aos DimensionValuePair, por exemplo, o InputWallAhead cuja ativação é definida pelo MakePerceptionFromSensorialInput(). A percepção do SensoryInformation (o entendimento), que ocorre via CurrentAgent.Perceive(si), permite ao agente buscar uma ação externa (via CurrenteAgent.GetChosenExternalAction(si)) e convertê-la em comando para a performance do agente no ambiente WS3D (via OnNewExternalActionSelected(), isto é, termina na classe ExternalActionChunk que cria um objeto para cada ação possível). Esse esquema está resumido na Figura 3, já apresentada na Aula 8.

Figura 3: Estrutura de uma aplicação básica do CLARION:

 

A seguir, expomos de modo muito breve um trecho do código do WorldServer.cs que mostra uma parte da interface do agente com o WS3D. A codificação abaixo exibe dois exemplos do esquema de troca de mensagens: uma via comandos (Creature Command Methods, por exemplo o setGoTo) e outra pelo estado corrente do agente (via SendGetCreatureState).

                                
. . . 

namespace WorldServerLibrary {                  
 
   public class WorldServer:IDisposable{                  
         
        . . . 

        #region Creature Command Methods

        // Esta estrutura está associada ao delegate declarado no ClarionSimulation 
        public string SendSetGoTo(string creatureId, double vr, double vl, double x, double y) {

            String response = String.Empty;

            try {

                // Prepara a mensagem
                StringBuilder builder = new StringBuilder();
                builder.Append("setGoTo ");
                builder.Append(creatureId);
                builder.Append(" ");
                builder.Append(vr);
                builder.Append(" ");
                builder.Append(vl);
                builder.Append(" ");
                builder.Append(x);
                builder.Append(" ");
                builder.Append(y);

                // Envia a mensagem
                SendMessage(builder.ToString());

                // Lê a resposta
                response = ReadMessage();
            }

        . . .  
    
        // Envia o status do agente -- veja no MainClass do ClarionDEMO 
        // Esta estrutura está associada ao delegate declarado no ClarionSimulation 
        public List<Thing> SendGetCreatureState(string creatureId) {  

            List<Thing> returnDic = null;
            try {
                // Prepara a mensagem
                StringBuilder builder = new StringBuilder();
                builder.Append("getcreaturestate ");
                builder.Append(creatureId);

                // Envia a mensagem
                SendMessage(builder.ToString());

                // Lê a resposta
                String response = ReadMessage();

                // Parser da resposta
                returnDic = ParseGetCreatureStateResponse(response, new String[]{"||"} );
            }
           . . .  

   }                   
}
                   

 

Utilizamos o DemoCLARION como base para o desenvolvimento do Teste 1.

 


Desenvolvimento do Teste 1

Conforme discussões no laboratório, é necessário efetuar alguns ajustes no WS3D para o desenvolviemtno da Atividade: Teste 1. O Eduardo Jucá fez esses ajustes e disponibilizou uma versão jnlp funcional do WS3D [ aqui ] com seu respectivo código fonte [ aqui ].  Utilizamos nesta atividade a versão do Eduardo Jucá.

Neste teste, o agente (a criatura no WS3D) deve:

  • obter sua meta de aquisição de jóias a partir de seu leaflet
  • buscar de maneira mais rápida todas as pedras designadas
  • parar ao fim da tarefa. 

Assim como no experimento do Soar-WS3D (Aula 7), o agente CLARION deve coletar jóias da arena de acordo com os leaflets que recebe. Como o agente gasta energia ao longo do tempo, ele deve fazer recargas de energia (consumir alimentos) sempre que o nível de energia chegar a um determinado limite. A estrutura do bot é como segue: 

  • Os sensores do bot são visuais (os mesmos do agente do Demo-CLARION).
  • As ações do bota se restringem a (1) desviar de paredes, (2) mover-se em direção à (jóia ou alimento), (3) recarregar energia (comer) e (4) capturar jóias. 

A partir dessa descrição do bot estabelecemos uma estrutura CLARION cujo comportamento satisfaça o comports desejado.

 

Estrutura Geral do bot CLARION

Na estrutura aqui proposta, o bot possui duas características que podem ser consideradas primárias:

  • fome: característica associada à necessidade de reposição de energia, ocorre quando o nível de "combustível" está abaixo de um determinado limite (300 unidades de medida),  
  • sensação de perigo físico: associada ao risco iminente de colisão com alguma parede, ocorre quando a distância entre o bot e a parede é muito pequena (60 unidades de medida).

Nessa implementação, o bot "nasce sabendo" identificar os objetos que compõem o ambiente: comida, parede e jóias. O comportamento referente à coleta de jóias, de acordo com os leaflets, está associado a uma forma de conhecimento explícito, representado por regras e chunks. Nesse experimento, os módulos meta-cognitivos estão associados somente aos drives relacionados às características primárias.

O comportamento referente à captura de jóias está associado ao conhecimento explítico mantido no nível superior (top level) de cada subsistema que compõe a estrutura do bot CLARION, formado por regras e chunks. As regras incluem as action rules (ACS) e as associative rules (NACS). Os chunks estão envolvidos na representação dessas regras, descrevendo as condições e as conclusões das regras, são coleções de DV-pares que representam ou condições ou ações (no top level). Desse modo, a partir das entradas sensoriais e das ações são criadas estruturas internas do ACS que serão tratadas no topo-level (por regras), isto é, as ações do agente são determinadas por FixedRules, veja [ aqui ].

A seguir expomos trechos das codificações das duas partes: da que controla o comportamento do agente em relação às suas necessidades primária e da que determina as ações do agente em relação à coleta das jóias.  

 

Esquema do controle do comportamento em relação às necessidades primárias:

Para esta parte seguimos o tutorial Intermediate MS and MCS Setup, com especial atenção ao uso efetivo de DRIVES:

"Drives use factors from both the internal and external state information (located within the SensoryInformation object) to transform them into a “drive strength” (i.e., the amount of activation for a drive). However, without mechanisms to process these drive strengths and make decisions based upon them, the drives alone will have little effect on the overall operation of an agent. Therefore, we rely on meta-cognitive modules to make decisions based upon these drives strengths (as well as other factors) and to initiate a variety of internally-directed meta-cognitive actions."

Iniciamos declarando um agente cuja estrutura subjacente é a do framework CLARION:

                            
  . . .

#region Agent
  // The agent 
  private Clarion.Framework.Agent CurrentAgent;

  // For each cognitive cycle, this event will be called in order to the agent receives the 
  // current sensorial information
  public event InputVisualSensorialInformationEventHandler OnNewVisualSensorialInformation;

  // For each cognitive cycle, this event will be called when the agent selects one action
  public event OutputActionChunkEventHandler OnNewExternalActionSelected;

  private Creature creature = null;
#endregion Agent

  . . .
           
                       

 

Definimos alguns elementos básicos (constantes e pares DV) e seguimos com a construção do agente:

                           
  . . .

public class ClarionAgent {

    #region Constants
     // Constants: represents the "visual sensor dimension" and objects ahead
     private String SENSOR_VISUAL_DIMENSION = "VisualSensor";
     private String DIMENSION_FOOD_AHEAD = "FoodAhead";
     private String DIMENSION_WALL_AHEAD = "WallAhead";

     // Food stimulus: minimum fuel level 
     private double FUEL_MIN = 300.0;

     // Wall avoidance stimulus: minimum distance 
     private double DIST_MIN = 60.0;
     . . .

     #endregion Constants

  . . .

}
  . . .
           

 

                                     
  . . .
             
#region Simulation
  . . .
  
  //Environment Information about food: Input/Output
  DimensionValuePair InputFood;
  DimensionValuePair InputWall;

  ExternalActionChunk OutputEatFood;
  ExternalActionChunk OutputAvoidWall;

  // Goal Chunk 
  GoalChunk GoalEatFood = World.NewGoalChunk(EAT);      // Vide ações do agente em ClarionAgentActionType 
  GoalChunk GoalAvoidWall = World.NewGoalChunk(ROTATE_CLOCKWISE);   // Idem
#endregion Simulation

  . . .
                  

 

Aqui fazemos uma observação, em parte exposta na Aula 8, cada drive no MS está associado a metas. Os drive strengths inflenciam na determinação dos goal strengths, cada drive strenght i é uma função linear: dsi = (ai )(stimulusi)(deficiti) + (bi ), com ai e bi parâmetros de influência sobre o estímulo corrente  e o déficit percebido. Esse mecanismo está embutido no GoalSelectionEquation.

         
  . . .
                    
#region Constructor
public ClarionAgent()  {

   // Initialize the agent
   CurrentAgent = World.NewAgent("Marvin The Martian");

   . . .
   // ACS Module: Goals 
   SimplifiedQBPNetwork net = 
           AgentInitializer.InitializeImplicitDecisionNetwork(CurrentAgent, SimplifiedQBPNetwork.Factory);
  
   // Add inputs and output to QBPNet 
   net.Input.Add(InputFood); 
   net.Input.Add(GoalEatFood); 
   net.Input.Add(InputWall); 
   net.Input.Add(GoalAvoidWall); 

   net.Output.Add(OutputEatFood);    
   net.Output.Add(OutputAvoidWall);    
  
   // Learning rate, agent commit with QBPNet and rule refinament for action rule   
   net.Parameters.LEARNING_RATE = 1;  
 
   CurrentAgent.Commit(net); 

   RefineableActionRule.GlobalParameters.INFORMATION_GAIN_OPTION = RefineableActionRule.IGOptions.PERFECT;

   // MS Module: Drives and Drive Equation:: Food and Wall drive. Also, drive equation. 
   // FoodDrive type: BAS drive, WallDrive type: Bis drive
   FoodDrive foodDrive = AgentInitializer.InitializeDrive(CurrentAgent, FoodDrive.Factory, .5); 
   AvoidingPhysicalDangerDrive wallDrive = AgentInitializer.InitializeDrive(CurrentAgent, 
                                                                 AvoidingPhysicalDangerDrive.Factory, .5); 

   DriveEquation foodEquation = AgentInitializer.InitializeDriveComponent(foodDrive, 
                                                                         DriveEquation.Factory);

   DriveEquation wallEquation = AgentInitializer.InitializeDriveComponent(wallDrive, 
                                                                         DriveEquation.Factory);

   foodDrive.Commit(foodEquation);
   CurrentAgent.Commit(foodDrive);
   wallDrive.Commit(wallEquation);
   CurrentAgent.Commit(wallDrive);
   
   // MCS Module: Goal selection module          
   GoalSelectionModule gsm = AgentInitializer.InitializeMetaCognitiveModule(CurrentAgent, 
                                                                   GoalSelectionModule.Factory);
   
   // Goal Selection: combine goal strengths
   GoalSelectionEquation gse = AgentInitializer.InitializeMetaCognitiveDecisionNetwork(gsm, 
                                                                 GoalSelectionEquation.Factory);
   // Make goal recommendations for the goal structure based  
   gse.Input.Add(foodDrive.GetDriveStrength());    
   gse.Input.Add(wallDrive.GetDriveStrength());    

   // Goal Selection Equation: provide information to GoalSelectionModule
   GoalStructureUpdateActionChunk goalActFood = World.NewGoalStructureUpdateActionChunk();
   GoalStructureUpdateActionChunk goalActWall = World.NewGoalStructureUpdateActionChunk();

   // update the goals in MS subsystem
   goalActFood.Add(GoalStructure.RecognizedActions.SET_RESET, GoalEatFood); 
   goalActWall.Add(GoalStructure.RecognizedActions.SET_RESET, GoalAvoidWall); 

   //Add output, set relevance and commit
   gse.Output.Add(goalActFood);
   gse.Output.Add(goalActWall);

   gsm.SetRelevance(goalActFood, foodDrive, 1); 
   gsm.SetRelevance(goalActWall, wallDrive, 1); 

   gsm.Commit(gse);
   CurrentAgent.Commit(gsm);

   CurrentAgent.MS.Parameters.CURRENT_GOAL_ACTIVATION_OPTION = 
                                                       MotivationalSubsystem.CurrentGoalActivationOptions.FULL;
    . . .

}
   . . .
     
          

 

O próximo trecho refere-se à construção da percepção do agente referente aos objetos food e wall: conversão dos dados sensoriais em informação: 

                           
  . . .
            
private SensoryInformation MakePerceptionFromSensorialInput(IList<Thing> sensorialInformation) {       

   // New sensory information
   SensoryInformation si = World.NewSensoryInformation(CurrentAgent);

   // Stimulus for foodDrive and wallDrive 
   si[typeof(FoodDrive), FoodDrive.MetaInfoReservations.STIMULUS] = creature.Fuel < FUEL_MIN ? 1 : 0;

   Boolean wallAhead = sensorialInformation.Where(item => (item.CategoryId == Thing.CATEGORY_BRICK && 
                                                           item.DistanceToCreature <= DIST_MIN)).Any();
   si[typeof(AvoidingPhysicalDangerDrive), AvoidingPhysicalDangerDrive.MetaInfoReservations.STIMULUS] = 
                                                            wallAhead ? 1 : 0;

   //creature.Fuel<300?CurrentAgent.Parameters.MAX_ACTIVATION:CurrentAgent.Parameters.MIN_ACTIVATION;
   double foodActivationValue = creature.Fuel < FUEL_MIN ? CurrentAgent.Parameters.MAX_ACTIVATION : 
                                                                             CurrentAgent.Parameters.MIN_ACTIVATION;
   double wallActivationValue = wallAhead ? CurrentAgent.Parameters.MAX_ACTIVATION : 
                                                                             CurrentAgent.Parameters.MIN_ACTIVATION;

   si.Add(InputFood, foodActivationValue);
   si.Add(InputWall, wallActivationValue);

   return si;
}
  . . .
      


Finalmente, o método para executar a thread. O trecho abaixo contém somente a parte referente às ações (EAT e ROTATE_CLOCKWISE) sobre fome e evitar colisões:           

                         
   . . .

namespace ClarionSimulation {

    // As informações visuais (na forma de lista) são fornecidas no início de cada ciclo cognitivo. 
    // Armazena (recebe) o estado atual do agente CLARION
    public delegate IList<Thing> InputVisualSensorialInformationEventHandler();

    // As ações externas escolhidas são disparadas ao fim de cada ciclo cognitivo 
    // Este delegate está associado ao envio de comandos: o agete o cria para envio de comandos
    public delegate void OutputActionChunkEventHandler(ClarionAgentActionType externalAction);

    // Abaixo estão todas as ações que o agente pode executar (similar ao tratamento feito no Soar).
    public enum ClarionAgentActionType {
        DO_NOTHING,                             
        ROTATE_CLOCKWISE, // Assosiado ao GoalChunk   - avoid wall
        EAT,                // Assosiado ao GoalChunk   - eat food
        GO_AHEAD,         // Associado ao esquema de controle análogo ao do DemoCLARION 
        GET,              // Idem
        DELIVER,          // Idem
        DIE               // Idem
   } 

  . . .

  #region Run Thread Method
  private void RunThread(object obj) { 

    // Set environment (initialization) and output chunk
    InputFood = World.NewDimensionValuePair(SENSOR_VISUAL_DIMENSION, "Food");
    OutputEatFood = World.NewExternalActionChunk(ClarionAgentActionType.EAT.ToString());
    OutputEatFood.Add (World.NewDimensionValuePair("type", ClarionAgentActionType.EAT.ToString()));

    InputWall = World.NewDimensionValuePair(SENSOR_VISUAL_DIMENSION, "Wall");
    OutputAvoidWall = World.NewExternalActionChunk(ClarionAgentActionType.ROTATE_CLOCKWISE.ToString());
    OutputAvoidWall.Add (World.NewDimensionValuePair("type", 
                                                  ClarionAgentActionType.ROTATE_CLOCKWISE.ToString()));

    // Cognitive Cycle starts here getting sensorial information
    Console.WriteLine("Starting Cognitive Cycle ... press CTRL-C to finish!\n");
    while (CurrentCognitiveCycle != MaxNumberOfCognitiveCycles) {

          // Get current sensorial information                    
          IList<Thing> sensorialInformation = OnNewVisualSensorialInformation();

          // Make the perception
          SensoryInformation si = MakePerceptionFromSensorialInput(sensorialInformation);

          //Perceive the sensory information
          CurrentAgent.Perceive(si);

          //Choose an action
          ExternalActionChunk chosen = CurrentAgent.GetChosenExternalAction(si);         

          . . .

          String actionLabel = chosen.LabelAsIComparable.ToString();
          ClarionAgentActionType actionType = 
                   (ClarionAgentActionType)Enum.Parse(typeof(ClarionAgentActionType), actionLabel, true);

          if (OnNewExternalActionSelected != null)  {

              switch (actionType) {
                case  ClarionAgentActionType.EAT:
                      if (si[InputFood] == CurrentAgent.Parameters.MAX_ACTIVATION && 
                                                          CurrentAgent.CurrentGoal == GoalEatFood) {
                        OnNewExternalActionSelected(actionType);  
                        CurrentAgent.ReceiveFeedback(si, 1.0);                        
                      } 
                      else {
                        CurrentAgent.ReceiveFeedback(si, 0.0);
                      }
                      break;

                case  ClarionAgentActionType.ROTATE_CLOCKWISE:
                      if (si[InputWall] == CurrentAgent.Parameters.MAX_ACTIVATION && 
                                                        CurrentAgent.CurrentGoal == GoalAvoidWall) {
                        OnNewExternalActionSelected(actionType);  
                        CurrentAgent.ReceiveFeedback(si, 1.0);                        
                      } 
                      else {
                        CurrentAgent.ReceiveFeedback(si, 0.0);
                      }
                      break;
              . . .

              }
          }

          // Increment the number of cognitive cycles
          CurrentCognitiveCycle++;

          // Wait to the agent accomplish his job
          if (TimeBetweenCognitiveCycles > 0)  {
               Thread.Sleep(TimeBetweenCognitiveCycles);
          }
    }

  }
  #endregion Run Thread Method
  . . .
}               
                  

 

A seguir expomos a parte que trata do controle das ações para a coleta de jóias de acordo com os leaflets. São ações que não estão diretamente associadas às necessidades primárias do agente. Disponibilizamos a codificação de um agente CLARION em que a ação "desviar da parede" está associada a uma característica primária do agente (medo de colisão), isto é, este agente não segue o design do agente no DemoCLARION - veja [ aqui ].

 

Esquema do controle das ações para a coleta das jóias:              

O esquema do controle das ações sobre a captura de jóias é análogo ao sistema de controle de navegação fornecido no DemoCLARION.  O conjunto de regras FixedRule não sofre muitas alterações: 

                        
// Se o alimento está a uma distância inferior a trinta unidades, então recomenda-se a ação de captura 
// (comer). Caso contrário, a ação não é recomendada. A condição da regra é dada pelo método delegate.
// Em pseudo-código:   

public double Delegate_FixedRule_ToEatFood(SensoryInformation si, Rule target) {

  return 1.0 if, {distancia, d} is activated and {d <= 30}
         Otherwise, 0.0
} 
                          

 

A classe FixedRules  fornece os mecanismos necessários para codificar uma regra. Para inicializar uma regra basta especificar um método delegate. Ou seja, definir o método que será usado para calcular o suporte para a regra , isto é feito via SupportCalculator delegate. Essa medida do suporte determina se uma regra é elegível para ser recomendar uma dada ação num dado momento, baseado num "partial match threshold", capturado pelo PARTIAL_MATCH_THRESHOLD parameter. O input para o suporte é um elemento da classe SensoryInformation, cuja base é o ActivationColection do Clarion.Framework namespace.  Desse modo, podemos reescrever a regra acima usando o seguinte esquema (é somente um esquema, a estrutura sintática do código é a mesma do DemoCLARION): 

                           
// Perception input
private DimensionValuePair InputFoodAhead;

// O agente interpreta os dados do sensor visual 
private SensoryInformation MakePerceptionFromSensorialInput(IList<Thing> sensorialInformation) {

   // Dados sensoriais 
   SensoryInformation si = World.NewSensoryInformation(CurrentAgent);

   // Detect if we have a wall ahead
   Boolean foodAhead = sensorialInformation.Where(item => (item.CategoryId == Thing.CATEGORY_BRICK && 
                                                           item.DistanceToCreature <= 30)).Any();
   double foodAheadActivationValue = 
          foodAhead ? CurrentAgent.Parameters.MAX_ACTIVATION : CurrentAgent.Parameters.MIN_ACTIVATION;
   
   si.Add(InpuFoodAhead, foodAheadActivationValue);

   return si;
}

                     
private double Delegate_FixedRule_ToEatFood(ActivationCollection currentInput, Rule target) {

   return ((currentInput.Contains(InputFoodAhead, CurrentAgent.Parameters.MAX_ACTIVATION))) ? 1.0 : 0.0;
 }

// Configuração do ACS
 private void SetupACS() {

    SupportCalculator avoidCollisionWallSupportCalculator = FixedRuleDelegateToAvoidColissionWall;
} 
   

 

 

                   
 // Configuração do ACS
 private void SetupACS() {

  // Cria as regras para "Colission-Wall" e "Go Ahead"
  SupportCalculator avoidCollisionWallSupportCalculator = FixedRuleDelegateToAvoidColissionWall;
  SupportCalculator goAheadSupportCalculator = FixedRuleDelegateToGoAhead;
  FixedRule ruleAvoidCollisionWall = AgentInitializer.InitializeActionRule(CurrentAgent, 
                                                          FixedRule.Factory, OutputRotateClockwise, 
                                                          avoidCollisionWallSupportCalculator);
  FixedRule ruleGoAhead = AgentInitializer.InitializeActionRule(CurrentAgent, FixedRule.Factory, 
                                                                OutputGoAhead, goAheadSupportCalculator);

  // Agrega as regras ao agente (no ACS)
  CurrentAgent.Commit(ruleAvoidCollisionWall);             
  CurrentAgent.Commit(ruleGoAhead);

  // Desativa a regras de refinamento 
  CurrentAgent.ACS.Parameters.PERFORM_RER_REFINEMENT = false;

 // Estabelece a forma de seleção: probabilística
 CurrentAgent.ACS.Parameters.LEVEL_SELECTION_METHOD = 
                                                ActionCenteredSubsystem.LevelSelectionMethods.STOCHASTIC;

 // A seleção da ação é fixa, definida acima.
 CurrentAgent.ACS.Parameters.LEVEL_SELECTION_OPTION = ActionCenteredSubsystem.LevelSelectionOptions.FIXED;

  // Estabelece os valores probabilísticos
  CurrentAgent.ACS.Parameters.FIXED_FR_LEVEL_SELECTION_MEASURE = 1;
  CurrentAgent.ACS.Parameters.FIXED_IRL_LEVEL_SELECTION_MEASURE = 0;
  CurrentAgent.ACS.Parameters.FIXED_BL_LEVEL_SELECTION_MEASURE = 0;
  CurrentAgent.ACS.Parameters.FIXED_RER_LEVEL_SELECTION_MEASURE = 0;
 }

 

 

       

 

 

 

Interface com o WS3D

Como mencionamos no início desta seção, conforme as discussões com colegas, foram feitos alguns ajustes no WS3D para o desenvolviemtno da Atividade: Teste 1. A implementação que o Eduardo Jucá disponibilizou contém esses ajustes. Utilizamos nesta atividade a versão do Eduardo Jucá: versão jnlp funcional do WS3D [ aqui ], o código fonte [ aqui ] e comentários sobre as alterações [ aqui ]. 

 

Conclusão

A proposta de modelo de arquitetura cognitiva CLARION toma como base a distinção entre processos (e de representação de conhecimento, parte da cognição) explícitos (via regras e chunks) e implícitos (via redes neurais) associados à cognição humana. Nesta atividade exploramos o uso desses processos nas tomadas de decisões referentes às necessidades primárias e à tarefa de coletar jóias de acordo com leaflets. O ACS cuida das decisões sobre as ações a serem executadas, com suporte do NACS que auxilia tratando o conhecimento declarativo. O MS estabelece o direcionamento (determinado pelos níveis dos drives em relação às necessidades básicas do agente) das decisões em relação às metas. O MCS cuida do auto-monitoramento e a configuração dos parâmetros que atuam no ACS e NACS. O MCS também pode interferir no MS ajustando o nível dos drives.

 

 


Desenvolvimento do Teste 2

 

Não realizamos esta parte da atividade.

 

 



 

    

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer