Differences Between TinySoar and Soar8

TinySoar, in order to be tiny, does not implement many of the features available in Soar8. This document lists some of the differences between TinySoar and Soar8, as well as some of the known issues (ahem, bugs) in TinySoar.

No support for chunking, justifications, or impasses

TinySoar currently doesn't implement chunking or justifications, and thus has no way to resolve impasses. This is currently being implemented on the trunk, but is highly experimental at this point.

Conjunctive negative conditions are not supported

In Soar8, you can write a rule with conjunctive negative conditions; i.e., a negative test that is the conjunction of several tests. For example:

sp {check*no*operator*foo
    (state <s> ^superstate nil)
  -{(<s> ^operator <o>)
    (<o> ^name foo)}
    /* do something */}

This production will match when there is no ^operator with a ^name of foo on the state. Here's another example:

sp {check*no*foo*and*bar
    (state <s> ^superstate nil)
   -(<s> ^foo t ^bar t)
    /* do something */}

This production will match when ^foo t and ^bar t are both not present on the state at the same time.

Most of the time, it should be possible to implement equivalent functionality by breaking a rule with conjunctive negative conditions into two rules: one that detects the negative condition and annotates the state, and another that detects the state annotation and triggers the original intended operation. For example, check*no*foo*and*bar could re-written in two rules without a conjunctive negative condition as follows:

sp {check*foo*and*bar
    (state <s> ^superstate nil ^foo t ^bar t)
    (<s> ^foo-and-bar t)}

sp {check*no*foo-and-bar
    (state <s> ^superstate nil -^foo-band-bar t)
    /* do something */}

Unfortunately, there are some issues with this approach. For example, to break check*no*operator*foo into two productions, we'd end up with a ^operator-foo t annotation on the state that is o-supported because it's tested the operator.

So, it's not clear at this time whether implementing conjunctive negative conditions in TinySoar would be a good thing to do or not. It certainly is a wonderful convenience for authoring rules, and may even be a necessity to achieve some sorts of behavior. However, that convenience comes at the price of additional runtime code, which is at a premium.

Expressions are not supported in a rule's RHS

In Soar8, you can write a rule like this:

sp {increment*foo
   (state <s> ^foo <i>)
   (<s> ^foo <i> - ^foo (+ <i> 1) +)}

In other words, replace the integer value <i> with <i> + 1. This is not currently supported.

The runtime can run out of identifiers

Identifiers are not heap-allocated objects, like they are in Soar8: each new identifier is assigned a monotonically increasing integral value. Unfortunately, on a real computer, that means you can overflow the representation. For example, on the Lego Mindstorms RCX, there are 14 bits available to store the identifier's value, allowing for no more than 16,384 identifiers. When an overflow occurs, behavior becomes undefined -- definitely a bug! (The current plan is to fix this by recycling the identifier values that aren't in use.)