\import Arith.Nat
\import Data.Array
\import Function
\import Function.Meta
\import Logic
\import Logic.Meta
\import Paths
\import Paths.Meta
\truncated \data Bar {A : \Set} (P : Array A -> \Prop) (l : Array A) : \Prop
| bar-stop (P l)
| bar-ask (h : \Pi (a : A) -> Bar P (a :: l))
\lemma bounded-bar {A : \Set} {P : Array A -> \Prop} (n : Nat) (b : \Pi (l : Array A n) -> P l) : Bar P nil
=> induction n b n idp
\where {
\protected \lemma induction (n : Nat) (b : \Pi (l : Array A n) -> P l) {l : Array A} (k : Nat) (p : l.len Nat.+ k = n) : Bar P l \elim k
| 0 => bar-stop \case \elim n, \elim p, \elim b \with {
| _, idp, b => b \new l
}
| suc k => bar-ask \lam a => induction n b k p
}
\data IsInvPrefix {A : \Set} (l : Array A) (s : Nat -> A) \elim l
| nil => invPrefix-nil
| a :: l => invPrefix-:: (a = s l.len) (IsInvPrefix l s)
\where {
\lemma toIndex {l : Array A} (p : IsInvPrefix l s) {i : Fin l.len} : l i = s (l.len -' suc i) \elim l, p, i
| a :: l, invPrefix-:: p q, 0 => p *> pmap s (inv -'0)
| a :: l, invPrefix-:: p q, suc i => toIndex q
}
\lemma bar-stream {A : \Set} {P : Array A -> \Prop} (b : Bar P nil) (s : Nat -> A)
: ∃ (r : Array A) (IsInvPrefix r s) (P r)
=> induction b invPrefix-nil
\where
\protected \lemma induction {l : Array A} (b : Bar P l) {s : Nat -> A} (sp : IsInvPrefix l s)
: ∃ (r : Array A) (IsInvPrefix r s) (P r) \elim b
| bar-stop p => inP (l,sp,p)
| bar-ask h => induction (h (s l.len)) (invPrefix-:: idp sp)
\lemma bar-surj {A B : \Set} (f : A -> B) (fs : IsSurj f) {P : Array B -> \Prop} (b : Bar (\lam as => P (map f as)) nil) : Bar P nil
=> induction fs b
\where
\protected \lemma induction (fs : IsSurj f) {P : Array B -> \Prop} {l : Array A} (b : Bar (\lam as => P (map f as)) l) : Bar P (map f l) \elim b
| bar-stop Pl => bar-stop Pl
| bar-ask h => bar-ask \lam b => \case fs b \with {
| inP (a,fa=b) => rewriteI fa=b $ induction fs (h a)
}
\lemma bar-map {A B : \Set} (f : A -> B) {P : Array B -> \Prop} (l : Array A) (b : Bar P (map f l)) : Bar (\lam as => P (map f as)) l \elim b
| bar-stop Pl => bar-stop Pl
| bar-ask h => bar-ask \lam a => bar-map f (a :: l) $ h (f a)
\lemma bar-impl {A : \Set} {P Q : Array A -> \Prop} (PQ : ∀ {l : P} (Q l)) {l : Array A} (b : Bar P l) : Bar Q l \elim b
| bar-stop p => bar-stop (PQ p)
| bar-ask h => bar-ask \lam a => bar-impl PQ (h a)
\lemma bar-rel {A B : \Set} (R : A -> B -> \Prop) (Rs : ∀ b ∃ (a : A) (R a b)) {P : Array A -> \Prop} {Q : Array B -> \Prop}
(PQ : \Pi (as : Array A) (bs : Array B as.len) -> ∀ j (R (as j) (bs j)) -> P as -> Q bs) (b : Bar P nil) : Bar Q nil
=> induction b \case __
\where
\protected \lemma induction {as : Array A} (b : Bar P as) {bs : Array B as.len} (c : ∀ j (R (as j) (bs j))) : Bar Q bs \elim b
| bar-stop p => bar-stop (PQ as bs c p)
| bar-ask h => bar-ask \lam b => \case Rs b \with {
| inP (a,Rab) => induction (h a) \case \elim __ \with {
| 0 => Rab
| suc j => c j
}
}
\lemma bar-shift-left {A : \Set} {P : Array A -> \Prop} {l : Array A} (b : Bar P l) : Bar (\lam l' => P (l' ++ l)) nil
=> induction b
\where {
\protected \lemma induction {l r : Array A} (b : Bar P (l ++ r)) : Bar (\lam l' => P (l' ++ r)) l \elim b
| bar-stop p => bar-stop p
| bar-ask h => bar-ask \lam a => induction (h a)
}
\lemma bar-shift-right {A : \Set} {P : Array A -> \Prop} {l : Array A} (b : Bar (\lam l' => P (l' ++ l)) nil) : Bar P l
=> induction b
\where {
\protected \lemma induction {l r : Array A} (b : Bar (\lam x => P (x ++ r)) l) : Bar P (l ++ r) \elim b
| bar-stop p => bar-stop p
| bar-ask h => bar-ask \lam a => induction (h a)
}
\func IsBarMonotone {A : \Type} (P : Array A -> \Prop) : \Prop
=> \Pi {a : A} {l : Array A} -> P l -> P (a :: l)
\lemma barMonotone_++ {A : \Set} {P : Array A -> \Prop} (Pm : IsBarMonotone P) {r : Array A} : IsBarMonotone (\lam l => P (l ++ r))
=> Pm __
\lemma barMonotone_map {A B : \Set} (f : A -> B) {P : Array B -> \Prop} (Pm : IsBarMonotone P) : IsBarMonotone (\lam l => P (map f l))
=> Pm __
\lemma bar-monotone {A : \Set} {P : Array A -> \Prop} (Pm : IsBarMonotone P) : IsBarMonotone (Bar P)
=> induction
\where {
\private \lemma induction {a : A} {l : Array A} (b : Bar P l) : Bar P (a :: l) \elim b
| bar-stop p => bar-stop (Pm p)
| bar-ask h => bar-ask \lam a' => induction (h a)
}
\lemma bar-conj {A : \Set} {P Q : Array A -> \Prop} (Pm : IsBarMonotone P) (Qm : IsBarMonotone Q)
{l : Array A} (b1 : Bar P l) (b2 : Bar Q l) : Bar (\lam l' => \Sigma (P l') (Q l')) l \elim b1
| bar-stop p1 => aux p1 b2
| bar-ask h1 => bar-ask \lam a => bar-conj Pm Qm (h1 a) (bar-monotone Qm b2)
\where {
\private \lemma aux {l : Array A} (Pl : P l) (b : Bar Q l) : Bar (\lam l' => \Sigma (P l') (Q l')) l \elim b
| bar-stop Ql => bar-stop (Pl,Ql)
| bar-ask h => bar-ask \lam a => aux (Pm Pl) (h a)
}
\lemma bar-++-insert {A : \Set} {P : Array A -> \Prop} (h : \Pi {l m r : Array A} -> P (l ++ r) -> P (l ++ m ++ r))
{l m r : Array A} (b : Bar P (l ++ r)) : Bar P (l ++ m ++ r) \elim b
| bar-stop p => bar-stop (h p)
| bar-ask p => bar-ask \lam a => bar-++-insert h {a :: l} (p a)