Estoy leyendo "Introducción al algoritmo" por CLRS. En el capítulo 2, los autores mencionan "invariantes de bucle". ¿Qué es un bucle invariante?
268
Estoy leyendo "Introducción al algoritmo" por CLRS. En el capítulo 2, los autores mencionan "invariantes de bucle". ¿Qué es un bucle invariante?
Respuestas:
En palabras simples, un bucle invariante es un predicado (condición) que se cumple para cada iteración del bucle. Por ejemplo, veamos un
for
bucle simple que se ve así:En este ejemplo, es cierto (para cada iteración) que
i + j == 9
. Un invariante más débil que también es cierto es esoi >= 0 && i <= 10
.fuente
Me gusta esta definición muy simple: ( fuente )
Por sí solo, un bucle invariante no hace mucho. Sin embargo, dado un invariante apropiado, puede usarse para ayudar a probar la exactitud de un algoritmo. El ejemplo simple en CLRS probablemente tiene que ver con la ordenación. Por ejemplo, deje que su bucle invariante sea algo así, al comienzo del bucle,
i
se ordenan las primeras entradas de esta matriz. Si puede probar que esto es, de hecho, un bucle invariante (es decir, que se mantiene antes y después de cada iteración del bucle), puede usar esto para probar la corrección de un algoritmo de clasificación: al final del bucle, el bucle invariante aún está satisfecho , y el contadori
es la longitud de la matriz. Por lo tanto, las primerasi
entradas están ordenadas significa que toda la matriz está ordenada.Un ejemplo aún más simple: Invariantes de bucles, corrección y derivación de programa .
La forma en que entiendo un bucle invariante es como una herramienta sistemática y formal para razonar sobre los programas. Hacemos una sola afirmación en la que nos enfocamos en demostrar que es verdadera, y la llamamos invariante del ciclo. Esto organiza nuestra lógica. Si bien podemos debatir informalmente sobre la corrección de algún algoritmo, el uso de un bucle invariante nos obliga a pensar con mucho cuidado y garantiza que nuestro razonamiento sea hermético.
fuente
Hay una cosa que muchas personas no se dan cuenta de inmediato cuando se trata de bucles e invariantes. Se confunden entre el bucle invariante y el bucle condicional (la condición que controla la terminación del bucle).
Como la gente señala, el bucle invariante debe ser cierto
(aunque puede ser temporalmente falso durante el cuerpo del bucle). Por otro lado, el bucle condicional debe ser falso después de que el bucle termina; de lo contrario, el bucle nunca terminaría.
Por lo tanto, el bucle invariante y el bucle condicional deben ser condiciones diferentes.
Un buen ejemplo de un bucle complejo invariante es para la búsqueda binaria.
Por lo tanto, el bucle condicional parece bastante sencillo: cuando inicio> fin, el bucle termina. Pero, ¿por qué es correcto el bucle? ¿Cuál es el bucle invariante que demuestra su corrección?
La invariante es la declaración lógica:
Esta afirmación es una tautología lógica: siempre es cierta en el contexto del bucle / algoritmo específico que estamos tratando de probar . Y proporciona información útil sobre la corrección del bucle después de que finaliza.
Si volvemos porque encontramos el elemento de la matriz a continuación, la declaración es claramente cierto, ya que si
A[mid] == a
sea
está en la matriz ymid
debe estar entre inicio y fin. Y si el bucle termina, porquestart > end
entonces no puede haber un número tal questart <= mid
ymid <= end
y por lo tanto sabemos que la declaraciónA[mid] == a
debe ser falsa. Sin embargo, como resultado, la declaración lógica general sigue siendo cierta en sentido nulo. (En lógica, la declaración if (false) then (something) siempre es verdadera).Ahora, ¿qué pasa con lo que dije sobre el bucle condicional que necesariamente es falso cuando el bucle termina? Parece que cuando el elemento se encuentra en la matriz, entonces el condicional del bucle es verdadero cuando el bucle termina. En realidad no lo es, porque el bucle condicional implícito es realmente
while ( A[mid] != a && start <= end )
pero acortamos la prueba real ya que la primera parte está implícita. Este condicional es claramente falso después del ciclo, independientemente de cómo termine el ciclo.fuente
a
esté presenteA
. Informalmente sería, "si la clavea
está presente en la matriz, debe ocurrir entrestart
eend
inclusive". Luego se deduce que siA[start..end]
está vacío, esoa
no está presente en A.Las respuestas anteriores han definido un bucle invariante de una muy buena manera.
A continuación se muestra cómo los autores de CLRS usaron el bucle invariante para probar la corrección del tipo de inserción.
Algoritmo de clasificación de inserción (como se da en el libro):
Invariante de bucle en este caso: la submatriz [1 a j-1] siempre se ordena.
Ahora verifiquemos esto y demostremos que el algoritmo es correcto.
Inicialización : antes de la primera iteración j = 2. Entonces sub-array [1: 1] es el array a ser probado. Como solo tiene un elemento, está ordenado. Así invariante está satisfecho.
Mantenimiento : Esto puede verificarse fácilmente marcando la invariante después de cada iteración. En este caso está satisfecho.
Terminación : este es el paso donde probaremos la corrección del algoritmo.
Cuando el ciclo termina, entonces el valor de j = n + 1. Nuevamente, el bucle invariante está satisfecho. Esto significa que la sub-matriz [1 a n] debe ordenarse.
Esto es lo que queremos hacer con nuestro algoritmo. Por lo tanto, nuestro algoritmo es correcto.
fuente
Además de todas las buenas respuestas, creo que un gran ejemplo de Cómo pensar en algoritmos, de Jeff Edmonds, puede ilustrar muy bien el concepto:
fuente
Cabe señalar que un Loop Invariant puede ayudar en el diseño de algoritmos iterativos cuando se considera una afirmación que expresa relaciones importantes entre las variables que deben ser verdaderas al comienzo de cada iteración y cuando el ciclo termina. Si esto se cumple, el cálculo está en camino a la efectividad. Si es falso, entonces el algoritmo ha fallado.
fuente
Invariante en este caso significa una condición que debe ser verdadera en un cierto punto en cada iteración del ciclo.
En la programación por contrato, una invariante es una condición que debe ser verdadera (por contrato) antes y después de que se llame a cualquier método público.
fuente
El significado de invariante nunca cambia
Aquí, el invariante del bucle significa "El cambio que sucede a la variable en el bucle (incremento o decremento) no está cambiando la condición del bucle, es decir, la condición es satisfactoria", de modo que el concepto invariante del bucle ha llegado
fuente
La propiedad invariante de bucle es una condición que se cumple para cada paso de la ejecución de un bucle (es decir, para bucles, bucles while, etc.)
Esto es esencial para una Prueba Invariante de Bucle, donde uno puede demostrar que un algoritmo se ejecuta correctamente si en cada paso de su ejecución se mantiene esta propiedad invariante de bucle.
Para que un algoritmo sea correcto, la Invariante de bucle debe mantenerse en:
Inicialización (el comienzo)
Mantenimiento (cada paso después)
Terminación (cuando está terminado)
Esto se utiliza para evaluar un montón de cosas, pero el mejor ejemplo son los algoritmos codiciosos para el cruce de gráficos ponderados. Para que un algoritmo codicioso produzca una solución óptima (una ruta a través del gráfico), debe llegar a conectar todos los nodos en la ruta de menor peso posible.
Por lo tanto, la propiedad invariante del bucle es que la ruta tomada tiene el menor peso. Al principio no hemos agregado ningún borde, por lo que esta propiedad es verdadera (no es falsa, en este caso). En cada paso , seguimos el borde de menor peso (el paso codicioso), por lo que nuevamente estamos tomando la ruta de menor peso. Al final , hemos encontrado la ruta más baja ponderada, por lo que nuestra propiedad también es cierta.
Si un algoritmo no hace esto, podemos demostrar que no es óptimo.
fuente
Es difícil hacer un seguimiento de lo que sucede con los bucles. Los bucles que no terminan o terminan sin lograr su objetivo de comportamiento es un problema común en la programación de computadoras. Los invariantes de bucle ayudan. Un ciclo invariante es una declaración formal sobre la relación entre las variables en su programa que es verdadera justo antes de que el ciclo se ejecute (estableciendo el invariante) y es verdadera nuevamente en la parte inferior del ciclo, cada vez a través del ciclo (manteniendo el invariante ) Aquí está el patrón general del uso de invariantes de bucle en su código:
... // la Invariante del bucle debe ser verdadera aquí
mientras que (CONDICIÓN DE PRUEBA) {
// parte superior del bucle
...
// parte inferior del bucle
// la Invariante del bucle debe ser verdadera aquí
}
// Terminación + Invariante del bucle = Meta
...
Entre la parte superior e inferior del bucle, presumiblemente se avanza hacia alcanzar la meta del bucle. Esto podría perturbar (hacer falso) lo invariante. El punto de las invariantes de bucle es la promesa de que la invariante se restaurará antes de repetir el cuerpo del bucle cada vez. Hay dos ventajas para esto:
El trabajo no se traslada al siguiente paso de formas complicadas que dependen de los datos. Cada paso a través del bucle es independiente de todos los demás, y el invariante sirve para unir los pases en un todo funcional. El razonamiento de que su ciclo funciona se reduce al razonamiento de que el ciclo invariante se restaura con cada pasada a través del ciclo. Esto divide el complicado comportamiento general del bucle en pequeños pasos simples, cada uno de los cuales puede considerarse por separado. La condición de prueba del bucle no es parte de la invariante. Es lo que hace que el ciclo termine. Considera por separado dos cosas: por qué el ciclo debería terminar alguna vez, y por qué el ciclo logra su objetivo cuando termina. El bucle terminará si cada vez que se acerque al bucle se acerque para satisfacer la condición de terminación. A menudo es fácil asegurar esto: por ejemplo pasando una variable de contador por una hasta que alcance un límite superior fijo. A veces el razonamiento detrás de la terminación es más difícil.
El bucle invariante debe crearse de modo que cuando se alcance la condición de terminación y el invariante sea verdadero, se alcance el objetivo:
invariante + terminación => objetivo
Se necesita práctica para crear invariantes que sean simples y se relacionen y que capturen todo el logro del objetivo, excepto la terminación. Es mejor usar símbolos matemáticos para expresar invariantes de bucle, pero cuando esto lleva a situaciones demasiado complicadas, confiamos en una prosa clara y sentido común.
fuente
Lo siento, no tengo permiso para comentar.
@Tomas Petricek como mencionaste
¿Cómo es un bucle invariante?
Espero no estar equivocado, por lo que entiendo [1] , la invariante de bucle será verdadera al comienzo del bucle (Inicialización), será verdadera antes y después de cada iteración (Mantenimiento) y también será verdadera después La terminación del bucle (terminación) . Pero después de la última iteración, se convierte en 10. Entonces, la condición i> = 0 && i <10 se convierte en falsa y termina el ciclo. Viola la tercera propiedad (Terminación) del bucle invariante.
[1] http://www.win.tue.nl/~kbuchin/teaching/JBP030/notebooks/loop-invariants.html
fuente
Loop invariant es una fórmula matemática como
(x=y+1)
. En ese ejemplo,x
yy
representan dos variables en un bucle. Teniendo en cuenta el cambio de comportamiento de esas variables a lo largo de la ejecución del código, es casi imposible probar todo posiblex
yy
los valores y ver si se produce ningún error. Digamos quex
es un número entero. El entero puede contener un espacio de 32 bits en la memoria. Si ese número excede, se produce un desbordamiento del búfer. Por lo tanto, debemos asegurarnos de que durante la ejecución del código, nunca exceda ese espacio. para eso, necesitamos entender una fórmula general que muestre la relación entre variables. Después de todo, solo tratamos de entender el comportamiento del programa.fuente
En palabras simples, es una condición LOOP que es verdadera en cada iteración de bucle:
En esto podemos decir que el estado de i es
i<10 and i>=0
fuente
Un bucle invariante es una afirmación que es verdadera antes y después de la ejecución del bucle.
fuente
En la búsqueda lineal (según el ejercicio dado en el libro), necesitamos encontrar el valor V en una matriz dada.
Es simple como escanear la matriz desde 0 <= k <longitud y comparar cada elemento. Si se encuentra V, o si el escaneo alcanza la longitud de la matriz, simplemente finalice el ciclo.
Según mi comprensión en el problema anterior
Invariantes de bucle (inicialización): V no se encuentra en la iteración k - 1. Primera iteración, esto sería -1, por lo tanto, podemos decir que V no se encuentra en la posición -1
Mantenimiento: en la próxima iteración, V no encontrado en k-1 es verdadero
Terminación: si V se encuentra en la posición k o k alcanza la longitud de la matriz, finalice el bucle.
fuente