Inteligencia Artificial · Capítulo 12

Algoritmos de Búsqueda y Optimización: La Base de la IA Clásica

Cómo los agentes inteligentes encuentran soluciones navegando espacios de estados, desde el puzzle de 8 piezas hasta el juego de ajedrez


Resolución de Problemas como Búsqueda

Antes de que el aprendizaje profundo dominara la IA, el paradigma central era la resolución de problemas mediante búsqueda en espacios de estados. Este enfoque sigue siendo relevante hoy: la planificación de rutas en GPS, los puzzles lógicos, los juegos de estrategia y muchos problemas de optimización industrial se resuelven con variantes de los algoritmos que estudiaremos en este capítulo. Más importante aún: el entrenamiento de cualquier modelo de machine learning es, en su esencia, un problema de optimización.

Componentes formales de un problema de búsqueda:

Ejemplo concreto: el puzzle de 8 piezas

El puzzle de 8 piezas consiste en un tablero 3×3 con 8 fichas numeradas y un espacio vacío. El objetivo es llegar a la configuración ordenada (1,2,3 / 4,5,6 / 7,8,_) desde una configuración inicial aleatoria, moviendo fichas al espacio vacío. Este problema tiene 9!/2 = 181.440 estados alcanzables. Aunque manejable para una computadora, ilustra perfectamente los conceptos clave: el espacio de estados es el grafo de todas las configuraciones posibles; los operadores son mover la ficha arriba, abajo, izquierda o derecha; el objetivo es una configuración específica.

Búsqueda No Informada (Ciega)

Los algoritmos de búsqueda no informada exploran el espacio de estados sin conocimiento específico del dominio: solo saben si un estado es el objetivo o no. Su eficiencia depende enteramente de la estructura del problema.

Búsqueda en Anchura (BFS — Breadth-First Search)

BFS expande primero todos los nodos a profundidad 1, luego todos a profundidad 2, y así sucesivamente. Utiliza una cola (FIFO) como estructura de datos.

Propiedades de BFS:
Completo: Sí (siempre encuentra una solución si existe, en espacios finitos)
Óptimo: Sí (encuentra el camino más corto en número de pasos)
Complejidad temporal: O(bd) donde b = factor de ramificación, d = profundidad de la solución
Complejidad espacial: O(bd) — el problema crítico: con b=10 y d=10, necesita almacenar 10.000 millones de nodos

Conclusión: BFS es óptimo pero con uso de memoria prohibitivo para problemas profundos.

Búsqueda en Profundidad (DFS — Depth-First Search)

DFS expande primero el nodo más profundo del árbol. Utiliza una pila (LIFO) o recursión.

Propiedades de DFS:
Completo: No en grafos infinitos (puede perderse en ramas infinitas)
Óptimo: No (puede encontrar soluciones subóptimas)
Complejidad temporal: O(bm) donde m = profundidad máxima del árbol
Complejidad espacial: O(b·m) — lineal en profundidad, enorme ventaja sobre BFS

Conclusión: DFS usa poca memoria pero puede no terminar o encontrar soluciones muy largas.

DFS con Profundidad Iterativa (IDDFS)

IDDFS combina lo mejor de ambos mundos: ejecuta DFS repetidamente con un límite de profundidad creciente (1, 2, 3, ...) hasta encontrar la solución. Aunque parece ineficiente por repetir trabajo, el análisis demuestra que la redundancia es mínima: en el caso con b=10, el nivel d tiene 10d nodos, mientras el nivel d-1 tiene 10d-1, que es solo el 10% de d. La expansión repetida de los niveles superiores agrega solo un factor constante.

IDDFS: el algoritmo de búsqueda ciega preferido en la práctica
Completo: Sí | Óptimo: Sí | Temporal: O(bd) | Espacial: O(b·d) — combina la optimalidad de BFS con el uso de memoria de DFS.

Búsqueda de Costo Uniforme (UCS)

UCS generaliza BFS al caso donde los pasos tienen costos distintos: expande siempre el nodo con menor costo de camino acumulado. Es completo y óptimo para costos positivos. Es equivalente al algoritmo de Dijkstra para grafos de caminos mínimos.

Búsqueda Informada (Heurística)

La búsqueda heurística usa conocimiento del dominio para guiar la exploración hacia el objetivo más eficientemente. Una heurística h(n) estima el costo desde el nodo n hasta el objetivo.

El algoritmo A*: el rey de la búsqueda informada

A* (pronunciado "A estrella") combina el costo acumulado g(n) con la estimación heurística h(n) para calcular f(n) = g(n) + h(n), expandiendo siempre el nodo con menor f(n).

Ejemplo paso a paso: Romania de Arad a Bucharest

El mapa de Romania tiene ciudades conectadas por carreteras con distancias conocidas. La heurística h(n) es la distancia en línea recta (distancia aérea) desde cada ciudad hasta Bucharest.

Heurísticas h (distancia aérea a Bucharest):
— Arad: 366 km | Sibiu: 253 km | Rimnicu Vilcea: 193 km | Pitesti: 100 km | Bucharest: 0

Iteración 1: Cola: {Arad: f=0+366=366}
Expandir Arad → vecinos: Zerind (75+374=449), Timisoara (118+329=447), Sibiu (140+253=393)
Cola: {Sibiu:393, Timisoara:447, Zerind:449}

Iteración 2: Expandir Sibiu (f=393) → Rimnicu Vilcea (140+80+193=413), Fagaras (140+99+178=417), Oradea (140+151+380=671)
Cola: {Rimnicu:413, Fagaras:417, Timisoara:447, Zerind:449}

Iteración 3: Expandir Rimnicu Vilcea (f=413) → Pitesti (140+80+97+100=417), Craiova (418+160=738)
Cola: {Fagaras:417, Pitesti:417, Timisoara:447, Zerind:449}

Continuando... A* encuentra el camino Arad→Sibiu→Rimnicu Vilcea→Pitesti→Bucharest con costo total 418 km, que es el óptimo.
Heurísticas admisibles y consistentes:

Búsqueda Greedy Best-First

La búsqueda greedy usa solo la heurística h(n) ignorando el costo acumulado g(n). Es muy rápida pero no garantiza soluciones óptimas: puede quedar atrapada en callejones sin salida heurísticos. Funciona bien cuando la heurística es confiable y la solución aproximada es aceptable.

Búsqueda en Juegos: Minimax y Poda Alfa-Beta

El algoritmo Minimax

Los juegos de dos jugadores de suma cero (ajedrez, damas, tres en raya) se modelan como árboles de juego donde los jugadores alternan turnos. El jugador MAX intenta maximizar su puntuación; MIN intenta minimizarla. Minimax asume que ambos jugadores juegan óptimamente.

Ejemplo: árbol minimax para tres en raya (tic-tac-toe)

Desde la posición inicial vacía, MAX (X) tiene 9 opciones. Para cada una, MIN (O) tiene 8 opciones. El árbol completo tiene 9! = 362.880 hojas (en realidad menos por simetría y estados terminales). En estados terminales: X gana = +1, O gana = -1, empate = 0.

Minimax propaga los valores hacia arriba:
— Nodo MIN: devuelve el mínimo de los valores de sus hijos
— Nodo MAX: devuelve el máximo de los valores de sus hijos

La complejidad es O(bm): para ajedrez, b≈35 y m≈80, dando 3580 ≈ 10123 nodos — inmanejable sin optimizaciones.

Poda Alfa-Beta

La poda alfa-beta reduce drásticamente el número de nodos que necesita explorar Minimax, sin afectar el resultado. Mantiene dos valores: α (mejor garantía actual para MAX) y β (mejor garantía actual para MIN). Cuando β ≤ α, la rama se poda porque MIN nunca elegirá este camino.

Eficiencia de la poda alfa-beta:
En el caso ideal (orden perfecto de nodos), la poda alfa-beta reduce la complejidad de O(bm) a O(bm/2). Para ajedrez esto significa que en lugar de explorar bm nodos exploramos bm/2, permitiendo buscar el doble de profundidad con el mismo tiempo. En la práctica con ordenamiento heurístico de movimientos, se logra cerca del caso ideal. Este fue el principio fundamental de Deep Blue de IBM, que derrotó a Garry Kasparov en 1997.

Optimización: Descenso de Gradiente

El descenso de gradiente es el algoritmo de optimización más importante del machine learning moderno. La intuición es simple: imagina que estás en una montaña con niebla espesa y quieres llegar al valle más bajo. No puedes ver lejos, pero puedes sentir el suelo bajo tus pies e identificar en qué dirección está la pendiente más pronunciada. Si siempre caminas "cuesta abajo", eventualmente llegarás a un valle (un mínimo local o global).

Fórmula del descenso de gradiente:
θ ← θ − α · ∇J(θ)

Donde: θ = parámetros del modelo, α = tasa de aprendizaje (learning rate), ∇J(θ) = gradiente de la función de pérdida respecto a los parámetros.

Selección de la tasa de aprendizaje

La tasa de aprendizaje α es el "tamaño del paso" en cada iteración. Su selección es crítica:

Variantes del descenso de gradiente

VarianteDatos usados por actualizaciónVentajaDesventaja
Batch GDTodo el datasetGradiente preciso, convergencia suaveMuy lento en datasets grandes
Stochastic GD (SGD)1 ejemplo aleatorioMuy rápido, puede escapar mínimos localesOscilación ruidosa, no converge exactamente
Mini-batch GDLote de 32-256 ejemplosEquilibrio entre precisión y velocidad, paralelizable en GPUHiperparámetro adicional (tamaño del lote)

El mini-batch GD es el estándar en deep learning: permite vectorización eficiente en GPUs y el ruido del gradiente actúa como regularización implícita.

Algoritmos Evolutivos: Algoritmos Genéticos

Los algoritmos genéticos (GA) se inspiran en la evolución darwiniana. Son útiles cuando el espacio de búsqueda es enorme, discontinuo o mal comprendido, y cuando las soluciones pueden representarse como "cromosomas".

GA aplicado al Problema del Viajante (TSP)

El TSP: dado un conjunto de ciudades, encontrar la ruta más corta que visita cada ciudad exactamente una vez y regresa al origen. Con 20 ciudades hay 20!/2 ≈ 1018 rutas posibles — imposible por fuerza bruta.

Representación: una permutación de ciudades = [3,7,1,5,2,8,4,6] representa una ruta
Selección: las rutas más cortas tienen mayor probabilidad de reproducirse (selección por torneo o ruleta)
Cruce (crossover): dos rutas padre generan una hija combinando segmentos: padre1=[1,2,3,4,5,6], padre2=[3,5,2,6,1,4] → hija=[1,2,3,6,4,5] (preservando segmento del padre1 y completando con orden del padre2)
Mutación: con baja probabilidad, intercambiar dos ciudades en la ruta: [1,2,3,6,4,5]→[1,5,3,6,4,2]
Resultado: tras cientos de generaciones, la población converge hacia rutas cortas sin garantizar el óptimo global.

Recocido Simulado (Simulated Annealing)

El recocido simulado se inspira en el proceso metalúrgico de calentar un metal y enfriarlo lentamente para minimizar su energía interna. El algoritmo acepta soluciones peores con una probabilidad que disminuye con el tiempo (temperatura), permitiéndole escapar de mínimos locales al principio y refinar la solución al final.

La probabilidad de aceptar una solución peor es: P = e-ΔE/T, donde ΔE es el empeoramiento de la solución y T es la temperatura actual. Con T alto (inicio), casi cualquier solución se acepta. Con T bajo (final), solo mejoras se aceptan. El recocido simulado garantiza convergencia al óptimo global en tiempo infinito, y es prácticamente efectivo en tiempos razonables para muchos problemas combinatorios.

Satisfacción de Restricciones: Sudoku como CSP

Los Problemas de Satisfacción de Restricciones (CSP) consisten en asignar valores a variables respetando un conjunto de restricciones. El Sudoku es un ejemplo perfecto: 81 variables (cada celda), dominio {1-9}, restricciones de unicidad en filas, columnas y subcuadros 3×3.

Algoritmos para CSP:

Backtracking: asignar un valor a una variable; si viola restricciones, retroceder e intentar el siguiente valor. Para Sudoku fácil puede resolver en milisegundos; para Sudoku extremo puede necesitar millones de intentos.

Forward Checking: al asignar un valor, eliminar inmediatamente los valores incompatibles del dominio de las variables vecinas. Si alguna variable queda sin valores posibles, retroceder antes de seguir explorando — evita muchas ramas fallidas.

Arc Consistency (AC-3): propaga restricciones entre pares de variables hasta alcanzar consistencia. Muchos Sudokus de dificultad media se resuelven completamente solo con AC-3, sin necesidad de búsqueda.

Por Qué Importa: El Entrenamiento de ML es Optimización

La conexión entre búsqueda/optimización y el machine learning moderno es fundamental y directa. Cuando entrenamos una red neuronal, estamos buscando en un espacio de millones o miles de millones de parámetros (pesos) el punto que minimiza la función de pérdida. GPT-4 tiene aproximadamente 1,8 billones de parámetros; optimizar este espacio requiere variantes sofisticadas del descenso de gradiente (Adam, AdamW, LAMB) que adaptan la tasa de aprendizaje individualmente para cada parámetro.

El aprendizaje por refuerzo utiliza explícitamente algoritmos de búsqueda: AlphaGo y AlphaZero de DeepMind combinan redes neuronales con Monte Carlo Tree Search (MCTS), una variante del árbol de juego con exploración aleatoria guiada. Los sistemas de planificación de robots usan A* para encontrar trayectorias en espacios continuos. Los algoritmos de routing de paquetes en internet son variantes del algoritmo de Dijkstra ejecutándose millones de veces por segundo.

Resumen del Capítulo