Reverse Engineering the AIMA
ModelBasedReflexVacuumAgent

To try to get a handle on the upcoming AI class code I reverse engineered the Java TrivialVacuumDemo Agent demo code while it was running as a ModelBasedReflexVacuumAgent.

I started by (trying to) generate a class diagram, however the Green UML tool for Eclipse that I used was somewhat less than responsive. I did finally -- mostly by brute force -- get it to cough up some pretty pictures of significant portions of the class structure. These are included below under Class Diagrams.

However for me, class diagrams don't provide a suscinct description of the program's Data Schema. By this I mean what might be in an Entity Relationship diagram: What data elements are contained in the main classes and what values can they assume? So (by hand) I dug through the class structure and collated the functional data elements contained in each hierarchy, along with various pre-defined values used in the program's state transitions. The possible Actions and the values for the Environment's Locations and State/Percepts are in VacuumEnvironment.java and the names of the Agent's state attributes are in ModelBasedReflexVacuumAgent.java. Agent state attributes can take the values defined in the Environment as passed through a VacuumEnvPercept object -- note that null is a valid value, but not defined as such. This is shown under Data Schema.

And speaking of state transitions, Object (dis)Oriented software makes it nearly impossible to tell, from the source, what objects are actually used when the program runs. What I wanted was a good old fashioned Flow Chart. While looking for a tool that would automate this, I discovered that the JDK has a "Trace" program (man page) buried in [JDK]/demo/jpda/com/sun/tools/example/trace/Trace.java which does a fairly good job of printing out the actual classes and methods that are executed during a program run. (Note that you must elect to install the example programs when installing the JDK, and then extract the source and compile it on your own. Also note that this is a demo and I can find no wizzy-wyg tool that implements this functionality -- which seems pretty basic to me). What you see under Code Trace is the heavily edited and notated output thereof.

The demo Agent program implements a basic state machine driven behavior but it is not explicitly constructed as such. As is often the case for a Moore FSA, what might be States are loosely overloaded as Percepts {Clean,Dirty}. The state transitions are coded into the Rule set but, because the rules are interpreted in precidence order, they reduce to an IF->>THEN->ELSE list. Therefore I will leave the state-transition diagram as an exercise for the reader. A complicating factor is that the demo is supposed to be "model driven" but there is an unused model field in ModelBasedReflexAgentProgram.java. After a fair amount of head-banging I realized that the model is contained in the Agent class's DynamicState state field as the attributes:

    "stateLocationA" -> {Clean,Dirty}
    "stateLocationB" -> {Clean,Dirty}
The values of these attributes are copied from the VacuumEnvPercept on each execution's updateState() pass and thus form the Agent's historical view of the Environment -- which is assumed not to change unilaterially.









Class Diagrams

environment

agent

basic objects

Data Schema


MAIN PROGRAM (TrivialVacuumDemo)

  ENVIRONMENT (VacuumEnvironment)
    Action definitions (DynamicAction)
      "Left"
      "Right"
      "Suck"
    Location definitions (String)
      "A"
      "B"
    Percept definitions (enum LocationState)
     (Note: "percept" and "state" are overloaded terms in this context)
      Clean
      Dirty
    VacuumEnvironmentState envState; (the Environment description)
    Set<EnvironmentObject> envObjects;
    Set<Agent> agents;
      (Note: AGENT is added to both envObject and agent Sets(!?))
    Set<EnvironmentView> views;
    Map<Agent, Double> performanceMeasures;
      Agent(object) -> Double value
      (Note: values are hard coded in VacuumEnvironment.executeAction())
    
  AGENT (ModelBasedReflexVacuumAgent)
    DynamicState attribute names (String)
      "currentLocation"
      "currentState"
      "stateLocationA"
      "stateLocationB"
    AgentProgram program; (ModelBasedReflexAgentProgram)
      DynamicState state; (Agent state, also used as Model)
      Model model; (not used!?!)
      Set<Rule> rules; (Percept->Action rule set)
        State-transitions, operate over DynamicState attributes
         (defined in ModelBasedReflexVacuumAgent.getRuleSet())
          stateLocation[A&B]==Clean -> NO_OP (using Model attributes)
          currentState==Dirty -> "Suck" (using Percept attributes)
          currentLocation=="A" -> "Right"
          currentLocation=="B" -> "Left"
    
Rule (state transition definition)
  Condition con; (Percept conditions to match)
  Action action; (Action to execute)

DynamicAction (Action to execute)
  Map<Object, Object> attributes;
    "name" -> {"Left","Right","Suck"}

VacuumEnvPercept (Percept passed into Agent from Environment)
  Map<Object, Object> attributes;
    "agentLocation" -> {"A","B"}
    "state" -> {Clean,Dirty}

DynamicState (Agent's internal state description)
  Map<Object, Object> attributes;
    Percept attributes:
      "currentLocation" -> {"A","B"}
      "currentState" -> {Clean,Dirty}
    Model attributes:
      "stateLocationA" -> {Clean,Dirty}
      "stateLocationB" -> {Clean,Dirty}

VacuumEnvironmentState (Environment description)
  Map<String, LocationState> state; (state of each location)
    "A" -> {Clean,Dirty}
    "B" -> {Clean,Dirty}
  Map<Agent, String> agentLocations; (location of each agent)
    Agent(object) -> {"A","B"}


Code Execution Trace


====== main ======
main -- aima.gui.demo.agent.TrivialVacuumDemo

 ======== ENVIRONMENT init ========
  <clinit> -- ...environment.vacuum.VacuumEnvironment
  =========== define and instantiate static Actions: Left, Right, Suck
  ===========  note: also defines LocationState enum: Clean, Dirty
  ===========         and Location Strings: A, B
  | <init> -- ...agent.impl.DynamicAction
  || <init> -- ...agent.impl.ObjectWithDynamicAttributes
  || setAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  | <init> -- ...agent.impl.DynamicAction
  || <init> -- ...agent.impl.ObjectWithDynamicAttributes
  || setAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  | <init> -- ...agent.impl.DynamicAction
  || <init> -- ...agent.impl.ObjectWithDynamicAttributes
  || setAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  =========== construct VacuumEnvironment
  | <init> -- ...environment.vacuum.VacuumEnvironment
  || <init> -- ...agent.impl.AbstractEnvironment
    =========== construct VacuumEnvironmentState
    ===========  randomly initialize two Locations' States
  ||| <clinit> -- ...environment.vacuum.VacuumEnvironment$LocationState
  |||| <init> -- ...environment.vacuum.VacuumEnvironment$LocationState
  |||| <init> -- ...environment.vacuum.VacuumEnvironment$LocationState
  ||| <init> -- ...environment.vacuum.VacuumEnvironmentState
  |||| <init> -- ...environment.vacuum.VacuumEnvironmentState
 
 ======== VIEW init - display mechanism ========
  | <init> -- ...agent.impl.SimpleEnvironmentView
  ======== VIEW is contained in ENVIRONMENT
  | addEnvironmentView -- ...agent.impl.AbstractEnvironment
 
 ======== AGENT init ========
  <init> -- ...environment.vacuum.ModelBasedReflexVacuumAgent
  =========== AGENT creates and contains AgentProgram
  | <init> -- ...environment.vacuum.ModelBasedReflexVacuumAgent$1
  || <init> -- ...agent.impl.aprog.ModelBasedReflexAgentProgram
  ||| init -- ...environment.vacuum.ModelBasedReflexVacuumAgent$1
     =========== AgentProgram contains Agent State
  |||| <init> -- ...agent.impl.DynamicState
  ||||| <init> -- ...agent.impl.ObjectWithDynamicAttributes
  |||| setState -- ...agent.impl.aprog.ModelBasedReflexAgentProgram
     =========== AgentProgram contains a Rules Set
  |||| getRuleSet -- ...environment.vacuum.ModelBasedReflexVacuumAgent
      =========== Agent initializes Percept->Action Rule Set
      =========== create rule1: All Clean -> NoOP
  ||||| <clinit> -- ...agent.impl.aprog.simplerule.Rule
  ||||| <clinit> -- ...agent.impl.aprog.simplerule.ANDCondition
  ||||| <clinit> -- ...agent.impl.aprog.simplerule.EQUALCondition
  ||||| <init> -- ...agent.impl.aprog.simplerule.EQUALCondition
  |||||| <init> -- ...agent.impl.aprog.simplerule.Condition
  ||||| <init> -- ...agent.impl.aprog.simplerule.EQUALCondition
  |||||| <init> -- ...agent.impl.aprog.simplerule.Condition
  ||||| <init> -- ...agent.impl.aprog.simplerule.ANDCondition
  |||||| <init> -- ...agent.impl.aprog.simplerule.Condition
        ========== instantiate NoOPAction 
  ||||||| <clinit> -- ...agent.impl.NoOpAction
  |||||||| <init> -- ...agent.impl.NoOpAction
  ||||||||| <init> -- ...agent.impl.DynamicAction
  |||||||||| <init> -- ...agent.impl.ObjectWithDynamicAttributes
  |||||||||| setAttribute -- ...agent.impl.ObjectWithDynamicAttributes
      =========== put rule1 in Set<Rule>
  ||||| <init> -- ...agent.impl.aprog.simplerule.Rule
  ||||| hashCode -- ...agent.impl.aprog.simplerule.Rule
  |||||| toString -- ...agent.impl.aprog.simplerule.Rule
  ||||||| toString -- ...agent.impl.aprog.simplerule.ANDCondition
  |||||||| toString -- ...agent.impl.aprog.simplerule.EQUALCondition
  |||||||| toString -- ...agent.impl.aprog.simplerule.EQUALCondition
  ||||||| toString -- ...agent.impl.ObjectWithDynamicAttributes
  |||||||| describeType -- ...agent.impl.DynamicAction
  |||||||| describeAttributes -- ...agent.impl.ObjectWithDynamicAttributes
      =========== create rule2: Clean -> Suck
  ||||| <init> -- ...agent.impl.aprog.simplerule.EQUALCondition
  |||||| <init> -- ...agent.impl.aprog.simplerule.Condition
      =========== put rule2 in Set<Rule>
  ||||| <init> -- ...agent.impl.aprog.simplerule.Rule
  ||||| hashCode -- ...agent.impl.aprog.simplerule.Rule
  |||||| toString -- ...agent.impl.aprog.simplerule.Rule
  ||||||| toString -- ...agent.impl.aprog.simplerule.EQUALCondition
  ||||||| toString -- ...agent.impl.ObjectWithDynamicAttributes
  |||||||| describeType -- ...agent.impl.DynamicAction
  |||||||| describeAttributes -- ...agent.impl.ObjectWithDynamicAttributes
      =========== create rule3: InLocA -> MoveRight
  ||||| <init> -- ...agent.impl.aprog.simplerule.EQUALCondition
  |||||| <init> -- ...agent.impl.aprog.simplerule.Condition
      =========== put rule3 in Set<Rule>
  ||||| <init> -- ...agent.impl.aprog.simplerule.Rule
  ||||| hashCode -- ...agent.impl.aprog.simplerule.Rule
  |||||| toString -- ...agent.impl.aprog.simplerule.Rule
  ||||||| toString -- ...agent.impl.aprog.simplerule.EQUALCondition
  ||||||| toString -- ...agent.impl.ObjectWithDynamicAttributes
  |||||||| describeType -- ...agent.impl.DynamicAction
  |||||||| describeAttributes -- ...agent.impl.ObjectWithDynamicAttributes
      =========== create rule4: InLocB -> MoveLeft
  ||||| <init> -- ...agent.impl.aprog.simplerule.EQUALCondition
  |||||| <init> -- ...agent.impl.aprog.simplerule.Condition
      =========== put rule4 in Set<Rule>
  ||||| <init> -- ...agent.impl.aprog.simplerule.Rule
  ||||| hashCode -- ...agent.impl.aprog.simplerule.Rule
  |||||| toString -- ...agent.impl.aprog.simplerule.Rule
  ||||||| toString -- ...agent.impl.aprog.simplerule.EQUALCondition
  ||||||| toString -- ...agent.impl.ObjectWithDynamicAttributes
  |||||||| describeType -- ...agent.impl.DynamicAction
  |||||||| describeAttributes -- ...agent.impl.ObjectWithDynamicAttributes
     =========== save Rule Set in AgentProgram
  |||| setRules -- ...agent.impl.aprog.ModelBasedReflexAgentProgram
    =========== Complete AGENT constructor
  ||| <init> -- ...agent.impl.AbstractAgent

  =========== Add AGENT to ENVIRONMENT
  | addAgent -- ...environment.vacuum.VacuumEnvironment
   =========== set random initial AGENT location
  || setAgentLocation -- ...environment.vacuum.VacuumEnvironmentState
  || addAgent -- ...agent.impl.AbstractEnvironment
  ||| addEnvironmentObject -- ...agent.impl.AbstractEnvironment
  |||| updateEnvironmentViewsAgentAdded -- ...agent.impl.AbstractEnvironment
  ||||| getCurrentState -- ...environment.vacuum.VacuumEnvironment
      =========== notify VIEW that it has a new AGENT
  ||||| agentAdded -- ...agent.impl.SimpleEnvironmentView

 ======== STEP execution - loop N times ========
  | step -- ...agent.impl.AbstractEnvironment
   ======== STEP execution -- first pass (with initialization)
  || step -- ...agent.impl.AbstractEnvironment
  ||| isAlive -- ...agent.impl.AbstractAgent
    ======== Get the AGENT's Perception
  ||| getPerceptSeenBy -- ...environment.vacuum.VacuumEnvironment
     ======== Find AGENT's Location
  |||| getAgentLocation -- ...environment.vacuum.VacuumEnvironmentState
  ||||| <clinit> -- ...agent.impl.DynamicPercept
       ======== Get state of AGENT's Location
       ========  return a new VacuumEnvPercept object
  |||||| getLocationState -- ...environment.vacuum.VacuumEnvironmentState
  ||||||| <init> -- ...environment.vacuum.VacuumEnvPercept
  |||||||| <init> -- ...agent.impl.DynamicPercept
  |||||||||| <init> -- ...agent.impl.ObjectWithDynamicAttributes
  |||||||||| setAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  |||||||||| setAttribute -- ...agent.impl.ObjectWithDynamicAttributes
    ======== Get Action to execute from AgentProgram
  ||| execute -- ...agent.impl.AbstractAgent
  |||| execute -- ...agent.impl.aprog.ModelBasedReflexAgentProgram
      ======== Update AGENT state using current Location and Perception
  ||||| updateState -- ...environment.vacuum.ModelBasedReflexVacuumAgent$1
  |||||| getAgentLocation -- ...environment.vacuum.VacuumEnvPercept
  ||||||| getAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  |||||| setAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  |||||| getLocationState -- ...environment.vacuum.VacuumEnvPercept
  ||||||| getAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  |||||| setAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  |||||| getAgentLocation -- ...environment.vacuum.VacuumEnvPercept
  ||||||| getAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  |||||| getLocationState -- ...environment.vacuum.VacuumEnvPercept
  ||||||| getAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  |||||| setAttribute -- ...agent.impl.ObjectWithDynamicAttributes
      ======== Find Rule match
  ||||| ruleMatch -- ...agent.impl.aprog.ModelBasedReflexAgentProgram
  |||||| evaluate -- ...agent.impl.aprog.simplerule.Rule
  ||||||| evaluate -- ...agent.impl.aprog.simplerule.ANDCondition
  |||||||| evaluate -- ...agent.impl.aprog.simplerule.EQUALCondition
  ||||||||| getAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  |||||| evaluate -- ...agent.impl.aprog.simplerule.Rule
  ||||||| evaluate -- ...agent.impl.aprog.simplerule.EQUALCondition
  |||||||| getAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  |||||| evaluate -- ...agent.impl.aprog.simplerule.Rule
  ||||||| evaluate -- ...agent.impl.aprog.simplerule.EQUALCondition
  |||||||| getAttribute -- ...agent.impl.ObjectWithDynamicAttributes
  |||||| evaluate -- ...agent.impl.aprog.simplerule.Rule
  ||||||| evaluate -- ...agent.impl.aprog.simplerule.EQUALCondition
  |||||||| getAttribute -- ...agent.impl.ObjectWithDynamicAttributes
      ======== Get Action from Rule
  ||||| ruleAction -- ...agent.impl.aprog.ModelBasedReflexAgentProgram
  |||||| getAction -- ...agent.impl.aprog.simplerule.Rule
    ======== Execute the Action (finally...) and update performance
    ========  note: evaluations are hard coded here
  ||| executeAction -- ...environment.vacuum.VacuumEnvironment
     ======== Move AGENT
  |||| setAgentLocation -- ...environment.vacuum.VacuumEnvironmentState
     ======== Modify Performance measure
  |||| updatePerformanceMeasure -- ...agent.impl.AbstractEnvironment
  ||||| getPerformanceMeasure -- ...agent.impl.AbstractEnvironment
    ======== Tell the View to display new AGENT position
  ||| updateEnvironmentViewsAgentActed -- ...agent.impl.AbstractEnvironment
  |||| agentActed -- ...agent.impl.SimpleEnvironmentView
  ||||| toString -- ...agent.impl.ObjectWithDynamicAttributes
  |||||| describeType -- ...agent.impl.DynamicAction
  |||||| describeAttributes -- ...agent.impl.ObjectWithDynamicAttributes
    ======== Execute any external changes in system state - noop here
  ||| createExogenousChange -- ...agent.impl.AbstractEnvironment

  ................. N steps ....................

 ======== print performance ========
  | getPerformanceMeasure -- ...agent.impl.AbstractEnvironment
  | notifyViews -- ...agent.impl.AbstractEnvironment
  || notify -- ...agent.impl.SimpleEnvironmentView

====== main end ======
-- The application exited --