Nivel 8 · Quicksort verificado (experto)
Corrección II: ordenamiento
La prueba de ordenamiento descansa en dos cosas: cómo se comporta el predicado por pares de la
Definición 12.2bajo la concatenación, y la propiedad definitoria de las dos mitades de la partición.
Para una relación y listas ,
Asimismo .
A probar: las dos equivalencias del enunciado. La primera, por inducción sobre .
- . Entonces , es verdadero y la condición cruzada «» es vacua; los dos lados se reducen a .
- . Por la forma
cons(segunda equivalencia), Separando de en la primera conjunción y aplicando la hipótesis de inducción a la segunda, se obtiene .
La segunda equivalencia es la definición de sobre una lista cons. (En Lean
estos son los lemas de biblioteca List.pairwise_append y List.pairwise_cons.)
La observación decisiva es la separación garantizada por la partición: todo elemento de la mitad pequeña es y todo elemento de la mitad grande es (luego ). Combinado con la transitividad de , esto da la cota cruzada necesaria para pegar las mitades ordenadas recursivamente.
El teorema de ordenamiento
Para toda lista , .
A probar: , para toda . Por inducción bien fundamentada sobre .
-
. está ordenada de manera vacua.
-
. Abréviese y , de modo que . La hipótesis de inducción (aplicable porque son más cortas que ) da y .
Paso 1: cotas sobre las mitades.
- Sea . Por el Corolario 12.9, , esto es, aparece en y pasa la prueba; luego .
- Sea . Por el Corolario 12.9, , esto es, aparece en y falla la prueba . Como es lineal, implica , luego .
En resumen,
Paso 2: ensamblaje. Por el Lema 12.10 aplicado a , probar se reduce a tres obligaciones:
- : es la hipótesis de inducción.
- : por la forma
consdel Lema 12.10, equivale a , la mitad derecha de , junto con , la hipótesis de inducción. - Cota cruzada . Fíjense y . Si , entonces por la mitad izquierda de . Si , entonces por ambas mitades de y la transitividad de .
Las tres se cumplen, luego .
Las tres obligaciones corresponden exactamente a las tres «zonas» de la salida ensamblada y a las relaciones de orden entre ellas: dentro de y dentro de el orden se cumple por la hipótesis de inducción; a través del pivote se cumple por las cotas de la partición ; y la cota de largo alcance de a se sigue encadenando por , esto es, por transitividad. El widget de la
página del algoritmoverifica precisamente estas cotas en cada nodo del árbol de recursión.
Lean
La prueba en
Thesis/Sort/Quicksort.lean
nombra las mismas piezas: ih1, ih2 son , ; hsmall,
hlarge son las dos mitades de , cada una obtenida transportando la pertenencia de
vuelta por mem_quicksort
(Corolario 12.9) y
desplegando la prueba del filtro; pairwise_append y pairwise_cons son el
Lema 12.10; y el le_trans final es el paso de
transitividad de la obligación (3).
theorem quicksort_sorted : ∀ l : List α, Sorted (quicksort l) | [] => by simp [Sorted] | p :: rest => by have ih1 : Sorted (quicksort (rest.filter (fun x => decide (x ≤ p)))) := quicksort_sorted _ have ih2 : Sorted (quicksort (rest.filter (fun x => ! decide (x ≤ p)))) := quicksort_sorted _ simp only [Sorted] at ih1 ih2 ⊢ rw [quicksort_cons] -- todo elemento de la mitad "pequeña" es ≤ p have hsmall : ∀ a ∈ quicksort (rest.filter (fun x => decide (x ≤ p))), a ≤ p := by intro a ha have hmem : a ∈ rest.filter (fun x => decide (x ≤ p)) := mem_quicksort.1 ha simp only [mem_filter, decide_eq_true_eq] at hmem exact hmem.2 -- todo elemento de la mitad "grande" es ≥ p (de hecho > p) have hlarge : ∀ b ∈ quicksort (rest.filter (fun x => ! decide (x ≤ p))), p ≤ b := by intro b hb have hmem : b ∈ rest.filter (fun x => ! decide (x ≤ p)) := mem_quicksort.1 hb simp only [mem_filter, Bool.not_eq_true', decide_eq_false_iff_not] at hmem exact le_of_lt (not_le.1 hmem.2) rw [pairwise_append] refine ⟨ih1, ?_, ?_⟩ · -- el bloque derecho `p :: grande` está ordenado rw [pairwise_cons] exact ⟨hlarge, ih2⟩ · -- condición cruzada: todo elemento pequeño ≤ todo elemento de `p :: grande` intro a ha b hb rcases List.mem_cons.1 hb with hbp | hb' · subst hbp; exact hsmall a ha · exact le_trans (hsmall a ha) (hlarge b hb') termination_by l => l.length decreasing_by all_goals simp_wf all_goals exact le_trans (length_filter_le _ _) (le_of_eq (by simp))El teorema principal
Reuniendo las dos mitades se obtiene la especificación de la Definición 12.1.
Para toda lista sobre un tipo linealmente ordenado,
Es decir, quicksort devuelve una permutación ordenada de su entrada.
A probar: y , para toda .
- es el Teorema 12.8 (permutación).
- es el Teorema 12.11 (ordenamiento).
La conjunción de ambos es precisamente la corrección de quicksort.
theorem quicksort_correct (l : List α) : quicksort l ~ l ∧ Sorted (quicksort l) := ⟨quicksort_perm l, quicksort_sorted l⟩El término ⟨quicksort_perm l, quicksort_sorted l⟩ es el constructor anónimo de un par: la
conjunción es un tipo producto y su prueba, un par de pruebas, exactamente la lectura de
como de la correspondencia de
Curry–Howard . No queda obligación de prueba una vez que el núcleo verifica su tipo.