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.

(* Specifications: *)
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.
Lemma nth_map' :
forall {T1} x1 {T2} (f : T1 -> T2) n s,
nth (f x1) (map f s) n = f (nth x1 s n).
Lemma interp_ext :
forall l1 l2 e,
(forall k, nth 0 l1 k = nth 0 l2 k) ->
interp l1 e = interp l2 e.
Lemma interp_set_nth :
forall n l e,
interp (set_nth 0 l n (nth 0 l n)) e = interp l e.
Lemma interp_domain_ext :
forall l1 l2 b,
(forall k, nth 0 l1 k = nth 0 l2 k) ->
interp_domain l1 b -> interp_domain l2 b.
Lemma interp_domain_set_nth :
forall n l b,
interp_domain (set_nth 0 l n (nth 0 l n)) b <-> interp_domain l b.