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.
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.
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.
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.
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.)