Thursday, January 27, 2011

Clarification of my Spreading Activation Algorithm

I haven't found much in the way of detailed spreading activation algorithms, aside from the "Task Planning Under Uncertainty Using a Spreading Activation Network" paper. I've also found that many details of the implementation are dependent on the application. In my model, I've realized the need for a few things that complicate the simple spreading mechanism.

First of all, the spreading activation model I'm using is bi-directional. One activation from the source, which represents the current state of the environment and all possible actions from that state, and the goal, which is the command that should be fulfilled. The source activation travels along the outgoing edges, and the goal activation travels backward across incident edges. When they meet, I'll have a possible sequence of actions to go from the current state to the goal state. However, the first meet of the two activations would only be optimal if all the edges were equally weighted (they aren't in this case). That's complication #1, and so in my case the activation will continue until all of the activations have decayed past a certain threshold.

Edge decays range from 1.0, representing an effortless connection or action (like breathing), to 0, representing an impossible connection or action (like pulling my cat off a carpet). An activation is some empirically determined value, and represents the initiative the agent has in making the connection or achieving the goal. It can be thought of as a kind of radius that spreads outward from the goal and current state nodes.

The backwards propagation establishes the goal set - all the preconditions that are part of possible solutions to the problem. This can either simply be a flat structure of all possible preconditions, or it could be organized as a dependency graph to indicate possible sequential orderings of actions. The forward propagation then fills in the weights of the preconditions to find the best sequence of steps. I'm still working on the design of this part of the implementation, and it will be the main focus of this week's work.

The next complication is differentiating between AND and OR when it comes to preconditions and other relationships. If we assign a cost to a particular node in the graph corresponding to an action, say, "Make coffee", the cost will be some combination of all the requirements. So we need to get water, get coffee grounds (or get a grinder and beans for purists), and turn the coffee maker on. If any one of these tasks is particularly difficult for some reason, then the entire task will be difficult - this is an AND grouping of preconditions. Furthermore, if there are many tasks to be done, the difficulty increases.

To represent this, I'm going to say that the activation of an AND gate is the multiplication of the incident activations. This creates the effect that many effortless actions are still effortless, but even a small number of difficult actions make the action difficult.

For OR, it's the opposite case. If "Get coffee" can be satisfied by either "Making coffee" or "Buying coffee", then it doesn't matter how difficult the more difficult task is, it only matters how easy the easy task is. We'll take the path of least resistance - therefore the activation of an OR gate is the highest of the incident edges.

These two gates are essential, but other gates can be added with their own properties. If you've taken any intro Neuroscience class, you'll notice that these gates simulate the connections between neurons. This analogue will prove useful for other features as the project progresses as well.

I've decided to switch to C# from C++ after talking with Ben. This will make programming faster, and it also means I can easily use Unity for my virtual environment.

Tonight I finished my graph data structure and have some debugging info displayed. It's only rudimentary, and doesn't incorporate any of the features I've mentioned here yet.

2 comments: