module sets.nat.solver where
open import decidable
open import equality
open import function.core
hiding (const)
open import sets.nat.core
open import sets.nat.properties
open import sets.nat.ordering
open import sets.fin.core
hiding (_≟_)
open import sets.vec.core
open import sets.vec.dependent
data Exp (n : ℕ) : Set where
var : Fin n → Exp n
const : ℕ → Exp n
_:+_ : Exp n → Exp n → Exp n
infixl 6 _:+_
eval : ∀ {n} → (Fin n → ℕ) → Exp n → ℕ
eval env (var i) = env i
eval env (const x) = x
eval env (e₁ :+ e₂) = eval env e₁ + eval env e₂
NF : ℕ → Set
NF n = Vec ℕ n
evalNF' : ∀ {n} → (Fin n → ℕ) → NF n → ℕ
evalNF' _ [] = 0
evalNF' env (x ∷ xs) = x * env zero + evalNF' (env ∘' suc) xs
evalNF : ∀ {n} → (Fin n → ℕ) → NF (suc n) → ℕ
evalNF env xs = evalNF' (1 ∷∷ env) xs
decNF : ∀ {n}(xs ys : NF n) → Dec (xs ≡ ys)
decNF [] [] = yes refl
decNF (x ∷ xs) (y ∷ ys) with x ≟ y | decNF xs ys
decNF (x ∷ xs) (y ∷ ys) | _ | no u = no λ p → u (ap tail p)
decNF (x ∷ xs) (y ∷ ys) | no u | _ = no λ p → u (ap head p)
decNF (x ∷ xs) (y ∷ ys) | yes p | yes q = yes (ap₂ _∷_ p q)
emptyNF : ∀ {n} → NF n
emptyNF {zero} = []
emptyNF {suc n} = 0 ∷ emptyNF
eval-emptyNF : ∀ {n}(env : Fin n → ℕ) → evalNF' env emptyNF ≡ 0
eval-emptyNF {zero} env = refl
eval-emptyNF {suc n} env = eval-emptyNF {n} (env ∘' suc)
δ : ∀ {n} → Fin n → ℕ → NF n
δ zero val = val ∷ emptyNF
δ (suc i) val = 0 ∷ δ i val
eval-δ : ∀ {n}(i : Fin n)(val : ℕ)
→ (env : Fin n → ℕ)
→ evalNF' env (δ i val) ≡ val * env i
eval-δ zero val env = ap (_+_ (val * env zero)) (eval-emptyNF env)
· +-right-unit _
eval-δ (suc i) val env = eval-δ i val (env ∘' suc)
_+NF_ : ∀ {n} → NF n → NF n → NF n
[] +NF [] = []
(x ∷ xs) +NF (y ∷ ys) = (x + y) ∷ (xs +NF ys)
eval+NF : ∀ {n}(xs ys : NF n)(env : Fin n → ℕ)
→ evalNF' env (xs +NF ys)
≡ evalNF' env xs + evalNF' env ys
eval+NF [] [] env = refl
eval+NF (x ∷ xs) (y ∷ ys) env
= ap₂ _+_ (right-distr x y (env zero)) (eval+NF xs ys (env ∘' suc))
· lem (x * env zero) (y * env zero) (evalNF' (env ∘' suc) xs) (evalNF' (env ∘' suc) ys)
where
lem : ∀ a b c d → (a + b) + (c + d) ≡ (a + c) + (b + d)
lem a b c d
= +-associativity a b (c + d)
· ap (_+_ a) (sym (+-associativity b c d))
· ap (λ z → a + (z + d)) (+-commutativity b c)
· ap (_+_ a) (+-associativity c b d)
· sym (+-associativity a c (b + d))
nf : ∀ {n} → Exp n → NF (suc n)
nf (var i) = δ (suc i) 1
nf (const k) = δ zero k
nf (e₁ :+ e₂) = nf e₁ +NF nf e₂
nf-sound : ∀ {n}(env : Fin n → ℕ)(e : Exp n)
→ evalNF env (nf e) ≡ eval env e
nf-sound env (var i) = eval-δ i 1 env · +-right-unit (env i)
nf-sound env (const x) = ap (_+_ (x * 1)) (eval-emptyNF env)
· +-right-unit (x * 1)
· *-right-unit x
nf-sound env (e₁ :+ e₂) = eval+NF (nf e₁) (nf e₂) (1 ∷∷ env)
· ap₂ _+_ (nf-sound env e₁) (nf-sound env e₂)
HOTerm : ℕ → ℕ → Set
HOTerm n zero = Exp n
HOTerm n (suc i) = Exp n → HOTerm n i
private
exp' : (n i : ℕ) → i ≤ n → HOTerm n i → (Fin i → Exp n) → Exp n
exp' _ zero _ e _ = e
exp' zero (suc i) () e f
exp' (suc n) (suc i) p e f = exp' (suc n) i (trans≤ suc≤ p) (e (f zero)) (f ∘' suc)
exp : ∀ {n} → HOTerm n n → Exp n
exp {n} e = exp' n n refl≤ e var
solve : ∀ n (e₁ e₂ : Exp n){t : True (decNF (nf e₁) (nf e₂))}
→ (env : Fin n → ℕ)
→ eval env e₁ ≡ eval env e₂
solve n e₁ e₂ {t} env = sym (nf-sound env e₁)
· ap (evalNF env) (witness t)
· nf-sound env e₂