Nivel 8 · Quicksort verificado (experto)
Corrección I: permutación
La primera mitad de la
Definición 12.1afirma que la salida de quicksort contiene exactamente los mismos elementos que la entrada, con las mismas multiplicidades. Primero se registra el único hecho combinatorio sobre el filtrado que la prueba necesita: partir una lista por una prueba booleana y concatenar las dos mitades es una permutación de la original.
Para toda prueba booleana y lista ,
A probar: , donde se abrevia . Por inducción sobre .
- . Ambos filtrados son , luego por reflexividad.
- . Se distingue según .
- Si se cumple: y , de modo que
- Si falla: y , de modo que la concatenación es . Trasladar al frente es una permutación (las transposiciones adyacentes generan ), y se aplica la hipótesis de inducción:
El teorema de permutación
Para toda lista , .
A probar: . Por inducción bien fundamentada sobre (legítima por la Proposición 12.6).
- . por reflexividad.
- . Las dos llamadas recursivas son sobre y , ambas más cortas que (Proposición 12.6); la hipótesis de inducción da entonces y . Se encadenan tres permutaciones por transitividad: La primera permutación es la congruencia de para y aplicada a las dos hipótesis de inducción; la segunda es la permutación «del medio», que lleva el pivote al frente; y la tercera aplica el Lema 12.7 bajo la cabeza , pues . Por transitividad, .
Para todo y , .
A probar: . Por el Teorema 12.8, ; y dos listas permutadas contienen exactamente los mismos elementos (con las mismas multiplicidades), de donde, en particular, .
Este corolario, en apariencia modesto, es el puente hacia la mitad de ordenamiento: permitirá transportar la pertenencia a las salidas recursivas de vuelta a las mitades de la partición, donde la prueba del filtro da las cotas contra el pivote.
Lean
La prueba en
Thesis/Sort/Quicksort.lean
sigue la matemática línea por línea. Los dos have son las hipótesis de inducción (llamadas
recursivas sobre las mitades más cortas); ih1.append (ih2.cons p) es el paso de congruencia;
perm_middle lleva el pivote al frente; y filter_append_perm es el
Lema 12.7.
theorem quicksort_perm : ∀ l : List α, quicksort l ~ l | [] => by simp | p :: rest => by rw [quicksort_cons] -- las llamadas recursivas permutan las dos mitades de la partición have ih1 : quicksort (rest.filter (fun x => decide (x ≤ p))) ~ rest.filter (fun x => decide (x ≤ p)) := quicksort_perm _ have ih2 : quicksort (rest.filter (fun x => ! decide (x ≤ p))) ~ rest.filter (fun x => ! decide (x ≤ p)) := quicksort_perm _ -- pegar las mitades en torno al pivote y recombinar los dos filtros refine (ih1.append (ih2.cons p)).trans ?_ refine (perm_middle).trans ?_ exact (filter_append_perm (fun x => decide (x ≤ p)) rest).cons p termination_by l => l.length decreasing_by all_goals simp_wf all_goals exact le_trans (length_filter_le _ _) (le_of_eq (by simp))
theorem mem_quicksort {a : α} {l : List α} : a ∈ quicksort l ↔ a ∈ l := (quicksort_perm l).mem_iffObsérvese que quicksort_perm lleva sus propias cláusulas termination_by y decreasing_by,
idénticas a las de la definición: el teorema se prueba por la misma
recursión bien fundamentada con la que se
definió la función, y las llamadas quicksort_perm _ sobre las mitades son exactamente las
hipótesis de inducción del argumento matemático. En Lean, «inducción bien fundamentada siguiendo
la recursión» no es una metáfora: es literalmente el mismo mecanismo.