30
INTRODUCTION À L'INTELLIGENCE ARTIFICIELLE ET LA THÉORIE DE JEUX WIESLAW ZIELONKA WWW.IRIF.UNIV-PARIS-DIDEROT.FR/~ZIELONKA

INTRODUCTION À L'INTELLIGENCE ARTIFICIELLE ET LA ...zielonka/Enseignement/IA/2016/COURS...8 10^8 2 minutes 103 GB 10 10^10 3 heures 10 TB 12 10^12 13 jours 1 petabyte 14 10^14 3.5

  • Upload
    others

  • View
    6

  • Download
    0

Embed Size (px)

Citation preview

  • INTRODUCTION À L'INTELLIGENCE ARTIFICIELLE ET LA THÉORIE DE JEUX

    WIESLAW ZIELONKAWWW.IRIF.UNIV-PARIS-DIDEROT.FR/~ZIELONKA

    http://www.irif.univ-paris-diderot.fr/~zielonka

  • PROBLÈMES DE RECHERCHEJeu de Taquin

    • états

    • état initial

    • actions

    • transitions (état,action) → état

    • coût de chemin

    • teste de l'état final, état → true, false

    1 23

    4

    65

    7

    8

    1 2

    4 65

    7 8

    3

    Etat initial

    suite d'actions

    Etat final

  • PROBLÈME DE HUIT DAMES

    PROBLÈMES DE RECHERCHE

    État initial : échiquier vide (ou échiquier avec 8 dames dans les positions quelconques).

    Action - ajouter une dame sur une position vide

  • PLANIFICATION DE VOYAGE AVION

    difficile :

    • contraintes date de depart,

    • changement d'avion (sur un trajet A → B → C l'avion A → B doit arrivé avant le depart de l'avion B → C)

    • le coût

    • la durée totale

  • LE PROBLÈME DE COMMIVOYAGEUR

    Faire le tour de toutes les villes en passant par chaque ville une seule fois. Minimiser la longueur totale du trajet. NP-complet.

  • ALGORITHME GÉNÉRIQUE - TREE-SEARCH

    Les feuilles de l'arbre de recherche forment une frontière. On ne mémorise pas les noeuds déjà visités dont toutes les arêtes sortantes ont déjà été examinées.

    fonction tree-search(problème) retourne solution ou échec n = new noeud(état_init); frontière = { n }; loop do si frontière vide retourner échec n = élément de la frontière; supprimer n de la frontière; if n.état est un état but alors retourner solution pour chaque action a faire nouvel_état = transition(n.état, a) m = new noeud(nouvel_état) ajouter m dans la frontière fait end loop

  • ALGORITHME GÉNÉRIQUE — GRAPHE-SEARCH

    fonction graph-search(problème) retourne solution ou échec n = new noeud(état_init); frontière = { n }; closed_set = {}; loop do si frontière vide retourner échec n = élément de la frontière supprimer n de la frontière if n.état est un état but alors retourner solution ajouter n dans closed_set pour chaque action a faire nouvel_état = transition(n.état, a) si nouvel_état dans un noeud de la frontière ou dans un noeud de closed_set alors continue m = new noeud(nouvel_état) ajouter m dans la frontière fait end loop

    Quelle structure pour stocker les noeuds dans la frontière?

  • QUELLE FILE ?

    • FIFO — first in first out, file habituelle

    • LIFO — last in first out, pile

    • file de priorité

  • IMPLÉMENTER LA FRONTIÈRE COMME UNE FILE

    • créer_file() — retourne une file vide

    • est_vide(file) — retourne true si la file vide

    • premier(file) — retourne le premier élément (celui avec le coût minimal)

    • supprimer_premier(file) — supprime le premier élément de la file

    • insérer(file, élément) — ajouter un élément dans la file

  • INFRASTRUCTURE POUR LE PROBLÈME DE RECHERCHE

    • n.état — état du noed

    • n.parent — le parent du noeud

    • n.action — l'action qui appliquée au parent donne l'état du nouer

    • n.coût le coût du chemin de la racine jusqu'au noeud

    fonction créer_noeud(Noeud parent, Action action) retourne Noeud n = new noeud() n.état = transition(parent.état, action) n.action = action n.coût = parent.coût + coût(parent.état,action) n.parent = parent

  • INFRASTRUCTURE POUR LE PROBLÈME DE RECHERCHE

    fonction créer_noeud_initial(État état) retourne Noeud n = new noeud() n.état = état n.action = null n.coût = 0 n.parent = null

  • TREE-SEARCH

    fonction tree-search(problème) retourne solution ou échec

    n = créer_noeud_initial(état_initial)

    frontière = créer_file()

    loop do

    si est_vide(frontière) retourner échec

    n = premier(frontière); supprimer_premier(frontière);

    if n.état est un état but alors retourner n

    pour chaque action a faire

    nouveau_noeud = créer_noeud(n, a)

    insérer(frontière,nouveau_noeud)

    fait

    end loop

  • CRITÈRES DE PERFORMANCES

    • algorithme complet ? Oui, s'il trouve une solution quand elle existe.

    • l'algorithme optimal ? est-ce que la solution trouvée est optimale?

    • complexité en temps et espace

  • RECHERCHE EN LARGEUR

    • coût(état,action) est 1

    • la file : FIFO, arrêter de que la solution trouvé (teste de but avant de mettre le noeud dans la frontière et non pas à la sortie de la frontière)

    • Est-ce que l'algorithme est complet ?

    • Optimal?

    • complexité : si chaque sommet possède b fils et la solution se trouve à distance d de la racine alors le nombre de noeuds générés

    b+b^2+b^3+…+b^d = O(b^d)

  • RECHERCHE EN LARGEUR

    b = 10 (facteur de branchement)

    un million de noeuds par seconde, mémoire par noeud 1000 octets

    profondeur noeuds temps mémoire

    8 10^8 2 minutes 103 GB

    10 10^10 3 heures 10 TB

    12 10^12 13 jours 1 petabyte

    14 10^14 3.5 année 99 petabytes

    16 10^16 350 ans 10 exabytes

  • UNIFORM COST SEARCH

    • file = file de priorité

    • le coût coût(état,action) doit être positif

    • Trouve toujours le plus court chemin donc complet et optimal.

    • Il est très important que le teste de terminaison au moment ou un noeud sort de la frontière (si le teste à l'entrée de la frontière l'algorithme n'est plus optimal).

  • RECHERCHE EN PROFONDEUR

    • utilise LIFO (une pile)

    • ni complet ni optimal

    • quel coût en espace ?

    • une variante : backtracking search - on garde que le sommet courant, son parent, parent de parent etc.

  • ITERATIVE DEEPENING DEPTH-FIRST SEARCH

    limited_depth_first_search(k) — fait la recherche en profondeur jusqu'au niveau k et retourne soit une solution soit échec

    deepening_depth_first_search() for i=1 to infinity do solution = limited_depth_first_search(k) si solution != échec alors retourner solution done

  • RECHERCHE INFORMÉE (AVEC AIDE DE HEURISTIQUE)

    • appelé BEST_FIRST_SEARCH

    • la fonction heuristique h(n) — le coût estimé de chemin le plus court de sommet n jusqu'au but

    • g(n) — le coût de chemin le plus court de sommet initial vers le sommet n (calculé par l'algorithme)

    • f(n) — la fonction d'évaluation, à chaque iteration on cherche dans la frontière le sommet n avec f(n) minimal

  • HEURISTIQUE

    pour le plus court chemin entre les ville h(n) - la distance à vol d'oiseau de la ville n jusqu'à la ville destination

  • ALGO DE RECHERCHE GLOUTON (GREEDY BEST-FIRST SEARCH)

    • on prend f(n) = h(n) et on utilise la file de priorité où pour chaque sommet n on stocke la valeur h(n)

    • à chaque étape on prend de la file de priorité le sommet n avec f(n)=h(n) minimal

    • le coût du chemin de sommet source vers n n'est pas pris en compte

    • la version tree-like de l'algorithme n'est pas complète

    • la version graph-like est complète mais pas optimale

  • ALGO COÛT UNIFORME

    • si f(n)=g(n), c'est-à-dire on n'utilise pas la heuristique alors la recherche de coût uniforme (déjà étudiée)

  • ALGORITHME A^* - MINIMISER LE COÛT TOTAL

    • dans chaque sommet n on stocke g(n) et f(n)=g(n)+h(n)

    • la file de priorité pour les valeurs f(n), à chaque étape on choisit un noeud avec f(n) minimal

  • INFRASTRUCTURE POUR L'ALGORITHME A^*

    • n.état — état du noed

    • n.parent — le parent du noeud

    • n.action — l'action qui appliquée au parent donne l'état du nouer

    • n.coût — le coût du chemin de la racine jusqu'au noeud, c'est g(n)

    • n.f — la valeur f(n), la file de priorité selon les valeur n.f

    fonction créer_noeud(Noeud parent, Action action) retourne Noeud n = new noeud() n.état = transition(parent.état, action) n.action = action n.coût = parent.coût + coût(parent.état,action) n.parent = parent n.f = n.coût + h(n.état)

  • INFRASTRUCTURE POUR L'ALGORITHME A^*

    fonction créer_noeud_initial(État état) retourne Noeud n = new noeud() n.état = état n.action = null n.coût = 0 n.parent = null n.f = 0

  • ALGORITHME A^*

    Le même que tree-search avec les modifications sur les deux transparents précédents et avec la fille de priorité qui retourne à l'appel

    premier(file)

    le noeud n avec n.f minimal

  • HEURISTIQUE ADMISSIBLE

    la fonction heuristique h est admissible si pour chaque sommet n

    h(n)

  • HEURISTIQUE CONSISTANTE

    Une heuristique est consistante si elle satisfait l'inégalité de triangle:

    pour chaque couple de sommets n et m et action a telle que

    m=transition(n,a) on a

    h(n)

  • OPTIMALITÉ DE A^*

    • Si la heuristique h est admissible alors la version tree-search de l'algorithme A^* est optimale.

    • Si la heuristique h est consistante alors la version graph-searche de l'algorithme A^* est optimale.

  • COMMENT TROUVER LES HEURISTIQUES OPTIMALES?

    • en assouplissant les conditions (ajoutant les actions)

    • en travaillant avec des sous-problèmes