{-# OPTIONS --rewriting #-}
module Examples.Exp2 where
open import Algebra.Cost
parCostMonoid = ℕ²-ParCostMonoid
open ParCostMonoid parCostMonoid
open import Calf costMonoid
open import Calf.Parallel parCostMonoid
open import Calf.Data.Bool
open import Calf.Data.Nat
open import Calf.Data.IsBounded costMonoid
open import Calf.Data.BigO costMonoid
open import Relation.Binary.PropositionalEquality as Eq using (_≡_; refl; _≢_; module ≡-Reasoning)
open import Data.Nat as Nat using (_+_; pred; _*_; _^_; _⊔_)
import Data.Nat.Properties as N
open import Data.Nat.PredExp2
open import Data.Empty
open import Function using (_∘_)
Correct : cmp (Π nat λ _ → F nat) → Set
Correct exp₂ = (n : ℕ) → ◯ (exp₂ n ≡ ret (2 ^ n))
module Slow where
exp₂ : cmp (Π nat λ _ → F nat)
exp₂ zero = ret (suc zero)
exp₂ (suc n) =
bind (F nat) (exp₂ n ∥ exp₂ n) λ (r₁ , r₂) →
step (F nat) (1 , 1) (ret (r₁ + r₂))
exp₂/bound : cmp (Π nat λ _ → F nat)
exp₂/bound n = step (F nat) (pred[2^ n ] , n) (ret (2 ^ n))
exp₂/is-bounded : ∀ n → exp₂ n ≤⁻[ F nat ] exp₂/bound n
exp₂/is-bounded zero = ≤⁻-refl
exp₂/is-bounded (suc n) =
let open ≤⁻-Reasoning (F nat) in
begin
(bind (F nat) (exp₂ n ∥ exp₂ n) λ (r₁ , r₂) →
step (F nat) (1 , 1) (ret (r₁ + r₂)))
≲⟨
≤⁻-mono₂ (λ e₁ e₂ → bind (F nat) (e₁ ∥ e₂) λ (r₁ , r₂) → step (F nat) (1 , 1) (ret (r₁ + r₂)))
(exp₂/is-bounded n)
(exp₂/is-bounded n)
⟩
(bind (F nat) ((step (F nat) (pred[2^ n ] , n) (ret (2 ^ n))) ∥ (step (F nat) (pred[2^ n ] , n) (ret (2 ^ n)))) λ (r₁ , r₂) →
step (F nat) (1 , 1) (ret (r₁ + r₂)))
≡⟨⟩
step (F nat) (pred[2^ n ] + pred[2^ n ] + 1 , n ⊔ n + 1) (ret (2 ^ n + 2 ^ n))
≡⟨
Eq.cong₂ (step (F nat))
(Eq.cong₂ _,_
(Eq.trans (N.+-comm _ 1) (pred[2^suc[n]] n))
(Eq.trans (N.+-comm _ 1) (Eq.cong (1 +_) (N.⊔-idem n))))
(Eq.cong ret (lemma/2^suc n))
⟩
step (F nat) (pred[2^ suc n ] , suc n) (ret (2 ^ suc n))
∎
exp₂/correct : Correct exp₂
exp₂/correct n u = Eq.trans (≤⁻-ext-≡ u (exp₂/is-bounded n)) (step/ext (F nat) (ret (2 ^ n)) (pred[2^ n ] , n) u)
exp₂/asymptotic : given nat measured-via (λ n → n) , exp₂ ∈𝓞(λ n → 2 ^ n , n)
exp₂/asymptotic =
f[n]≤g[n]via λ n →
≤⁻-mono (λ e → bind (F _) e (λ _ → ret triv))
(≤⁻-trans (exp₂/is-bounded n) (step-monoˡ-≤⁻ (ret (2 ^ n)) (N.pred[n]≤n {2 ^ n} , N.≤-refl {n})))
module Fast where
exp₂ : cmp (Π nat λ _ → F nat)
exp₂ zero = ret (suc zero)
exp₂ (suc n) =
bind (F nat) (exp₂ n) λ r →
step (F nat) (1 , 1) (ret (r + r))
exp₂/bound : cmp (Π nat λ _ → F nat)
exp₂/bound n = step (F nat) (n , n) (ret (2 ^ n))
exp₂/is-bounded : ∀ n → exp₂ n ≤⁻[ F nat ] exp₂/bound n
exp₂/is-bounded zero = ≤⁻-refl
exp₂/is-bounded (suc n) =
let open ≤⁻-Reasoning (F nat) in
begin
(bind (F nat) (exp₂ n) λ r →
step (F nat) (1 , 1) (ret (r + r)))
≲⟨ ≤⁻-mono (λ e → bind (F nat) e λ r → step (F nat) (1 , 1) (ret (r + r))) (exp₂/is-bounded n) ⟩
(bind (F nat) (step (F nat) (n , n) (ret (2 ^ n))) λ r →
step (F nat) (1 , 1) (ret (r + r)))
≡⟨⟩
step (F nat) (n + 1 , n + 1) (ret (2 ^ n + 2 ^ n))
≡⟨
Eq.cong₂ (step (F nat))
(Eq.cong₂ _,_ (N.+-comm _ 1) (N.+-comm _ 1))
(Eq.cong ret (lemma/2^suc n))
⟩
step (F nat) (suc n , suc n) (ret (2 ^ suc n))
∎
exp₂/correct : Correct exp₂
exp₂/correct n u = Eq.trans (≤⁻-ext-≡ u (exp₂/is-bounded n)) (step/ext (F nat) (ret (2 ^ n)) (n , n) u)
exp₂/asymptotic : given nat measured-via (λ n → n) , exp₂ ∈𝓞(λ n → n , n)
exp₂/asymptotic = f[n]≤g[n]via (≤⁻-mono (λ e → bind (F _) e _) ∘ exp₂/is-bounded)
slow≡fast : ◯ (Slow.exp₂ ≡ Fast.exp₂)
slow≡fast u = funext λ n →
begin
Slow.exp₂ n
≡⟨ Slow.exp₂/correct n u ⟩
ret (2 ^ n)
≡˘⟨ Fast.exp₂/correct n u ⟩
Fast.exp₂ n
∎
where open ≡-Reasoning