Go backward to Initialization of Soar.
Go up to Encoding A Task in Soar.
Go forward to Subgoal creation for operator application.
Proposal of the operator to perform the task
============================================
Once the top goal, problem space, and state are selected, the operator to
perform the task can be proposed. The task operator would usually contain
some description of the desired state that is to be achieved after all, the
purpose of an operator is to modify the world in some way. The desired state
may be based on input from the outside ("Please create a stack of blocks with
block A on block B, which is on block C, which is on the table."), as a
component of some other goal (to stack the blocks and line up the spheres),
or just because the system has the `urge' to do it ("I just hate it when
blocks are not stacked.").
For this demonstration, we will assume that the operator for creating a stack
of blocks A, B, and C is proposed whenever those blocks are available and not
in place. Different tasks can be attempted by modifying the productions that
propose the operator or by adding productions that propose alternative tasks.
In order to propose the operator, there must be a test that the blocks are
not already stacked. If such a test is not included, the system will
continually try to stack the blocks even when they are in position. The
easiest way to encode this test is to add a production that detects when the
blocks are in position and then test that the result of this production is
not in working memory. Below is a production to detect that the blocks are
correctly stacked.
(sp top-goal*elaborate*state*detect-tower
(goal <g> ^problem-space.name top-ps ^state <s>)
(<s> ^object-dynamic <blockA-dyn>
{ <> <blockA-dyn> <blockB-dyn> }
{ <> <blockA-dyn> <> <blockB-dyn> <blockC-dyn> }))
(<blockA-dyn> ^ontop <blockB> ^object-static <blockA>)
(<blockB-dyn> ^ontop <blockC> ^object-static <blockB>)
(<blockC-dyn> ^ontop <table> ^object-static <blockC>)
(<blockA> ^name A)
(<blockB> ^name B)
(<blockC> ^name C)
(<table> ^name table)
-->
(<s> ^object-dynamic <tower> + &)
(<tower> ^top-block <blockA>
^middle-block <blockB>
^bottom-block <blockC>))
The state is augmented with an object that has a top-block, a middle-block,
and a bottom-block. It could be further augmented with a type, such as
tower, although it is unnecessary for our example.
The next production tests that the blocks exist and that there is no tower.
The test that there is no tower is a conjunctive negation because it tests
for the absence of a set of conditions. This production will match as long
as there is no structure in working memory that matches all of the conditions
in the negation. The production creates an acceptable preference for the
operator, and augments it with a name and a desired state.
(sp top-goal*propose*operator*build-tower
(goal <g> ^problem-space <p> ^state <s>)
(<p> ^name top-ps)
(<s> ^object-dynamic <blockA-dyn>
<blockB-dyn>
<blockC-dyn>
<table-dyn>)
(<blockA-dyn> ^object-static <blockA>)
(<blockA> ^name A)
(<blockB-dyn> ^object-static <blockB>)
(<blockB> ^name B)
(<blockC-dyn> ^object-static <blockC>)
(<blockC> ^name C)
(<table-dyn> ^object-static <table>)
(<table> ^name table)
-{(<s> ^object-dynamic <tower>)
(<tower> ^top-block <blockA>
^middle-block <blockB>
^bottom-block <blockC>)}
-->
(<g> ^operator <o>)
(<o> ^name build-tower ^desired-state <ds>)
(<ds> ^ontop-count 3
^object-dynamic <dblockA-dyn> + &,
<dblockB-dyn> + &,
<dblockC-dyn> + &)
(<dblockA-dyn> ^ontop <blockB> ^object-static <blockA>)
(<dblockB-dyn> ^ontop <blockC> ^object-static <blockB>)
(<dblockC-dyn> ^ontop <table> ^object-static <blockC>)
(write (crlf) |The goal is to get A on B on C on the table|))
It is not absolutely necessary to create an explicit description of the
desired state in working memory. The task can be performed by a blind search
with only a test that a tower has been built. The explicit state description
will be useful for implementing means-ends analysis to control the selection
of operators.
In creating the desired state, this production must match the blocks in the
current state so that the identifiers of the blocks and table (<table>,
<blockB>, and <blockC>) are used in the desired state. This allows the
desired state to refer directly to the objects in the current state, thereby
simplifying the matching of the desired state against the current state. The
productions that test the desired state need only test the equality of the
identifiers, and do not have to test the actual names of the blocks. This
leads to more generality during chunking (see Section See Constants on
page See Constants).
The following trace shows where the build-tower operator is proposed and then
selected by the decision procedure to be the current operator of goal G1.
The d command is used to advance to the next decision (see See d on page
See d).
Soar> d 1
--- Input Phase ---
--- Preference Phase ---
Firing top-ps*propose*operator*build-tower
(7: G1 ^problem-space P1) (5: P1 ^name top-ps)
(11: G1 ^state S1) (15: S1 ^object-dynamic B3)
(29: B3 ^object-static B6) (32: B6 ^name c)
(16: S1 ^object-dynamic B2) (24: B2 ^object-static B5)
(27: B5 ^name b) (17: S1 ^object-dynamic B1)
(19: B1 ^object-static B4) (22: B4 ^name a)
(18: S1 ^object-dynamic T1) (35: T1 ^object-static T2)
(36: T2 ^name table)
The goal is to get A on B on C on the table.
--- Working Memory Phase ---
=>WM: (52: G1 ^operator O2 +)
=>WM: (51: D5 ^ontop T2)
=>WM: (50: D5 ^object-static B6)
=>WM: (49: D4 ^ontop B6)
=>WM: (48: D4 ^object-static B5)
=>WM: (47: D3 ^ontop B5)
=>WM: (46: D3 ^object-static B4)
=>WM: (45: D2 ^ontop-count 3)
=>WM: (44: D2 ^object-dynamic D3)
=>WM: (43: D2 ^object-dynamic D4)
=>WM: (42: D2 ^object-dynamic D5)
=>WM: (41: O2 ^desired-state D2)
=>WM: (40: O2 ^name build-tower)
--- Output Phase ---
--- Input Phase ---
--- Quiescence Phase ---
=>WM: (53: G1 ^operator O2)
3: O: O2 (build-tower)
At this point, operator O2 has been selected and the system is ready to
attempt the task of building a tower.