Section DomainInduction.
Hypothesis P : domain -> Prop.
Hypothesis P_Never : P Never.
Hypothesis P_Always : P Always.
Hypothesis P_Partial : forall p e, P (Partial p e).
Hypothesis P_Derivable : forall n k f le, P (Derivable n k f le).
Hypothesis P_Derivable2 : forall m n k f le, P (Derivable2 m n k f le).
Hypothesis P_Continuous : forall n e, P (Continuous n e).
Hypothesis P_Continuous2 : forall m n e, P (Continuous2 m n e).
Hypothesis P_Integrable : forall f e1 e2, P (Integrable f e1 e2).
Hypothesis P_ParamIntegrable : forall n f e1 e2, P (ParamIntegrable n f e1 e2).
Hypothesis P_LocallyParamIntegrable : forall n f e, P (LocallyParamIntegrable n f e).
Hypothesis P_And : forall ld, foldr (fun d acc  => P d /\ acc) True ld -> P (And ld).
Hypothesis P_Forall : forall e1 e2 d, P d -> P (Forall e1 e2 d).
Hypothesis P_Forone : forall e d, P d -> P (Forone e d).
Hypothesis P_Locally : forall n d, P d -> P (Locally n d).
Hypothesis P_Locally2 : forall m n d, P d -> P (Locally2 m n d).
Hypothesis P_ForallWide : forall n e1 e2 d, P d -> P (ForallWide n e1 e2 d).
Fixpoint domain_ind' (d : domain) : P d :=
match d return P d with
| Never => P_Never
| Always => P_Always
| Partial d e => P_Partial d e
| Derivable n k f le => P_Derivable n k f le
| Derivable2 m n k f le => P_Derivable2 m n k f le
| Continuous n e => P_Continuous n e
| Continuous2 m n e => P_Continuous2 m n e
| Integrable f e1 e2 => P_Integrable f e1 e2
| ParamIntegrable n f e1 e2 => P_ParamIntegrable n f e1 e2
| LocallyParamIntegrable n f e => P_LocallyParamIntegrable n f e
| And ld => P_And ld
((fix domain_ind'' (ld : seq domain) : foldr (fun d acc => P d /\ acc) True ld :=
match ld return foldr (fun d acc => P d /\ acc) True ld with
| nil => I
| cons h q => conj (domain_ind' h) (domain_ind'' q)
end) ld)
| Forall e1 e2 d => P_Forall e1 e2 d (domain_ind' d)
| Forone e d => P_Forone e d (domain_ind' d)
| Locally n d => P_Locally n d (domain_ind' d)
| Locally2 m n d => P_Locally2 m n d (domain_ind' d)
| ForallWide n e1 e2 d => P_ForallWide n e1 e2 d (domain_ind' d)
end.
End DomainInduction.
Fixpoint interp_domain (l : seq R) (d : domain) : Prop :=
match d with
| Never => False
| Always => True
| Partial p e => p (interp l e)
| Derivable n k f le => ex_derive_Rn k f n (nth 0 (map (interp l) le))
| Derivable2 m n k f le =>
let le' := map (interp l) le in
locally_2d (fun u v => ex_derive_Rn k f m (fun i => if ssrnat.eqn i m then u else if ssrnat.eqn i n then v else nth 0 le' i)) (nth 0 le' m) (nth 0 le' n) /\
continuity_2d_pt (fun u v => Derive_Rn k f m (fun i => if ssrnat.eqn i m then u else if ssrnat.eqn i n then v else nth 0 le' i)) (nth 0 le' m) (nth 0 le' n)
| Continuous n f => continuity_pt (fun x => interp (set_nth R0 l n x) f) (nth R0 l n)
| Continuous2 m n f => continuity_2d_pt (fun x y => interp (set_nth R0 (set_nth R0 l n y) m x) f) (nth R0 l m) (nth R0 l n)
| Integrable f e1 e2 => ex_RInt (fun x => interp (x :: l) f) (interp l e1) (interp l e2)
| ParamIntegrable n f e1 e2 =>
locally (nth R0 l n) (fun y => ex_RInt (fun t => interp (t :: set_nth R0 l n y) f) (interp l e1) (interp l e2))
| LocallyParamIntegrable n f e =>
let a := interp l e in
exists eps : posreal, locally (nth R0 l n) (fun y => ex_RInt (fun t => interp (t :: set_nth R0 l n y) f) (a - eps) (a + eps))
| And ld => foldr (fun d acc => interp_domain l d /\ acc) True ld
| Forall e1 e2 s =>
let a1 := interp l e1 in let a2 := interp l e2 in
forall t, Rmin a1 a2 <= t <= Rmax a1 a2 ->
interp_domain (t :: l) s
| Forone e s => interp_domain (interp l e :: l) s
| Locally n s =>
locally (nth R0 l n) (fun x => interp_domain (set_nth R0 l n x) s)
| Locally2 m n s =>
locally_2d (fun x y => interp_domain (set_nth R0 (set_nth R0 l n y) m x) s) (nth R0 l m) (nth R0 l n)
| ForallWide n e1 e2 s =>
let a1 := interp l e1 in let a2 := interp l e2 in
exists d : posreal,
forall t u, Rmin a1 a2 - d < t < Rmax a1 a2 + d -> Rabs (u - nth R0 l n) < d ->
interp_domain (t :: set_nth R0 l n u) s
end.
Fixpoint is_const (e : expr) n : bool :=
match e with
| Var v => negb (ssrnat.eqn v n)
| AppExt k f le => foldr (fun v acc => andb (is_const v n) acc) true le
| AppExtD k f p le => false
| App f e => andb (is_const f (S n)) (is_const e n)
| Subst f e => andb (orb (ssrnat.eqn n 0) (is_const f n)) (is_const e n)
| Cst _ => true
| Binary b e1 e2 => andb (is_const e1 n) (is_const e2 n)
| Unary u e => is_const e n
| Int f e1 e2 => andb (is_const f (S n)) (andb (is_const e1 n) (is_const e2 n))
end.

Lemma is_const_correct :
forall e n, is_const e n = true ->
forall l x1 x2,
interp (set_nth 0 l n x1) e = interp (set_nth 0 l n x2) e.