.he 'SEARCH2''Page %'
.fo 'Steven Hardy'- % -'14th, December 1976'
.ce 2
State space searching
=====================
.sp
The SEARCH1 demos gives an introduction to this topic.
.br
We assume the existence of the following functions: ISGOAL and EXPAND.
Both of these functions take as argument a (description of a) state of the world.
ISGOAL returns TRUE iff (if and only if) the state is a 'goal state`,
EXPAND returns a
.ul
list
of (descriptions of) states of the world which can be reached directly from the
given state.
.sp
Here is a simple function to search for a goal state:
 	: FUNCTION SEARCH(STATE) => STATE;
 	:	UNTIL ISGOAL(STATE) THEN
 	:		ONEOF(EXPAND(STATE)) -> STATE
 	:	CLOSE
 	: END;
.br
This function takes an intial state of the world as argument and searches
for a goal state, which it returns as its result.
This program has
.ul
many
disadvantages.
It might easily never find the goal, or get to a state from which there is no escape
or go round and round in a loop for ever.
.sp
.tp 11
Here is a more complicated function which performs a
'depth first search':
 	: FUNCTION SEARCH(STATE) => STATE;
 	:	VARS ALTERNATIVES;
 	:	NIL -> ALTERNATIVES;
 	:	UNTIL ISGOAL(STATE) THEN
 	:		EXPAND(STATE) <> ALTERNATIVES -> ALTERNATIVES;
 	:		HD(ALTERNATIVES) -> STATE;
 	:		TL(ALTERNATIVES) -> ALTERNATIVES;
 	:	CLOSE
 	: END;
.br
In this function, all possible moves at a state are remembered.
If a state leads to a 'dead end' (ie EXPAND returns NIL) the function SEARCH
goes back to the
.ul
most recent
alternative.
If there are no remaining alternatives this function causes an error.
This function can still get stuck in loops - but a dead end doesn't bother it over much.
.sp
.tp 11
To overcome the problem of looping we can perform a 'breadth first search', for example:
 	: FUNCTION SEARCH(STATE) => STATE;
 	:	VARS ALTERNATIVES;
 	:	NIL -> ALTERNATIVES;
 	:	UNTIL ISGOAL(STATE) THEN
 	:		ALTERNATIVES <> EXPAND(STATE) -> ALTERNATIVES;
 	:		HD(ALTERNATIVES) -> STATE;
 	:		TL(ALTERNATIVES) -> ALTERNATIVES;
 	:	CLOSE
 	: END;
.br
.sp
.tp 18
However, this function might still consider the same state
.ul
twice,
so we alter the SEARCH function:
 	: FUNCTION SEARCH(STATE) => STATE;
 	:	VARS ALTERNATIVES CONSIDERED TEMPLIST;
 	:	NIL -> ALTERNATIVES;
 	:	NIL -> CONSIDERED;
 	:	UNTIL ISGOAL(STATE) THEN
 	:		[%STATE%] <> CONSIDERED -> CONSIDERED;
 	:		FOR	EXPAND(STATE) -> TEMPLIST
 	:		STEP	TL(TEMPLIST) -> TEMPLIST
 	:		TILL	TEMPLIST = NIL
 	:		THEN	UNLESS	ISONEOF(HD(TEMPLIST),ALTERNATIVES)
 	:				OR	ISONEOF(HD(TEMPLIST),CONSIDERED)
 	:			THEN	INSERT(HD(TEMPLIST),ALTERNATIVES)
 	:					-> ALTERNATIVES
.br
 	:			CLOSE;
 	:		CLOSE;
 	:		HD(ALTERNATIVES) -> STATE;
 	:		TL(ALTERNATIVES) -> ALTERNATIVES
 	:	CLOSE
 	: END;
.br
.sp
.tp 9
We need definitions of
ISONEOF
and
INSERT.
 	: FUNCTION ISONEOF(STATE,LIST);
 	:	IF	LIST = NIL
 	:	THEN	FALSE
 	:	ELSEIF	SAMESTATE(STATE,HD(LIST))
 	:	THEN	TRUE
 	:	ELSE	ISONEOF(STATE,TL(LIST))
 	:	CLOSE
 	: END;
.br
where SAMESTATE is a function which takes two (descriptions of) states
and returns TRUE iff they are
.ul
equivalent.
This function must be provided by the user of the SEARCH function.
.sp
The
INSERT
function takes a state and a list of states and returns a new list
of states containing the given state.
If
INSERT
considers the given state
'important'
(ie close to the goal)
it will put it towards the beginning of the
result,
if it considers it not very exciting
(ie not very close to the goal)
it will put it towards the end of the list.
The following definition of
INSERT
considers all
NEW
states important and puts them at the HD of the result:
 	: FUNCTION INSERT(NEWSTATE,LIST);
 	:	[%NEWSTATE%] <> LIST
 	: END;
.br
This is a 'depth first search'.
.sp
This definition considers all new states very dull:
 	: FUNCTION INSERT(NEWSTATE,LIST);
 	:	LIST <> [%NEWSTATE%]
 	: END;
.br
.sp
.tp 10
This definition uses a user defined function, called
ISBETTER,
to assess a new state:
 	: FUNCTION INSERT(NEWSTATE,LIST);
 	:	IF	LIST = NIL
 	:		OR	ISBETTER(NEWSTATE,HD(LIST))
 	:	THEN	[%NEWSTATE%] <> LIST
 	:	ELSE	[%HD(LIST)%] <>
 	:			INSERT(NEWSTATE,TL(LIST))
 	:	CLOSE
 	: END;
.br
Notice that this definition can still make a depth first
search:
 	: FUNCTION ISBETTER(NEWSTATE,OLDSTATE);
 	:	TRUE
 	: END;
.br
This one makes a breadth first search:
 	: FUNCTION ISBETTER(NEWSTATE,OLDSTATE);
 	:	FALSE
 	: END;
.br
.sp
Exercise
.br
--------
.br
Write the functions ISGOAL, EXPAND, SAMESTATE and ISBETTER for a simple number game,
for example:
"get from some given number to some other given number using only the operations
SUBTRACTONE and DOUBLE"
.sp
I suggest you represent a state by a
.ul
list
of numbers - the 'current` number and the numbers from which it was got.
For example, the problem of getting from two to seven might look like:
 	: SEARCH([2]) =>
 	** [2 4 8 7]
.br
where the actions performed were DOUBLE, DOUBLE, DOUBLE, SUBTRACTONE.
.sp
Try this puzzle on various forms of the SEARCH function - you should insert appropriate
print statements in the SEARCH function (otherwise you won't know what its doing!).
.sp
Try various versions of
ISBETTER
for example:
.in +8
.ll -8
.br
"states with positive numbers are better than those without"
.br
"state A is better than state B if its current number
is closer to the desired number."
.br
"states with few numbers in them are better than those with
lots, that is
[2 4 8] is better than [2 4 8 16]
.in -8
.ll +8
.sp
Reading: PS.R
