For "less rough" notes, see Cognitive Modelling with Mathematical Logic.
Rough notes on CM design
- Representation of situations:
- Would like to represent uncertainty using interval-valued arithmetic, which we can get basically for free by using Oz's finite domain constraint system. A variable's current constraints define the set of values it might have.
- Traditional programming models don't work well with this paradigm. Constraint store allows information only to be added, meaning that domains can only get narrower, not wider. To examine a different situation, you need a new cspace. To examine possibilities in a given situation, you must express them as constraints within a cspace where the situation is defined. Cloning and injecting can be used to temporarily explore alternatives.
- This could end up being expensive. The overhead of cloning cspaces can't be trivial. On the other hand, Oz programming teams have won prizes for efficient problem solving. By all accounts, Oz is well suited to this kind of computation. But the algorithm may need tweaking for performance.
- Might be able to do something clever with "as-needed" variables to avoid inferring and storing completely unknown fluents. Trigger a procedure to infer current fluent domain based on predecessor situations. When creating new successor situations, assume all fluents unknown initially.
- On second thought, as-needed variables don't help with storage -- the variable still has to be defined. Plan on using procedural access to all fluent values so that some code has an opportunity to create a variable (field) for it, and trigger the actions mentioned above. Sigh -- that will make the knowledgebase more verbose, unless I come up with a preprocessor for it. Need to look into the Gump preprocessor system for this, I suppose.
- The primary computation tasks are:
- Given current situation, figure out possible actions.
- Given current situation and a hypothesized action, figure out the next situation.
- Evaluate the desirability of a situation. Desirability of situations may take into account desirability of predecessor situations to discourage generating plans with poor intermediate states.
- Search involves:
- Identifying potential solutions. Is a script of possible actions that lead to a non-catastrophic situation.
- Selecting among possible actions intelligently to find good situations faster. May involve consideration of action costs and durations, eventually provide for predefined scripts to guide likely search paths.
- Besides distributing the search (i.e. branching the search tree) based on selecting actions, we may sometimes distribute on a fluent's value. Normally, we won't do this, because there are many things in the world that will be uncertain no matter what we do. But if a sensing action can determine the value then we should try the sensing action, and examine the possible successor situations that we might find as a result of determining the fluent's value. Interesting! Definitely a custom distribution strategy, then. Many sensing actions will have low cost, so we should arrange for these to have high priority in the distribution strategy. (However, some could be costly in time -- for instance invoking the natural language engine to talk to a player character in order to determine his attitude! JDH: Nah, that's easy we just say "hi" and count the number of swear words in his reply))
- Evaluting desirability of situations will be interesting. Should be based on character's personality, and current goals. (AI characters can have missions, and better try to stick to them! Ferengi might be diverted by profit opportunities, however.)
- Once a sequence of actions has been chosen, it should probably not be sent to the game engine all at once. Instead, send it a bit at a time, and replan periodically. Scheduling the sending could be interesting -- we typically want to wait for some condition before moving to the next step in a plan. Hmm. (This all assumes plans with many steps, which may be unrealistic at first.)
- If following a long plan, it would be useful to check current situation against assumptions that were made in the script before taking the next step. This is another reason that it would be good to have only needed fluent variables in a situation record. This would let us compare the current situation against the assumed situation's constraints. If the latter contained a lot of extraneous data, the comparison would be more likely to fail for reasons that aren't relevant to our planned next action.
- Conversely, it might be sufficient to check that in the current situation, the next planned action is really possible.
- Ideally, plan steps have variable time duration. (Launch, fly to station X, dock. Evade until weapons recharge, attack.)
- Besides pre-planned actions, plans might include subgoals. That way if things don't match expectations, the overall plan might be salvageable by coming with alternate means of achieving a subgoal. (Okay, we're getting fancy here.)
Clipboard area -- old cruft
Our first propagation step applies constraints that narrow the domains of the successor situation variables based on the current situation variables. For example, assume that we're modelling the pilot of a spaceship. Our situation records include variables for our distance to a hostile enemy, our velocity relative to the enemy, our acceleration ability, and the enemy's acceleration ability. Then we should be able to come up with a constraint that defines a domain for our distance to the enemy in the successor situation for the next time tick.
Now assume that our initial situation's values for these four variables are {close}, {low}, {low}, and {low#medium}, respectively. (These names are actually all encoded as integers.) In the successor state, the estimate for our distance from the enemy would start out as unknown, i.e. {sittingOnMyFlokingWindshield#outOfSensorRange}. Applying our hypothetical constraint (which I won't even try to write yet), propagation might restrict this to {veryClose#close} -- obviously an undesirable situation that will influence our decisions!
After propagation is complete, we come to the distribution step. We have a list of action we can perform, along with precondition axioms and effect axioms. The precondition axioms tell us which actions are possible given the current situation. The effect axioms tell us what changes we expect if we perform an action, so that selecting an action leads to a narrowing of the domains of the successor situation's variables. So we distribute by "trying out" possible actions. Each attempt gives us a new successor situation, which we now treat as the initial
This is where things get really intereresting. Let's discuss some of the issues with the distribution strategy.
First, we need to limit the depth of the search tree. Always picking the "best" possible sequen Naive attempts to investigate every possible action in random order will be way to slow. Instead, we need to be clever about this. Also, we can't let the tree
An initial propagation step lets you deduce certain things about the situation. Ideally, nothing should fail at this stage, otherwise your knowledge of the world is just completely at odds with your domain knowledge in some way!
Based on the situation, you can determine what actions are open to you. So you distribute on these various actions. As always, the distribution step is critical, and I'll talk about this some more in a bit.
In each alternative computation space, you're modelling the effects of taking one or more actions.
Some constraints model what we know about how the world changes over time. They infer something about the possibilities of the next situation, narrowing the domain of variables in S0. (Remember that the domains of variables in S0 start out as wide as possible.)