3. Algorithmes de recherche dans les systèmes à agents
3.2. Recherche informée distribuée

3.2.1. Recherche heuristique de la solution

Les algorithmes présentés dans la section 3.1 ne peuvent pas résoudre beaucoup des problèmes réels à cause de la complexité de leurs espaces d`états.

La recherche heuristique représente alors une technique alternative de résolution de problèmes en intelligence artificielle, largement utilisée pour les problèmes qui sont caractérisés par une explosion combinatoire d`états. Alors que les algorithmes non-informés réalisent une recherche systématique et `aveugle`, les techniques de recherche heuristique utilisent un ensemble de règles qui permettent d`évaluer la probabilité qu`un chemin allant du nœud courant au nœud solution soit meilleur que les autres. Cette information qui permet l`estimation des bénéfices des divers chemins avant les parcourir améliore, dans la plupart des cas, le processus de recherche.

Les algorithmes de recherche heuristique utilisent des fonctions appelées fonctions heuristiques,

h : E –>R

où E est l`espace d`états et R l`ensemble de réels. La valeur h(s) estime, par exemple, le rapport coût / bénéfice de suivre un chemin vers la solution qui passe par l`état s dans E. Evidemment, si le nœud s est le nœud solution alors on a la contrainte h(s)=0.

Remarque: Si h(s) = 0 sur les états solutions, c'est donc le minimum de l'heuristique que l'on recherche en chaque état.

L`idée de base d`un tel algorithme consiste dans la détermination pour chaque nœud n exploré de l`ensemble:

H(n) = { h(s) / chacune s dans successeurs(n) }

et de continuer la recherche avec le nœud so, tel que h(so) soit le minimum / maximum de H(n), selon l`heuristique utilisée.

Parce que les algorithmes de recherche heuristique tirent profit d`une information partielle, en dehors de l`espace d'états, ils sont appelés aussi des algorithmes informés.

L`algorithme de recherche du meilleur d`abord (Best-First Search)

Dans cette technique de recherche on étend toujours le nœud qui a la meilleure valeur h(s). Cet algorithme peut être obtenu par la particularisation de l`algorithme général de recherche présenté dans la section 3.1.1 en utilisant pour la structure S une file ordonnée.

Fonction RechercheMeilleurD_abord (étatInitial, ensemble_opérateurs, h) est

 S = FileOrdonnéVide()
 Insérer( S, (Nœud(étatInitial), 0) )
 tant que non Vide(S)  faire
      NœudCourant = Extraire ( S )
      if Test_But(NœudCourant)= vrai 
      alors
            Détruire (S)
            retourne NœudCourant
      sinon
            pour
*) chacune op dans ensemble_opérateurs faire
            x = Successeur(NodeCourant,op)
            si Valide(x)
 
                 alors Insérer(S,x, h(x))
 
           fin si
            fin pour
      fin si
fin tant que
Détruire (S)
retourne vide
Fin

La fonction Insérer(S,x, h(x)) va insérer le nœud x dans la structure S, de façon que tous les éléments de S soient ordonnés dans l`ordre croissant des valeurs de la fonction heuristique  h(x).

La fonction Extraire(S) va retourner le nœud x ayant la plus petite valeur h(x) de tous les nœuds qui se trouvent en S puis cette fonction va éliminer x de S. Dans les cas où il y a un ensemble de nœuds ayant la même valeur minimum on va décider en faveur du nœud solution, s`il est contenu dans cet ensemble, sinon on choisit au hasard.

L`algorithme combine les avantages des principaux algorithmes non-informés :

  • en profondeur : il cherche toujours un seul chemin, le plus prometteur selon la fonction heuristique utilisée;
  • en largeur : à chaque pas il prend en considération tous les successeurs d`un nœud pour déterminer l`ensemble H(n)

Le choix de la fonction heuristique s`avère très important pour l`efficacité de la recherche effectuée par l`algorithme.

Qualité des fonctions heuristiques

L`utilité des fonctions heuristiques réside dans la limitation du nombre d'états à développer ou autrement dit, dans la diminution de branchements effectués pendant la recherche, ce qui conduit à une économie de temps et d`espace mémoire.

Pour évaluer la qualité d`une fonction heuristique on peut calculer le facteur de branchement effectif qui est une valeur a posteriori du processus de recherche. Soit N le nombre d`états explorés pendant un processus de recherche de la solution d`un problème concret en utilisant une fonction heuristique h() et  soit P la profondeur du nœud solution dans ce processus de recherche. Pour calculer la valeur du facteur de branchement effective be  on considère un arbre fictif, parfaitement équilibré ayant le branchement be dont le nombre de nœuds peut être calculé par l`équation 

N = 1 + be + be2 + … + beP

et N, le nombre d`états explorés, doit être égal au nombre de nœuds dans cet arbre fictif.

Une heuristique de bonne qualité aura la valeur du facteur de branchement effective be très proche de 1. Dans le cas idéal, où on trouve la solution sans étendre d'autres nœuds que ceux situés sur le chemin entre l`état initial et la solution, on a be =1. 

Il existe plusieurs méthodes de recherche heuristiques.

La recherche gourmande (Greedy Search)

Cette technique représente la plus simple variante de la stratégie de recherche le meilleur d`abord (Best Search). Pour construire l`algorithme de recherche gourmande on modifie l`algorithme RechercheMeilleurD_abord, mais en utilisant une fonction heuristique h(n) qui estime le coût du chemin entre le nœud courant et le nœud solution. La fonction Insérer(S,x, h(x)) va insérer le nœud x dans la structure S, de façon que tous les éléments de S soient ordonnés dans l`ordre croissant des valeurs de la fonction heuristique h(x). La fonction Extraire(S) va donc retourner et va éliminer de S le nœud le plus proche du nœud solution.

Analyse de l`algorithme de recherche gourmande (Greedy Search)
Complétude – NON, on peut rester pris dans une boucle ; il peut être complet  pour les espaces d`états finis et acycliques
Complexité en temps – exponentielle : O(b p) où p est la profondeur et b est le facteur de branchement
Complexité en  espace – exponentielle : O(b p )
Optimalité - NON

Avec des bonnes heuristiques on peut avoir des complexités en temps meilleures.

La recherche en coût uniforme (Uniform Cost Search)

Cet algorithme utilise une heuristique qui calcule pour chaque nœud n le coût chemin g(n) depuis l`état initial jusqu'au nœud n. Le coût chemin g(n) est une fonction croissante le long d`un chemin : chacune n dans E, s dans Successeurs(n),   g(n) <= g(s).

Les nœuds sont insérés dans la file ordonnée S dans l`ordre croissant de la fonction g(n), de façon qu`à chaque itération le nœud qui minimise g(n) soit développé pour obtenir ainsi un chemin de coût minimum entre l `état initial et la solution.

L`algorithme est complet et optimal, mais a une efficacité réduite.

Programmation dynamique asynchrone. La recherche du plus court chemin

On considère un graphe orienté où les nœuds correspondent aux états du problème. Il y a un nœud de départ s et plusieurs nœuds but. Entre les nœuds existent des liens représentant les opérateurs qui sont appliqués aux états du problème.

Les poids des liens sont considerés comme des distances. Soit d(i,j) la distance entre les nœuds i et j. Le problème de la recherche du plus court chemin exige de trouver le chemin de coût minimum (exprimé à l`aide des distances) entre le nœud s et un nœud but.

La programmation dynamique est basée sur le principe d`optimalité qui affirme qu`un chemin est optimal si tous ces ses sous chemins le sont.

Pour évaluer le coût d`un chemin qui part d'un nœud i et va jusqu`à un nœud but il faut évaluer les coûts de tous les chemins qui partent de i et passent par les nœuds j, successeurs de i:

f*(j) = d(i,j) + h*(j)

h*(j) est la distance la plus courte de i jusqu'à un nœud but. On aura h*(i) = min { f*(j) / chacune j dans Successeurs(i)}.

Un algorithme de programmation dynamique utilise le principe d`optimalité pour construire pas à pas le chemin vers la solution en étendant des sous chemins de longueur croissante, qui sont tous optimaux.

Algorithme de programmation dynamique asynchrone

La programmation dynamique asynchrone représente une technique de recherche distribuée basée sur un réseaux d`agents. Pour chaque nœud i du graphe modélisant l`espace d`états on a un agent Ai qui va calculer en mode répété h(i), une estimation de h*(i). Tous les agents connaissent les successeurs j et les distances d(i,j) entre le nœud courant i et ses successeurs, ainsi que les valeurs initiales de h(i) qui sont égales à la valeur maximale admise (VAL_MAX) pour tous les agents sauf les agents des nœuds but qui ont h(i)=h*(i)=0.

Chaque agent Ai exécute en principe des traitements selon le pseudo code suivant et détermine le nœud successeur jmin(i), afin que le principe d`optimalité soit respecté.

pour *) chacune op dans ensemble_opérateurs, avec op valide faire
      j = Successeur(i,op)
      f(j) = d(i,j) + h(j)
      si h(i) > f(j)
            alors
            h(i)=f(j)
            jmin(i) = j
      fin si
fin pour

Le chemin sera représenté par le chaîne : s, jmin(s), jmin( jmin(s) ) , … , but

Remarque. Le chaîne h(i) converge vers h*(i) parce que les distances d(i,j) sont positives.

Pour les problèmes réels la technique présente le désavantage de nécessiter un très grand nombre des agents.

L`algorithme A*

Cet algorithme est aussi un cas particulier de l`algorithme de recherche du meilleur d`abord. Il combine les avantages des algorithmes de recherche en coût uniforme et de recherche gourmande (Greedy Search), en utilisant une heuristique f()

f(n) = g(n) + h(n)

n est un nœud représentant un état dans l`espace d`états du problème et g(n) et h(n) ont les significations utilisées dans le cas de ces deux algorithmes. Cette heuristique estime le coût total du chemin entre l`état initial et l`état solution qui passe par n. On remarque qu`il s`agit d`une estimation f(n) obtenue par la somme d`une valeur exacte g(n) issue du chemin parcouru de l`état initial jusqu`au nœud n et d`une estimation h(n) du coût du chemin optimal qui lie le nœud n avec au nœud solution.

Pour chaque nœud exploré n on va étendre le successeur x qui minimise la fonction heuristique f()

f(x) = min { f(s) / s dans Successeurs( n )  }

Définition. Une fonction heuristique est dite admissible si

h(s) <=h*(s), chacune s dans E

h*(s) est le coût minimum depuis s au nœud solution.

Analyse de l`algorithme de recherche A*
Complet pour les espaces d`états avec du coût du chemin optimal qui relie le nœud n au nœud solution s ayant f(s)<=f(but)
Complexité en temps – exponentielle
Complexité en  espace– exponentielle
Optimalité – l`algorithme A* est optimal ; il étend toujours les nœuds dans l`ordre croissant de valeurs heuristiques ; l`optimalité de l`algorithme A* est garantie si on utilise une heuristique admissible

Remarques

  1. On observe que l`algorithme A* peut être construit sur la base de l`algorithme de recherche du meilleur d`abord (Best First Search) en utilisant une fonction heuristique égale à la somme du coût calculé pour arriver dans le nœud n et du coût estimé pour atteindre un état solution. Si la fonction qui estime le coût nécessaire pour atteindre un état but ne surévalue jamais le coût réel, alors l`algorithme A* est optimal.
  2. Il arrive que l'on ait à choisir parmi plusieurs fonctions heuristiques admissibles. Un critère est fourni ci-dessous:

Soit deux fonctions heuristiques admissibles h1(s) et h2(s). Si

h1(s) >= h2(s), chacune s dans E

on dit alors que h1(s) domine h2(s) et que h1(s) produit une recherche plus efficace.

Exemple. On considère un jeu de Taquin 3x3 (voir figure 3.2.1).

     

Figure 3.2.1. L`état initial et final dans un jeu de Taquin

à chaque état du jeu on peut appliquer des opérateurs qui permettent de déplacer les pièces voisines de la position libre. Le but de jeu de Taquin est de trouver une séquence optimale d'opérateurs qui mène les pièces de la configuration de l'état initial à l'état but.

 On peut considérer deux heuristiques :

  • h1(i) exprimé comme le nombre des pièces mal placées dans l`état i
  • h2(i) calculé comme la somme des distances Manhattan entre la position dans l`état i et la position dans l`état final de chaque pièce.

Pour les états représentés dans la figure 3.2.1 on a

h1(s) = 5
h2(s) = 0 + 0 +3 + 1 + 0 +2 + 2  + 2 = 10

On observe que h2(s) > h1(s). Si cette inégalité est valable pour tous les états on peut dire que h2(s) est une heuristique dominante.

Les heuristiques dominantes sont préférées tant qu`elles ne surestiment pas le coût minimum.

Question. Quel sera l`état suivant, selon l`algorithme A* appliqué pour la situation présentée dans la figure 3.2.1, en considérant l`heuristique dominante h2(x) ?

Cliquer ici pour voir la réponse


Variantes de l`algorithme A*

La recherche de la solution des problèmes concrets se confronte avec des espaces d`états très grands, qui soulèvent des difficultés majeures en termes d`espace de mémoire nécessaire, même dans le cas des algorithmes heuristiques.

Deux variantes de l`algorithme A* essaient d`aboutir à une solution avec les ressources disponibles :

  • IDA* (Iterated-Depending A*) qui est un algorithme A* qui effectue des approfondissements successifs en rapport avec des valeurs limites pour f(n) ; IDA* est complète et optimale et sa complexité en espace mémoire est de l`ordre O(b×p)
  • SMA* (Simplified Memory-Bounded A*) qui est un algorithme A* qui effectue la gestion de sa propre mémoire disponible: élimine les nœuds ayant les valeurs de f(n) plus élevées quand la file ordonnée est pleine. L`algorithme SMA* est complet si l`espace mémoire disponible est suffisant pour contenir le chemin état initial – état solution. L`algorithme SMA* retourne toujours la meilleure solution qui peut être obtenue avec l`espace mémoire alloué.
<< Section précédente Table de matières Section suivante >>

Politechnica University of Bucharest - 2002