Subido por rrgalan

Clase

Anuncio
Complejidad computacional
Hoy vamos a entender el campo de la Complejidad Computacional.
Normalmente, en el campo de la Computación nos dedicamos básicamente
a hablar de problemas y algoritmos que se resuelven en tiempo polinomial.
Hoy vamos a hablar de cuando no se puede hacer esto. Algunas veces
podemos demostrar que no podemos resolver un problema en tiempo
polinomial. Algunas veces, estamos bastante seguros de que no podemos
hacerlo (pero no podemos demostrarlo).
Para empezar, entendamos los que hay detrás de 3 clases de “complejidad”
(hablamos de Complejidad Computacional): P, EXP y R.
¿Qué es P? Pues P es el conjunto (una clase de complejidad) que incluye a
todos aquellos problemas que podemos resolver en tiempo polinomial. A
estos nos dedicamos en el campo de la Informática: resolver problemas
utilizando algoritmos; pero solo podemos resolver aquellos que consumen
un tiempo polinomial, un tiempo aceptable. P.
Spoiler: ¿Alguien conoce la excepción? Seria NO P. Lo que no es P. NP.
¿Qué sigue a P? EXP. Exponencial. Es el conjunto (una clase) que incluye a
todos aquellos problemas que podemos resolver en tiempo exponencial.
Podemos decir que es 2n.Si queremos generalizar, podemos decir mn.
Elementalmente, un exponencial es una generalización de un polinomial,
por lo que la clase EXP incluye a la clase P.
Tiempo exponencial es mucho tiempo…
Podemos pintar estas clases en un eje, que llamaremos dificultad
computacional. Este dibujo no es un verdadero diagrama, pero es una
buena guía para visualizar lo que nos pasa con la complejidad de los
problemas.
Sigamos por este eje; tenemos a continuación a R. ¿Qué es R?. R es la clase
de problemas que podemos resolver en tiempo finito. R es Recursivo. El
tiempo finito es un requisito razonable para todos los algoritmos.
Pero la línea de dificultad computacional continua… es algo desalentador,
pero tenemos que decirlo: hay problemas que no tienen solución (en un
tiempo finito). Vamos a demostrarlo, pero antes vamos a ver algunos
ejemplos:
- Un ajedrez nxn. Te doy un tablero de tamaño n y un montón de piezas
de ajedrez para ese tablero y te pregunto desde una posición
concreta, ¿ganan las blancas? ¿o ganan las negras? Este problema se
puede resolver en tiempo exponencial; es suficiente con jugar todas
las posibles partidas y ver quien gana. No está en P (no se puede
resolver en tiempo polinomial).
La complejidad computacional tiene que ver con el orden de
crecimiento del problema.
- Go también está en EXP pero no está en P.
Y así muchos juegos, muchos juegos complejos.
- Tetris, pero un Tetris especial. Te digo la ficha que va a venir a
continuación (si no te la digo, estamos poniendo un nivel de
aleatoriedad que no nos ayuda a resolver el problema; no nos ayuda
a definir una estrategia). Quiero saber si puedo sobrevivir en una
posición de tablero inicial dado y para una secuencia determinada de
piezas. Esto también se puede resolver en tiempo exponencial. Basta
con probar todas las posibilidades. En este caso no sabemos si está
en P; estamos bastante seguros de que no está en P. Y, espero, que
al final de esta charla se entenderá por qué creemos que no está en
P.
A Tetris le ponemos por aquí en medio. Pero no hemos definido lo
que es aquí en medio (todavía…).
- Por último, un problema un poco “especial”: El problema de detener
un programa informático. Nos da lo mismo el lenguaje de
programación (son todos iguales en un sentido teórico). Escribes un
código y lo has ejecutado durante horas y no sabes si, porque hay un
error o porque tienes un bucle infinito o porque es realmente
¿lento?, se va a detener en algún momento; no estaría mal dárselo a
un programa de verificación y que nos diga si se ejecutará para
siempre o terminará en algún momento. Este problema no está en R;
no existe un algoritmo correcto para resolver este problema en
tiempo finito; no hay forma de saber, dado un programa arbitrario
cualesquiera si este se detendrá o se ejecutará indefinidamente.
Claro que si, por ejemplo, tengo un programa vacío, puedo decir que
se detiene. O tengo un subconjunto de programas llamémosles
“simples” puedo decir que se detienen o no. Pero no existe un
algoritmo que resuelva esta duda para todos los programas en un
tiempo finito. Claro que lo puedo resolver en un tiempo infinito para
cualquier programa: simplemente le dejo ejecutarse…
Bien, vistos estos ejemplos, vamos a demostrar que casi todos los
problemas (interesantes) no están en P. Para ello necesitamos entender un
concepto: problemas de decisión.
Un problema de decisión podemos entenderlo como aquel cuya respuesta
es binaria: sí o no. ¿Ganan las blancas desde esta posición? Sí o no. ¿podrás
sobrevivir en Tetris? Sí o no. Y, claro, ¿se detiene el programa?
Por varias razones, básicamente por conveniencia, todo el campo de la
complejidad computacional se centra en los problemas de decisión. Y, de
hecho, los problemas de decisión son aquellos en los que la respuesta es sí
o no. Eso es todo. ¿Por qué?
Esencialmente, si tomamos cualquier problema que nos importe, podemos
convertirlo en un problema de decisión. Los problemas de decisión son
básicamente tan difíciles como cualquier problema de optimización.
Centrémonos en los problemas de decisión. La respuesta es sí o no. Vamos
a afirmar que la mayoría de ellos son indiscutibles (no sabemos decir sí o
no). Y podemos probar esto con bastante facilidad si conocemos un poco
de teoría de conjuntos.
Por un lado, tengo problemas que quiero resolver. Estos son los problemas
de decisión (ya hemos dicho que todo problema lo podemos convertir, de
alguna forma, en un problema de decisión). Por otro lado, tengo algoritmos
o programas de ordenador para resolver estos problemas. Vamos a hablar,
en vez de algoritmo, de programa de ordenador porque con algoritmo igual
nos cuesta un poco más pensar en pseudocódigo: lo que es válido / lo que
no es válido.
Los programas de ordenador son muy claros. Te doy un código. Lo codificas
en, por ejemplo, Phyton. O funciona o no. Y hace algo. Se ejecuta durante
un tiempo.
¿Cómo puedo pensar en el espacio de todos los programas
posibles? Bueno, los programas son, al fin y al cabo, cosas que escribo en
un ordenador en ASCII. Al final, puedes pensar en ellos como una cadena
binaria. De alguna manera podemos asumir que se codifica en binario. Todo
se reduce a binario en un ordenador.
Entonces tenemos una cadena binaria. Ahora, también puede pensar en
una cadena binaria que representa un número (en binario). Entonces,
también puede pensar en un programa como un número natural; solo 0, 1,
2, 3. Puede pensar que cada programa es, en última instancia, un número
entero. Es un gran número entero, pero bueno. Es un entero. Entonces ese
es el espacio de todos los programas. ℕ
Ahora, quiero pensar en el espacio de todos los problemas de
decisión. Entonces, ¿cómo puedo definir un problema de decisión? Bueno,
la forma natural de pensar en un problema de decisión es como una función
que asigna entradas a sí o no. Función de entradas a sí o no (a 1 y 0).
Entonces, ¿qué es una entrada? Bueno, una entrada es una cadena
binaria. Entonces, una entrada es un número: un número natural. La
entrada es una cadena binaria, que podemos pensar que está en ℕ. Es decir,
tenemos una función de ℕ a 0,1.
Entonces, otra forma de representar una de estas funciones es como una
tabla. Podría simplemente escribir todas las respuestas (como hemos
hecho en programación dinámica). Así que tengo que la entrada podría ser
0 y la salida el número 0. La entrada podría ser 1 y, tal vez, la salida sea 0.
Entonces, la entrada podría ser 2, 3, 4, 5, 1, 0, 1, 1, etc. Tengo que poder
escribir la tabla de todas las respuestas. Esta es otra forma de ver esta
función.
Lo que tenemos aquí es una cadena infinita de bits. Cada uno de ellos puede
dar como resultado un 0 o 1. Cualquier cadena infinita de bits representa
un problema de decisión. Son lo mismo. Entonces, un problema de
decisión es una cadena infinita de bits. Pero un programa es una cadena
finita de bits. Son cosas diferentes.
Vamos a poner un punto decimal en esta idea. Una forma de ver que son
diferentes es poner un punto decimal en esta cadena infinita de bits. Ahora,
esta cadena infinita es un número real entre 0 y 1. El número real está
escrito en binario, pero es un número real con un punto binario.
Entonces… cualquier número real puede expresarse mediante una cadena
infinita de bits, cualquier numero real entre 0 y 1. Entonces un problema de
decisión es algo que esta en R, el conjunto de todos los números reales,
mientras que un programa de ordenador es algo que esta en N, el conjunto
de los números naturales. Y la cosa es que el número de números reales es
mucho, mucho mayor que el número de enteros. En un sentido formal,
llamamos a R incontablemente infinito, y a N contablemente infinito. Esto
no lo vamos a probar, pero es una demostración matemática muy estética.
https://www.youtube.com/watch?v=TUFQKN5mIWM
Y esto es una mala noticia: significa que hay muchos más problemas de los
que hay programas de ordenador para resolverlos. Significa que casi todos
los problemas que podemos concebir son irresolubles por un programa de
ordenador.
Y esto es bastante deprimente.
Y algo raro. Porque la mayoría de los problemas que pensamos son
computables.
Eso es todo lo que voy a decir sobre R. Puedes pensar en esta línea como
una línea infinita y solo hay esta pequeña porción que son cosas que puedes
resolver
Ahora vamos a hablar sobre esta nueva muesca, que es NP. Al igual que P,
EXP y R, NP es un conjunto de problemas de decisión; pero no, NP no
significa No Polinomial… Significa Polinomio No Determinista. Veremos que
es No Determinista. La primera idea es que incluye a todos los problemas
de decisión que se pueden resolver en tiempo polinomial (esto nos suena a
P); pero ahora viene la mala noticia: se pueden resolver a través de un
algoritmo de “suerte” o afortunado (que hace conjeturas). Un algoritmo
afortunado solo necesita probar una posibilidad porque es “afortunado”;
siempre adivina la elección correcta. Esto no es un modelo de cálculo
realista, pero es un modelo computacional llamado no determinista.
En un modelo de computación no determinista, un algoritmo puede
calcular cosas, pero realmente hace suposiciones.
Hablemos de Tetris; esta en NP. Sabemos como solucionarlo en tiempo
exponencial; pruebo todas las opciones y ya está. Pero, de hecho, no
necesito probar todas las opciones; basta con usar la magia “no
determinista”. Podría decir ¿Debo dejar la pieza aquí, aquí, aquí, aquí, aquí
o aquí? Y debería ser rotado así, o así, o así, ¿o así? No lo sé. Así que
supongo. Y solo coloca esa pieza. Adivino de nuevo dónde colocar la
siguiente pieza.
Cualquier elección que tengas que hacer para jugar al Tetris, puedes
adivinarla. Solo hay polinomialmente muchas conjeturas que necesitas
hacer. Entonces todavía es tiempo polinomial. Eso es importante. No es
que no podamos hacer nada. Podemos hacer en un número polinomial
estas conjeturas mágicas. Y luego, al final, determinar si morimos, o mejor
dicho, si sobrevivimos.
Otra forma de pensar en NP. Y puede que encontremos esto más intuitivo
porque hemos estado haciendo muchas conjeturas. Es un poco loco. Hay
otra forma que es más intuitiva para muchas personas. Otra forma de
pensar en NP, que resulta ser equivalente, es que no pienses tanto sobre
algoritmos para resolver un problema, sino que pienses en algoritmos para
comprobar la solución a un problema. Por lo general, es mucho más fácil
verificar un trabajo que resolver un problema. Y NP tiene que ver con ese
tema. Así que piensa en problemas de decisión y piensa si tienen una
solución. Si lo aplicamos a Tetris, diremos que Tetris tiene solución. Y
puedes probarlo en tiempo polinomial.
Es decir, NP es el conjunto de problemas que solo hemos encontrado la
forma de resolverlos en tiempo exponencial, pero que podemos verificar
que una solución es una solución (conseguida de forma “mágica”) en
tiempo polinomial.
Y nos aparece la pregunta del millón (de dólares): ¿Es P igual a NP? La
mayoría de la gente piensa que P no es igual a NP. Cada año hay gente que
intenta demostrar que no es igual (o que es igual).
Piensa en lo que esto realmente significa: P son los problemas que podemos
resolver en un ordenador y NP son los problemas que podemos resolver
“de forma mágica” en un ordenador… Otra forma de verlo es que resolver
problemas es más difícil que verificar las soluciones dadas para un
problema. Es más difícil probar un teorema que comprobar la prueba de un
teorema. Todos sabemos verificar la prueba de un teorema: lo escribes con
precisión y te aseguras de que cada paso sigue a los anteriores. Hecho. Pero
demostrar un teorema es difícil; necesita inspiración; necesitas una idea
inteligente. Necesitas adivinar.
Afortunadamente, este no es final de la historia; podemos decir mas cosas
sobre Tetris. Sabemos que Tetris esta en NP menos P. Y sabemos que hay
muchos problemas en ese mismo sitio.
Realmente, a este punto le llamamos NP-completo; y ¿Qué significa NPcompleto? Significa que es tan difícil como cada problema en NP. Por eso lo
ponemos en el extremo de NP.
Y podemos seguir poniendo nombres: NP-hard. Decimos que un problema
en NP-hard cuando es al menos tan difícil como cualquier problema en NP.
Y podemos seguir poniendo nombres: EXP-completo. Y tenemos en EXPcompleto: el ajedrez. Es el problema EXP más difícil. Y tambien tenemos
EXP-hard….
Ahora nos aparecen nuevas preguntas, aunque no tan famosas: ¿Es NP igual
a EXP?
Vamos a introducir un nuevo concepto: las reducciones. Si tienes un
problema A que deseas resolver (pero no sabes) y lo puedes convertir (y lo
conviertes) en un problema B que ya sabes resolver. Voilá…
¿Cómo resuelvo el problema de encontrar el camino mas corto no
ponderado? Te doy un grafo sin pesos en los bordes y quiero el camino más
corto. Ahora te digo Djikstra. Pero no puedo aplicarlo porque no tengo
pesos…
Bueno, hago una reducción: aplico un peso de 1 a cada nodo. Y ya está.
Las reducciones nos ayudan mucho porque no queremos implementar un
algoritmo para cada problema que tengamos; es bueno poder reutilizar
algunos de los algoritmos que ya tenemos. Pues las reducciones nos
permiten hacer esto.
Bien, pues utilicemos las reducciones. Voy a asegurar que el problema
Partición de 3 se puede reducir a Tetris. Contemos que es el problema
Partición de 3: te doy n números y quiero saber si se pueden dividirlos en
tres grupos, cada uno de la misma suma. Suena fácil, pero es un problema
NP-completo.
Necesito concentrarme para demostrar que Tetris es más difícil que
Partición de 3. Más difícil significa, cuando puedo reducir un problema A a
un problema B, que B es al menos tan difícil como A. Esto es porque puedo
resolver A resolviendo B. Si tengo una buena manera de resolver B entonces
se convertiría en una buena manera de resolver A.
Realmente, todos los problemas NP-completos se pueden reducir entre sí.
Es decir, las reducciones son muy útiles para obtener resultados positivos
en la creación de nuevos algoritmos, pero también para demostrar
resultados negativos mostrando que un problema es más difícil que otro.
Veamos, como punto final más problemas conocidos. El problema de
viajante: dado un grafo quiero encontrar el camino más corto que recorre
todos los vértices. Este problema es NP-completo.
Si te doy n-cadenas en las que se necesita encontrar la subsecuencia común
más larga, es NP-completo.
El buscaminas, el sudoku, la mayoría de los rompecabezas interesantes son
NP-completos.
Descargar