Built with Alectryon, running Coq+SerAPI v8.10.0+0.7.0. Coq sources are in this panel; goals and messages will appear in the other. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑ Ctrl+↓ to navigate, Ctrl+🖱️ to focus.
(************************************************************************)
(* * The Coq Proof Assistant / The Coq Development Team *)
(* v * INRIA, CNRS and contributors - Copyright 1999-2018 *)
(* <O___,, * (see CREDITS file for the list of authors) *)
(* \VV/ **************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(* * (see LICENSE file for the text of the license) *)
(************************************************************************)
A modular implementation of mergesort (the complexity is O(n.log n) in
the length of the list)
(* Initial author: Hugo Herbelin, Oct 2009 *) Require Import List Setoid Permutation Sorted Orders.
Notations and conventions
Local Notation "[ ]" := nil. Local Notation "[ a ; .. ; b ]" := (a :: .. (b :: []) ..). Open Scope bool_scope. Coercion is_true : bool >-> Sortclass.
The main module defining mergesort on a given boolean
order <=?. We require minimal hypotheses : this boolean
order should only be total: ∀ x y, (x<=?y) ∨ (y<=?x).
Transitivity is not mandatory, but without it one can
only prove LocallySorted and not StronglySorted.
Module Sort (Import X:Orders.TotalLeBool'). Fixpoint merge l1 l2 := let fix merge_aux l2 := match l1, l2 with | [], _ => l2 | _, [] => l1 | a1::l1', a2::l2' => if a1 <=? a2 then a1 :: merge l1' l2 else a2 :: merge_aux l2' end in merge_aux l2.
We implement mergesort using an explicit stack of pending mergings.
Pending merging are represented like a binary number where digits are
either None (denoting 0) or Some list to merge (denoting 1). The n-th
digit represents the pending list to be merged at level n, if any.
Merging a list to a stack is like adding 1 to the binary number
represented by the stack but the carry is propagated by merging the
lists. In practice, when used in mergesort, the n-th digit, if non 0,
carries a list of length 2^n. For instance, adding singleton list
3 to the stack Some 4::Some 2;6::None::Some 1;3;5;5
reduces to propagate the carry 3;4 (resulting of the merge of 3
and 4) to the list Some 2;6::None::Some 1;3;5;5, which reduces
to propagating the carry 2;3;4;6 (resulting of the merge of 3;4 and
2;6) to the list None::Some 1;3;5;5, which locally produces
Some 2;3;4;6::Some 1;3;5;5, i.e. which produces the final result
None::None::Some 2;3;4;6::Some 1;3;5;5.
For instance, here is how 6;2;3;1;5 is sorted:
operation stack list iter_merge [] [6;2;3;1;5] = append_list_to_stack [ + [6]] [2;3;1;5] -> iter_merge [[6]] [2;3;1;5] = append_list_to_stack [[6] + [2]] [3;1;5] = append_list_to_stack [ + [2;6];] [3;1;5] -> iter_merge [[2;6];] [3;1;5] = append_list_to_stack [[2;6]; + [3]] [1;5] -> merge_list [[2;6];[3]] [1;5] = append_list_to_stack [[2;6];[3] + [1] [5] = append_list_to_stack [[2;6] + [1;3];] [5] = append_list_to_stack [ + [1;2;3;6];;] [5] -> merge_list [[1;2;3;6];;] [5] = append_list_to_stack [[1;2;3;6];; + [5]] [] -> merge_stack [[1;2;3;6];;[5]] = [1;2;3;5;6]The complexity of the algorithm is n*log n, since there are 2^(p-1) mergings to do of length 2, 2^(p-2) of length 4, ..., 2^0 of length 2^p for a list of length 2^p. The algorithm does not need explicitly cutting the list in 2 parts at each step since it the successive accumulation of fragments on the stack which ensures that lists are merged on a dichotomic basis.
Fixpoint merge_list_to_stack stack l := match stack with | [] => [Some l] | None :: stack' => Some l :: stack' | Some l' :: stack' => None :: merge_list_to_stack stack' (merge l' l) end. Fixpoint merge_stack stack := match stack with | [] => [] | None :: stack' => merge_stack stack' | Some l :: stack' => merge l (merge_stack stack') end. Fixpoint iter_merge stack l := match l with | [] => merge_stack stack | a::l' => iter_merge (merge_list_to_stack stack [a]) l' end. Definition sort := iter_merge [].
The proof of correctness
Notation Sorted := (LocallySorted leb) (only parsing). Fixpoint SortedStack stack := match stack with | [] => True | None :: stack' => SortedStack stack' | Some l :: stack' => Sorted l /\ SortedStack stack' end. Ltac invert H := inversion H; subst; clear H. Fixpoint flatten_stack (stack : list (option (list t))) := match stack with | [] => [] | None :: stack' => flatten_stack stack' | Some l :: stack' => l ++ flatten_stack stack' end.forall l1 l2 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l2)forall l1 l2 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l2)a:tl1:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) l2)H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)LocallySorted (fun x x0 : t => x <=? x0) (if a <=? a0 then a :: merge l1 (a0 :: l2) else a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tl1:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) l2)H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = trueLocallySorted (fun x x0 : t => x <=? x0) (a :: merge l1 (a0 :: l2))a:tl1:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) l2)H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = falseLocallySorted (fun x x0 : t => x <=? x0) (a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) [ ] -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge [ ] l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) [a] -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge [a] l2)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = trueLocallySorted (fun x x0 : t => x <=? x0) (a :: merge [ ] (a0 :: l2))a, b:tl:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) (b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (b :: l) l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: b :: l) l2)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = trueH3:LocallySorted (fun x x0 : t => x <=? x0) (b :: l)H4:is_true (a <=? b)LocallySorted (fun x x0 : t => x <=? x0) (a :: merge (b :: l) (a0 :: l2))a:tl1:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) l2)H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = falseLocallySorted (fun x x0 : t => x <=? x0) (a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) [ ] -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge [ ] l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) [a] -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge [a] l2)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = trueLocallySorted (fun x x0 : t => x <=? x0) (a :: a0 :: l2)a, b:tl:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) (b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (b :: l) l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: b :: l) l2)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = trueH3:LocallySorted (fun x x0 : t => x <=? x0) (b :: l)H4:is_true (a <=? b)LocallySorted (fun x x0 : t => x <=? x0) (a :: merge (b :: l) (a0 :: l2))a:tl1:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) l2)H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = falseLocallySorted (fun x x0 : t => x <=? x0) (a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a, b:tl:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) (b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (b :: l) l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: b :: l) l2)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = trueH3:LocallySorted (fun x x0 : t => x <=? x0) (b :: l)H4:is_true (a <=? b)LocallySorted (fun x x0 : t => x <=? x0) (a :: merge (b :: l) (a0 :: l2))a:tl1:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) l2)H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = falseLocallySorted (fun x x0 : t => x <=? x0) (a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a, b:tl:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) (b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (b :: l) l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: b :: l) l2)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = trueH3:LocallySorted (fun x x0 : t => x <=? x0) (b :: l)H4:is_true (a <=? b)H:LocallySorted (fun x x0 : t => x <=? x0) (merge (b :: l) (a0 :: l2))LocallySorted (fun x x0 : t => x <=? x0) (a :: merge (b :: l) (a0 :: l2))a:tl1:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) l2)H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = falseLocallySorted (fun x x0 : t => x <=? x0) (a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a, b:tl:list ta0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) ((fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: b :: l | a2 :: l2' => if a <=? a2 then a :: (fix merge_aux0 (l1 : list t) : list t := match l1 with | [ ] => b :: l | a1 :: l2'0 => if b <=? a1 then b :: merge l l1 else a1 :: merge_aux0 l2'0 end) l0 else a2 :: merge_aux l2' end) l2)Heq1:a <=? a0 = trueH4:is_true (a <=? b)H:LocallySorted (fun x x0 : t => x <=? x0) (if b <=? a0 then b :: merge l (a0 :: l2) else a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => b :: l | a2 :: l2' => if b <=? a2 then b :: merge l l0 else a2 :: merge_aux l2' end) l2)LocallySorted (fun x x0 : t => x <=? x0) (a :: (if b <=? a0 then b :: merge l (a0 :: l2) else a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => b :: l | a2 :: l2' => if b <=? a2 then b :: merge l l0 else a2 :: merge_aux l2' end) l2))a:tl1:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) l2)H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = falseLocallySorted (fun x x0 : t => x <=? x0) (a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tl1:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) l2)H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = falseLocallySorted (fun x x0 : t => x <=? x0) (a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tl1:list tIHl1:forall l0 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l0)a0:tl2:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) l2)H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)H0:LocallySorted (fun x x0 : t => x <=? x0) (a0 :: l2)Heq1:a <=? a0 = falseH1:is_true (a0 <=? a)LocallySorted (fun x x0 : t => x <=? x0) (a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tl1:list tIHl1:forall l2 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l2)a0:tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) [ ] -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) [ ])H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)Heq1:a <=? a0 = falseH1:is_true (a0 <=? a)LocallySorted (fun x x0 : t => x <=? x0) (a0 :: a :: l1)a:tl1:list tIHl1:forall l2 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l2)a0, b:tl:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) (b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) (b :: l))H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)Heq1:a <=? a0 = falseH1:is_true (a0 <=? a)H4:LocallySorted (fun x x0 : t => x <=? x0) (b :: l)H5:is_true (a0 <=? b)LocallySorted (fun x x0 : t => x <=? x0) (a0 :: (if a <=? b then a :: merge l1 (b :: l) else b :: (fix merge_aux (l2 : list t) : list t := match l2 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l2 else a2 :: merge_aux l2' end) l))a:tl1:list tIHl1:forall l2 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l2)a0, b:tl:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) (b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) (b :: l))H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)Heq1:a <=? a0 = falseH1:is_true (a0 <=? a)H4:LocallySorted (fun x x0 : t => x <=? x0) (b :: l)H5:is_true (a0 <=? b)LocallySorted (fun x x0 : t => x <=? x0) (a0 :: (if a <=? b then a :: merge l1 (b :: l) else b :: (fix merge_aux (l2 : list t) : list t := match l2 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l2 else a2 :: merge_aux l2' end) l))a:tl1:list tIHl1:forall l2 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l2)a0, b:tl:list tIHl2:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1) -> LocallySorted (fun x x0 : t => x <=? x0) (b :: l) -> LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) (b :: l))H:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)Heq1:a <=? a0 = falseH1:is_true (a0 <=? a)H4:LocallySorted (fun x x0 : t => x <=? x0) (b :: l)H5:is_true (a0 <=? b)H0:LocallySorted (fun x x0 : t => x <=? x0) (merge (a :: l1) (b :: l))LocallySorted (fun x x0 : t => x <=? x0) (a0 :: (if a <=? b then a :: merge l1 (b :: l) else b :: (fix merge_aux (l2 : list t) : list t := match l2 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l2 else a2 :: merge_aux l2' end) l))destruct (a <=? b); constructor; auto. Qed.a:tl1:list tIHl1:forall l2 : list t, LocallySorted (fun x x0 : t => x <=? x0) l1 -> LocallySorted (fun x x0 : t => x <=? x0) l2 -> LocallySorted (fun x x0 : t => x <=? x0) (merge l1 l2)a0, b:tl:list tH:LocallySorted (fun x x0 : t => x <=? x0) (a :: l1)Heq1:a <=? a0 = falseH1:is_true (a0 <=? a)H4:LocallySorted (fun x x0 : t => x <=? x0) (b :: l)H5:is_true (a0 <=? b)H0:LocallySorted (fun x x0 : t => x <=? x0) (if a <=? b then a :: merge l1 (b :: l) else b :: (fix merge_aux (l2 : list t) : list t := match l2 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l2 else a2 :: merge_aux l2' end) l)LocallySorted (fun x x0 : t => x <=? x0) (a0 :: (if a <=? b then a :: merge l1 (b :: l) else b :: (fix merge_aux (l2 : list t) : list t := match l2 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l2 else a2 :: merge_aux l2' end) l))forall l1 l2 : list t, Permutation (l1 ++ l2) (merge l1 l2)forall l1 l2 : list t, Permutation (l1 ++ l2) (merge l1 l2)l2:list tPermutation ([ ] ++ l2) ((fix merge_aux (l0 : list t) : list t := l0) l2)a:tl1:list tIHl1:forall l0 : list t, Permutation (l1 ++ l0) (merge l1 l0)l2:list tPermutation ((a :: l1) ++ l2) ((fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)l2:list tPermutation ([ ] ++ l2) l2a:tl1:list tIHl1:forall l0 : list t, Permutation (l1 ++ l0) (merge l1 l0)l2:list tPermutation ((a :: l1) ++ l2) ((fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tl1:list tIHl1:forall l0 : list t, Permutation (l1 ++ l0) (merge l1 l0)l2:list tPermutation ((a :: l1) ++ l2) ((fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tl1:list tIHl1:forall l2 : list t, Permutation (l1 ++ l2) (merge l1 l2)Permutation ((a :: l1) ++ [ ]) (a :: l1)a:tl1:list tIHl1:forall l0 : list t, Permutation (l1 ++ l0) (merge l1 l0)a0:tl2:list tIHl2:Permutation ((a :: l1) ++ l2) ((fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)Permutation ((a :: l1) ++ a0 :: l2) (if a <=? a0 then a :: merge l1 (a0 :: l2) else a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tl1:list tIHl1:forall l2 : list t, Permutation (l1 ++ l2) (merge l1 l2)Permutation (a :: l1) (a :: l1)a:tl1:list tIHl1:forall l0 : list t, Permutation (l1 ++ l0) (merge l1 l0)a0:tl2:list tIHl2:Permutation ((a :: l1) ++ l2) ((fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)Permutation ((a :: l1) ++ a0 :: l2) (if a <=? a0 then a :: merge l1 (a0 :: l2) else a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tl1:list tIHl1:forall l0 : list t, Permutation (l1 ++ l0) (merge l1 l0)a0:tl2:list tIHl2:Permutation ((a :: l1) ++ l2) ((fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)Permutation ((a :: l1) ++ a0 :: l2) (if a <=? a0 then a :: merge l1 (a0 :: l2) else a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)a:tl1:list tIHl1:forall l0 : list t, Permutation (l1 ++ l0) (merge l1 l0)a0:tl2:list tIHl2:Permutation ((a :: l1) ++ l2) ((fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)Permutation ((a :: l1) ++ a0 :: l2) (a :: merge l1 (a0 :: l2))a:tl1:list tIHl1:forall l0 : list t, Permutation (l1 ++ l0) (merge l1 l0)a0:tl2:list tIHl2:Permutation ((a :: l1) ++ l2) ((fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)Permutation ((a :: l1) ++ a0 :: l2) (a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)apply Permutation_sym, Permutation_cons_app, Permutation_sym, IHl2. Qed.a:tl1:list tIHl1:forall l0 : list t, Permutation (l1 ++ l0) (merge l1 l0)a0:tl2:list tIHl2:Permutation ((a :: l1) ++ l2) ((fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)Permutation ((a :: l1) ++ a0 :: l2) (a0 :: (fix merge_aux (l0 : list t) : list t := match l0 with | [ ] => a :: l1 | a2 :: l2' => if a <=? a2 then a :: merge l1 l0 else a2 :: merge_aux l2' end) l2)forall (stack : list (option (list t))) (l : list t), SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l -> SortedStack (merge_list_to_stack stack l)forall (stack : list (option (list t))) (l : list t), SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l -> SortedStack (merge_list_to_stack stack l)l:list tH:SortedStack [ ]H0:LocallySorted (fun x x0 : t => x <=? x0) lLocallySorted (fun x x0 : t => x <=? x0) l /\ Truel:list tstack:list (option (list t))IHstack:forall l1 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l1 -> SortedStack (merge_list_to_stack stack l1)l0:list tH:SortedStack (Some l :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) l0SortedStack (merge_list_to_stack stack (merge l l0))stack:list (option (list t))IHstack:forall l0 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> SortedStack (merge_list_to_stack stack l0)l:list tH:SortedStack (None :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) lLocallySorted (fun x x0 : t => x <=? x0) l /\ SortedStack stackl:list tstack:list (option (list t))IHstack:forall l1 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l1 -> SortedStack (merge_list_to_stack stack l1)l0:list tH:SortedStack (Some l :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) l0SortedStack (merge_list_to_stack stack (merge l l0))stack:list (option (list t))IHstack:forall l0 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> SortedStack (merge_list_to_stack stack l0)l:list tH:SortedStack (None :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) lLocallySorted (fun x x0 : t => x <=? x0) l /\ SortedStack stackl:list tstack:list (option (list t))IHstack:forall l1 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l1 -> SortedStack (merge_list_to_stack stack l1)l0:list tH:SortedStack (Some l :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) l0SortedStack stackl:list tstack:list (option (list t))IHstack:forall l1 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l1 -> SortedStack (merge_list_to_stack stack l1)l0:list tH:SortedStack (Some l :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) l0LocallySorted (fun x x0 : t => x <=? x0) (merge l l0)stack:list (option (list t))IHstack:forall l0 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> SortedStack (merge_list_to_stack stack l0)l:list tH:SortedStack (None :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) lLocallySorted (fun x x0 : t => x <=? x0) l /\ SortedStack stackl:list tstack:list (option (list t))IHstack:forall l1 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l1 -> SortedStack (merge_list_to_stack stack l1)l0:list tH1:SortedStack stackH0:LocallySorted (fun x x0 : t => x <=? x0) l0SortedStack stackl:list tstack:list (option (list t))IHstack:forall l1 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l1 -> SortedStack (merge_list_to_stack stack l1)l0:list tH:SortedStack (Some l :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) l0LocallySorted (fun x x0 : t => x <=? x0) (merge l l0)stack:list (option (list t))IHstack:forall l0 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> SortedStack (merge_list_to_stack stack l0)l:list tH:SortedStack (None :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) lLocallySorted (fun x x0 : t => x <=? x0) l /\ SortedStack stackl:list tstack:list (option (list t))IHstack:forall l1 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l1 -> SortedStack (merge_list_to_stack stack l1)l0:list tH1:SortedStack stackH0:LocallySorted (fun x x0 : t => x <=? x0) l0SortedStack stackl:list tstack:list (option (list t))IHstack:forall l1 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l1 -> SortedStack (merge_list_to_stack stack l1)l0:list tH:SortedStack (Some l :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) l0LocallySorted (fun x x0 : t => x <=? x0) (merge l l0)stack:list (option (list t))IHstack:forall l0 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> SortedStack (merge_list_to_stack stack l0)l:list tH:SortedStack (None :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) lLocallySorted (fun x x0 : t => x <=? x0) l /\ SortedStack stackl:list tstack:list (option (list t))IHstack:forall l1 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l1 -> SortedStack (merge_list_to_stack stack l1)l0:list tH:SortedStack (Some l :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) l0LocallySorted (fun x x0 : t => x <=? x0) (merge l l0)stack:list (option (list t))IHstack:forall l0 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> SortedStack (merge_list_to_stack stack l0)l:list tH:SortedStack (None :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) lLocallySorted (fun x x0 : t => x <=? x0) l /\ SortedStack stackauto. Qed.stack:list (option (list t))IHstack:forall l0 : list t, SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) l0 -> SortedStack (merge_list_to_stack stack l0)l:list tH:SortedStack (None :: stack)H0:LocallySorted (fun x x0 : t => x <=? x0) lLocallySorted (fun x x0 : t => x <=? x0) l /\ SortedStack stackforall (stack : list (option (list t))) (l : list t), Permutation (l ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l))forall (stack : list (option (list t))) (l : list t), Permutation (l ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l))l:list tPermutation (l ++ [ ]) (l ++ [ ])l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation (l0 ++ l ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack (merge l l0)))stack:list (option (list t))IHstack:forall l0 : list t, Permutation (l0 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l0))l:list tPermutation (l ++ flatten_stack stack) (l ++ flatten_stack stack)l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation (l0 ++ l ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack (merge l l0)))stack:list (option (list t))IHstack:forall l0 : list t, Permutation (l0 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l0))l:list tPermutation (l ++ flatten_stack stack) (l ++ flatten_stack stack)l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation ((l0 ++ l) ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack (merge l l0)))stack:list (option (list t))IHstack:forall l0 : list t, Permutation (l0 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l0))l:list tPermutation (l ++ flatten_stack stack) (l ++ flatten_stack stack)l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation ((l0 ++ l) ++ flatten_stack stack) ?yl:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation ?y (flatten_stack (merge_list_to_stack stack (merge l l0)))stack:list (option (list t))IHstack:forall l0 : list t, Permutation (l0 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l0))l:list tPermutation (l ++ flatten_stack stack) (l ++ flatten_stack stack)l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation (l0 ++ l) ?l'l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation (?l' ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack (merge l l0)))stack:list (option (list t))IHstack:forall l0 : list t, Permutation (l0 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l0))l:list tPermutation (l ++ flatten_stack stack) (l ++ flatten_stack stack)l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation (l0 ++ l) ?yl:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation ?y ?l'l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation (?l' ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack (merge l l0)))stack:list (option (list t))IHstack:forall l0 : list t, Permutation (l0 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l0))l:list tPermutation (l ++ flatten_stack stack) (l ++ flatten_stack stack)l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation (l ++ l0) ?l'l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation (?l' ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack (merge l l0)))stack:list (option (list t))IHstack:forall l0 : list t, Permutation (l0 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l0))l:list tPermutation (l ++ flatten_stack stack) (l ++ flatten_stack stack)l:list tstack:list (option (list t))IHstack:forall l1 : list t, Permutation (l1 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l1))l0:list tPermutation (merge l l0 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack (merge l l0)))stack:list (option (list t))IHstack:forall l0 : list t, Permutation (l0 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l0))l:list tPermutation (l ++ flatten_stack stack) (l ++ flatten_stack stack)reflexivity. Qed.stack:list (option (list t))IHstack:forall l0 : list t, Permutation (l0 ++ flatten_stack stack) (flatten_stack (merge_list_to_stack stack l0))l:list tPermutation (l ++ flatten_stack stack) (l ++ flatten_stack stack)forall stack : list (option (list t)), SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)forall stack : list (option (list t)), SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)H:TrueLocallySorted (fun x x0 : t => x <=? x0) [ ]l:list tstack:list (option (list t))IHstack:SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)H:LocallySorted (fun x x0 : t => x <=? x0) l /\ SortedStack stackLocallySorted (fun x x0 : t => x <=? x0) (merge l (merge_stack stack))stack:list (option (list t))IHstack:SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)H:SortedStack stackLocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)l:list tstack:list (option (list t))IHstack:SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)H:LocallySorted (fun x x0 : t => x <=? x0) l /\ SortedStack stackLocallySorted (fun x x0 : t => x <=? x0) (merge l (merge_stack stack))stack:list (option (list t))IHstack:SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)H:SortedStack stackLocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)auto. Qed.stack:list (option (list t))IHstack:SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)H:SortedStack stackLocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)forall stack : list (option (list t)), Permutation (flatten_stack stack) (merge_stack stack)forall stack : list (option (list t)), Permutation (flatten_stack stack) (merge_stack stack)Permutation [ ] [ ]l:list tstack:list (option (list t))IHstack:Permutation (flatten_stack stack) (merge_stack stack)Permutation (l ++ flatten_stack stack) (merge l (merge_stack stack))stack:list (option (list t))IHstack:Permutation (flatten_stack stack) (merge_stack stack)Permutation (flatten_stack stack) (merge_stack stack)l:list tstack:list (option (list t))IHstack:Permutation (flatten_stack stack) (merge_stack stack)Permutation (l ++ flatten_stack stack) (merge l (merge_stack stack))stack:list (option (list t))IHstack:Permutation (flatten_stack stack) (merge_stack stack)Permutation (flatten_stack stack) (merge_stack stack)l:list tstack:list (option (list t))IHstack:Permutation (flatten_stack stack) (merge_stack stack)Permutation (l ++ flatten_stack stack) (l ++ merge_stack stack)l:list tstack:list (option (list t))IHstack:Permutation (flatten_stack stack) (merge_stack stack)Permutation (l ++ merge_stack stack) (merge l (merge_stack stack))stack:list (option (list t))IHstack:Permutation (flatten_stack stack) (merge_stack stack)Permutation (flatten_stack stack) (merge_stack stack)l:list tstack:list (option (list t))IHstack:Permutation (flatten_stack stack) (merge_stack stack)Permutation (l ++ merge_stack stack) (merge l (merge_stack stack))stack:list (option (list t))IHstack:Permutation (flatten_stack stack) (merge_stack stack)Permutation (flatten_stack stack) (merge_stack stack)assumption. Qed.stack:list (option (list t))IHstack:Permutation (flatten_stack stack) (merge_stack stack)Permutation (flatten_stack stack) (merge_stack stack)forall (stack : list (option (list t))) (l : list t), SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) (iter_merge stack l)forall (stack : list (option (list t))) (l : list t), SortedStack stack -> LocallySorted (fun x x0 : t => x <=? x0) (iter_merge stack l)stack:list (option (list t))H:SortedStack stackLocallySorted (fun x x0 : t => x <=? x0) (merge_stack stack)stack:list (option (list t))a:tl:list tH:SortedStack stackIHl:forall stack0 : list (option (list t)), SortedStack stack0 -> LocallySorted (fun x x0 : t => x <=? x0) (iter_merge stack0 l)LocallySorted (fun x x0 : t => x <=? x0) (iter_merge (merge_list_to_stack stack [a]) l)stack:list (option (list t))a:tl:list tH:SortedStack stackIHl:forall stack0 : list (option (list t)), SortedStack stack0 -> LocallySorted (fun x x0 : t => x <=? x0) (iter_merge stack0 l)LocallySorted (fun x x0 : t => x <=? x0) (iter_merge (merge_list_to_stack stack [a]) l)auto using Sorted_merge_list_to_stack. Qed.stack:list (option (list t))a:tl:list tH:SortedStack stackIHl:forall stack0 : list (option (list t)), SortedStack stack0 -> LocallySorted (fun x x0 : t => x <=? x0) (iter_merge stack0 l)H0:LocallySorted (fun x x0 : t => x <=? x0) [a]LocallySorted (fun x x0 : t => x <=? x0) (iter_merge (merge_list_to_stack stack [a]) l)forall (l : list t) (stack : list (option (list t))), Permutation (flatten_stack stack ++ l) (iter_merge stack l)forall (l : list t) (stack : list (option (list t))), Permutation (flatten_stack stack ++ l) (iter_merge stack l)stack:list (option (list t))Permutation (flatten_stack stack ++ [ ]) (merge_stack stack)a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation (flatten_stack stack ++ a :: l) (iter_merge (merge_list_to_stack stack [a]) l)stack:list (option (list t))Permutation (flatten_stack stack) (merge_stack stack)a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation (flatten_stack stack ++ a :: l) (iter_merge (merge_list_to_stack stack [a]) l)a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation (flatten_stack stack ++ a :: l) (iter_merge (merge_list_to_stack stack [a]) l)a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation (flatten_stack stack ++ [a] ++ l) (iter_merge (merge_list_to_stack stack [a]) l)a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation ((flatten_stack stack ++ [a]) ++ l) (iter_merge (merge_list_to_stack stack [a]) l)a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation ((flatten_stack stack ++ [a]) ++ l) ?ya:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation ?y (iter_merge (merge_list_to_stack stack [a]) l)a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation (flatten_stack stack ++ [a]) ?l'a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation (?l' ++ l) (iter_merge (merge_list_to_stack stack [a]) l)a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation (flatten_stack stack ++ [a]) ?ya:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation ?y ?l'a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation (?l' ++ l) (iter_merge (merge_list_to_stack stack [a]) l)a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation ([a] ++ flatten_stack stack) ?l'a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation (?l' ++ l) (iter_merge (merge_list_to_stack stack [a]) l)apply IHl. Qed.a:tl:list tIHl:forall stack0 : list (option (list t)), Permutation (flatten_stack stack0 ++ l) (iter_merge stack0 l)stack:list (option (list t))Permutation (flatten_stack (merge_list_to_stack stack [a]) ++ l) (iter_merge (merge_list_to_stack stack [a]) l)forall l : list t, LocallySorted (fun x x0 : t => x <=? x0) (sort l)forall l : list t, LocallySorted (fun x x0 : t => x <=? x0) (sort l)constructor. Qed.l:list tSortedStack [ ]forall l : list t, Sorted.Sorted (fun x x0 : t => x <=? x0) (sort l)intro; eapply Sorted_LocallySorted_iff, Sorted_sort; auto. Qed.forall l : list t, Sorted.Sorted (fun x x0 : t => x <=? x0) (sort l)forall l : list t, Permutation l (sort l)intro; apply (Permuted_iter_merge l []). Qed.forall l : list t, Permutation l (sort l)forall l : list t, Transitive (fun x x0 : t => x <=? x0) -> StronglySorted (fun x x0 : t => x <=? x0) (sort l)auto using Sorted_StronglySorted, LocallySorted_sort. Qed. End Sort.forall l : list t, Transitive (fun x x0 : t => x <=? x0) -> StronglySorted (fun x x0 : t => x <=? x0) (sort l)
An example
Module NatOrder <: TotalLeBool. Definition t := nat. Fixpoint leb x y := match x, y with | 0, _ => true | _, 0 => false | S x', S y' => leb x' y' end. Infix "<=?" := leb (at level 35).forall a1 a2 : nat, a1 <=? a2 \/ a2 <=? a1induction a1; destruct a2; simpl; auto. Qed. End NatOrder. Module Import NatSort := Sort NatOrder. Example SimpleMergeExample := Eval compute in sort [5;3;6;1;8;6;0].forall a1 a2 : nat, a1 <=? a2 \/ a2 <=? a1