Solo questione di ricerca?

Era il 1971 quando in un celebre libro comparve la frase

Nell’analizzare variazioni complicate si deve esaminare ogni ramo dell’albero una ed una sola volta.

A scriverla non un informatico ne un matematico bensì il maestro di scacchi sovietico Alexander Kotov nel suo famoso Pensa come un Grande Maestro.

La cosa che più sorprende della frase, nonché di tutta l’opera di Kotov, è che in un epoca in cui l’informatica muoveva i suoi primi passi, un maestro sovietico di scacchi usasse con tanta naturalezza termini come ramo ed albero per descrivere il processo umano di analisi di una posizione scacchistica e della ricerca della migliore soluzione.

Ed è proprio la parola “ricerca”, secondo Kotov, il centro nevralgico di tutto il gioco: il grande maestro si differenzia dal principiante per la sua capacità di organizzare la mente, di strutturare il pensiero e di cercare in modo efficiente la migliore mossa possibile.

Oggi, a 40 anni di distanza da quelle parole, sappiamo che quelle parole erano vere e sono ancora oggi la base di tutta l’AI moderna. Il concetto di ricerca infatti rappresenta le fondamenta di tutte le tecniche di AI. Sia che si tratti di cercare un percorso, pianificare una serie di azioni, trovare una mossa in un gioco o il minimo di una funzione non-lineare, tutta l’intelligenza sintetica ha in comune lo stesso principio: navigare l’incerto alla ricerca della soluzione migliore.

La differenza vera riguarda il come questa ricerca viene effettuata. Gli algoritmi di ricerca solitamente si possono descrivere in 20 righe di pseudocodice, eppure nessuno di questi algoritmi, preso così com’è, potrebbe essere applicato con successo ad un problema reale. Prendiamo ad esempio l’alpha-beta pruning, algoritmo alla base di un infinità di intelligenze artificiali di giochi.

def alphabeta(node, depth, alpha, beta, Player)        
    if  depth == 0 or node is a terminal node
        return the heuristic value of node
    if  Player == MaxPlayer
        for each child in node
            alpha = max(alpha, alphabeta(child, depth-1, alpha, beta, not(Player) ))    
            if beta ? alpha
                break                             #(* Beta cut-off *)
        return alpha
    else
        for each child of node
            beta = min(beta, alphabeta(child, depth-1, alpha, beta, not(Player) ))    
            if beta ? alpha
                break                             #(* Alpha cut-off *)
        return ?beta
#(* Initial call *)
alphabeta(origin, depth, -infinity, +infinity, MaxPlayer)

L’algoritmo è tutto qui, poco meno di 20 righe, eppure preso così è inutile. Prima bisogna rispondere a domande del tipo “Come costruisco l’albero?” o “Come posso valutare in modo preciso un nodo?” e “Come minimizzare il numero di nodi esplorati?”. Risposte che richiedono centinaia e centinaia di righe di codice e dalla cui risposta dipendono drammaticamente le prestazioni di ricerca.

Ad esempio sia Deep Blue che Junior utilizzano come base l’alpha-beta pruning per la ricerca e l’analisi di una posizione scacchistica, eppure Deep Blue, che altro non è che un gigantesco mainframe divora mosse, viene tranquillamente stracciato da Junior (che tra l’altro gira su un normalissimo PC) grazie ad una serie di ottimizzazioni che rendono il suo gioco molto più intelligente.

A questo punto la domanda sorge spontanea: quanto è simile tutto questo all’intelligenza umana? Onestamente credo che la risposta non abbia molta importanza. Per dirla come Drew McDermott

Dire che Deep Blue non pensa davvero quando gioca a scacchi equivale dire che un aereo non vola davvero perchè non sbatte le ali.