Qué no puede calcular un computador
Un problema indecidible es una pregunta de sí o no para la que ningún programa puede dar siempre la respuesta correcta. Otros problemas sí tienen programa, pero tardan tanto en crecer los datos que no sirven en la práctica.
Saber dónde están esos dos límites te ahorra buscar algo imposible, y te avisa cuando una solución no escalará.
Al final de esta lección
Nota
Puedo explicar por qué ningún programa decide todas las preguntas y qué significa que un problema sea demasiado lento.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Decidible | un problema de sí o no que un programa siempre resuelve | |
| Indecidible | un problema de sí o no que ningún programa resuelve siempre | |
| Problema de la parada | saber si un programa acaba o se queda en bucle | |
| Fuerza bruta | probar todas las posibilidades, una por una | |
| Crecimiento exponencial | un trabajo que se duplica al añadir un dato | 2 elevado a n |
| Subconjunto | parte de una lista, que puede ser vacía o entera |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Decidible: un programa siempre responde
Un problema de decisión es una pregunta de sí o no sobre un dato. «¿Es 91 un número primo?» es uno. «¿Tiene esta lista un número repetido?» es otro.
Es decidible si existe un programa que, para cualquier dato, acaba y da la respuesta correcta. Casi todos los problemas que conoces lo son. Pero no todos.
Ningún programa puede saber si otro acaba
El problema de la parada pregunta: dado un programa y su dato, ¿acabará o se quedará en bucle para siempre? Alan Turing demostró en 1936 que ningún programa lo resuelve siempre.
La idea es una paradoja. Supón que existe un detector. Escribimos un programa que lo consulta sobre sí mismo y hace lo contrario de lo que el detector prediga.
Algunos problemas se resuelven, pero demasiado despacio
Un problema puede ser decidible y aun así inútil. Con la fuerza bruta pruebas todo y siempre aciertas. Pero a veces hay tantas posibilidades que no acabarías.
Ejemplo: tienes una lista de números y un objetivo. ¿Hay un subconjunto que sume el objetivo? Cada número está dentro o fuera: con n números hay 2 elevado a n subconjuntos.
Ejemplo: cuántos subconjuntos hay según el tamaño
| Números en la lista | Subconjuntos que probar |
|---|---|
| 4 | 16 |
| 10 | 1.024 |
| 20 | 1.048.576 |
| 30 | 1.073.741.824 |
| 40 | 1.099.511.627.776 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Fuerza bruta con cuatro números
# Fuerza bruta: probar todos los subconjuntos de una lista pequeña.
numeros = [4, 8, 15, 16]
objetivo = 23
n = len(numeros)
cuenta = 0
for mascara in range(2 ** n):
suma = 0
# Cada bit de la máscara dice si el número j entra en el subconjunto.
for j in range(n):
if (mascara // 2 ** j) % 2 == 1:
suma = suma + numeros[j]
if suma == objetivo:
cuenta = cuenta + 1
print("Sirve la máscara", mascara)
print("Subconjuntos revisados:", 2 ** n)
print("Los que suman", objetivo, ":", cuenta)
# Añade un quinto número a la lista y mira cuánto crece "revisados".
Comprobar es fácil, encontrar es difícil
Si alguien te da un subconjunto, comprobar su suma es rápido: sumas unos pocos números. Encontrarlo desde cero puede exigir probar muchísimos.
Muchos problemas famosos son así: horarios sin choques, rutas de reparto, colocar paquetes. Hoy nadie sabe si existe un método rápido para todos ellos. Es una de las grandes preguntas abiertas de la informática.
Cuánto crece 2 elevado a n
Los Runs de abajo calculan en una línea las potencias y los factoriales que miden el crecimiento. Solo cuentan pasos: no miden tiempo, porque el tiempo depende de la máquina.
Un factorial crece aún más deprisa: ordenar diez paradas de un reparto de todas las formas posibles son 3.628.800 recorridos.
Subconjuntos de 10 números
python3 -c "print(2 ** 10)"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Subconjuntos de 30 números
python3 -c "print(2 ** 30)"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Subconjuntos de 40 números
python3 -c "print(2 ** 40)"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Recorridos de 10 paradas
python3 -c "import math; print(math.factorial(10))"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un error frecuente
Advertencia
Mucha gente cree que un problema lento se arregla con un ordenador más rápido. Si el trabajo se duplica con cada dato nuevo, un ordenador diez veces más rápido solo permite tres datos más. La solución es otro método, no más potencia.
Para ir más lejos
Elige una lista de 6 pesos de tu mochila y un objetivo, y busca con tu función todos los subconjuntos que lo suman.
Después cuenta cuántos subconjuntos revisó tu programa con 6, 12 y 18 números. ¿Qué pasa con ese número cada vez que añades seis números?