Cognitive_Modelling_With_Mathematical_Logic/Test1
SDxWiki
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Situation records
%
% situation(
%            prev:        !<previous situation record>
%            poss:        [
%                          <action1>: <action possibility var1>
%                          <actionN>: <action possibility varN>
%                         ]
%            <fluent1>:   <fluent variable>
%            ...
%            <fluentN>: <fluent variable>
%          )
%
% This arrangement allows easy reference to the fluents by name. For instance:
%
%   {Planner mkSitRec(SPrev S)}
%   S.temperature =: S.prev.temperature + 10
%
% Situation records use constraints to represent uncertainty.

%The fluent variables are all finite domain variables. WRONG

%It's common for
% some fluents to be constrained but not determined, so care must be
% taken in referencing fluent variables so as not to inadvertently
% block on an undetermined (and quite likely undeterminable)
% value. The fully determined fluent values are *not* the variables
% for which our system is being solved. In the original situation
% record of a plan, the domains of the fluent variables are the inputs
% to the system. The domains of intermediate and final situations
% computed by the system are ancillary to the decision outputs.
%
% The poss entry contains a list with one pair per primitive
% action. The first element of each pair atom is the action. The
% second element is a 0/1 integer indicating if that action is
% possible
%
% During the search for desirable consequent actions, we first try
% various actions which are definitely possibly (their entry in poss
% is determined and non-zero) If the search fails to find attractive
% alternatives, actions are explored whose entries are not
% determined. Primitive actions whose preconditions resolve to
% determinate false values are not explored.
%
% Note on possible modeling of time:
%
% Time is represented as a fluent. Each primitive player action has an
% associated duration ration which is used to add a constraint to this
% this fluent to indicate how long they will take. Consequently, each
% situation is stamped with a (possibly constrained but indeterminate)
% time which indicates when the situation is expected to pertain.
%
% Note on possible addition of exogenous actions:
%
% Exogenous actions can be modelled as constraints that, unlike
% the axioms of a character action, can reference the hypothetical
% new situation record as well as the current situation. Thus the
% constraints can take into account the character action's expected effects.
% This means that exogenous action constraints can be applied to a current
% situation before exploring decision alternatives.
%
% This arrangement reflects the fact that the character knows or
% assumes that certain things can happen of their own accord, but
% expects occurence and effect to be influenced by his actions and by
% the passage of time.
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Decision records
%
% A decision record is the
% decision(
%           situation:  <previous situation record>
%           consequent: <resulting situation record>
%           action:     <chosen action>
%           inputs:     var(
%                          <choice1>:  <choice variable>
%                          ...
%                          <choiceN>:  <choice variable>
%                        )
%         )
%
% Decision records are the root variables of the computation spaces
% used to explore possible actions in a situation.  Given an input
% situation and a selected action to explore, a decision record is
% built from the current situation, a freshly created consequent
% situation, the action, and the definition of the action's input
% variables. If there are no input variables, the action's time
% constraint and effect axiom are immediately applied. Otherwise, we
% distribute further on the various choice variables before exploring
% the action's effects. When an action is finally selected and
% actually executed, the determinate values of the input variables
% are available as input parameters to the action's effector.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

local
  [Plan] = {Module.link ["~/SpookyDistance/Plan.ozf"]}
  %% Fluent definitions
  %
  % Each fluent represents a variable of interest about the current
  % situation. Note that the fluents model the character's mind; they
  % may represent what the character thinks he knows about his
  % environment, or something about his emotional state, or they might
  % represent a variable of sSome fluents represent internal states of
  % the character's mind. (
  Fluents =
  [
   fluent(
     name:	temperature
     desc:	"ambient temperature"
     init:	0#130
     infer:	proc {$ S ?T}
		  % Assume that the temperature can't change too quickly.
		  T =<: S.temperature + 2
		  T >=: S.temperature - 2
		end
     )
   fluent(
     name:	thermostat
     desc:	"thermostat setting"
     init:	32#90
     infer:	true		% Thermostat setting should be stable.
     )
   fluent(
     name:	alive
     init:	0#1
     infer:     fun {$ S} S.temperature <: 120 end
     )
   % location 0,0 == at thermostat
   fluent(
     name:	locationX
     init:	0#9
     infer:	true		% Our location shouldn't change on its own!
     )
   fluent(
     name:	locationY
     init:	0#9
     infer:	true
     )
  ]
  % Note that the effectors assume their inputs are determined, since
  % we're simulating the model for this test.
  Actions =
  [
   action(
     name:	walk
     pre:	fun  {$ S} S.alive end
     effect:	proc {$ S I}
		  S.locationX =: S.prev.locationX + I.dirX - 1
		  S.locationY =: S.prev.locationY + I.dirY - 1
		end
     effector:	proc {$ S I}
		  % An effector proc would normally queue up a message
		  % for the game engine. We cheat here for testing.
		  S.locationX = S.prev.locationX + I.dirX - 1
		  S.locationY = S.prev.locationY + I.dirY - 1
		end
     inputs:	proc {$ S ?I}
		  I = var(
		    dirX: {FD.int 0#2} % 0=W, 1=none, 2=E
		    dirY: {FD.int 0#2} % 0=S, 1=none, 2=N
			)
		  % Prevent noop moves 
		  {FD.impl I.dirX =: 1 I.dirY \=: 1} = 1
		end
     )   
   action(
     name:      turnTempUp
     pre:	fun {$ S}
		  {FD.conj
		   {FD.conj S.alive =: 1 S.locationX =: 0}
		   S.locationY =: 0}
		end
     effect:	proc {$ S _} S.thermostat = {FD.max S.prev.thermostat + 5 90}
		end
     effector:	proc {$ S _} S.thermostat = {Min S.prev.thermostat + 5 90} end
     )
   action(
     name:      turnTempDown
     pre:	fun {$ S}
		  {FD.conj
		   {FD.conj S.alive =: 1 S.locationX =: 0}
		   S.locationY =: 0}
		end
     effect:	proc {$ S _} S.thermostat = {FD.min S.prev.thermostat - 5 32}
		end
     effector:	proc {$ S _} S.thermostat = {Min S.prev.thermostat - 5 32} end
     )
  ]
  
  Planner={New Plan.planner init(Fluents Actions)}
  
  %%
  % Get input from the game engine and merge it into the current
  % situtation record.
  %
  % TODO: Because of the (eventual) asynchronous model of arriving
  % sensory data, we will have to code this so that values that
  % were already determined can be replaced by newer values.
  %
  proc {GetInput Tick S ?Continue}
    proc {DeferredActions}
      D
    in
      % Testing hack. Apply effects of previous decision to this new state.
      {Exchange ActionLoopback D nil}
      case D
      of nil then skip
      [] decision(...) then
	{Show [deferred D.action.name D.inputs]}
	{D.action.effector S D.inputs}
      end
    end

  in
    {Show [tick Tick]}
    if Tick >= 2 then		% Stop running when this is true
      Continue = false
    elseif Tick == 0 then
      % Set up initial state.
      S.locationX = {OS.rand} mod 10
      S.locationY = {OS.rand} mod 10
      S.alive = 1
      S.temperature = 110
      S.thermostat = 90
      Continue = true
    else
      {DeferredActions}
      Continue = true
    end
  end

  %%
  % Send actions from our plan to the game engine.
  %
  proc {ExecuteActions D}
    % For now, we cheat and assume that the input in the next
    % tick will be exactly those effects that we predicted
    % during planning.
    {Assign ActionLoopback D}
  end
  
  proc {Main SituationPrev Tick}
    Situation = {Planner mkSitRec(SituationPrev $)}
    Decision
  in
    if {GetInput Tick Situation} then
      {Planner exploreActions(Situation)} % For debugging the search tree.
      {Planner chooseAction(Situation Decision)}
      if Decision == nil then
	raise paralyzed(debug:Situation) end
      else
	{ExecuteActions Decision}
	{Main Situation Tick+1}
      end
    end
  end
  
  SDefault
  ActionLoopback = {NewCell nil} % For testing
in
  {Browser.object clear}
  {System.printInfo "\n**** Test1 ****\n"}
  SDefault={Planner mkSitRec(nil $)}
  {Main SDefault 0}
  {Show done}
end