Go backward to Operator proposal.
Go up to Encoding A Task in Soar.
Go forward to Operator application.
Operator comparison
===================
Operator comparison is the process of creating desirability preferences for
competing operators. Soar's preference scheme supports relative comparisons,
such as that operator O32 is *better than* operator o25, and it supports
absolute preferences, such as that operator o25 is {worst} (see Section
See preferences on page See preferences for more information on the
semantics of preferences).
Below is an example operator-comparison production that prefers operators
that move a block into its position over operators that do not. This
production alone is not sufficient to distinguish between all possible
competing operators (see Section See Operator comparison on page
See Operator comparison). Additional productions are needed that prefer
operators that move blocks at the bottom of the tower into place and clear
off blocks that need to be moved.
(sp blocks-world*compare*operator*move-block*into-place*better
(goal <g> ^problem-space.name blocks-world
^desired <d>
^operator <o1> + ^operator { <> <o1> <o2>} +)
(<d> ^object-dynamic
(^object-static <blockA> ^ontop <destinationA>))
(<o1> ^name move-block ^moving-block <blockA> ^destination <destinationA>)
(<o2> ^name move-block ^moving-block <blockB> ^destination <destinationB>)
-(<d> ^object-dynamic
(^object-static <blockB> ^ontop <destinationB>))
-->
(<g> ^operator <O1> > <o2>))
The first condition tests for the current problem space, state, and desired
state. It also includes tests for two acceptable operator preferences
(^operator <o1> + ^operator <o2> +). By testing for acceptable preferences,
this production can fire *before* either operator is selected. The next two
conditions test that the desired state has an ontop relation that operator
<o1> will achieve. The remaining conditions test that operator <o2> will not
achieve part of the desired state. The action of the production is to create
a preference that makes operator <o1> better than <o2>.
One problem with this production is that it must partially match against all
pairs of acceptable operators, which can be computationally expensive. A
possible alternative is to only match against one operator, and create a
unary preference, such as best or worst for that operator. For example, the
following productions will create a best preference for an operator that
moves a block into its desired position, and a worst preference for an
operator that does not move a block into its desired position or onto the
table.
(sp blocks-world*compare*operator*move-block*into-place*best
"Prefer moving blocks into their desired location"
(goal <g> ^problem-space.name blocks-world ^state <s> ^desired <d>
^operator <O1> +)
(<d> ^object-dynamic (^object-static <blockA> ^ontop <blockB>))
(<O1> ^name move-block ^moving-block <blockA> ^destination <blockB>)
-->
(<g> ^operator <O1> >, =))
(sp blocks-world*compare*operator*move-block*not-into-place*worst
(goal <g> ^problem-space.blocks-world ^desired <d>
^operator <o2> +)
(<o2> ^name move-block ^moving-block <dblockA> ^destination <destination>)
-(<d> ^object-dynamic (^object-static <dblockA> ^ontop <destination>))
-(<destination> ^type block)
-->
(<g> ^operator <o2> <, =))
These productions will be much more efficient to match; however, these
productions will have slightly different semantics, and will lead to
different results if additional better preferences are available. For
example, if operator X moved a block into its desired position, and operator
Y did not move a block into its desired position, the first production will
create a preference that X is better than Y. If there is an additional
production that creates a preference that operator Y is better than X, then a
conflict impasse will arise. If the productions that create the worst and
best preferences are used, no conflict will arise because the better
preference will dominate and X will be selected. Thus, for the remainder of
this example we will not include these two productions.
Other productions can be added to further control the selection of operators.
The previous productions do not create any preferences between two operators
that both move blocks into their desired locations. Obviously, the system
should prefer stacking lower blocks first. It should always build from the
bottom up and never attempt to create partial towers. The following
production prefers operators that move a block into its desired position over
operators that will move a block into place on top of the block being moved
by the first operator. This creates a partial ordering that leads to having
the bottom block always placed first, followed by the one on top of that and
so on until all blocks are in place.
(sp blocks-world*compare*operator*move-block*lower*better
(goal <g> ^problem-space.name blocks-world
^desired <d>
^operator <O1> + ^operator <o2> +)
(<d> ^object-dynamic <dblockA-dyn>
{ <> <dblockA-dyn> <dblockB-dyn> })
(<dblockA-dyn> ^object-static <dblockA> ^ontop <dblockB>)
(<dblockB-dyn> ^object-static <dblockB> ^ontop <dblockC>)
(<O1> ^name move-block ^moving-block <dblocka> ^destination <dblockb>)
(<o2> ^name move-block ^moving-block <dblockb> ^destination <dblockc>)
-->
(<g> ^operator <O1> < <o2>))
The final operator selection production fires even when it is not possible to
move a block into its desired position. This is the case in our example when
A is on B and both B and C are on the table. The only available operators
are to move A onto C or the table and to move C onto A. This final
production creates worst preferences for operators that move blocks onto
other blocks, when that is not their desired position. In general, this
allows other operators that merely unstack blocks to be chosen.
(sp blocks-world*compare*operator*move-block*not-into-position*worst
(goal <g> ^problem-space.name blocks-world
^state <s>
^desired <d>
^operator <O1> +)
(<d> ^object-dynamic (^object-static <dblockA> ^ontop <dblockB>))
(<O1> ^name move-block ^moving-block <dblockA>
^destination (<> <dblockB> ^type block))
-->
(<g> ^operator <O1> <, =))
Another operator selection production would be required to select randomly
between operators that build different towers if the desired state is not a
single tower of blocks (see Section See Blocks World Knowledge on page
See Blocks World Knowledge).
The trace below shows a (watch 1) trace of the proposal and comparison of
operators that lead to the selection of the first operator.
Soar> watch 1
Soar> run 1
--- Input Phase ---
--- Preference Phase ---
Firing blocks-world*propose*operator*move-block 65 63 70 18 34 17 20 35 19 23
Firing blocks-world*propose*operator*move-block 65 63 70 17 20 15 30 19 29 33
Firing blocks-world*propose*operator*move-block 65 63 70 15 30 17 20 29 19 23
--- Working Memory Phase ---
--- Output Phase ---
Soar> run 1
--- Input Phase ---
--- Preference Phase ---
Firing blocks-world*compare*operator*move-block*not-into-position*worst
81 74 76 23 65 63 75 60 42 50 51 70
Firing blocks-world*compare*operator*move-block*not-into-position*worst
82 77 79 33 65 63 78 60 44 46 47 70
--- Working Memory Phase ---
--- Output Phase ---
Three operators are proposed: move A to the table, move A to C, and move C to
A. Worst preferences are created for moving A to C, and moving C to A, since
neither one moves a block into its desired location. Moving A to the table
does not move a block into a desired position, but it does move the block to
the table, so it is not made worst.
To examine the preferences, the preferences function can be used (see Section
See preferences on page See preferences for more details).
Preferences will display all of the active preferences for a given identifier
and attribute. In this case, we want to examine the ^operator attribute of
the current goal: G2.
Soar> preferences g2 operator
Preferences for G2 ^operator:
Acceptables:
O3 (move-block) +
O4 (move-block) +
O5 (move-block) +
Worsts:
O4 (move-block) <
O5 (move-block) <
Unary Indifferents:
O4 (move-block) =
O5 (move-block) =
It is often useful to be able to determine which production was responsible
for creating a preference. By giving the extra parameter 2 to preferences,
it displays this extra information:
Soar> preferences g2 operator 2
Preferences for G2 ^operator:
Acceptables:
O3 (move-block) +
From blocks-world*propose*operator*move-block 65 63 70 18 34 17 20 35 19 23
O4 (move-block) +
From blocks-world*propose*operator*move-block 65 63 70 17 20 15 30 19 29 33
O5 (move-block) +
From blocks-world*propose*operator*move-block 65 63 70 15 30 17 20 29 19 23
Worsts:
O4 (move-block) <
From blocks-world*compare*operator*move-block*not-into-position*worst
81 74 76 23 65 63 75 60 42 50 51 70
O5 (move-block) <
From blocks-world*compare*operator*move-block*not-into-position*worst
82 77 79 33 65 63 78 60 44 46 47 70
Unary Indifferents:
O4 (move-block) =
From blocks-world*compare*operator*move-block*not-into-position*worst
81 74 76 23 65 63 75 60 42 50 51 70
O5 (move-block) =
From blocks-world*compare*operator*move-block*not-into-position*worst
82 77 79 33 65 63 78 60 44 46 47 70
All of the currently active preferences are supported by either I-support or
O-support. I-support means that the preference is supported by a production
instantiation, while O-support means that a preference is supported by the
augmentation or application of an operator (see Section *Note The semantics
of productions:: on page See The semantics of productions for more
details on support). By examining the preferences it easy to see that only O3
does not have a worst preference and thus will be selected.
Soar> run 1
--- Input Phase ---
--- Quiescence Phase ---
7: O: O3 (move-block)