com.thesett.aima.search.impl.bidirectional.BaseBiDirectionalQueueSearch Maven / Gradle / Ivy
Show all versions of search Show documentation
/*
* Copyright The Sett Ltd, 2005 to 2014.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.thesett.aima.search.impl.bidirectional;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import com.thesett.aima.search.Operator;
import com.thesett.aima.search.QueueBasedSearchMethod;
import com.thesett.aima.search.RepeatedStateFilter;
import com.thesett.aima.search.SearchNode;
import com.thesett.aima.search.SearchNotExhaustiveException;
import com.thesett.aima.search.Successor;
import com.thesett.aima.search.Traversable;
import com.thesett.aima.search.spi.PathJoinAlgorithm;
import com.thesett.common.error.NotImplementedException;
import com.thesett.common.util.logic.UnaryPredicate;
/**
* BaseBiDirectionalQueueSearch provides a base implementation for deriving new bidirectional searches from by providing
* different queue implementations for the forward and reverse portions of the search. For example using a LIFO queue
* generates depth first search and a FIFO queue generates breadth first. Heuristic searches can easily be implemented
* by using priority queues with ordering predicates based on a heuristic evaluation.
*
* The search proceeds by taking the next element of the forward search fringe and testing to see if it matches one
* element of the reverse fringe. It then expands the forward fringe with the successor nodes if no match is found. Then
* it takes the next element of the reverse fringe and does the same matching and expanding process against the forward
* fringe. The states need to be hashable in order to make the fringe matching efficient.
*
*
Once a match between the forward and reverse fringes has been found it then walks backwards along the node found
* on the reverse fringe adding all its states and operations to the forward search path. This class implements a
* standard algorithm for doing this. It assumes that the state space being searched by both halfs of the search is over
* the same states. It also assumes that the applied operations in the reverse search node have already been reverse.
* For example, if the search space was the eight tiles game then the moves stored in the reverse half of the search
* would have to be stored in the reverse direction to that in which they are applied when really playing the game
* backwards. This means that two implementations of {@link com.thesett.aima.search.TraversableState} are needed, one
* that gives its operators reversed.
*
*
It is possible to supply an alternative path joining algorithm that does know how to reverse the operators. Set
* this algorithm by calling the {@link #setPathJoinAlgorithm} method. This is an alternative to writing two
* implementatios of {@link com.thesett.aima.search.TraversableState}
*
*
CRC Card
* Responsibilities Collaborations
* Bidirectional search state space using specified queue implementations {@link SearchNode}
*
*
* @author Rupert Smith
* @todo At least one of the directions ought to be a breadth first search. Provide some explanation of this from the
* literature as well as some other saliant information about bi-directional searches.
*/
public class BaseBiDirectionalQueueSearchNote that the {@link com.thesett.aima.search.GoalState} interface itself defines the method
* {@link com.thesett.aima.search.GoalState#isGoal} which tests if a state is a goal state. It is therefore not
* necessary to call this method to set goal states where the goal definition is defined already in the states.
* Setting goal states through this method, when it is supported by an algorithm overrides the goal definition in
* the states themselves.
*
* @param unaryPredicate The goal predicate.
*
* @throws UnsupportedOperationException if the search algorithm does not accept goal states.
*/
public void setGoalPredicate(UnaryPredicate This method implements a standard algorithm for doing this. It assumes that the state space being searched by
* both halfs of the search is over the same states. It also assumes that the applied operations in the reverse
* search node have already been reverse. For example, if the search space was the eight tiles game then the moves
* stored in the reverse half of the search would have to be stored in the reverse direction to that in which they
* are applied when really playing the game backwards. This means that two implementations of
* {@link com.thesett.aima.search.TraversableState} are needed, one that gives its operators reversed.
*
* It is possible to supply an alternative path joining algorithm that does know how to reverse the operators.
* Set this in this search algorithm by calling the {@link #setPathJoinAlgorithm} method. This is an alternative to
* writing two implementatios of {@link com.thesett.aima.search.TraversableState}
*
* @param forwardPath a search node for the forward portion of the goal path
* @param reversePath a search node for the reverse portion of the goal path
*
* @return a search node corresponding to the path right from start to goal
*
* @throws SearchNotExhaustiveException If the node implementation does not allow new nodes to be created from old.
* See the {@link SearchNode#makeNode} method for more information.
*/
private SearchNode