{-# OPTIONS --rewriting #-} module Examples.Decalf.Nondeterminism where open import Algebra.Cost costMonoid = ℕ-CostMonoid open CostMonoid costMonoid using (ℂ; _+_) open import Calf costMonoid hiding (A) open import Calf.Data.Nat as Nat using (nat; zero; suc; _*_) import Data.Nat.Properties as Nat open import Data.Nat.Square open import Calf.Data.List as List using (list; []; _∷_; [_]; _++_; length) import Data.Fin as Fin open import Calf.Data.Bool using (bool; false; true; if_then_else_) open import Calf.Data.Product using (unit; _×⁺_) open import Calf.Data.Equality as Eq using (_≡_; refl; module ≡-Reasoning) open import Calf.Data.IsBoundedG costMonoid open import Calf.Data.IsBounded costMonoid open import Relation.Nullary open import Function postulate branch : (X : tp⁻) → cmp X → cmp X → cmp X fail : (X : tp⁻) → cmp X branch/idˡ : {e : cmp X} → branch X (fail X) e ≡ e branch/idʳ : {e : cmp X} → branch X e (fail X) ≡ e branch/assoc : {e₀ e₁ e₂ : cmp X} → branch X (branch X e₀ e₁) e₂ ≡ branch X e₀ (branch X e₁ e₂) branch/comm : {e₀ e₁ : cmp X} → branch X e₀ e₁ ≡ branch X e₁ e₀ branch/idem : {e : cmp X} → branch X e e ≡ e branch/step : (c : ℂ) {e₀ e₁ : cmp X} → step X c (branch X e₀ e₁) ≡ branch X (step X c e₀) (step X c e₁) fail/step : (c : ℂ) → step X c (fail X) ≡ fail X bind/fail : {A : tp⁺} {f : val A → cmp X} → bind X (fail (F A)) f ≡ fail X bind/branch : {A : tp⁺} {e₀ e₁ : cmp (F A)} {f : val A → cmp X} → bind X (branch (F A) e₀ e₁) f ≡ branch X (bind X e₀ f) (bind X e₁ f) {-# REWRITE bind/fail bind/branch #-} open import Examples.Sorting.Sequential.Comparable module QuickSort (M : Comparable) where open Comparable M open import Examples.Sorting.Sequential.Core M choose : cmp $ Π (list A) λ l → F (Σ⁺ A λ pivot → Σ⁺ (list A) λ l' → meta⁺ (l ↭ pivot ∷ l')) choose [] = fail (F _) choose (x ∷ xs) = branch (F _) (bind (F _) (choose xs) λ (pivot , l , xs↭pivot∷l) → ret (pivot , x ∷ l , trans (prep x xs↭pivot∷l) (swap x pivot refl))) (ret (x , xs , refl)) choose/cost : cmp $ Π (list A) λ _ → cost choose/cost l = ret triv choose/is-bounded : ∀ x xs → IsBoundedG _ (choose (x ∷ xs)) (choose/cost (x ∷ xs)) choose/is-bounded x [] = ≤⁻-reflexive branch/idˡ choose/is-bounded x (x' ∷ xs) = let open ≤⁻-Reasoning cost in begin branch (F unit) (bind (F unit) (choose (x' ∷ xs)) λ _ → ret triv) (ret triv) ≲⟨ ≤⁻-mono (λ e → branch (F unit) (bind (F unit) e λ _ → ret triv) (ret triv)) (choose/is-bounded x' xs) ⟩ branch (F unit) (ret triv) (ret triv) ≡⟨ branch/idem ⟩ ret triv ∎ partition : cmp $ Π A λ pivot → Π (list A) λ l → F (Σ⁺ (list A) λ l₁ → Σ⁺ (list A) λ l₂ → meta⁺ (All (_≤ pivot) l₁) ×⁺ meta⁺ (All (pivot ≤_) l₂) ×⁺ meta⁺ (l₁ ++ l₂ ↭ l)) partition pivot [] = ret ([] , [] , [] , [] , refl) partition pivot (x ∷ xs) = bind (F _) (partition pivot xs) λ (xs₁ , xs₂ , h₁ , h₂ , xs₁++xs₂↭xs) → bind (F _) (x ≤? pivot) $ case-≤ (λ x≤pivot → ret (x ∷ xs₁ , xs₂ , x≤pivot ∷ h₁ , h₂ , prep x xs₁++xs₂↭xs)) (λ x≰pivot → ret (xs₁ , x ∷ xs₂ , h₁ , ≰⇒≥ x≰pivot ∷ h₂ , trans (shift-↭ x xs₁ xs₂) (prep x xs₁++xs₂↭xs))) partition/cost : cmp $ Π A λ a → Π (list A) λ l → cost partition/cost _ l = step⋆ (length l) partition/is-bounded : ∀ pivot l → IsBoundedG _ (partition pivot l) (partition/cost pivot l) partition/is-bounded pivot [] = ≤⁻-refl partition/is-bounded pivot (x ∷ xs) = let open ≤⁻-Reasoning cost in begin ( bind (F unit) (partition pivot xs) λ (xs₁ , xs₂ , h₁ , h₂ , xs₁++xs₂↭xs) → bind (F unit) (x ≤? pivot) λ x≤?pivot → bind {Σ⁺ (list A) λ l₁ → Σ⁺ (list A) λ l₂ → meta⁺ (All (_≤ pivot) l₁) ×⁺ meta⁺ (All (pivot ≤_) l₂) ×⁺ meta⁺ (l₁ ++ l₂ ↭ x ∷ xs)} (F unit) ( case-≤ (λ x≤pivot → ret (x ∷ xs₁ , xs₂ , x≤pivot ∷ h₁ , h₂ , prep x xs₁++xs₂↭xs)) (λ x≰pivot → ret (xs₁ , x ∷ xs₂ , h₁ , ≰⇒≥ x≰pivot ∷ h₂ , trans (shift-↭ x xs₁ xs₂) (prep x xs₁++xs₂↭xs))) x≤?pivot ) (λ _ → ret triv) ) ≡⟨ ( Eq.cong (bind (F unit) (partition pivot xs)) $ funext λ (xs₁ , xs₂ , h₁ , h₂ , xs₁++xs₂↭xs) → Eq.cong (bind (F unit) (x ≤? pivot)) $ funext $ bind/case-≤ {B = Σ⁺ (list A) λ l₁ → Σ⁺ (list A) λ l₂ → meta⁺ (All (_≤ pivot) l₁) ×⁺ meta⁺ (All (pivot ≤_) l₂) ×⁺ meta⁺ (l₁ ++ l₂ ↭ x ∷ xs)} {X = F unit} {f = λ _ → ret triv} (λ x≤pivot → ret (x ∷ xs₁ , xs₂ , x≤pivot ∷ h₁ , h₂ , prep x xs₁++xs₂↭xs)) (λ x≰pivot → ret (xs₁ , x ∷ xs₂ , h₁ , ≰⇒≥ x≰pivot ∷ h₂ , trans (shift-↭ x xs₁ xs₂) (prep x xs₁++xs₂↭xs))) ) ⟩ ( bind (F unit) (partition pivot xs) λ _ → bind (F unit) (x ≤? pivot) $ case-≤ (λ _ → ret triv) (λ _ → ret triv) ) ≡⟨ ( Eq.cong (bind (F unit) (partition pivot xs)) $ funext λ (xs₁ , xs₂ , h₁ , h₂ , xs₁++xs₂↭xs) → Eq.cong (bind (F unit) (x ≤? pivot)) $ funext $ case-≤/idem (ret triv) ) ⟩ ( bind (F unit) (partition pivot xs) λ _ → bind (F unit) (x ≤? pivot) λ _ → ret triv ) ≲⟨ ( ≤⁻-mono {Π (Σ⁺ (list A) λ l₁ → Σ⁺ (list A) λ l₂ → meta⁺ (All (_≤ pivot) l₁) ×⁺ meta⁺ (All (pivot ≤_) l₂) ×⁺ meta⁺ (l₁ ++ l₂ ↭ xs)) λ _ → F unit} (bind (F unit) (partition pivot xs)) $ λ-mono-≤⁻ λ _ → h-cost x pivot ) ⟩ ( bind (F unit) (partition pivot xs) λ _ → step⋆ 1 ) ≡⟨⟩ ( bind (F unit) (bind (F unit) (partition pivot xs) λ _ → ret triv) λ _ → step⋆ 1 ) ≲⟨ ≤⁻-mono (λ e → bind (F unit) (bind (F unit) e λ _ → ret triv) λ _ → step (F unit) 1 (ret triv)) (partition/is-bounded pivot xs) ⟩ ( bind (F unit) (step (F unit) (length xs) (ret triv)) λ _ → step⋆ 1 ) ≡⟨⟩ step⋆ (length xs + 1) ≡⟨ Eq.cong step⋆ (Nat.+-comm (length xs) 1) ⟩ step⋆ (length (x ∷ xs)) ∎ {-# TERMINATING #-} sort : cmp $ Π (list A) λ _ → F (list A) sort [] = ret [] sort (x ∷ xs) = bind (F _) (choose (x ∷ xs)) λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → bind (F _) (sort l₁) λ l₁' → bind (F _) (sort l₂) λ l₂' → ret (l₁' ++ [ x ] ++ l₂') sort/cost : cmp $ Π (list A) λ _ → cost sort/cost l = step⋆ (length l ²) sort/arithmetic : (m n : val nat) → m ² + n ² Nat.≤ (m + n) ² sort/arithmetic m n = let open Nat.≤-Reasoning in begin m ² + n ² ≤⟨ Nat.+-mono-≤ (Nat.m≤m+n (m * m) (n * m)) (Nat.m≤n+m (n * n) (m * n)) ⟩ (m * m + n * m) + (m * n + n * n) ≡˘⟨ Eq.cong₂ _+_ (Nat.*-distribʳ-+ m m n) (Nat.*-distribʳ-+ n m n) ⟩ (m + n) * m + (m + n) * n ≡˘⟨ Nat.*-distribˡ-+ (m + n) m n ⟩ (m + n) * (m + n) ∎ {-# TERMINATING #-} sort/is-bounded : ∀ l → IsBoundedG _ (sort l) (sort/cost l) sort/is-bounded [] = ≤⁻-refl sort/is-bounded (x ∷ xs) = let open ≤⁻-Reasoning cost in begin ( bind (F _) (choose (x ∷ xs)) λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → bind (F _) (sort l₁) λ _ → bind (F _) (sort l₂) λ _ → ret triv ) ≲⟨ ( ≤⁻-mono {Π (Σ⁺ A λ pivot → Σ⁺ (list A) λ l' → meta⁺ (x ∷ xs ↭ pivot ∷ l')) λ _ → F unit} {F unit} (bind (F unit) (choose (x ∷ xs))) {λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → bind (F _) (sort l₁) λ _ → bind (F _) (sort l₂) λ _ → ret triv} {λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → bind (F _) (sort l₁) λ _ → step⋆ (length l₂ ²)} $ λ-mono-≤⁻ λ (pivot , l , x∷xs↭pivot∷l) → ≤⁻-mono {Π (Σ⁺ (list A) λ l₁ → Σ⁺ (list A) λ l₂ → meta⁺ (All (_≤ pivot) l₁) ×⁺ meta⁺ (All (pivot ≤_) l₂) ×⁺ meta⁺ (l₁ ++ l₂ ↭ l)) λ _ → F unit} {F unit} (bind (F unit) (partition pivot l)) $ λ-mono-≤⁻ λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → ≤⁻-mono (λ e → bind (F unit) (sort l₁) λ _ → e) $ sort/is-bounded l₂ ) ⟩ ( bind (F _) (choose (x ∷ xs)) λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → bind (F _) (sort l₁) λ _ → step⋆ (length l₂ ²) ) ≲⟨ ( ≤⁻-mono {Π (Σ⁺ A λ pivot → Σ⁺ (list A) λ l' → meta⁺ (x ∷ xs ↭ pivot ∷ l')) λ _ → F unit} {F unit} (bind (F _) (choose (x ∷ xs))) {λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → bind (F _) (sort l₁) λ _ → step⋆ (length l₂ ²)} {λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → step⋆ (length l₁ ² + length l₂ ²)} $ λ-mono-≤⁻ λ (pivot , l , x∷xs↭pivot∷l) → ≤⁻-mono {Π (Σ⁺ (list A) λ l₁ → Σ⁺ (list A) λ l₂ → meta⁺ (All (_≤ pivot) l₁) ×⁺ meta⁺ (All (pivot ≤_) l₂) ×⁺ meta⁺ (l₁ ++ l₂ ↭ l)) λ _ → F unit} {F unit} (bind (F _) (partition pivot l)) $ λ-mono-≤⁻ λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → bind-irr-monoˡ-≤⁻ (sort/is-bounded l₁) ) ⟩ ( bind (F _) (choose (x ∷ xs)) λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → step⋆ (length l₁ ² + length l₂ ²) ) ≲⟨ ( ≤⁻-mono {Π (Σ⁺ A λ pivot → Σ⁺ (list A) λ l' → meta⁺ (x ∷ xs ↭ pivot ∷ l')) λ _ → F unit} {F unit} (bind (F _) (choose (x ∷ xs))) {λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → step⋆ (length l₁ ² + length l₂ ²)} {λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ _ → step⋆ (length l ²)} $ λ-mono-≤⁻ λ (pivot , l , x∷xs↭pivot∷l) → ≤⁻-mono {Π (Σ⁺ (list A) λ l₁ → Σ⁺ (list A) λ l₂ → meta⁺ (All (_≤ pivot) l₁) ×⁺ meta⁺ (All (pivot ≤_) l₂) ×⁺ meta⁺ (l₁ ++ l₂ ↭ l)) λ _ → F unit} {F unit} (bind (F _) (partition pivot l)) $ λ-mono-≤⁻ λ (l₁ , l₂ , h₁ , h₂ , l₁++l₂↭l) → ≤⁺-mono step⋆ $ ≤⇒≤⁺ (Nat.≤-trans (sort/arithmetic (length l₁) (length l₂)) (Nat.≤-reflexive (Eq.cong _² (Eq.trans (Eq.sym (length-++ l₁)) (↭-length l₁++l₂↭l))))) ) ⟩ ( bind (F _) (choose (x ∷ xs)) λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ _ → step⋆ (length l ²) ) ≲⟨ ( ≤⁻-mono {Π (Σ⁺ A λ pivot → Σ⁺ (list A) λ l' → meta⁺ (x ∷ xs ↭ pivot ∷ l')) λ _ → F unit} {F unit} (bind (F _) (choose (x ∷ xs))) {λ (pivot , l , x∷xs↭pivot∷l) → bind (F _) (partition pivot l) λ _ → step⋆ (length l ²)} {λ (pivot , l , x∷xs↭pivot∷l) → step⋆ (length l + length l ²)} $ λ-mono-≤⁻ λ (pivot , l , x∷xs↭pivot∷l) → bind-irr-monoˡ-≤⁻ (partition/is-bounded pivot l) ) ⟩ ( bind (F _) (choose (x ∷ xs)) λ (pivot , l , x∷xs↭pivot∷l) → step⋆ (length l + length l ²) ) ≡˘⟨ ( Eq.cong (bind (F _) (choose (x ∷ xs))) $ funext λ (pivot , l , x∷xs↭pivot∷l) → Eq.cong (λ c → step⋆ (c + c ²)) {length xs} {length l} (Eq.cong Nat.pred (↭-length x∷xs↭pivot∷l)) ) ⟩ ( bind (F _) (choose (x ∷ xs)) λ _ → step⋆ (length xs + length xs ²) ) ≲⟨ bind-irr-monoˡ-≤⁻ (choose/is-bounded x xs) ⟩ step⋆ (length xs + length xs ²) ≲⟨ step⋆-mono-≤⁻ (Nat.+-mono-≤ (Nat.n≤1+n (length xs)) (Nat.*-monoʳ-≤ (length xs) (Nat.n≤1+n (length xs)))) ⟩ step⋆ (length (x ∷ xs) + length xs * length (x ∷ xs)) ≡⟨⟩ step⋆ (length (x ∷ xs) ²) ∎ module Lookup {A : tp⁺} where lookup : cmp $ Π (list A) λ _ → Π nat λ _ → F A lookup [] i = fail (F _) lookup (x ∷ xs) zero = ret x lookup (x ∷ xs) (suc i) = step (F _) 1 (lookup xs i) lookup/bound : cmp $ Π (list A) λ _ → Π nat λ _ → F A lookup/bound l i with i Nat.<? length l ... | yes p = step (F _) i (ret (List.lookup l (Fin.fromℕ< p))) ... | no _ = fail (F _) lookup/is-bounded : (l : val (list A)) (i : val nat) → lookup l i ≤⁻[ F A ] lookup/bound l i lookup/is-bounded l i with i Nat.<? length l ... | yes p = lemma l i p where lemma : (l : val (list A)) (i : val nat) (p : i Nat.< length l) → lookup l i ≤⁻[ F A ] step (F _) i (ret (List.lookup l (Fin.fromℕ< p))) lemma (x ∷ xs) zero (Nat.s≤s Nat.z≤n) = ≤⁻-refl lemma (x ∷ xs) (suc i) (Nat.s≤s p) = ≤⁻-mono (step (F _) 1) (lemma xs i p) ... | no ¬p = lemma l i (Nat.≮⇒≥ ¬p) where lemma : (l : val (list A)) (i : val nat) → i Nat.≥ length l → lookup l i ≤⁻[ F A ] fail (F A) lemma [] i Nat.z≤n = ≤⁻-refl lemma (x ∷ xs) (suc i) (Nat.s≤s p) = let open ≤⁻-Reasoning (F _) in begin step (F _) 1 (lookup xs i) ≲⟨ ≤⁻-mono (step (F _) 1) (lemma xs i p) ⟩ step (F _) 1 (fail (F _)) ≡⟨ fail/step 1 ⟩ fail (F _) ∎ module Pervasive where e : cmp $ F bool e = branch (F bool) (step (F bool) 3 (ret true)) (step (F bool) 12 (ret false)) e/is-bounded : e ≤⁻[ F bool ] step (F bool) 12 (branch (F bool) (ret true) (ret false)) e/is-bounded = let open ≤⁻-Reasoning (F bool) in begin e ≡⟨⟩ branch (F bool) (step (F bool) 3 (ret true)) (step (F bool) 12 (ret false)) ≲⟨ ≤⁻-mono (λ e → branch (F bool) e (step (F bool) 12 (ret false))) (step-monoˡ-≤⁻ {F bool} (ret true) (Nat.s≤s (Nat.s≤s (Nat.s≤s Nat.z≤n)))) ⟩ branch (F bool) (step (F bool) 12 (ret true)) (step (F bool) 12 (ret false)) ≡˘⟨ branch/step 12 ⟩ step (F bool) 12 (branch (F bool) (ret true) (ret false)) ∎ e/is-bounded' : IsBounded bool e 12 e/is-bounded' = let open ≤⁻-Reasoning (F unit) in begin bind (F unit) e (λ _ → ret triv) ≲⟨ ≤⁻-mono (λ e → bind (F _) e (λ _ → ret triv)) e/is-bounded ⟩ bind (F unit) (step (F bool) 12 (branch (F bool) (ret true) (ret false))) (λ _ → ret triv) ≡⟨⟩ step (F unit) 12 (branch (F unit) (ret triv) (ret triv)) ≡⟨ Eq.cong (step (F unit) 12) branch/idem ⟩ step⋆ 12 ∎