Friday, June 29, 2007

More on the TACTIVATION class

Here's an update on the TACTIVATION class. Here's what it looks like (at this stage).

Tactivation = class
number_discrete_steps: integer;
current_state, level, increment: real;
procedure Recompute_Level;

function GetNumSteps: integer;
Constructor Create(steps: integer);
procedure increase (steps: integer);
Function Get_Level:real;
function Get_CurrentState:integer;
function Get_Increment: real;
Procedure Reset_Increment;
procedure decay;

Only two methods are actually larger than 3 lines: Recompute_Level and increase. Recompute_level is private and computes the sigmoid as a function of the current_state. I'll talk a little about increase here, because it's used also for spreading activation. I'll be updating the source to the googlegroup. Here are the descriptions of the public functions:

Constructor Create(steps: integer);
Gets the stage ready.

Function GetNumSteps: integer;
Function Get_Level:real;
Function Get_CurrentState:integer;
Function Get_Increment: real;
These are "Getters", so that nobody should mess around with the data directly.

Procedure Reset_Increment;
Sets variable increment to zero;

procedure decay;

This is obvious. Decays (currently) simply brings current_state one step down and recomputes the activation function.

One thing that's not really needed now, but for the future. Both decay and recompute_level should be in the future generalized as strategy patterns. After all, Copycat implemented an activation function, Tabletop a different one, Phaeaco a different one, and, while I do believe that there must be only one that's a best fit with psychological plausibility, the only way I'd envision that discovery would be to have modularized versions being compared against each other.

That's not a concern for now, but someday in the near future it really should be done.

procedure increase (steps: integer);
if (increment<(steps/number_discrete_steps)) then
If (Increment>0) then
If (Current_State>1) then Current_State:=1;

The objective of this method is to increase activation as a function of the number of steps (passed as a discrete parameter). It does have that weird "increment" variable thrown in, though. That's for activation spreading to other nodes, more on this later on.

So this method will be called by some codelets that want to increase activation of something; and also by nodes spreading activation to a new node. (NOTE that TACTIVATION is not a node, it is just a property of a node, we'll get to TNODES soon). Our implementation of activation is different from Copycat and from Tabletop, but maintains the same general spirit.

If this method is called by some codelet for the first time, then increment will be just the number of steps passed to it, divided by the maximum number possible (remember Harry's work: "steps" here on the x axis are discrete; and we're using 100 maximum steps). However, if the method already had some "increment" received from a node or codelet or something, it will add that increment to the receiving activation, in order to "correctly" spread activation to forthcoming nodes.

You might ask, that is,
of course, if you are geek enough to be interested in these types of things, "why not simply update with steps and be done with it?" Why use increment? Moreover, increment just keeps on adding up and up and up? When should it go down?

First, why use increment instead of steps? Increment's real difference is to increase activation when it is coming from multiple sources. It is then and there that increment will be way better than just steps. Next: when should the bloody thing go down? It goes down (to zero) whenever Reset_Increment is called.

Ask not when Reset_Increment is called, ask who can call it. Here we go into a basic philosophical principle of software design: the Hollywood principle

The hollywood principle. Don't call us, we'll call you!

Just like Hollywood, you have dreams of becoming a movie star, only to hear, in studio after studio, "don't call us, we'll call you". The basic idea behind the Hollywood principle in OO design is that you shouldn't have a class A calling a class B calling a class C calling a class A, and so forth. Why s that? Well, whenever you need to understand how the whole thing fits together, in order to change something, this intermingling of classes will drive you nuts, especially in large, complex systems. So the idea is that a class like TACTIVATION should get Reset_Increment called whenever a node X that's spreading activation to neighbors finishes that job. Then and there increment goes to zero and a new round of activation must be received in order for the node to spread it.

More on nodes & spreading activation soon.