Il est toujours possible d’´ecrire `a la pi`ece un algorithme de recherche pour un besoin sp´ecifique. Il est cependant plus productif d’´ecrire sa boˆıte `a outil d’algorithmes de recherche
”g´en´erique”. Nous devons pour cela d´efinir :
• Une fa¸con d’exprimer le probl`eme
• Une ou plusieurs fa¸cons de repr´esenter une frange
• Une structure permettant d’encoder un nœud de l’arbre de recherche
• Les algorithmes de recherche !
En cours nous avons vu desinterfaces de chacune de ces composantes. Reste `a les mettre en œuvre.
Une approche g´ en´ erique. . .
Pro : meilleure conception, utilisabilit´e accrue Cons : plus de code `a ´ecrire !
Prenons Java comme langage d’impl´ementation1.
Nous avons besoin de manipuler un´etat, et ce quelque soit le probl`eme. Soit IState une interface permettant de manipuler des ´etats de mani`ere polymorphique.
interface IState { }
1Je ne programme pasJava, aussi, je ne suis pas au fait des facilit´es templateoffertes par les nouveaux compilateurs et qui devraient ˆetre ici
Tous les probl`emes seront manipul´es via cette interface : interface IProblem {
public IState INIT();
public boolean GOAL( IState state );
public LinkedList< Triplet > SUCCESSOR_FN(IState state);
}
o`u Triplet est une structure permettant de stocker :
<action,nouvel-etat,step-cost>.
Les interfaces
Nous allons manipuler diff´erents types de frange (qui d´efiniront le type de recherche effectu´ee).
interface IFrange {
public Node REMOVE_FIRST();
public boolean EMPTY();
public void INSERT_ALL(LinkedList <Node> l);
public void INSERT(Node n);
Une classe pour repr´esenter un nœud : class Node {
private Node parent;
private IState etat;
private int path_cost,profondeur;
private String action;
public IState STATE() {return etat;}
public int PATH_COST() {return path_cost;}
public int DEPTH() {return profondeur;}
public Node PARENT() {return parent;}
public String ACTION() {return action;}
public Node(IState state, Node parent, String action, int costChemin, int depth) {}
public Node(IState state) {}
Les classes
Dans le doute : class Triplet {
private IState state;
private String action;
private int step_cost;
public Triplet(IState state_,String action_, int step_cost_) { state = state_;
action = action_;
step_cost = step_cost_;
}
public IState getState() {return state;}
public String getAction() {return action;}
public int getStepCost() {return step_cost;}
Pour la recherche en largeur d’abord, nous avons besoin d’une file FIFO :
class FIFO implements IFrange {
private LinkedList < Node > frange;
public FIFO() { frange = new LinkedList <Node>(); } public Node
REMOVE_FIRST() { return frange.removeLast(); } public boolean EMPTY() { return frange.size() == 0;}
public void
INSERT_ALL(LinkedList <Node> l) {frange.addAll(0,l);}
public void INSERT(Node n) { frange.addFirst(n);}
Les classes
Tous lessolverspartagent ces fonctions : class ISolver {
protected void SOLUTION(Node node) { /* to do */}
protected LinkedList< Node >
EXPAND(IProblem problem, Node node) {
LinkedList< Node > succs = new LinkedList< Node >();
for ( Triplet t : problem.SUCCESSOR_FN(node.STATE()) ) succs.add(
new Node(t.getState(), node, t.getAction(), node.PATH_COST() + t.getStepCost(), node.DEPTH() + 1));
return succs;
}
Il ne manque que l’algorithme de recherche : class TreeSearch extends ISolver {
public TreeSearch(IProblem problem, IFrange fringe) { fringe.INSERT(new Node(problem.INIT()));
do {
Node node = fringe.REMOVE_FIRST();
if (problem.GOAL(node.STATE())) { SOLUTION(node); } fringe.INSERT_ALL(EXPAND(problem,node));
}
while (fringe.EMPTY() == false);
}
Et enfin ... le probl` eme en lui mˆ eme !
class StateAspirateur implements IState { private boolean dirty [];
private int pos_x; // la position du robot
public StateAspirateur(int x, boolean dirt []) { dirty = new boolean [dirt.length];
System.arraycopy(dirt,0,dirty,0,dirt.length);
pos_x = x;
}
public int getPos() {return pos_x;}
public boolean allClean() {
for (int i=0; i<dirty.length; ++i) if (dirty[i]) return false;
return true;
}
public void setDirtLocation(int pos, boolean dirt) { dirty[pos] = dirt;
}
public String toString() { String s = "";
for (boolean b : dirty) s += (b + " ");
return "pos=" + pos_x + " dirt=[ " + s + "]";
}
Et enfin ... le probl` eme en lui mˆ eme !
class ProblemAspirateur implements IProblem { private static final int N = 8;
private static final int STEP_COST = 1;
public IState INIT() {
boolean dirty[] = {true, false, true, true, true, true, true, false};
return new StateAspirateur(1,dirty);
}
public boolean GOAL(IState state) {
return ((StateAspirateur) state).allClean();
}
public LinkedList< Triplet >
SUCCESSOR_FN( IState istate ) {
StateAspirateur state = (StateAspirateur) istate;
// action 1 : aspirer
if (state.getDirtLocations()[state.getPos()]) { succs.add(
new Triplet(
new StateAspirateur( state.getPos(), state.getDirtLocations()),
"Aspire", STEP_COST ));
StateAspirateur etat =
(StateAspirateur) succs.getLast().getState();
etat.setDirtLocation(state.getPos(),false);
Et enfin ... le probl` eme en lui mˆ eme !
if (((StateAspirateur) state).getPos() > 0) succs.add( // action 2 : aller a gauche
new Triplet(
new StateAspirateur(state.getPos()-1,
state.getDirtLocations()),
"Gauche", STEP_COST ));
if (state.getPos() < (N-1) )
succs.add( // action 3 : aller a droite new Triplet (
new StateAspirateur(state.getPos()+1, state.getDirtLocations()),
"Droite", STEP_COST ));
return succs;
Graph-Search
Solution de cout: 13 profondeur: 13 nodes extended: 823 pos=1 dirt=[ D . D D D D D . ]
Gauche pos=0 dirt=[ D . D D D D D . ] Aspire pos=0 dirt=[ . . D D D D D . ] Droite pos=1 dirt=[ . . D D D D D . ] Droite pos=2 dirt=[ . . D D D D D . ] Aspire pos=2 dirt=[ . . . D D D D . ] Droite pos=3 dirt=[ . . . D D D D . ] Aspire pos=3 dirt=[ . . . . D D D . ] Droite pos=4 dirt=[ . . . . D D D . ] Aspire pos=4 dirt=[ . . . D D . ] Droite pos=5 dirt=[ . . . D D . ] Aspire pos=5 dirt=[ . . . D . ] Droite pos=6 dirt=[ . . . D . ]
Aspirateur en largeur, Tree-Search
Solution de cout: 13 profondeur: 13 nodes extended: 97579 pos=1 dirt=[ D . D D D D D . ]
Gauche pos=0 dirt=[ D . D D D D D . ] Aspire pos=0 dirt=[ . . D D D D D . ] Droite pos=1 dirt=[ . . D D D D D . ] Droite pos=2 dirt=[ . . D D D D D . ] Aspire pos=2 dirt=[ . . . D D D D . ] Droite pos=3 dirt=[ . . . D D D D . ] Aspire pos=3 dirt=[ . . . . D D D . ] Droite pos=4 dirt=[ . . . . D D D . ] Aspire pos=4 dirt=[ . . . D D . ] Droite pos=5 dirt=[ . . . D D . ] Aspire pos=5 dirt=[ . . . D . ] Droite pos=6 dirt=[ . . . D . ]
Graph-Search
Solution de cout: 11 profondeur: 11 nodes extended: 29 Rive 1 M3 C3 ~~~ M0 C0
action [1 each] Rive 2 M2 C2 ~~~ M1 C1 action [1 miss] Rive 1 M3 C2 ~~~ M0 C1 action [2 cann] Rive 2 M3 C0 ~~~ M0 C3 action [1 cann] Rive 1 M3 C1 ~~~ M0 C2 action [2 miss] Rive 2 M1 C1 ~~~ M2 C2 action [1 each] Rive 1 M2 C2 ~~~ M1 C1 action [2 miss] Rive 2 M0 C2 ~~~ M3 C1 action [1 cann] Rive 1 M0 C3 ~~~ M3 C0 action [2 cann] Rive 2 M0 C1 ~~~ M3 C2 action [1 cann] Rive 1 M0 C2 ~~~ M3 C1
Cannibale en largeur, Tree-Search
Solution de cout: 11 profondeur: 11 nodes extended: 11852 Rive 1 M3 C3 ~~~ M0 C0
action [1 each] Rive 2 M2 C2 ~~~ M1 C1 action [1 miss] Rive 1 M3 C2 ~~~ M0 C1 action [2 cann] Rive 2 M3 C0 ~~~ M0 C3 action [1 cann] Rive 1 M3 C1 ~~~ M0 C2 action [2 miss] Rive 2 M1 C1 ~~~ M2 C2 action [1 each] Rive 1 M2 C2 ~~~ M1 C1 action [2 miss] Rive 2 M0 C2 ~~~ M3 C1 action [1 cann] Rive 1 M0 C3 ~~~ M3 C0 action [2 cann] Rive 2 M0 C1 ~~~ M3 C2 action [1 cann] Rive 1 M0 C2 ~~~ M3 C1