theory Safe_Distance_Isar
imports
  Safe_Distance_Auxiliarities
  "~~/src/HOL/Library/Sum_of_Squares"
  "~~/src/HOL/Decision_Procs/Approximation"
  "$AFP/Sturm_Sequences/Sturm"
begin

subsection \<open>quadratic equations\<close>
text \<open>\label{sec:quadroot}\<close>

lemma discriminant: "a * x\<^sup>2 + b * x + c = (0::real) \<Longrightarrow> 0 \<le> b\<^sup>2 - 4 * a * c"
  by (sos "(((A<0 * R<1) + (R<1 * (R<1 * [2*a*x + b]^2))))")

lemma quadratic_eq_factoring:
  assumes D: "D = b\<^sup>2 - 4 * a * c"
  assumes nn: "0 \<le> D"
  assumes x1: "x\<^sub>1 = (-b + sqrt D) / (2 * a)"
  assumes x2: "x\<^sub>2 = (-b - sqrt D) / (2 * a)"
  assumes a: "a \<noteq> 0"
  shows "a * x\<^sup>2 + b * x + c = a * (x - x\<^sub>1) * (x - x\<^sub>2)"
  using nn
  by (simp add: D x1 x2)
    (simp add: assms algebra_simps power2_eq_square power3_eq_cube divide_simps)

lemma quadratic_eq_zeroes_iff:
  assumes D: "D = b\<^sup>2 - 4 * a * c"
  assumes x1: "x\<^sub>1 = (-b + sqrt D) / (2 * a)"
  assumes x2: "x\<^sub>2 = (-b - sqrt D) / (2 * a)"
  assumes a: "a \<noteq> 0"
  shows "a * x\<^sup>2 + b * x + c = 0 \<longleftrightarrow> (D \<ge> 0 \<and> (x = x\<^sub>1 \<or> x = x\<^sub>2))" (is "?z \<longleftrightarrow> _")
  using quadratic_eq_factoring[OF D _ x1 x2 a, of x] discriminant[of a x b c] a
  by (auto simp: D)

subsubsection\<open>convexity condition\<close>
text \<open>\label{sec:convex}\<close>

lemma p_convex:
  fixes a b c x y z::real
  assumes p_def: "p = (\<lambda>x. a * x\<^sup>2 + b * x + c)"
  assumes less: "x < y" "y < z" and ge: "p x > p y" "p y \<le> p z"
  shows "a > 0"
  using less ge unfolding p_def
  by (sos "((((A<0 * (A<1 * A<2)) * R<1) + (((A<2 * R<1) * (R<1/4 * [y + ~1*z]^2)) +
    (((A<=1 * R<1) * (R<1 * [x + ~1*y]^2)) + (((A<=1 * (A<0 * (A<1 * R<1))) * (R<1/4 * [1]^2)) +
    (((A<=0 * R<1) * (R<1/4 * [~1*y^2 + x*y + ~1*x*z + y*z]^2)) +
    ((A<=0 * (A<0 * (A<1 * R<1))) * (R<1 * [x + ~1/2*y + ~1/2*z]^2))))))))")

definition root_in::"real \<Rightarrow> real \<Rightarrow> (real \<Rightarrow> real) \<Rightarrow> bool" where
  "root_in m M f = (\<exists>x\<in>{m .. M}. f x = 0)"

definition "quadroot_in m M a b c = root_in m M (\<lambda>x. a * x^2 + b * x + c)"

lemma card_iff_exists: "0 < card X \<longleftrightarrow> finite X \<and> (\<exists>x. x \<in> X)"
  by (auto simp: card_gt_0_iff)

lemma quadroot_in_sturm[code]:
  "quadroot_in m M a b c \<longleftrightarrow> (a = 0 \<and> b = 0 \<and> c = 0 \<and> m \<le> M) \<or>
    (m \<le> M \<and> poly [:c, b, a:] m = 0) \<or>
    count_roots_between [:c, b, a:] m M > 0"
  apply (cases "a = 0 \<and> b = 0 \<and> c = 0 \<and> m \<le> M")
  apply (force simp: quadroot_in_def root_in_def)
  apply (cases "m \<le> M \<and> poly [:c, b, a:] m = 0")
  apply (force simp: quadroot_in_def root_in_def algebra_simps power2_eq_square count_roots_between_correct card_iff_exists)
proof -
  assume H: "\<not> (a = 0 \<and> b = 0 \<and> c = 0 \<and> m \<le> M)" "\<not> (m \<le> M \<and> poly [:c, b, a:] m = 0)"
  hence "poly [:c, b, a:] m \<noteq> 0 \<or> m > M"
    by auto
  then have "quadroot_in m M a b c \<longleftrightarrow> 0 < count_roots_between [:c, b, a:] m M"
  proof (rule disjE)
    assume pnz: "poly [:c, b, a:] m \<noteq> 0"
    then have nz: "[:c, b, a:] \<noteq> 0" by auto
    show ?thesis
      unfolding count_roots_between_correct card_iff_exists
      apply safe
      apply (rule finite_subset[where B="{x. poly [:c, b, a:] x = 0}"])
      apply force
      apply (rule poly_roots_finite)
      apply (rule nz)
      using pnz
      apply (auto simp add: count_roots_between_correct quadroot_in_def root_in_def card_iff_exists
        algebra_simps power2_eq_square)
      apply (case_tac "x = m")
      apply (force simp: algebra_simps)
      apply force
      done
  qed (auto simp: quadroot_in_def count_roots_between_correct root_in_def card_eq_0_iff)
  then show "quadroot_in m M a b c = (a = 0 \<and> b = 0 \<and> c = 0 \<and> m \<le> M \<or>
     m \<le> M \<and> poly [:c, b, a:] m = 0 \<or>
     0 < count_roots_between [:c, b, a:] m M)"
    using H by metis
qed

lemma sqrt_divide: "b \<ge> 0 \<Longrightarrow> sqrt a / b = sqrt (a / b\<^sup>2)"
  by (auto simp: real_sqrt_divide)

lemma check_quadroot_linear:
  fixes a b c::real
  assumes "a = 0"
  shows "\<not> quadroot_in m M a b c \<longleftrightarrow>
    ((b = 0 \<and> c = 0 \<and> M < m) \<or> (b = 0 \<and> c \<noteq> 0) \<or>
     (b \<noteq> 0 \<and> (let x = - c / b in m > x \<or> x > M)))"
proof -
  have "quadroot_in m M a b c \<longleftrightarrow> (b = 0 \<longrightarrow> quadroot_in m M a b c) \<and> (b \<noteq> 0 \<longrightarrow> quadroot_in m M a b c)"
    by auto
  also have "(b = 0 \<longrightarrow> quadroot_in m M a b c) \<longleftrightarrow>
    ((b = 0 \<longrightarrow> c = 0 \<longrightarrow> m \<le> M) \<and> (b \<noteq> 0 \<or> c = 0))"
    by (auto simp: quadroot_in_def Let_def root_in_def assms field_simps divide_simps
      intro!: bexI[where x="-c / b"])
  also have "(b \<noteq> 0 \<longrightarrow> quadroot_in m M a b c) \<longleftrightarrow> (b = 0 \<or> (let x = -c / b in m \<le> x \<and> x \<le> M))"
    apply (auto simp: quadroot_in_def Let_def root_in_def assms field_simps divide_simps
      intro!: bexI[where x="-c / b"])
    apply (metis mult.commute mult_le_cancel_left_neg add_eq_0_iff)
    apply (metis mult.commute mult_le_cancel_left_neg add_eq_0_iff)
    apply (metis mult.commute add_eq_0_iff real_mult_le_cancel_iff2)
    by (metis mult.commute add_eq_0_iff real_mult_le_cancel_iff2)
  finally show ?thesis
    by (simp add: Let_def not_less not_le)
qed

lemma check_quadroot_nonlinear:
  assumes "a \<noteq> 0"
  shows "quadroot_in m M a b c =
    (let D = b^2 - 4 * a * c in D \<ge> 0 \<and>
      ((let x = (-b + sqrt D)/(2*a) in m \<le> x \<and> x \<le> M) \<or>
      (let x = (-b - sqrt D)/(2*a) in m \<le> x \<and> x \<le> M)))"
  by (auto simp: quadroot_in_def Let_def root_in_def
    quadratic_eq_zeroes_iff[OF refl refl refl assms])

lemma ncheck_quadroot:
  shows "\<not>quadroot_in m M a b c \<longleftrightarrow>
    (a = 0 \<longrightarrow>\<not>quadroot_in m M a b c) \<and>
    (a = 0 \<or> \<not>quadroot_in m M a b c)"
  by auto

locale movement = fixes a v s0 :: real
begin

text \<open>
  function to compute the distance using equation
    @{text "s(t) = s\<^sub>0 + v\<^sub>0 \<cdot> t + 1/2 \<cdot> a \<cdot> t\<^sup>2"}

  Input parameters :
     1. @{term s\<^sub>0}     :   initial distance
     2. @{term v\<^sub>0}     :   initial velocity (positive means forward direction and the converse is true)
     3. @{term a}      :   acceleration (positive for increasing and negative for decreasing)
     4. @{term t}      :   time

  For the time @{term "t < 0"}, we assume the output of the function is @{term s\<^sub>0}. Otherwise, the output
  is calculated according to the equation above.
\<close>

subsubsection \<open>continuous dynamics\<close>
text \<open>\label{sec:cont-dynamics}\<close>
definition "p t = s0 + v * t + 1/2 * a * t\<^sup>2"

lemma p_all_zeroes:
  assumes D: "D = v\<^sup>2 - 2 * a * s0"
  shows "p t = 0 \<longleftrightarrow> ((a \<noteq> 0 \<and> 0 \<le> D \<and> ((t = (- v + sqrt D) / a) \<or> t = (- v - sqrt D) / a)) \<or>
    (a = 0 \<and> v = 0 \<and> s0 = 0) \<or> (a = 0 \<and> v \<noteq> 0 \<and> t = (- s0 / v)))"
  using quadratic_eq_zeroes_iff[OF refl refl refl, of "a / 2" t v s0]
  by (auto simp: movement.p_def algebra_simps D power2_eq_square divide_simps)

lemma p_zero[simp]: "p 0 = s0"
  by (simp add: p_def)

lemma p_continuous[continuous_intros]: "continuous_on T p"
  by (auto intro!: continuous_intros simp: p_def)

lemma isCont_p[continuous_intros]: "isCont p x"
  using p_continuous[of UNIV]
  by (auto simp: continuous_on_eq_continuous_at)

definition "p' t = v + a * t"

lemma p'_zero: "p' 0 = v"
  by (simp add: p'_def)

lemma p_has_vector_derivative[derivative_intros]: "(p has_vector_derivative p' t) (at t within s)"
  by (auto simp: p_def[abs_def] p'_def has_vector_derivative_def algebra_simps
    intro!: derivative_eq_intros)

lemma p_has_real_derivative[derivative_intros]: "(p has_real_derivative p' t) (at t within s)"
  using p_has_vector_derivative
  by (simp add: has_field_derivative_iff_has_vector_derivative)

definition "p'' t = a"

lemma p'_has_vector_derivative[derivative_intros]: "(p' has_vector_derivative p'' t) (at t within s)"
  by (auto simp: p'_def[abs_def] p''_def has_vector_derivative_def algebra_simps
    intro!: derivative_eq_intros)

lemma p'_has_real_derivative[derivative_intros]: "(p' has_real_derivative p'' t) (at t within s)"
  using p'_has_vector_derivative
  by (simp add: has_field_derivative_iff_has_vector_derivative)

definition t_stop :: real where "t_stop = - v / a"

lemma p'_stop_zero: "p' t_stop = (if a = 0 then v else 0)" by (auto simp: p'_def t_stop_def)

lemma p'_pos_iff: "p' x > 0 \<longleftrightarrow>
    (if a > 0 then x > -v / a else if a < 0 then x < -v / a else v > 0)"
  by (auto simp: p'_def divide_simps algebra_simps)

lemma le_t_stop_iff: "a \<noteq> 0 \<Longrightarrow> x \<le> t_stop \<longleftrightarrow> (if a < 0 then p' x \<ge> 0 else p' x \<le> 0)"
  by (auto simp: p'_def divide_simps algebra_simps t_stop_def)

lemma p'_continuous[continuous_intros]: "continuous_on T p'"
  by (auto simp: p'_def intro!: continuous_intros)

lemma isCont_p'[continuous_intros]: "isCont p' x"
  using p'_continuous[of UNIV]
  by (auto simp: continuous_on_eq_continuous_at)

definition p_max :: real where "p_max = p t_stop"

lemmas p_t_stop = p_max_def[symmetric]

lemma p_max_eq: "p_max = s0 - v\<^sup>2 / a / 2"
  by (auto simp: p_max_def p_def t_stop_def algebra_simps divide_simps power2_eq_square)

subsubsection \<open>Hybrid dynamics\<close>
text \<open>\label{sec:hybrid-dynamics}\<close>
definition
  "s t = (     if t \<le> 0      then s0
          else if t \<le> t_stop then p t
          else                p_max)"

definition
  "q t = s0 + v * t"

definition
  "q' t = v"

lemma init_q: "q 0 = s0" unfolding q_def by auto

lemma q_continuous[continuous_intros]: "continuous_on T q"
  by (auto intro!: continuous_intros simp:q_def)

lemma isCont_q[continuous_intros]: "isCont q x"
  using q_continuous[of UNIV]
  by (auto simp:continuous_on_eq_continuous_at)

lemma q_has_vector_derivative[derivative_intros]: "(q has_vector_derivative q' t) (at t within u)"
  by (auto simp: q_def[abs_def] q'_def has_vector_derivative_def algebra_simps
          intro!: derivative_eq_intros)

lemma q_has_real_derivative[derivative_intros]: "(q has_real_derivative q' t) (at t within u)"
  using q_has_vector_derivative
  by (simp add:has_field_derivative_iff_has_vector_derivative)

lemma
  s_cond_def:
  "t \<le> 0 \<Longrightarrow> s t = s0"
  "0 \<le> t \<Longrightarrow> t \<le> t_stop \<Longrightarrow> s t = p t"
  by (simp_all add: s_def)

end

locale braking_movement = movement +
assumes decel: "a < 0"
assumes nonneg_vel: "v \<ge> 0"
begin

lemma t_stop_nonneg: "0 \<le> t_stop"
  using decel nonneg_vel
  by (auto simp: t_stop_def divide_simps)

lemma t_stop_pos:
  assumes "v \<noteq> 0"
  shows "0 < t_stop"
  using decel nonneg_vel assms
  by (auto simp: t_stop_def divide_simps)

lemma t_stop_zero:
  assumes "t_stop = 0"
  shows "v = 0"
  using assms decel
  by (auto simp: t_stop_def)

lemma t_stop_zero_not_moving: "t_stop = 0 \<Longrightarrow> q t = s0" unfolding q_def using t_stop_zero by auto

abbreviation "s_stop \<equiv> s t_stop"

lemma s_t_stop: "s_stop = p_max"
  using t_stop_nonneg
  by (auto simp: s_def t_stop_def p_max_def p_def)

thm mult_nonneg_nonneg

lemma s0_le_s_stop: "s0 \<le> s_stop"
proof (rule subst[where t="s_stop" and s="p_max"])
  show "p_max = s_stop" by (rule sym[OF s_t_stop])
next
  show "s0 \<le> p_max"
  proof (rule subst[where t="p_max" and s="s0 - v\<^sup>2 / a / 2"])
    show " s0 - v\<^sup>2 / a / 2 = p_max" using p_max_eq by auto
  next
    have "0 \<le> - v\<^sup>2 / a / 2" using decel zero_le_square[of v]
    proof -
      have f1: "a \<le> 0"
        using \<open>a < 0\<close> by linarith
      have "(- 1 * v\<^sup>2 \<le> 0) = (0 \<le> v\<^sup>2)"
        by auto
      then have "0 \<le> - 1 * v\<^sup>2 / a"
        using f1 by (meson zero_le_divide_iff zero_le_power2)
      then show ?thesis
        by force
    qed
    thus "s0 \<le> s0 - v\<^sup>2 / a / 2" by auto
  qed
qed

lemma p_mono: "x \<le> y \<Longrightarrow> y \<le> t_stop \<Longrightarrow> p x \<le> p y"
  using decel
  unfolding p_max_def p_def t_stop_def
  by (sos "((((A<0 * A<1) * R<1) + ((R<1 * (R<2 * [a*x + ~1*a*y]^2)) +
    ((A<=0 * (A<=1 * (A<0 * R<1))) * (R<4 * [1]^2)))))")

lemma p_antimono: "x \<le> y \<Longrightarrow> t_stop \<le> x \<Longrightarrow> p y \<le> p x"
  using decel
  unfolding p_max_def p_def t_stop_def
  by (sos "((((A<0 * A<1) * R<1) + ((R<1 * (R<2 * [a*x + ~1*a*y]^2)) +
    ((A<=0 * (A<=1 * (A<0 * R<1))) * (R<4 * [1]^2)))))")

lemma p_strict_mono: "x < y \<Longrightarrow> y \<le> t_stop \<Longrightarrow> p x < p y"
  using decel
  unfolding p_max_def p_def t_stop_def
  by (sos "((((A<0 * A<1) * ((A<0 * A<1) * R<1)) + (((A<=1 * (A<0 * R<1)) * (R<1/2 * [1]^2)) +
    ((A<=0 * (A<0 * (A<1 * R<1))) * (R<2 * [1]^2)))))")

lemma p_strict_antimono: "x < y \<Longrightarrow> t_stop \<le> x\<Longrightarrow> p y < p x"
  using decel
  unfolding p_max_def p_def t_stop_def
  by (sos "((((A<0 * A<1) * ((A<0 * A<1) * R<1)) + (((A<=1 * (A<0 * R<1)) * (R<1/2 * [1]^2)) +
    ((A<=0 * (A<0 * (A<1 * R<1))) * (R<2 * [1]^2)))))")

lemma p_max: "p x \<le> p_max"
  unfolding p_max_def
  by (cases "x \<le> t_stop") (auto intro: p_mono p_antimono)

lemma continuous_on_s[continuous_intros]: "continuous_on T s"
  unfolding s_def[abs_def]
  using t_stop_nonneg
  by (intro continuous_on_subset[where t=T and s = "{.. 0}\<union>({0 .. t_stop} \<union> {t_stop ..})"] continuous_on_If)
    (auto simp: p_max_def continuous_intros antisym_conv[where x=0])

lemma isCont_s[continuous_intros]: "isCont s x"
  using continuous_on_s[of UNIV]
  by (auto simp: continuous_on_eq_continuous_at)

definition "s' t = (if t \<le> t_stop then p' t else 0)"

lemma s_has_real_derivative:
  assumes "t \<ge> 0" "v / a \<le> 0" "a \<noteq> 0"
  shows "(s has_real_derivative s' t) (at t within {0..})"
proof -
  from assms have *: "t \<le> t_stop \<longleftrightarrow> t \<in> {0 .. t_stop}" by simp
  from assms have "0 \<le> t_stop" by (auto simp: t_stop_def)

  have "((\<lambda>t. if t \<in> {0 .. t_stop} then p t else p_max) has_real_derivative
    (if t \<in> {0..t_stop} then p' t else 0)) (at t within {0..})"
    unfolding s_def[abs_def] s'_def
      has_field_derivative_iff_has_vector_derivative
    apply (rule has_vector_derivative_If[where t = "{t_stop ..}"])
    using \<open>0 \<le> t_stop\<close> \<open>a \<noteq> 0\<close>
    by (auto simp: assms p'_stop_zero p_t_stop max_def insert_absorb
      intro!: p_has_vector_derivative)
  from _ _ this show ?thesis
    unfolding has_vector_derivative_def has_field_derivative_iff_has_vector_derivative
      s'_def s_def[abs_def] *
    by (rule has_derivative_transform)
      (auto simp: assms s_def p_max_def t_stop_def)
qed

lemma s_has_vector_derivative[derivative_intros]:
  assumes "t \<ge> 0" "v / a \<le> 0" "a \<noteq> 0"
  shows  "(s has_vector_derivative s' t) (at t within {0..})"
  using s_has_real_derivative[OF assms]
  by (simp add:has_field_derivative_iff_has_vector_derivative)

lemma s_has_field_derivative[derivative_intros]:
  assumes "t \<ge> 0" "v / a \<le> 0" "a \<noteq> 0"
  shows "(s has_field_derivative s' t) (at t within {0..})"
  using s_has_vector_derivative[OF assms]
  by(simp add:has_field_derivative_iff_has_vector_derivative)

lemma s_has_real_derivative_at:
  assumes "0 < x" "0 \<le> v" "a < 0"
  shows "(s has_real_derivative s' x) (at x)"
proof -
  from assms have "(s has_real_derivative s' x) (at x within {0 ..})"
    by (intro s_has_real_derivative) (auto intro!: divide_nonneg_nonpos)
  then have "(s has_real_derivative s' x) (at x within {0<..})"
    by (rule DERIV_subset) auto
  then show "(s has_real_derivative s' x) (at x)" using assms
    by (subst (asm) at_within_open) auto
qed

lemma s_delayed_has_field_derivative[derivative_intros]:
  assumes "\<delta> < t" "0 \<le> v" "a < 0"
  shows "((\<lambda>x. s (x - \<delta>)) has_field_derivative s' (t - \<delta>)) (at t within {\<delta><..})"
proof -
  from assms have "((\<lambda>x. s (x + - \<delta>)) has_real_derivative s' (t - \<delta>)) (at t)"
  using DERIV_shift[of "s" "(s' (t - \<delta>))" t "-\<delta>"] s_has_real_derivative_at
  by auto

  thus "((\<lambda>x. s (x - \<delta>)) has_field_derivative s' (t - \<delta>)) (at t within {\<delta><..})"
  using has_field_derivative_at_within by auto
qed

lemma s_delayed_has_vector_derivative[derivative_intros]:
  assumes "\<delta> < t" "0 \<le> v" "a < 0"
  shows  "((\<lambda>x. s (x - \<delta>)) has_vector_derivative s' (t - \<delta>)) (at t within {\<delta><..})"
  using s_delayed_has_field_derivative[OF assms]
  by(simp add:has_field_derivative_iff_has_vector_derivative)

lemma s'_nonneg: "0 \<le> v \<Longrightarrow> a \<le> 0 \<Longrightarrow> 0 \<le> s' x"
  by (auto simp: s'_def p'_def divide_simps t_stop_def algebra_simps)

lemma s'_pos: "0 \<le> x \<Longrightarrow> x < t_stop \<Longrightarrow> 0 \<le> v \<Longrightarrow> a \<le> 0 \<Longrightarrow> 0 < s' x"
  by (intro le_neq_trans s'_nonneg)
    (auto simp: s'_def p'_def divide_simps t_stop_def algebra_simps)

subsubsection \<open>Monotonicity of movement\<close>
text \<open>\label{sec:mono}\<close>

lemma s_mono:
  assumes "t \<ge> u" "u \<ge> 0"
  shows "s t \<ge> s u"
  using p_mono[of u t] assms p_max[of u]
  by (auto simp: s_def)

lemma s_strict_mono:
  assumes "u < t" "t \<le> t_stop" "u \<ge> 0"
  shows "s u < s t"
  using p_strict_mono[of u t] assms p_max[of u]
  by (auto simp: s_def)

lemma s_antimono:
  assumes "x \<le> y"
  assumes "t_stop \<le> x"
  shows "s y \<le> s x"
proof -
  from assms have "t_stop \<le> y" by auto
  hence "s y \<le> p_max" unfolding s_def p_max_eq
    using p_max_def p_max_eq s0_le_s_stop s_t_stop by auto
  also have "... \<le> s x"
    using \<open>t_stop \<le> x\<close> s_mono s_t_stop t_stop_nonneg by fastforce
  ultimately show "s y \<le> s x" by auto
qed

lemma q_min: "0 \<le> t \<Longrightarrow> s0 \<le> q t"
  unfolding q_def
  using nonneg_vel by auto

lemma q_mono: "x \<le> y \<Longrightarrow> q x \<le> q y"
  unfolding q_def using nonneg_vel by (auto simp: mult_left_mono)

subsubsection \<open>maximum at stopping time\<close>
text \<open>\label{sec:tstop}\<close>
lemma s_max: "s x \<le> s_stop"
  using p_max[of x] p_max[of 0]
  unfolding s_t_stop
  by (auto simp: s_def)

lemma s_eq_s_stop: "NO_MATCH t_stop x \<Longrightarrow> x \<ge> t_stop \<Longrightarrow> s x = s_stop"
  using t_stop_nonneg
  by (auto simp: s_def p_max_def)

end

locale safe_distance =
  fixes a\<^sub>e v\<^sub>e s\<^sub>e :: real
  fixes a\<^sub>o v\<^sub>o s\<^sub>o :: real
  assumes nonneg_vel_ego   : "0 \<le> v\<^sub>e"
  assumes nonneg_vel_other : "0 \<le> v\<^sub>o"
  assumes decelerate_ego   : "a\<^sub>e < 0"
  assumes decelerate_other : "a\<^sub>o < 0"
  assumes in_front         : "s\<^sub>e < s\<^sub>o"
begin

lemmas hyps =
  nonneg_vel_ego
  nonneg_vel_other
  decelerate_ego
  decelerate_other
  in_front

sublocale ego: braking_movement a\<^sub>e v\<^sub>e s\<^sub>e by (unfold_locales; rule hyps)
sublocale other: braking_movement a\<^sub>o v\<^sub>o s\<^sub>o by (unfold_locales; rule hyps)
sublocale ego_other: movement "a\<^sub>o - a\<^sub>e" "v\<^sub>o - v\<^sub>e" "s\<^sub>o - s\<^sub>e" by unfold_locales

subsubsection \<open>collision\<close>
text \<open>\label{sec:collision}\<close>
definition collision :: "real set \<Rightarrow> bool" where
"collision time_set \<equiv> (\<exists>t\<in>time_set. ego.s t = other.s t )"

abbreviation no_collision :: "real set \<Rightarrow> bool" where
"no_collision time_set \<equiv> \<not> collision time_set"

lemma no_collision_initially : "no_collision {.. 0}"
  using decelerate_ego nonneg_vel_ego
  using decelerate_other nonneg_vel_other in_front
  by (auto simp: divide_simps collision_def ego.s_def other.s_def)

lemma
  no_collisionI:
  assumes "\<And>t. t \<in> S \<Longrightarrow> ego.s t \<noteq> other.s t"
  shows "no_collision S"
  using assms
  unfolding collision_def
  by blast

subsubsection \<open>Theorem 1\<close>
text \<open>\label{sec:thm1}\<close>

(* condition 1 : ego.s_stop < s\<^sub>o *)
theorem cond_1 : "ego.s_stop < s\<^sub>o \<Longrightarrow> no_collision {0..}"
proof (rule no_collisionI, simp)
  fix t::real
  assume "t \<ge> 0"
  have "ego.s t \<le> ego.s_stop"
    by (rule ego.s_max)
  also assume "\<dots> < s\<^sub>o"
  also have "\<dots> = other.s 0"
    by (simp add: other.init_s)
  also have "\<dots> \<le> other.s t"
    using \<open>0 \<le> t\<close> hyps
    by (intro other.s_mono) auto
  finally show "ego.s t \<noteq> other.s t"
    by simp
qed

subsubsection \<open>Lemma 1\<close>
text \<open>\label{sec:lemma1}\<close>

lemma ego_other_strict_ivt:
  assumes "ego.s t > other.s t"
  shows "collision {0 ..< t}"
proof cases
  assume "0 \<le> t"
  with assms in_front
  have "\<exists>x\<ge>0. x \<le> t \<and> other.s x - ego.s x = 0"
    by (intro IVT2)
    (auto intro!: continuous_intros simp: ego_other.s_def ego.init_s other.init_s)
  then show ?thesis
    using assms
    by (auto simp add: algebra_simps collision_def Bex_def order.order_iff_strict)
qed (insert assms hyps, auto simp: collision_def ego.init_s other.init_s intro!: bexI[where x=0])

lemma collision_subset: "collision s \<Longrightarrow> s \<subseteq> t \<Longrightarrow> collision t"
  by (auto simp: collision_def)

lemma ego_other_ivt:
  assumes "ego.s t \<ge> other.s t"
  shows "collision {0 .. t}"
proof cases
  assume "ego.s t > other.s t"
  from ego_other_strict_ivt[OF this]
  show ?thesis
    by (rule collision_subset) auto
qed (insert hyps assms; cases "t \<ge> 0"; force simp: collision_def ego.init_s other.init_s)

subsubsection \<open>Theorem 2\<close>
text \<open>\label{sec:thm2}\<close>

(* condition 2: ego.s_stop \<ge> other.s_stop *)
theorem cond_2 :
  assumes "ego.s_stop \<ge> other.s_stop"
  shows "collision {0 ..}"
  using assms
  apply (intro collision_subset[where t="{0 ..}" and s = "{0 .. max ego.t_stop other.t_stop}"])
  apply (intro ego_other_ivt[where t = "max ego.t_stop other.t_stop"])
  apply (auto simp: ego.s_eq_s_stop other.s_eq_s_stop)
  done

abbreviation D2 :: "real" where
"D2 \<equiv> (v\<^sub>o - v\<^sub>e)^2 - 2 * (a\<^sub>o - a\<^sub>e) * (s\<^sub>o - s\<^sub>e)"

abbreviation  t\<^sub>D' :: "real" where
"t\<^sub>D' \<equiv> sqrt (2 * (ego.s_stop - other.s_stop) / a\<^sub>o)"

lemma
  pos_via_half_dist:
  "dist a b < b / 2 \<Longrightarrow> b > 0 \<Longrightarrow> a > 0"
  by (auto simp: dist_real_def abs_real_def split: if_splits)

subsubsection \<open>Lemma 2\<close>
text \<open>\label{sec:lemma2}\<close>

lemma collision_within_p:
  assumes "s\<^sub>o \<le> ego.s_stop" "ego.s_stop < other.s_stop"
  shows "collision {0..} \<longleftrightarrow> (\<exists>t\<ge>0. ego.p t = other.p t \<and> t < ego.t_stop \<and> t < other.t_stop)"
proof (auto simp: collision_def, goal_cases)
  case (2 t)
  then show ?case
    by (intro bexI[where x = t]) (auto simp: ego.s_def other.s_def)
next
  case (1 t)
  then show ?case using assms hyps ego.t_stop_nonneg other.t_stop_nonneg
    apply (auto simp: ego.s_def other.s_def ego.s_t_stop other.s_t_stop ego.p_t_stop other.p_t_stop
      split: if_splits)
    defer
    apply (auto simp: not_le)
  proof goal_cases
    case 1
    from 1 have le: "ego.t_stop \<le> other.t_stop" by auto
    from 1 have "ego.t_stop < t" by simp
    from other.s_strict_mono[OF this] 1
    have "other.s ego.t_stop < other.s t"
      by auto
    also have "\<dots> = ego.s ego.t_stop"
      using ego.s_t_stop ego.t_stop_nonneg 1 other.s_def by auto
    finally have "other.s ego.t_stop < ego.s ego.t_stop" .
    from ego_other_strict_ivt[OF this] le in_front
    show ?case
      by (auto simp add: collision_def) (auto simp: movement.s_def split: if_splits)
  next
    case 2
    from 2 have "other.p_max = ego.p t" by simp
    also have "\<dots> \<le> ego.p ego.t_stop"
      using 2
      by (intro ego.p_mono) auto
    also have "\<dots> = ego.p_max"
      by (simp add: ego.p_t_stop)
    also note \<open>\<dots> < other.p_max\<close>
    finally show ?case by arith
  next
    case 3
    thus ?case
      apply (cases "t = other.t_stop")
      apply (simp add: other.p_t_stop )
      apply (metis (no_types) ego.p_max not_le)
      apply (cases "t = ego.t_stop")
      apply (simp add: ego.p_t_stop)
      defer
      apply force
    proof goal_cases
      case (1)
      let ?d = "\<lambda>t. other.p' t - ego.p' t"
      def d' \<equiv> "?d ego.t_stop / 2"
      have d_cont: "isCont ?d ego.t_stop"
        by (auto intro!: continuous_intros)
      have "?d ego.t_stop > 0"
        using 1
        by (simp add: ego.p'_stop_zero other.p'_pos_iff) (simp add: ego.t_stop_def other.t_stop_def)
      then have "d' > 0" by (auto simp: d'_def)
      from d_cont[unfolded continuous_at_eps_delta, THEN spec, rule_format, OF \<open>d' > 0\<close>]
      obtain e where e: "e > 0" "\<And>x. dist x ego.t_stop < e \<Longrightarrow> ?d x > 0"
        unfolding d'_def
        using \<open>?d ego.t_stop > 0\<close> pos_via_half_dist
        by force
      def t' \<equiv> "ego.t_stop - min (ego.t_stop / 2) (e / 2)"
      have "0 < ego.t_stop" using 1 by auto
      have "other.p t' - ego.p t' < other.p ego.t_stop - ego.p ego.t_stop"
        apply (rule DERIV_pos_imp_increasing[of t'])
        apply (force simp: t'_def e min_def \<open>0 < ego.t_stop\<close>)
        apply (auto intro!: exI[where x = "?d x" for x] intro!: derivative_intros e)
        using \<open>e > 0\<close>
        apply (auto simp: t'_def dist_real_def algebra_simps)
        done
      also have "\<dots> = 0" using 1 by (simp add: ego.p_t_stop)
      finally have less: "other.p t' < ego.p t'" by simp
      have "t' > 0"
        using 1 by (auto simp: t'_def algebra_simps min_def)
      have "t' < ego.t_stop" by (auto simp: t'_def \<open>e > 0\<close> \<open>ego.t_stop > 0\<close>)
      from less_le_trans[OF \<open>t' < ego.t_stop\<close> \<open>ego.t_stop \<le> other.t_stop\<close>]
      have "t' < other.t_stop" .
      from ego_other_strict_ivt[of t'] less
      have "collision {0..<t'}"
        using \<open>t' > 0\<close> \<open>t' < ego.t_stop\<close> \<open>t' < other.t_stop\<close>
        by (auto simp: other.s_def ego.s_def split: if_splits)
      thus ?case
        using \<open>t' > 0\<close> \<open>t' < ego.t_stop\<close> \<open>t' < other.t_stop\<close>
        apply (auto simp: collision_def ego.s_def other.s_def movement.p_def
          split: if_splits)
        apply (rule_tac x = t in exI) apply (auto simp: movement.p_def)[]
        done
    qed
  qed
qed

lemma collision_within_eq:
  assumes "s\<^sub>o \<le> ego.s_stop" "ego.s_stop < other.s_stop"
  shows "collision {0..} \<longleftrightarrow> collision {0 ..< min ego.t_stop other.t_stop}"
  unfolding collision_within_p[OF assms]
  unfolding collision_def
  by (safe;
    force
      simp: ego.s_def other.s_def movement.p_def ego.t_stop_def other.t_stop_def
      split: if_splits)

lemma collision_excluded: "(\<And>t. t \<in> T \<Longrightarrow> ego.s t \<noteq> other.s t) \<Longrightarrow> collision S \<longleftrightarrow> collision (S - T)"
  by (auto simp: collision_def)

lemma collision_within_less:
  assumes "s\<^sub>o \<le> ego.s_stop" "ego.s_stop < other.s_stop"
  shows "collision {0..} \<longleftrightarrow> collision {0 <..< min ego.t_stop other.t_stop}"
proof -
  note collision_within_eq[OF assms]
  also have "collision {0 ..< min ego.t_stop other.t_stop} \<longleftrightarrow>
    collision ({0 ..< min ego.t_stop other.t_stop} - {0})"
    using hyps assms
    by (intro collision_excluded) (auto simp: ego.s_def other.s_def)
  also have "{0 ..< min ego.t_stop other.t_stop} - {0} = {0 <..< min ego.t_stop other.t_stop}"
    by auto
  finally show ?thesis
    unfolding collision_def
    by (safe;
      force
        simp: ego.s_def other.s_def movement.p_def ego.t_stop_def other.t_stop_def
        split: if_splits)
qed

subsubsection \<open>Theorem 3\<close>
text \<open>\label{sec:thm3}\<close>

theorem cond_3 :
  assumes "s\<^sub>o \<le> ego.s_stop" "ego.s_stop < other.s_stop"
  shows "collision {0..} \<longleftrightarrow> (a\<^sub>o > a\<^sub>e \<and> v\<^sub>o < v\<^sub>e \<and> 0 \<le> D2 \<and> sqrt D2 > v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o)"
proof -
  have "v\<^sub>o \<noteq> 0"
    using assms(1) assms(2) movement.s_def movement.t_stop_def by auto
  with hyps have "v\<^sub>o > 0" by auto
  note hyps = hyps this
  def t1 \<equiv> "(- (v\<^sub>o - v\<^sub>e) + sqrt D2) / (a\<^sub>o - a\<^sub>e)"
  def t2 \<equiv> "(- (v\<^sub>o - v\<^sub>e) - sqrt D2) / (a\<^sub>o - a\<^sub>e)"
  def bounded \<equiv> "\<lambda>t. (0 \<le> t \<and> t \<le> ego.t_stop \<and> t \<le> other.t_stop)"
  have ego_other_conv:
    "\<And>t. bounded t \<Longrightarrow> ego.p t = other.p t \<longleftrightarrow> ego_other.p t = 0"
    by (auto simp: movement.p_def algebra_simps divide_simps)
  let ?r = "{0 <..< min ego.t_stop other.t_stop}"
  have D2: "D2 = (v\<^sub>o - v\<^sub>e)\<^sup>2 - 4 * ((a\<^sub>o - a\<^sub>e) / 2) * (s\<^sub>o - s\<^sub>e)" by simp
  def D \<equiv> D2
  note D = D_def[symmetric]
  def x1 \<equiv> "(- (v\<^sub>o - v\<^sub>e) + sqrt D2) / (2 * ((a\<^sub>o - a\<^sub>e) / 2))"
  def x2 \<equiv> "(- (v\<^sub>o - v\<^sub>e) - sqrt D2) / (2 * ((a\<^sub>o - a\<^sub>e) / 2))"
  have x2: "x2 =(- (v\<^sub>o - v\<^sub>e) - sqrt D2) / (a\<^sub>o - a\<^sub>e)"
    by (simp add: x2_def divide_simps algebra_simps)
  have x1: "x1 =(- (v\<^sub>o - v\<^sub>e) + sqrt D2) / (a\<^sub>o - a\<^sub>e)"
    by (simp add: x1_def divide_simps algebra_simps)
  from collision_within_less[OF assms]
  have coll_eq: "collision {0..} = collision ?r"
    by (auto simp add: bounded_def)
  also have "\<dots> \<longleftrightarrow> (a\<^sub>o > a\<^sub>e \<and> v\<^sub>o < v\<^sub>e \<and> 0 \<le> D2 \<and> sqrt D2 > v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o)"
  proof safe
    assume H: "a\<^sub>e < a\<^sub>o" "v\<^sub>o < v\<^sub>e" "0 \<le> D2"
    assume sqrt: "sqrt D2 > v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o"
    have nz: "(a\<^sub>o - a\<^sub>e) / 2 \<noteq> 0" using \<open>a\<^sub>e < a\<^sub>o\<close> by simp
    note sol = quadratic_eq_zeroes_iff[OF D2 x1_def[THEN meta_eq_to_obj_eq] x2_def[THEN meta_eq_to_obj_eq] nz]
    from sol[of x2] \<open>0 \<le> D2\<close>
    have "other.p x2 = ego.p x2"
      by (auto simp: ego.p_def other.p_def algebra_simps divide_simps)
    moreover
    have "x2 > 0"
    proof (rule ccontr)
      assume "\<not> 0 < x2"
      then have "ego_other.p x2 \<ge> ego_other.p 0"
        using H hyps
        by (intro DERIV_nonpos_imp_nonincreasing[of x2])
          (auto intro!: exI[where x="ego_other.p' x" for x] derivative_eq_intros
            simp: ego_other.p'_def add_nonpos_nonpos mult_nonneg_nonpos)
      also have "ego_other.p 0 > 0" using hyps by (simp add: ego_other.p_def)
      finally (xtrans) show False using \<open>other.p x2 = ego.p x2\<close>
        by (simp add: movement.p_def algebra_simps divide_simps power2_eq_square)
    qed
    moreover
    have "x2 < other.t_stop"
      using sqrt H hyps
      by (auto simp: x2 other.t_stop_def divide_simps algebra_simps power2_eq_square)

    ultimately
    show "collision {0<..<min ego.t_stop other.t_stop}"
    proof (cases "x2 < ego.t_stop", goal_cases)
      case 2
      then have "other.s x2 = other.p x2"
        by (auto simp: other.s_def)
      also from 2 have "\<dots> \<le> ego.p ego.t_stop"
        by (auto intro!: ego.p_antimono)
      also have "\<dots> = ego.s x2"
        using 2 by (auto simp: ego.s_def ego.p_t_stop)
      finally have "other.s x2 \<le> ego.s x2" .
      from ego_other_ivt[OF this]
      show ?thesis
        unfolding coll_eq[symmetric]
        by (rule collision_subset) auto
    qed (auto simp: collision_def ego.s_def other.s_def not_le intro!: bexI[where x=x2])
  next
    let ?max = "max ego.t_stop other.t_stop"
    let ?min = "min ego.t_stop other.t_stop"
    assume "collision ?r"
    then obtain t where t: "ego.p t = other.p t" "0 < t" "t < ?min"
      by (auto simp: collision_def ego.s_def other.s_def)
    then have "t < - (v\<^sub>e / a\<^sub>e)" "t < - (v\<^sub>o / a\<^sub>o)" "t < other.t_stop"
      by (simp_all add: ego.t_stop_def other.t_stop_def)
    from t have "ego_other.p t = 0"
      by (auto simp: algebra_simps movement.p_def divide_simps)
    from t have "t < ?max" by auto
    from hyps assms have "0 < ego_other.p 0"
      by simp
    from ego_other.p_def[abs_def, THEN meta_eq_to_obj_eq]
    have eop_eq: "ego_other.p = (\<lambda>t. 1 / 2 * (a\<^sub>o - a\<^sub>e) * t\<^sup>2 + (v\<^sub>o - v\<^sub>e) * t + (s\<^sub>o - s\<^sub>e))"
      by (simp add: algebra_simps)
    show "a\<^sub>o > a\<^sub>e"
    proof -
      have "ego.p other.t_stop \<le> ego.p_max"
        by (rule ego.p_max)
      also have "... \<le> other.p other.t_stop" using hyps assms
        by (auto simp:other.s_def ego.s_def ego.p_t_stop split:if_splits)
      finally have "0 \<le> ego_other.p other.t_stop"
        by (auto simp add:movement.p_def field_simps)
      from p_convex[OF eop_eq, of 0 t other.t_stop, simplified \<open>ego_other.p t = 0\<close>,
        OF \<open>0 < t\<close> \<open>t < other.t_stop\<close> \<open>0 < ego_other.p 0\<close> \<open>0 \<le> ego_other.p other.t_stop\<close>]
      show "a\<^sub>o > a\<^sub>e" by (simp add: algebra_simps)
    qed
    have rewr: "4 * ((a\<^sub>o - a\<^sub>e) / 2) = 2 * (a\<^sub>o - a\<^sub>e)" by simp
    from \<open>a\<^sub>o > a\<^sub>e\<close> \<open>ego_other.p t = 0\<close> ego_other.p_all_zeroes[OF D2[symmetric], of t]
    have "0 \<le> D2" and disj: "(t = (- (v\<^sub>o - v\<^sub>e) + sqrt D2) / (a\<^sub>o - a\<^sub>e) \<or> t = (- (v\<^sub>o - v\<^sub>e) - sqrt D2) / (a\<^sub>o - a\<^sub>e))"
      using hyps assms
      unfolding rewr by simp_all
    show "0 \<le> D2" by fact
    from add_strict_mono[OF \<open>t < - (v\<^sub>e / a\<^sub>e)\<close> \<open>t < - (v\<^sub>o / a\<^sub>o)\<close>] `0 < t` \<open>a\<^sub>o > a\<^sub>e\<close>
    have "0 < - (v\<^sub>e / a\<^sub>e) + - (v\<^sub>o / a\<^sub>o)" by (simp add: divide_simps)
    then have "0 > v\<^sub>e * a\<^sub>o + a\<^sub>e * v\<^sub>o" using hyps
      by (simp add: mult_less_0_iff divide_simps algebra_simps split: if_splits)
    show "v\<^sub>o < v\<^sub>e"
      using `a\<^sub>e < a\<^sub>o` `movement.p (a\<^sub>o - a\<^sub>e) (v\<^sub>o - v\<^sub>e) (s\<^sub>o - s\<^sub>e) t = 0` in_front  t(2)
      apply (auto simp: movement.p_def divide_less_0_iff algebra_simps power2_eq_square)
      by (smt divide_less_0_iff mult_le_cancel_right mult_mono mult_nonneg_nonneg nonneg_vel_ego)
    from disj have "x2 < ?min"
    proof rule
      assume "t = (- (v\<^sub>o - v\<^sub>e) - sqrt D2) / (a\<^sub>o - a\<^sub>e)"
      then show ?thesis
        using \<open>t < ?min\<close>
        by (simp add: x2)
    next
      assume "t = (- (v\<^sub>o - v\<^sub>e) + sqrt D2) / (a\<^sub>o - a\<^sub>e)"
      also have "\<dots> \<ge> x2"
        unfolding x2
        apply (rule divide_right_mono)
        apply (subst (2) diff_conv_add_uminus)
        apply (rule add_left_mono)
        using \<open>a\<^sub>o > a\<^sub>e\<close> \<open>D2 \<ge> 0\<close>
        by auto
      also (xtrans) note \<open>t < ?min\<close>
      finally show ?thesis .
    qed
    then show "sqrt D2 > v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o"
      using hyps \<open>a\<^sub>o > a\<^sub>e\<close>
      by (auto simp: x2 divide_simps algebra_simps other.t_stop_def)
  qed
  finally show ?thesis .
qed

thm cond_1 cond_2 cond_3

section{* Formalising the definition of safe distance *}

(* First definition of safe distance which is based on cond_1 above *)

definition "absolute_safe_distance = - v\<^sub>e\<^sup>2 / (2 * a\<^sub>e)"

lemma absolute_safe_distance:
  assumes "s\<^sub>o - s\<^sub>e > absolute_safe_distance"
  shows "no_collision {0..}"
  proof -
  from assms hyps absolute_safe_distance_def have "ego.s_stop < s\<^sub>o"
    by (auto simp add:ego.s_def ego.p_def ego.t_stop_def power_def)
  thus ?thesis by (rule cond_1)
  qed

(* first definition of safe distance if absolute safe distance is not satisfied *)
definition "fst_safe_distance = v\<^sub>o\<^sup>2 / (2 * a\<^sub>o) - v\<^sub>e\<^sup>2 / (2 * a\<^sub>e)"

(* distance to ensure that sqrt D2 \<le>  v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o*)
definition "distance_leq_d2 = (a\<^sub>e + a\<^sub>o) / (2 * a\<^sub>o\<^sup>2) * v\<^sub>o\<^sup>2 - v\<^sub>o * v\<^sub>e / a\<^sub>o"

subsubsection \<open>Lemma 3\<close>
text \<open>\label{sec:lemma3}\<close>

lemma snd_leq_fst_exp: "distance_leq_d2 \<le> fst_safe_distance"
proof -
  have "0 \<le> (other.t_stop - ego.t_stop)\<^sup>2" by auto

  -- \<open>expanding the expression on the RHS\<close>
  hence "- ego.t_stop\<^sup>2 \<le> other.t_stop\<^sup>2 - 2 * other.t_stop * ego.t_stop" by (simp add:power_def algebra_simps)
  -- \<open>multiply both sides with @{term "a\<^sub>e / 2"}\<close>
  with hyps(3) have "- ego.t_stop\<^sup>2 * (a\<^sub>e / 2) \<ge> (other.t_stop\<^sup>2 - 2 * other.t_stop * ego.t_stop) * (a\<^sub>e / 2)"
    by (smt half_gt_zero_iff mult_le_cancel_right)

  -- \<open>simplifying both sides\<close>
  with ego.t_stop_def other.t_stop_def hyps
  have "- v\<^sub>e\<^sup>2 / (2 * a\<^sub>e) \<ge> a\<^sub>e * v\<^sub>o\<^sup>2 / (2 * a\<^sub>o\<^sup>2) - v\<^sub>o * v\<^sub>e / a\<^sub>o" by (simp add:power_def algebra_simps)

  -- \<open>add both sides with the term @{term "v\<^sub>o\<^sup>2 / (2 * a\<^sub>o)"}\<close>
  with fst_safe_distance_def distance_leq_d2_def
  have 1: "fst_safe_distance \<ge>  a\<^sub>e * v\<^sub>o\<^sup>2 / (2 * a\<^sub>o\<^sup>2) - v\<^sub>o * v\<^sub>e / a\<^sub>o + v\<^sub>o\<^sup>2 / (2 * a\<^sub>o)" by (auto simp add:algebra_simps)

  -- \<open>prove that RHS is \<open>snd_safe_distance\<close>\<close>
  have "a\<^sub>e * v\<^sub>o\<^sup>2 / (2 * a\<^sub>o\<^sup>2) - v\<^sub>o * v\<^sub>e / a\<^sub>o + v\<^sub>o\<^sup>2 / (2 * a\<^sub>o) = distance_leq_d2" (is "?LHS = _")
  proof -
    have "?LHS = a\<^sub>e * v\<^sub>o\<^sup>2 / (2 * a\<^sub>o\<^sup>2) - v\<^sub>o * v\<^sub>e / a\<^sub>o + a\<^sub>o * v\<^sub>o\<^sup>2 / (2 * a\<^sub>o\<^sup>2)"
    by (auto simp add:algebra_simps power_def)

    also have "...  = distance_leq_d2"
    by (auto simp add: algebra_simps power_def divide_simps distance_leq_d2_def)

    finally show ?thesis by auto
  qed
  with 1 show ?thesis by auto
qed

lemma sqrt_D2_leq_stop_time_diff:
  assumes "a\<^sub>e < a\<^sub>o"
  assumes "0 \<le> v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o "
  assumes "s\<^sub>o - s\<^sub>e \<ge> distance_leq_d2"
  shows "sqrt D2 \<le> v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o"
proof -
  from assms have "- 2 * (a\<^sub>o - a\<^sub>e) * (s\<^sub>o - s\<^sub>e) \<le> - 2 * (a\<^sub>o - a\<^sub>e) * distance_leq_d2" (is "?L \<le> ?R")
  by simp
  hence "D2 \<le> (v\<^sub>o - v\<^sub>e)\<^sup>2 - 2 * (a\<^sub>o - a\<^sub>e) * distance_leq_d2" by (simp add:algebra_simps)
  also have "... = (v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o)\<^sup>2"
  proof -
    from distance_leq_d2_def
    have 1: "(v\<^sub>o - v\<^sub>e)\<^sup>2 - 2 * (a\<^sub>o - a\<^sub>e) * distance_leq_d2 =
             (v\<^sub>o - v\<^sub>e)\<^sup>2 - (a\<^sub>o - a\<^sub>e) * (a\<^sub>e + a\<^sub>o) / a\<^sub>o\<^sup>2 * v\<^sub>o\<^sup>2 + 2 * (a\<^sub>o - a\<^sub>e) * v\<^sub>o * v\<^sub>e / a\<^sub>o"
    -- \<open>expanding the subtrahend\<close>
    by (auto simp add:algebra_simps divide_simps)
    with hyps(4) have "... = (v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o)\<^sup>2"
    -- \<open>expanding the minuend, simplifying terms, and regrouping into quadratic terms\<close>
    by (auto simp add:algebra_simps power_def divide_simps)
    with 1 show ?thesis by auto
  qed
  finally show ?thesis  by (smt assms(2) real_le_lsqrt real_sqrt_le_0_iff)
qed

lemma cond2_imp_pos_vo:
  assumes "s\<^sub>o \<le> ego.s_stop" "ego.s_stop < other.s_stop"
  shows "v\<^sub>o \<noteq> 0"
proof (rule ccontr)
  assume "\<not> v\<^sub>o \<noteq> 0"
  with other.s_def other.t_stop_def have "other.s_stop = s\<^sub>o" by auto
  with assms(2) have "ego.s_stop < s\<^sub>o" by auto
  with assms(1) show "False" by auto
qed

lemma cond2_imp_gt_fst_sd:
  assumes "s\<^sub>o \<le> ego.s_stop" "ego.s_stop < other.s_stop"
  shows "fst_safe_distance < s\<^sub>o - s\<^sub>e"
proof (cases "v\<^sub>e \<noteq> 0")
  case True
  from fst_safe_distance_def assms ego.s_def ego.t_stop_pos[OF \<open>v\<^sub>e \<noteq> 0\<close>] ego.p_def ego.t_stop_def
       other.s_def other.t_stop_pos[OF cond2_imp_pos_vo[OF assms]] other.p_def other.t_stop_def hyps
  show ?thesis by (simp add:power_def algebra_simps)
next
  case False
  with fst_safe_distance_def  have "fst_safe_distance = v\<^sub>o\<^sup>2 / (2 * a\<^sub>o)" by auto
  also have "... \<le> 0"  by (simp add: divide_nonneg_neg hyps)
  also have "... < s\<^sub>o - s\<^sub>e" by (simp add:algebra_simps hyps)
  finally show ?thesis by auto
qed

definition "snd_safe_distance = (v\<^sub>o - v\<^sub>e)\<^sup>2 / (2 * (a\<^sub>o - a\<^sub>e))"

lemma fst_leq_snd_safe_distance:
  assumes "a\<^sub>e < a\<^sub>o"
  shows"fst_safe_distance \<le> snd_safe_distance"
proof -
  have "0 \<le> (v\<^sub>o / a\<^sub>o - v\<^sub>e / a\<^sub>e)\<^sup>2" by auto
  hence 1: "0 \<le> (v\<^sub>o / a\<^sub>o)\<^sup>2 - 2 * v\<^sub>o * v\<^sub>e / (a\<^sub>o * a\<^sub>e) + (v\<^sub>e / a\<^sub>e)\<^sup>2" by (auto simp add:power_def algebra_simps)
  from hyps have "0 \<le> a\<^sub>o * a\<^sub>e"  by (simp add: mult_nonpos_nonpos)
  from mult_right_mono[OF 1 this] hyps
  have "0 \<le> v\<^sub>o\<^sup>2 * a\<^sub>e / a\<^sub>o - 2 * v\<^sub>o * v\<^sub>e  + v\<^sub>e\<^sup>2 * a\<^sub>o / a\<^sub>e" by (auto simp add:power_def algebra_simps)
  with hyps have 2: "(v\<^sub>o\<^sup>2 / (2 * a\<^sub>o) - v\<^sub>e\<^sup>2 / (2 * a\<^sub>e)) * (2 * (a\<^sub>o - a\<^sub>e)) \<le> (v\<^sub>o - v\<^sub>e)\<^sup>2" by (auto simp add:power_def divide_simps algebra_simps)
  from assms have "0 \<le> 2 * (a\<^sub>o - a\<^sub>e)" by auto
  from divide_right_mono[OF 2 this] assms fst_safe_distance_def snd_safe_distance_def
  show ?thesis by auto
qed

lemma t_stop_diff_neg_means_leq_D2:
  assumes "s\<^sub>o \<le> ego.s_stop" "ego.s_stop < other.s_stop" "a\<^sub>e < a\<^sub>o" "0 \<le> D2"
  shows "v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o < 0 \<longleftrightarrow> sqrt D2 > v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o"
proof
  assume only_if: "v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o < 0"
  from assms have "... \<le> sqrt D2" by auto
  with only_if show "v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o < sqrt D2" by linarith
next
  assume if_part: "v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o < sqrt D2"
  from cond2_imp_gt_fst_sd[OF assms(1) assms(2)] snd_leq_fst_exp have "distance_leq_d2 \<le> s\<^sub>o - s\<^sub>e" by auto
  from if_part and sqrt_D2_leq_stop_time_diff [OF \<open>a\<^sub>e < a\<^sub>o\<close> _ \<open>distance_leq_d2 \<le> s\<^sub>o - s\<^sub>e\<close>]
  show " v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o < 0"  by linarith
qed

    from t_stop_diff_neg_means_leq_D2[OF assms \<open>a\<^sub>e < a\<^sub>o\<close>]
    have "... = (a\<^sub>e < a\<^sub>o \<and> v\<^sub>o < v\<^sub>e \<and> 0 \<le> D2 \<and> sqrt D2 > v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o)" by auto

    with 1 cond_3[OF assms] show ?thesis by blast
  qed
qed

lemma "v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o < 0 \<longleftrightarrow> ego.t_stop < other.t_stop"
  unfolding "ego.t_stop_def" "other.t_stop_def"
  using hyps
  by (auto simp add:algebra_simps divide_simps)

definition "d t =
  (if t \<le> 0 then s\<^sub>o - s\<^sub>e
  else if t \<le> ego.t_stop \<and> t \<le> other.t_stop then ego_other.p t
  else if ego.t_stop \<le> t \<and> t \<le> other.t_stop then other.p t - ego.s_stop
  else if other.t_stop \<le> t \<and> t \<le> ego.t_stop then other.s_stop - ego.p t
  else other.s_stop - ego.s_stop)"

lemma d_diff: "d t = other.s t - ego.s t"
  by (auto simp: d_def ego.s_eq_s_stop other.s_eq_s_stop ego.s_cond_def other.s_cond_def
    movement.p_def divide_simps algebra_simps)

lemma collision_d: "collision S \<longleftrightarrow> (\<exists>t\<in>S. d t = 0)"
  by (force simp: d_diff collision_def )

lemma collision_restrict: "collision {0..} \<longleftrightarrow> collision {0..max ego.t_stop other.t_stop}"
  by (auto simp: max.coboundedI1 ego.t_stop_nonneg min_def
    ego.s_eq_s_stop other.s_eq_s_stop collision_def
    intro!: bexI[where x = "min t (max (movement.t_stop a\<^sub>e v\<^sub>e) (movement.t_stop a\<^sub>o v\<^sub>o))" for t])

lemma collision_union: "collision (A \<union> B) \<longleftrightarrow> collision A \<or> collision B"
  by (auto simp: collision_def)

subsubsection \<open>Theorem 4\<close>
text \<open>\label{sec:thm4}\<close>

lemma symbolic_checker:
  "collision {0..} \<longleftrightarrow>
    (quadroot_in 0 (min ego.t_stop other.t_stop) (1/2 * (a\<^sub>o - a\<^sub>e)) (v\<^sub>o - v\<^sub>e) (s\<^sub>o - s\<^sub>e)) \<or>
    (quadroot_in ego.t_stop other.t_stop (1/2 * a\<^sub>o) v\<^sub>o (s\<^sub>o - ego.s_stop)) \<or>
    (quadroot_in other.t_stop ego.t_stop (1/2 * a\<^sub>e) v\<^sub>e (s\<^sub>e - other.s_stop))"
 (is "_ \<longleftrightarrow> ?q1 \<or> ?q2 \<or> ?q3")
proof -
  have *: "{0..max ego.t_stop other.t_stop} =
    {0 .. min ego.t_stop other.t_stop} \<union> {ego.t_stop .. other.t_stop} \<union> {other.t_stop .. ego.t_stop}"
    using ego.t_stop_nonneg other.t_stop_nonneg
    by auto
  have "collision {0..min (movement.t_stop a\<^sub>e v\<^sub>e) (movement.t_stop a\<^sub>o v\<^sub>o)} = ?q1"
    by (force simp: collision_def quadroot_in_def root_in_def d_def
      algebra_simps power2_eq_square divide_simps movement.p_def movement.s_cond_def)
  moreover
  have "collision {ego.t_stop .. other.t_stop} = ?q2"
    using ego.t_stop_nonneg
    by (force simp: collision_def quadroot_in_def root_in_def d_def
      ego.s_eq_s_stop movement.s_cond_def movement.p_def)
  moreover
  have "collision {other.t_stop .. ego.t_stop} = ?q3"
    using other.t_stop_nonneg
    by (force simp: collision_def quadroot_in_def root_in_def d_def
      other.s_eq_s_stop movement.s_cond_def movement.p_def)
  ultimately
  show ?thesis
    unfolding collision_restrict * collision_union
    by auto
qed

end

subsection \<open>Extending Analysis with a reaction time delay\<close>

locale safe_distance_normal = safe_distance +
  fixes \<delta> :: real
  assumes pos_react         : "0 < \<delta>"
begin

sublocale ego2: braking_movement a\<^sub>e v\<^sub>e "(ego.q \<delta>)" ..

lemma ego2_s_init: "ego2.s 0 = ego.q \<delta>" unfolding ego2.s_def by auto

definition "\<tau>  (t::real) = t - \<delta>"
definition "\<tau>' (t::real) = 1"

lemma \<tau>_continuous[continuous_intros]: "continuous_on T \<tau>"
  by (auto intro!: continuous_intros simp:\<tau>_def)

lemma isCont_\<tau>[continuous_intros]: "isCont \<tau> x"
  using \<tau>_continuous[of UNIV]
  by (auto simp:continuous_on_eq_continuous_at)

lemma del_has_vector_derivative[derivative_intros]: "(\<tau> has_vector_derivative \<tau>' t) (at t within u)"
  by (auto simp: \<tau>_def[abs_def] \<tau>'_def has_vector_derivative_def algebra_simps
          intro!: derivative_eq_intros)

lemma del_has_real_derivative[derivative_intros]: "(\<tau> has_real_derivative \<tau>' t) (at t within u)"
  using del_has_vector_derivative
  by (simp add:has_field_derivative_iff_has_vector_derivative)

lemma delay_image: "\<tau> ` {\<delta>..} = {0..}"
proof (rule subset_antisym, unfold image_def, unfold \<tau>_def)
  show "{y. \<exists>x\<in>{\<delta>..}. y = x - \<delta>} \<subseteq> {0..}" by auto
next
  show "{0..} \<subseteq> {y. \<exists>x\<in>{\<delta>..}. y = x - \<delta>}"
  proof (rule subsetI)
    fix a
    assume "(a::real) \<in> {0..}"
    hence "0 \<le> a" by simp
    hence "\<exists>x\<in>{\<delta>..}. a = x - \<delta>" using bexI[where x = "a + \<delta>"] by auto
    thus "a \<in> {y. \<exists>x\<in>{\<delta>..}. y = x - \<delta>}" by auto
  qed
qed

lemma s_delayed_has_real_derivative[derivative_intros]:
  assumes "\<delta> \<le> t"
  shows "((ego2.s \<circ> \<tau>) has_field_derivative ego2.s' (t - \<delta>) * \<tau>' t) (at t within {\<delta>..})"
proof (rule DERIV_image_chain)
  from assms have 0: "0 \<le> t - \<delta>" by simp
  from ego2.t_stop_nonneg have 1: "v\<^sub>e / a\<^sub>e \<le> 0" unfolding ego2.t_stop_def by simp
  from ego2.decel have 2: "a\<^sub>e \<noteq> 0" by simp
  show "(ego2.s has_real_derivative ego2.s' (t - \<delta>)) (at (\<tau> t) within \<tau> ` {\<delta>..})"
  using ego2.s_has_real_derivative[OF 0 1 2] sym[OF delay_image]
  unfolding \<tau>_def by simp
next
  from del_has_real_derivative show "(\<tau> has_real_derivative \<tau>' t) (at t within {\<delta>..})"
  by auto
qed

lemma s_delayed_has_real_derivative' [derivative_intros]:
  assumes "\<delta> \<le> t"
  shows "((ego2.s \<circ> \<tau>) has_field_derivative (ego2.s' \<circ> \<tau>) t) (at t within {\<delta>..})"
proof -
  from s_delayed_has_real_derivative[OF assms] have
  "((ego2.s \<circ> \<tau>) has_field_derivative ego2.s' (t - \<delta>) * \<tau>' t) (at t within {\<delta>..})"
  by auto
  hence "((ego2.s \<circ> \<tau>) has_field_derivative ego2.s' (t - \<delta>) * 1) (at t within {\<delta>..})"
  using \<tau>'_def[of t] by metis
  hence "((ego2.s \<circ> \<tau>) has_field_derivative ego2.s' (t - \<delta>)) (at t within {\<delta>..})"
  by (simp add:algebra_simps)
  thus ?thesis unfolding comp_def \<tau>_def by auto
qed

lemma s_delayed_has_vector_derivative' [derivative_intros]:
  assumes "\<delta> \<le> t"
  shows "((ego2.s \<circ> \<tau>) has_vector_derivative (ego2.s' \<circ> \<tau>) t) (at t within {\<delta>..})"
  using s_delayed_has_real_derivative'[OF assms]
  by (simp add:has_field_derivative_iff_has_vector_derivative)

definition
  "u t = (     if t \<le> 0 then s\<^sub>e
          else if t \<le> \<delta> then ego.q t
          else          (ego2.s \<circ> \<tau>) t)"

lemma init_u: "t \<le> 0 \<Longrightarrow> u t = s\<^sub>e" unfolding u_def by auto

lemma u_delta: "u \<delta> = ego2.s 0"
proof -
  have "u \<delta> = ego.q \<delta>" using pos_react unfolding u_def by auto
  also have "... = ego2.s 0" unfolding ego2.s_def by auto
  finally show "u \<delta> = ego2.s 0" .
qed

lemma q_delta: "ego.q \<delta> = ego2.s 0" using u_delta pos_react unfolding u_def by auto

definition
  "u' t = (if t \<le> \<delta> then ego.q' t else ego2.s' (t - \<delta>))"

lemma u'_delta: "u' \<delta> = ego2.s' 0"
proof -
  have "u' \<delta> = ego.q' \<delta>" unfolding u'_def by auto
  also have "... = v\<^sub>e" unfolding ego2.q'_def by simp
  also have "... = ego2.p' 0" unfolding ego2.p'_def by simp
  also have "... = ego2.s' 0" using ego2.t_stop_nonneg unfolding ego2.s'_def by auto
  finally show "u' \<delta> = ego.s' 0" .
qed

lemma q'_delta: "ego.q' \<delta> = ego2.s' 0" using u'_delta unfolding u'_def by auto

lemma u_has_real_derivative[derivative_intros]:
  assumes nonneg_t: "t \<ge> 0"
  shows "(u has_real_derivative u' t) (at t within {0..})"
proof -
  from pos_react have "0 \<le> \<delta>" by simp

  have temp: "((\<lambda>t. if t \<in> {0 .. \<delta>} then ego.q t else (ego2.s \<circ> \<tau>) t) has_real_derivative
    (if t \<in> {0..\<delta>} then ego.q' t else (ego2.s' \<circ> \<tau>) t)) (at t within {0..})" (is "(?f1 has_real_derivative ?f2) (?net)")
    unfolding u_def[abs_def] u'_def
      has_field_derivative_iff_has_vector_derivative
    apply (rule has_vector_derivative_If[where t = "{\<delta>..}"])
    using \<open>0 \<le> \<delta>\<close> q_delta q'_delta ego.s_has_vector_derivative[OF assms] ego.decel ego.t_stop_nonneg
    s_delayed_has_vector_derivative'[of "t"] \<tau>_def
    unfolding comp_def
    by (auto simp: assms  max_def insert_absorb
      intro!: ego.q_has_vector_derivative)
  show ?thesis
    unfolding has_vector_derivative_def has_field_derivative_iff_has_vector_derivative
      u'_def u_def[abs_def]
    proof (rule has_derivative_transform[where f="(\<lambda>t. if t \<in> {0..\<delta>} then ego.q t else (ego2.s \<circ> \<tau>) t)"])
      from nonneg_t show " t \<in> {0..}" by auto
    next
      fix x
      assume "(x::real) \<in> {0..}"
      hence  "x \<le> \<delta> \<longleftrightarrow> x \<in> {0 .. \<delta>}" by simp
      thus  " (if x \<le> 0 then s\<^sub>e else if x \<le> \<delta> then ego.q x else (ego2.s \<circ> \<tau>) x) =
         (if x \<in> {0..\<delta>} then ego.q x else (ego2.s \<circ> \<tau>) x)" using pos_react unfolding ego.q_def by auto
    next
      from temp have "(?f1 has_vector_derivative ?f2) ?net"
      using has_field_derivative_iff_has_vector_derivative by auto
      moreover with assms have "t \<in> {0 .. \<delta>} \<longleftrightarrow> t \<le> \<delta>" by auto
      ultimately show " ((\<lambda>t. if t \<in> {0..\<delta>} then ego.q t else (ego2.s \<circ> \<tau>) t) has_derivative
              (\<lambda>x. x *\<^sub>R (if t \<le> \<delta> then ego2.q' t else ego2.s' (t - \<delta>)))) (at t within {0..})"
      unfolding comp_def \<tau>_def has_vector_derivative_def by auto
    qed
qed

definition t_stop :: real where "t_stop = ego2.t_stop + \<delta>"

lemma t_stop_nonneg: "0 \<le> t_stop"
  unfolding t_stop_def
  using ego2.t_stop_nonneg pos_react
  by auto

lemma t_stop_pos: "0 < t_stop"
  unfolding t_stop_def
  using ego2.t_stop_nonneg pos_react
  by auto

lemma t_stop_zero:
  assumes "t_stop \<le> x"
  assumes "x \<le> \<delta>"
  shows "v\<^sub>e = 0"
  using assms unfolding t_stop_def using ego2.t_stop_nonneg pos_react ego2.t_stop_zero by auto

lemma u'_stop_zero: "u' t_stop = 0"
  unfolding u'_def t_stop_def ego2.q'_def ego2.s'_def
  using ego2.t_stop_nonneg ego2.p'_stop_zero decelerate_ego ego2.t_stop_zero by auto

definition u_max :: real where "u_max = u (ego2.t_stop + \<delta>)"

lemma u_max_eq: "u_max = ego.q \<delta> - v\<^sub>e\<^sup>2 / a\<^sub>e / 2"
proof (cases "ego2.t_stop = 0")
  assume "ego2.t_stop = 0"
  hence "v\<^sub>e = 0" using ego2.t_stop_zero by simp
  with \<open>ego2.t_stop = 0\<close> show "u_max = ego.q \<delta> - v\<^sub>e\<^sup>2 / a\<^sub>e / 2"  unfolding u_max_def u_def using pos_react by auto
next
  assume "ego2.t_stop \<noteq> 0"
  hence "u_max = (ego2.s \<circ> \<tau>) (ego2.t_stop + \<delta>)"
    unfolding u_max_def u_def  using ego2.t_stop_nonneg pos_react by auto
  moreover have "... = ego2.s ego2.t_stop" unfolding comp_def \<tau>_def by auto
  moreover have "... = ego2.p_max"
    unfolding ego2.s_def ego2.p_max_def using \<open>ego2.t_stop \<noteq> 0\<close> ego2.t_stop_nonneg by auto
  moreover have "... = ego.q \<delta> - v\<^sub>e\<^sup>2 / a\<^sub>e / 2" using ego2.p_max_eq .
  ultimately show ?thesis by auto
qed

lemma u_mono: assumes "x \<le> y" and "y \<le> t_stop"
              shows "u x \<le> u y"
proof -
  have "y \<le> 0 \<or> (0 < y \<and> y \<le> \<delta>) \<or> \<delta> < y" by auto

  moreover
  { assume "y \<le> 0"
    with assms have "x \<le> 0" by auto
    with \<open>y \<le> 0\<close> have "u x \<le> u y" unfolding u_def by auto }

  moreover
  { assume "0 < y \<and> y \<le> \<delta>"
    with assms have "x \<le> \<delta>" by auto
    hence "u x \<le> u y"
    proof (cases "x \<le> 0")
      assume "x \<le> 0"
      with \<open>x \<le> \<delta>\<close> and \<open>0 < y \<and> y \<le> \<delta>\<close> show "u x \<le> u y"  unfolding u_def using ego.q_min by auto
    next
      assume "\<not> x \<le> 0"
      with \<open>0 < y \<and> y \<le> \<delta>\<close> and assms show "u x \<le> u y"
        unfolding u_def  using ego.q_mono by auto
    qed }

  moreover
  { assume "\<delta> < y"
    have "u x \<le> u y"
    proof (cases "\<delta> < x")
      assume "\<delta> < x"
      with pos_react have "\<not> x \<le> 0" by auto
      moreover from \<open>\<delta> < y\<close> and pos_react have "\<not> y \<le> 0" by auto
      ultimately show "u x \<le> u y"  unfolding u_def comp_def
        using assms ego2.s_mono[of "x - \<delta>" "y - \<delta>"] \<open>\<delta> < y\<close> \<open>\<delta> < x\<close> by (auto simp:\<tau>_def)
    next
      assume "\<not> \<delta> < x"
      hence "x \<le> \<delta>" by simp
      hence "u x \<le> ego.q \<delta>" unfolding u_def using pos_react nonneg_vel_ego
        by (auto simp add:ego.q_def mult_left_mono)
      also have "... = ego2.s (\<tau> \<delta>)" unfolding ego2.s_def unfolding \<tau>_def by auto
      also have "... \<le> ego2.s (\<tau> y)" unfolding \<tau>_def using \<open>\<delta> < y\<close> by (auto simp add:ego2.s_mono)
      also have "... = u y" unfolding u_def using \<open>\<delta> < y\<close> pos_react by auto
      ultimately show "u x \<le> u y" by auto
    qed }

  ultimately show "u x \<le> u y" by auto
qed

lemma u_antimono: "x \<le> y \<Longrightarrow> t_stop \<le> x \<Longrightarrow> u y \<le> u x"
proof -
  assume 1: "x \<le> y"
  assume 2: "t_stop \<le> x"
  hence "\<delta> \<le> x" unfolding \<tau>_def t_stop_def using pos_react ego2.t_stop_nonneg by auto
  with 1 have "\<delta> \<le> y" by auto
  from 1 and 2 have 3: "t_stop \<le> y" by auto
  show "u y \<le> u x"
  proof (cases "x \<noteq> \<delta> \<and> y \<noteq> \<delta>")
    assume "x \<noteq> \<delta> \<and> y \<noteq> \<delta>"
    hence "x \<noteq> \<delta>" and "y \<noteq> \<delta>" by auto
    have "u y \<le> (ego2.s \<circ> \<tau>) y" unfolding u_def using \<open>\<delta> \<le> y\<close> \<open>y \<noteq> \<delta>\<close> pos_react by auto
    also have "... \<le> (ego2.s \<circ> \<tau>) x" unfolding comp_def
    proof (intro ego2.s_antimono)
      show "\<tau> x \<le> \<tau> y" unfolding \<tau>_def using \<open>x \<le> y\<close> by auto
    next
      show "ego2.t_stop \<le> \<tau> x" unfolding \<tau>_def using \<open>t_stop \<le> x\<close> by (auto simp: t_stop_def)
    qed
    also have "... \<le> u x" unfolding u_def using \<open>\<delta> \<le> x\<close>\<open>x \<noteq> \<delta>\<close> pos_react by auto
    ultimately show "u y \<le> u x" by auto
  next
    assume "\<not> (x \<noteq> \<delta> \<and> y \<noteq> \<delta>)"
    have "x \<noteq> \<delta> \<longrightarrow> y \<noteq> \<delta>"
    proof (rule impI; erule contrapos_pp[where Q="\<not> x = \<delta>"])
      assume "\<not> y \<noteq> \<delta>"
      hence "y = \<delta>" by simp
      with \<open>t_stop \<le> y\<close> have "ego2.t_stop = 0" unfolding t_stop_def
        using ego2.t_stop_nonneg by auto
      with \<open>t_stop \<le> x\<close> have "x = \<delta>" unfolding t_stop_def using \<open>x \<le> y\<close> \<open>y = \<delta>\<close> by auto
      thus "\<not> x \<noteq> \<delta>" by auto
    qed
    with \<open>\<not> (x \<noteq> \<delta> \<and> y \<noteq> \<delta>)\<close> have "(x = \<delta> \<and> y = \<delta>) \<or> (x = \<delta>)" by auto

    moreover
    { assume "x = \<delta> \<and> y = \<delta>"
      hence "x = \<delta>" and "y = \<delta>" by auto
      hence "u y \<le> ego.q \<delta>" unfolding u_def using pos_react by auto
      also have "... \<le> u x" unfolding u_def using \<open>x = \<delta>\<close> pos_react by auto
      ultimately have "u y \<le> u x" by auto }

    moreover
    { assume "x = \<delta>"
      hence "ego2.t_stop = 0" using \<open>t_stop \<le> x\<close> ego2.t_stop_nonneg by (auto simp:t_stop_def)
      hence "v\<^sub>e = 0" by (rule ego2.t_stop_zero)
      hence "u y \<le> ego.q \<delta>"
        using pos_react \<open>x = \<delta>\<close> \<open>x \<le> y\<close> \<open>v\<^sub>e = 0\<close>
        unfolding u_def comp_def \<tau>_def ego2.s_def ego2.p_def ego2.p_max_def ego2.t_stop_def
        by auto
      also have "... \<le> u x" using \<open>x = \<delta>\<close> pos_react unfolding u_def by auto
      ultimately have "u y \<le> u x" by auto }

    ultimately show ?thesis by auto
  qed
qed

lemma u_max: "u x \<le> u_max"
  unfolding u_max_def using t_stop_def
  by (cases "x \<le> t_stop") (auto intro: u_mono u_antimono)

lemma u_eq_u_stop: "NO_MATCH t_stop x \<Longrightarrow> x \<ge> t_stop \<Longrightarrow> u x = u_max"
proof -
  assume "t_stop \<le> x"
  with t_stop_pos have "0 < x" by auto
  from \<open>t_stop \<le> x\<close> have "\<delta> \<le> x" unfolding t_stop_def using ego2.t_stop_nonneg by auto
  show  "u x = u_max"
  proof (cases "x \<le> \<delta>")
    assume "x \<le> \<delta>"
    with \<open>t_stop \<le> x\<close> have "v\<^sub>e = 0" by (rule t_stop_zero)
    also have "x = \<delta>" using \<open>x \<le> \<delta>\<close> and \<open>\<delta> \<le> x\<close> by auto
    ultimately have "u x = ego.q \<delta>" unfolding u_def using pos_react by auto
    also have "... = u_max" unfolding u_max_eq using \<open>v\<^sub>e = 0\<close> by auto
    ultimately show "u x = u_max" by simp
  next
    assume "\<not> x \<le> \<delta>"
    hence "\<delta> < x" by auto
    hence "u x = (ego2.s \<circ> \<tau>) x" unfolding u_def using pos_react by auto
    also have "... = ego2.s ego2.t_stop"
      proof (unfold comp_def; unfold \<tau>_def; intro order.antisym)
        have "x - \<delta> \<ge> ego2.t_stop" using \<open>t_stop \<le> x\<close> unfolding t_stop_def by auto
        thus "ego2.s (x - \<delta>) \<le> ego2.s ego2.t_stop" by (rule ego2.s_antimono) simp
      next
        thm ego2.s_mono
        have "x - \<delta> \<ge> ego2.t_stop" using \<open>t_stop \<le> x\<close> unfolding t_stop_def by auto
        thus "ego2.s ego2.t_stop \<le> ego2.s (x - \<delta>)" using ego2.t_stop_nonneg by (rule ego2.s_mono)
      qed
    also have "... = u_max" unfolding u_max_eq ego2.s_t_stop ego2.p_max_eq by auto
    ultimately show "u x = u_max" by auto
  qed
qed

lemma at_least_delta:
  assumes "x \<le> \<delta>"
  assumes "t_stop \<le> x"
  shows "ego.q x = ego2.s (x - \<delta>)"
  using assms ego2.t_stop_nonneg
  unfolding t_stop_def ego2.s_def by smt

lemma continuous_on_u[continuous_intros]: "continuous_on T u"
  unfolding u_def[abs_def]
  using t_stop_nonneg pos_react at_least_delta
  proof (intro continuous_on_subset[where t=T and s = "{..0} \<union> ({0..\<delta>} \<union> ({\<delta> .. t_stop} \<union> {t_stop ..}))"] continuous_on_If continuous_intros)
    fix x
    assume " \<not> x \<le> \<delta>"
    assume "x \<in> {0..\<delta>}"
    hence "0 \<le> x" and "x \<le> \<delta>" by auto
    thus "ego.q x = (ego2.s \<circ> \<tau>) x"
      unfolding comp_def \<tau>_def ego2.s_def
      using \<open>\<not> x \<le> \<delta>\<close> by auto
  next
    fix x
    assume "x \<in> {\<delta>..t_stop} \<union> {t_stop..}"
    hence "\<delta> \<le> x" unfolding t_stop_def using pos_react ego.t_stop_nonneg by auto
    also assume "x \<le> \<delta>"
    ultimately have "x = \<delta>" by auto
    thus "ego.q x = (ego2.s \<circ> \<tau>) x" unfolding comp_def \<tau>_def ego2.s_def by auto
  next
    fix t::real
    assume "t \<in> {.. 0}"
    hence "t \<le> 0" by auto
    also assume "\<not> t \<le> 0"
    ultimately have "t = 0" by auto
    hence "s\<^sub>e = ego.q t" unfolding ego.q_def by auto
    with pos_react \<open>t = 0\<close> show "s\<^sub>e = (if t \<le> \<delta> then ego.q t else (ego2.s \<circ> \<tau>) t)" by auto
  next
    fix t::real
    assume "t \<in> {0..\<delta>} \<union> ({\<delta>..t_stop} \<union> {t_stop..})"
    hence "0 \<le> t" using pos_react ego2.t_stop_nonneg by (auto simp: t_stop_def)
    also assume "t \<le> 0"
    ultimately have "t = 0" by auto
    hence " s\<^sub>e = (if t \<le> \<delta> then ego.q t else (ego2.s \<circ> \<tau>) t)" using pos_react ego.init_q by auto
    thus "s\<^sub>e = (if t \<le> \<delta> then ego.q t else (ego2.s \<circ> \<tau>) t)" by auto
  next
    show "T \<subseteq> {..0} \<union> ({0..\<delta>} \<union> ({\<delta>..t_stop} \<union> {t_stop..}))" by auto
  qed

lemma isCont_u[continuous_intros]: "isCont u x"
  using continuous_on_u[of UNIV]
  by (auto simp:continuous_on_eq_continuous_at)

definition collision_react :: "real set \<Rightarrow> bool" where
"collision_react time_set \<equiv> (\<exists>t\<in>time_set. u t = other.s t )"

abbreviation no_collision_react :: "real set \<Rightarrow> bool" where
"no_collision_react time_set \<equiv> \<not> collision_react time_set"

lemma
  no_collision_reactI:
  assumes "\<And>t. t \<in> S \<Longrightarrow> u t \<noteq> other.s t"
  shows "no_collision_react S"
  using assms
  unfolding collision_react_def
  by blast

lemma
  no_collision_union:
  assumes "no_collision_react S"
  assumes "no_collision_react T"
  shows "no_collision_react (S \<union> T)"
  using assms
  unfolding collision_react_def
  by auto

lemma collision_trim_subset:
  assumes "collision_react S"
  assumes "no_collision_react T"
  assumes "T \<subseteq> S"
  shows "collision_react (S - T)"
  using assms
  unfolding collision_react_def by auto

theorem cond_1r : "u_max < s\<^sub>o \<Longrightarrow> no_collision_react {0..}"
proof (rule no_collision_reactI, simp)
  fix t :: real
  assume "0 \<le> t"
  have "u t \<le> u_max" by (rule u_max)
  also assume "... < s\<^sub>o"
  also have "... = other.s 0"
    by (simp add: other.init_s)
  also have "... \<le> other.s t"
    using \<open>0 \<le> t\<close> hyps
    by (intro other.s_mono) auto
  finally show "u t \<noteq> other.s t"
    by simp
qed

definition safe_distance_1r:: real where "safe_distance_1r = v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / a\<^sub>e / 2"

lemma sd_1r_eq: "(s\<^sub>o - s\<^sub>e > safe_distance_1r) = (u_max < s\<^sub>o)"
proof -
  have "(s\<^sub>o - s\<^sub>e > safe_distance_1r) = (s\<^sub>o - s\<^sub>e > v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / a\<^sub>e / 2)" unfolding safe_distance_1r_def by auto
  moreover have "... = (s\<^sub>e + v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / a\<^sub>e / 2 < s\<^sub>o)" by auto
  ultimately show ?thesis using u_max_eq ego.q_def by auto
qed

lemma sd_1r_correct:
  assumes "s\<^sub>o - s\<^sub>e > safe_distance_1r"
  shows "no_collision_react {0..}"
proof -
  from assms have "u_max < s\<^sub>o" using sd_1r_eq by auto
  thus ?thesis by (rule cond_1r)
qed

lemma u_other_strict_ivt:
  assumes "u t > other.s t"
  shows "collision_react {0..<t}"
proof cases
  assume "0 \<le> t"
  with assms in_front
  have "\<exists>x\<ge>0. x \<le> t \<and> other.s x - u x = 0"
    by (intro IVT2)
    (auto intro!: continuous_intros simp: init_u other.init_s)
  then show ?thesis
    using assms
    by (auto simp add:algebra_simps collision_react_def Bex_def order.order_iff_strict)
qed(insert assms hyps, auto simp: collision_react_def init_u other.init_s)

lemma collision_react_subset: "collision_react s \<Longrightarrow> s \<subseteq> t \<Longrightarrow> collision_react t"
  by (auto simp:collision_react_def)

lemma u_other_ivt:
  assumes "u t \<ge> other.s t"
  shows "collision_react {0 .. t}"
proof cases
  assume "u t > other.s t"
  from u_other_strict_ivt[OF this]
  show ?thesis
    by (rule collision_react_subset) auto
qed (insert hyps assms; cases "t \<ge> 0"; force simp: collision_react_def init_u other.init_s)

theorem cond_2r:
  assumes "u_max \<ge> other.s_stop"
  shows "collision_react {0 ..}"
  using assms
  apply(intro collision_react_subset[where t="{0..}" and s ="{0 .. max t_stop other.t_stop}"])
  apply(intro u_other_ivt[where t ="max t_stop other.t_stop"])
  apply(auto simp: u_eq_u_stop other.s_eq_s_stop)
  done

definition ego_other2 :: "real \<Rightarrow> real" where
  "ego_other2 t = other.s t - u t"

lemma continuous_on_ego_other2[continuous_intros]: "continuous_on T ego_other2"
  unfolding ego_other2_def[abs_def]
  by (intro continuous_intros)

lemma isCont_ego_other2[continuous_intros]: "isCont ego_other2 x"
  using continuous_on_ego_other2[of UNIV]
  by (auto simp: continuous_on_eq_continuous_at)

definition ego_other2' :: "real \<Rightarrow> real" where
  "ego_other2' t  = other.s' t - u' t"

lemma ego_other2_has_real_derivative[derivative_intros]:
  assumes "0 \<le> t"
  shows "(ego_other2 has_real_derivative ego_other2' t) (at t within {0..})"
  using assms other.t_stop_nonneg decelerate_other
  unfolding other.t_stop_def
  by (auto simp: ego_other2_def[abs_def] ego_other2'_def  algebra_simps
           intro!: derivative_eq_intros)

theorem cond_3r_1:
  assumes "u \<delta> \<ge> other.s \<delta>"
  shows "collision_react {0 .. \<delta>}"
  proof (unfold collision_react_def)
  have 1: "\<exists>t\<ge>0. t \<le> \<delta> \<and> ego_other2 t = 0"
    proof (intro IVT2)
      show "ego_other2 \<delta> \<le> 0" unfolding ego_other2_def using assms by auto
    next
      show "0 \<le> ego_other2 0" unfolding ego_other2_def
        using other.init_s[of 0] init_u[of 0] in_front by auto
    next
      show "0 \<le> \<delta>" using pos_react by auto
    next
      show "\<forall>t. 0 \<le> t \<and> t \<le> \<delta> \<longrightarrow> isCont ego_other2 t"
        using isCont_ego_other2 by auto
    qed
    then obtain t where "0 \<le> t \<and> t \<le> \<delta> \<and> ego_other2 t = 0" by auto
    hence "t \<in> {0 .. \<delta>}" and "u t = other.s t" unfolding ego_other2_def by auto
    thus "\<exists>t\<in>{0..\<delta>}. u t = other.s t" by (intro bexI)
  qed

definition distance0 :: real where "distance0 =  v\<^sub>e * \<delta> - v\<^sub>o * \<delta> - a\<^sub>o * \<delta>\<^sup>2 / 2"
definition distance0_2 :: real where "distance0_2 = v\<^sub>e * \<delta> + 1 / 2 * v\<^sub>o\<^sup>2 / a\<^sub>o"

theorem cond_3r_1':
  assumes "s\<^sub>o - s\<^sub>e \<le> distance0"
  assumes "\<delta> \<le> other.t_stop"
  shows "collision_react {0 .. \<delta>}"
proof -
  from assms have "u \<delta> \<ge> other.s \<delta>" unfolding distance0_def other.s_def
    other.p_def u_def ego.q_def using pos_react by auto
  thus ?thesis using cond_3r_1 by auto
qed

theorem distance0_2_eq:
  assumes "\<delta> > other.t_stop"
  shows "(u \<delta> < other.s \<delta>) = (s\<^sub>o - s\<^sub>e > distance0_2)"
proof -
  from assms have "(u \<delta> < other.s \<delta>) = (ego.q \<delta> < other.p_max)"
    using u_def other.s_def pos_react by auto
  also have "... = (s\<^sub>e + v\<^sub>e * \<delta> < s\<^sub>o + v\<^sub>o * (- v\<^sub>o / a\<^sub>o) + 1 / 2 * a\<^sub>o * (- v\<^sub>o / a\<^sub>o)\<^sup>2)"
    using ego.q_def other.p_max_def other.p_def other.t_stop_def by auto
  also have "... = (v\<^sub>e * \<delta> - v\<^sub>o * (- v\<^sub>o / a\<^sub>o) - 1 / 2 * a\<^sub>o * (- v\<^sub>o / a\<^sub>o)\<^sup>2 < s\<^sub>o - s\<^sub>e)" by linarith
  also have "... = (v\<^sub>e * \<delta> + v\<^sub>o\<^sup>2 / a\<^sub>o - 1 / 2 * v\<^sub>o\<^sup>2 / a\<^sub>o < s\<^sub>o - s\<^sub>e)"
    using other.p_def other.p_max_def other.p_max_eq other.t_stop_def by auto
  also have "... = (v\<^sub>e * \<delta> + 1 / 2 * v\<^sub>o\<^sup>2 / a\<^sub>o < s\<^sub>o - s\<^sub>e)" by linarith
  thus ?thesis using distance0_2_def by (simp add: calculation)
qed

lemma distance0_at_most_sd4r:
  assumes "a\<^sub>o > a\<^sub>e"
  shows "distance0 \<le> safe_distance_4r"
proof -
  from assms have "a\<^sub>o \<ge> a\<^sub>e" by auto
  have "0 \<le> (v\<^sub>o + a\<^sub>o * \<delta> - v\<^sub>e)\<^sup>2 / (2 * a\<^sub>o - 2 * a\<^sub>e)"
    by (rule divide_nonneg_nonneg) (auto simp add:assms `a\<^sub>e \<le> a\<^sub>o`)
  thus ?thesis unfolding distance0_def safe_distance_4r_def
    by auto
qed

definition safe_distance_2r::real where "safe_distance_2r = v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o"

lemma vo_start_geq_ve:
  assumes "\<delta> \<le> other.t_stop"
  assumes "other.s' \<delta> \<ge> v\<^sub>e"
  shows "u \<delta> < other.s \<delta>"
proof -
    from assms have "v\<^sub>e \<le> v\<^sub>o + a\<^sub>o * \<delta>" unfolding other.s'_def other.p'_def by auto
    with  mult_right_mono[OF this, of "\<delta>"] have "v\<^sub>e * \<delta> \<le> v\<^sub>o * \<delta> + a\<^sub>o * \<delta>\<^sup>2" (is "?l0 \<le> ?r0")
      using pos_react by (auto simp add:field_simps power_def)
    hence "s\<^sub>e + ?l0 \<le> s\<^sub>e + ?r0" by auto
    also have "... < s\<^sub>o + ?r0" using in_front by auto
    also have "... < s\<^sub>o + v\<^sub>o * \<delta> + a\<^sub>o * \<delta>\<^sup>2 / 2" using decelerate_other pos_react by auto
    finally show ?thesis using pos_react assms(1)
      unfolding u_def ego.q_def other.s_def other.t_stop_def other.p_def by auto
qed

theorem so_star_stop_leq_se_stop:
  assumes "\<delta> \<le> other.t_stop"
  assumes "other.s' \<delta> < v\<^sub>e"
  assumes "\<not> (a\<^sub>o > a\<^sub>e \<and> other.s' \<delta> < v\<^sub>e \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * other.s' \<delta> < 0)"
  shows "0 \<le> - v\<^sub>e\<^sup>2 / a\<^sub>e / 2 + (v\<^sub>o + a\<^sub>o * \<delta>)\<^sup>2 / a\<^sub>o / 2"
proof -
  consider "v\<^sub>e - a\<^sub>e / a\<^sub>o * other.s' \<delta> \<ge> 0" | "\<not> (v\<^sub>e - a\<^sub>e / a\<^sub>o * other.s' \<delta> \<ge> 0)" by auto
  thus ?thesis
  proof (cases)
    case 1
    hence "v\<^sub>e - a\<^sub>e / a\<^sub>o * (v\<^sub>o + a\<^sub>o * \<delta>) \<ge> 0" unfolding other.s'_def other.p'_def
      by (auto simp add:assms(1))
    hence "v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o - a\<^sub>e * \<delta> \<ge> 0" (is "?l0 \<ge> 0") using decelerate_other
      by (auto simp add:field_simps)
    hence "?l0 / a\<^sub>e \<le> 0" using divide_right_mono_neg[OF `?l0 \<ge> 0`] decelerate_ego by auto
    hence "0 \<ge> v\<^sub>e / a\<^sub>e - v\<^sub>o / a\<^sub>o - \<delta>" using decelerate_ego by (auto simp add:field_simps)
    hence *: "- v\<^sub>e / a\<^sub>e \<ge> - (v\<^sub>o + a\<^sub>o * \<delta>) / a\<^sub>o" using decelerate_other by (auto simp add:field_simps)
    from assms have **: "v\<^sub>o + a\<^sub>o * \<delta> \<le> v\<^sub>e" unfolding other.s'_def other.p'_def by auto
    have vo_star_nneg: "v\<^sub>o + a\<^sub>o * \<delta> \<ge> 0"
    proof -
      from assms(1) have "- v\<^sub>o \<le> a\<^sub>o * \<delta>" unfolding other.t_stop_def using decelerate_other
        by (auto simp add:field_simps)
      thus ?thesis by auto
    qed
    from mult_mono[OF * ** _ `0 \<le> v\<^sub>o + a\<^sub>o * \<delta>`]
    have "- (v\<^sub>o + a\<^sub>o * \<delta>) / a\<^sub>o * (v\<^sub>o + a\<^sub>o * \<delta>) \<le> - v\<^sub>e / a\<^sub>e * v\<^sub>e" using nonneg_vel_ego decelerate_ego
      by (auto simp add:field_simps)
    hence "- (v\<^sub>o + a\<^sub>o * \<delta>)\<^sup>2 / a\<^sub>o \<le> - v\<^sub>e\<^sup>2 / a\<^sub>e " by (auto simp add: field_simps power_def)
    thus ?thesis by (auto simp add:field_simps)
  next
    case 2
    with assms have "a\<^sub>o \<le> a\<^sub>e" by auto
    from assms(2) have "(v\<^sub>o + a\<^sub>o * \<delta>) \<le> v\<^sub>e" unfolding other.s'_def using assms unfolding other.p'_def
      by auto
    have vo_star_nneg: "v\<^sub>o + a\<^sub>o * \<delta> \<ge> 0"
    proof -
      from assms(1) have "- v\<^sub>o \<le> a\<^sub>o * \<delta>" unfolding other.t_stop_def using decelerate_other
        by (auto simp add:field_simps)
      thus ?thesis by auto
    qed
    with mult_mono[OF `v\<^sub>o + a\<^sub>o * \<delta> \<le> v\<^sub>e` `v\<^sub>o + a\<^sub>o * \<delta> \<le> v\<^sub>e`] have *: "(v\<^sub>o + a\<^sub>o * \<delta>)\<^sup>2 \<le> v\<^sub>e\<^sup>2"
      using nonneg_vel_ego by (auto simp add:power_def)
    from `a\<^sub>o \<le> a\<^sub>e` have "- 1 /a\<^sub>o \<le> - 1 / a\<^sub>e" using decelerate_ego decelerate_other
      by (auto simp add:field_simps)
    from mult_mono[OF * this] have "(v\<^sub>o + a\<^sub>o * \<delta>)\<^sup>2 * (- 1 / a\<^sub>o) \<le> v\<^sub>e\<^sup>2 * (- 1 / a\<^sub>e)"
      using nonneg_vel_ego decelerate_other by (auto simp add:field_simps)
    then show ?thesis by auto
  qed
qed

theorem distance0_at_most_distance2r:
  assumes "\<delta> \<le> other.t_stop"
  assumes "other.s' \<delta> < v\<^sub>e"
  assumes "\<not> (a\<^sub>o > a\<^sub>e \<and> other.s' \<delta> < v\<^sub>e \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * other.s' \<delta> < 0)"
  shows "distance0 \<le> safe_distance_2r"
proof -
  from so_star_stop_leq_se_stop[OF assms] have " 0 \<le> - v\<^sub>e\<^sup>2 / a\<^sub>e / 2 + (v\<^sub>o + a\<^sub>o * \<delta>)\<^sup>2 / a\<^sub>o / 2 " (is "0 \<le> ?term")
    by auto
  have "safe_distance_2r = v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o" unfolding safe_distance_2r_def by auto
  also have "... = v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + (v\<^sub>o + a\<^sub>o * \<delta>)\<^sup>2 / 2 / a\<^sub>o - v\<^sub>o * \<delta> - a\<^sub>o * \<delta>\<^sup>2 / 2"
    using decelerate_other by (auto simp add:field_simps power_def)
  also have "... = v\<^sub>e * \<delta> - v\<^sub>o * \<delta> - a\<^sub>o * \<delta>\<^sup>2 / 2 + ?term" (is "_ = ?left + ?term")
    by (auto simp add:field_simps)
  finally have "safe_distance_2r = distance0 + ?term" unfolding distance0_def by auto
  with `0 \<le> ?term` show "distance0 \<le> safe_distance_2r" by auto
qed

theorem dist0_sd2r_1:
  assumes "\<delta> \<le> other.t_stop"
  assumes "\<not> (a\<^sub>o > a\<^sub>e \<and> other.s' \<delta> < v\<^sub>e \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * other.s' \<delta> < 0)"
  assumes "s\<^sub>o - s\<^sub>e > safe_distance_2r"
  shows "s\<^sub>o - s\<^sub>e > distance0"
proof (cases "other.s' \<delta> \<ge> v\<^sub>e")
  assume "v\<^sub>e \<le> other.s' \<delta>"
  from vo_start_geq_ve[OF assms(1) this] have "u \<delta> < other.s \<delta>" by auto
  thus ?thesis unfolding distance0_def u_def using pos_react assms(1) unfolding ego.q_def
    other.s_def other.p_def by auto
next
  assume "\<not> v\<^sub>e \<le> other.s' \<delta>"
  hence "v\<^sub>e > other.s' \<delta>" by auto
  from distance0_at_most_distance2r[OF assms(1) this assms(2)] have "distance0 \<le> safe_distance_2r"
    by auto
  with assms(3) show ?thesis by auto
qed

theorem sd2r_eq:
  assumes "\<delta> > other.t_stop"
  shows "(u_max < other.s \<delta>) = (s\<^sub>o - s\<^sub>e > safe_distance_2r)"
proof -
  from assms have "(u_max < other.s \<delta>) = (ego2.s (- v\<^sub>e / a\<^sub>e) < other.p_max)"
    using u_max_def ego2.t_stop_def u_def other.s_def \<tau>_def pos_react ego2.p_max_eq ego2.s_t_stop u_max_eq by auto
  also have "... = (s\<^sub>e + v\<^sub>e * \<delta> + v\<^sub>e * (- v\<^sub>e / a\<^sub>e) + 1 / 2 * a\<^sub>e * (- v\<^sub>e / a\<^sub>e)\<^sup>2 < s\<^sub>o + v\<^sub>o * (- v\<^sub>o / a\<^sub>o) + 1 / 2 * a\<^sub>o * (- v\<^sub>o / a\<^sub>o)\<^sup>2)"
    using ego2.s_def ego2.p_def ego.q_def other.p_max_def other.p_def other.t_stop_def ego2.p_max_def ego2.s_t_stop ego2.t_stop_def by auto
  also have "... = (v\<^sub>e * \<delta> + v\<^sub>e * (- v\<^sub>e / a\<^sub>e) + 1 / 2 * a\<^sub>e * (- v\<^sub>e / a\<^sub>e)\<^sup>2 - v\<^sub>o * (- v\<^sub>o / a\<^sub>o) - 1 / 2 * a\<^sub>o * (- v\<^sub>o / a\<^sub>o)\<^sup>2 < s\<^sub>o  - s\<^sub>e)" by linarith
  also have "... = (v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / a\<^sub>e + 1 / 2 * v\<^sub>e\<^sup>2 / a\<^sub>e + v\<^sub>o\<^sup>2 / a\<^sub>o - 1 / 2 * v\<^sub>o\<^sup>2 / a\<^sub>o < s\<^sub>o  - s\<^sub>e)"
    using ego2.p_def ego2.p_max_def ego2.p_max_eq ego2.t_stop_def other.p_def other.p_max_def other.p_max_eq other.t_stop_def by auto
  also have "... = (v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o  < s\<^sub>o - s\<^sub>e)" by linarith
  thus ?thesis using distance0_2_def by (simp add: calculation safe_distance_2r_def)
qed

theorem dist0_sd2r_2:
  assumes "\<delta> > - v\<^sub>o / a\<^sub>o"
  assumes "s\<^sub>o - s\<^sub>e > safe_distance_2r"
  shows "s\<^sub>o - s\<^sub>e > distance0_2"
proof -
  have "- v\<^sub>e\<^sup>2 / 2 / a\<^sub>e \<ge> 0" using zero_le_power2 hyps(3) divide_nonneg_neg by (auto simp add:field_simps)
  hence "v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o \<ge> v\<^sub>e * \<delta> + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o" by simp
  hence "safe_distance_2r \<ge> distance0_2" using safe_distance_2r_def distance0_2_def by auto
  thus ?thesis using assms(2)  by linarith
qed
end

locale safe_distance_no_collsion_delta = safe_distance_normal +
assumes no_collision_delta: "u \<delta> < other.s \<delta>"
begin

sublocale delayed_safe_distance: safe_distance a\<^sub>e v\<^sub>e "ego.q \<delta>" a\<^sub>o "other.s' \<delta>" "other.s \<delta>"
  proof (unfold_locales)
    from nonneg_vel_ego show "0 \<le> v\<^sub>e" by auto
  next
    from nonneg_vel_other show "0 \<le> other.s' \<delta>" unfolding other.s'_def other.p'_def other.t_stop_def
      using decelerate_other by (auto simp add:algebra_simps divide_simps)
  next
    from decelerate_ego show "a\<^sub>e < 0" by auto
  next
    from decelerate_other show "a\<^sub>o < 0" by auto
  next
    from no_collision_delta show "ego.q \<delta> < other.s \<delta>" unfolding u_def using pos_react by auto
  qed

lemma no_collision_react_initially_strict:
  assumes "s\<^sub>o \<le> u_max"
  assumes "u_max < other.s_stop"
  shows "no_collision_react {0 <..< \<delta>}"
proof (rule no_collision_reactI)
  fix t::real
  assume "t \<in> {0 <..< \<delta>}"
  show "u t \<noteq> other.s t"
  proof (rule ccontr)
    assume "\<not> u t \<noteq> other.s t"
    hence "ego_other2 t = 0" unfolding ego_other2_def by auto
    from \<open>t \<in> {0 <..< \<delta>}\<close> have "ego_other2 t = other.s t - ego.q t"
      unfolding ego_other2_def u_def using ego.init_q by auto
    thm other.s_def
    have "\<delta> \<le> other.t_stop \<or> other.t_stop < \<delta>" by auto

    moreover
    { assume le_t_stop: "\<delta> \<le> other.t_stop"
      with \<open>ego_other2 t = other.s t - ego.q t\<close> have "ego_other2 t = other.p t - ego.q t"
        unfolding other.s_def using \<open>t \<in> {0 <..< \<delta>}\<close> by auto
      with \<open>ego_other2 t = 0\<close> have "other.p t - ego.q t = 0" by auto
      hence eq: "(s\<^sub>o- s\<^sub>e) + (v\<^sub>o - v\<^sub>e) * t + (1/2 * a\<^sub>o) * t\<^sup>2 = 0"
        unfolding other.p_def ego.q_def by (auto simp: algebra_simps)
      def p \<equiv> "\<lambda>x. (1/2 * a\<^sub>o) * x\<^sup>2 + (v\<^sub>o - v\<^sub>e) * x + (s\<^sub>o - s\<^sub>e)"
      have "0 < 1/2 * a\<^sub>o"
      proof (intro p_convex[where p=p and b="v\<^sub>o - v\<^sub>e" and c="s\<^sub>o - s\<^sub>e"])
        defer
          show "0 < t" using \<open>t \<in> {0 <..< \<delta>}\<close> by auto
        next
          show "t < \<delta>" using  \<open>t \<in> {0 <..< \<delta>}\<close> by auto
        next
          show "p t < p 0" unfolding p_def using eq in_front by (auto simp: algebra_simps)
        next
          from eq have "p t = 0" unfolding p_def by auto
          also have "... < p \<delta>"  using no_collision_delta pos_react le_t_stop
            unfolding p_def u_def other.s_def ego.q_def other.p_def by (auto simp:algebra_simps)
          finally have "p t < p \<delta>" by simp
          thus "p t \<le> p \<delta>" by auto
        next
          show "p = (\<lambda>x. 1 / 2 * a\<^sub>o * x\<^sup>2 + (v\<^sub>o - v\<^sub>e) * x + (s\<^sub>o - s\<^sub>e))" unfolding p_def
          by (rule refl)
      qed
      hence "0 < a\<^sub>o" by auto
      with decelerate_other have False by simp }

    moreover
    { assume gt_t_stop: "\<delta> > other.t_stop"
      have t_lt_t_stop: "t < other.t_stop"
      proof (rule ccontr)
        assume "\<not> t < other.t_stop"
        hence "other.t_stop \<le> t" by simp
        from \<open>ego_other2 t = 0\<close> have "ego.q t = other.p_max"
          unfolding ego_other2_def u_def other.s_def comp_def \<tau>_def other.p_max_def
          using \<open>t \<in> {0 <..< \<delta>}\<close> \<open>other.t_stop \<le> t\<close> gt_t_stop by (auto split:if_splits)
        have "ego.q t = u t" unfolding u_def using \<open>t \<in> {0 <..< \<delta>}\<close> by auto
        also have "... \<le> u_max" using u_max by auto
        also have "... < other.p_max" using assms(2) other.s_t_stop by auto
        finally have "ego.q t < other.p_max" by auto
        with \<open>ego.q t = other.p_max\<close> show False by auto
      qed

      with \<open>ego_other2 t = other.s t - ego.q t\<close> have "ego_other2 t = other.p t - ego.q t"
        unfolding other.s_def using \<open>t \<in> {0 <..< \<delta>}\<close> by auto
      with \<open>ego_other2 t = 0\<close> have "other.p t - ego.q t = 0" by auto
      hence eq: "(s\<^sub>o- s\<^sub>e) + (v\<^sub>o - v\<^sub>e) * t + (1/2 * a\<^sub>o) * t\<^sup>2 = 0"
        unfolding other.p_def ego.q_def by (auto simp: algebra_simps)
      def p \<equiv> "\<lambda>x. (1/2 * a\<^sub>o) * x\<^sup>2 + (v\<^sub>o - v\<^sub>e) * x + (s\<^sub>o - s\<^sub>e)"
      have "0 < 1/2 * a\<^sub>o"
      proof (intro p_convex[where p=p and b="v\<^sub>o - v\<^sub>e" and c="s\<^sub>o - s\<^sub>e"])
        defer
          show "0 < t" using \<open>t \<in> {0 <..< \<delta>}\<close> by auto
        next
          show "t < other.t_stop" using t_lt_t_stop by auto
        next
          show "p t < p 0" unfolding p_def using eq in_front by (auto simp: algebra_simps)
        next
          from eq have zero: "p t = 0" unfolding p_def by auto
          have eq: "p other.t_stop = ego_other2 other.t_stop"
            unfolding ego_other2_def other.s_t_stop u_def ego.q_def
                      other.s_def other.p_def p_def
            using \<open>\<delta> > other.t_stop\<close> other.t_stop_nonneg other.t_stop_def
            by (auto simp: field_simps)
          have "u other.t_stop \<le> u_max" using u_max by auto
          also have "... < other.s_stop" using assms by auto
          finally have "0 \<le> other.s_stop - u other.t_stop" by auto
          hence "0 \<le> ego_other2 other.t_stop" unfolding ego_other2_def by auto
          hence "0 \<le> p other.t_stop" using eq by auto
          with zero show "p t \<le> p other.t_stop" by auto
        next
          show "p = (\<lambda>x. 1 / 2 * a\<^sub>o * x\<^sup>2 + (v\<^sub>o - v\<^sub>e) * x + (s\<^sub>o - s\<^sub>e))"
          unfolding p_def by (rule refl)
      qed
      hence False using decelerate_other by auto }

     ultimately show False by auto
  qed
qed

lemma no_collision_react_initially:
  assumes "s\<^sub>o \<le> u_max"
  assumes "u_max < other.s_stop"
  shows "no_collision_react {0 .. \<delta>}"
proof -
  have "no_collision_react {0 <..< \<delta>}" by (rule no_collision_react_initially_strict[OF assms])
  have "u 0 \<noteq> other.s 0" using init_u other.init_s in_front by auto
  hence "no_collision_react {0}" unfolding collision_react_def by auto
  with \<open>no_collision_react {0 <..< \<delta>}\<close> have "no_collision_react ({0} \<union> {0 <..< \<delta>})"
    using no_collision_union[of "{0}" "{0 <..< \<delta>}"] by auto
  moreover have "{0} \<union> {0 <..< \<delta>} = {0 ..< \<delta>}" using pos_react by auto
  ultimately have "no_collision_react {0 ..< \<delta>}" by auto

  have "u \<delta> \<noteq> other.s \<delta>" using no_collision_delta by auto
  hence "no_collision_react {\<delta>}" unfolding collision_react_def by auto
  with \<open>no_collision_react {0 ..< \<delta>}\<close> have "no_collision_react ({\<delta>} \<union> {0 ..< \<delta>})"
    using no_collision_union[of "{\<delta>}" "{0 ..< \<delta>}"] by auto
  moreover have "{\<delta>} \<union> {0 ..< \<delta>} = {0 .. \<delta>}" using pos_react by auto
  ultimately show "no_collision_react {0 .. \<delta>}" by auto
qed

lemma collision_after_delta:
  assumes "s\<^sub>o \<le> u_max"
  assumes "u_max < other.s_stop"
  shows "collision_react {0 ..} \<longleftrightarrow> collision_react {\<delta>..}"
proof
  assume "collision_react {0 ..}"
  have "no_collision_react {0 .. \<delta>}" by (rule no_collision_react_initially[OF assms])
  with \<open>collision_react {0..}\<close> have "collision_react ({0..} - {0 .. \<delta>})"
  using pos_react by (auto intro: collision_trim_subset)

  moreover have "{0..} - {0 .. \<delta>} = {\<delta> <..}" using pos_react by auto
  ultimately have "collision_react {\<delta> <..}" by auto
  thus "collision_react {\<delta> ..}" by (auto intro:collision_react_subset)
next
  assume "collision_react {\<delta>..}"
  moreover have "{\<delta>..} \<subseteq> {0 ..}" using pos_react by auto
  ultimately show "collision_react {0 ..}" by (rule collision_react_subset)
qed

lemma collision_react_strict:
  assumes "s\<^sub>o \<le> u_max"
  assumes "u_max < other.s_stop"
  shows "collision_react {\<delta> ..} \<longleftrightarrow> collision_react {\<delta> <..}"
proof
  assume asm: "collision_react {\<delta> ..}"
  have "no_collision_react {\<delta>}" using no_collision_delta unfolding collision_react_def by auto
  thm collision_trim_subset
  moreover have "{\<delta> <..} \<subseteq> {\<delta> ..}" by auto
  ultimately have "collision_react ({\<delta> ..} - {\<delta>})" using asm collision_trim_subset by simp
  moreover have "{\<delta> <..} = {\<delta> ..} - {\<delta>}" by auto
  ultimately show "collision_react {\<delta> <..}" by auto
next
  assume "collision_react {\<delta> <..}"
  thus "collision_react {\<delta> ..}"
    using collision_react_subset[where t="{\<delta> ..}" and s="{\<delta> <..}"] by fastforce
qed

lemma delayed_other_s_stop_eq: "delayed_safe_distance.other.s_stop = other.s_stop"
proof (unfold other.s_t_stop; unfold delayed_safe_distance.other.s_t_stop; unfold movement.p_max_eq)
  have "\<delta> \<le> other.t_stop \<or> other.t_stop < \<delta>" by auto

  moreover
  { assume "\<delta> \<le> other.t_stop"
    hence "other.s \<delta> - (other.s' \<delta>)\<^sup>2 / a\<^sub>o / 2 = s\<^sub>o - v\<^sub>o\<^sup>2 / a\<^sub>o / 2"
    unfolding other.s_def other.s'_def
    using  pos_react decelerate_other
    by (auto simp add: other.p_def other.p'_def power2_eq_square algebra_simps divide_simps) }

  moreover
  { assume "other.t_stop < \<delta>"
    hence "other.s \<delta> - (other.s' \<delta>)\<^sup>2 / a\<^sub>o / 2 = s\<^sub>o - v\<^sub>o\<^sup>2 / a\<^sub>o / 2"
    unfolding other.s_def other.s'_def other.p_max_eq
    using pos_react decelerate_other
    by (auto) }

  ultimately show "other.s \<delta> - (other.s' \<delta>)\<^sup>2 / a\<^sub>o / 2 = s\<^sub>o - v\<^sub>o\<^sup>2 / a\<^sub>o / 2" by auto
qed

lemma delayed_cond3':
  assumes "other.s \<delta> \<le> u_max"
  assumes "u_max < other.s_stop"
  shows "delayed_safe_distance.collision {0 ..} \<longleftrightarrow>
          (a\<^sub>o > a\<^sub>e \<and> other.s' \<delta> < v\<^sub>e \<and> other.s \<delta> - ego.q \<delta> \<le> delayed_safe_distance.snd_safe_distance \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * other.s' \<delta> < 0)"
  proof (rule delayed_safe_distance.cond_3')
    have "other.s \<delta> \<le> u_max" using \<open>other.s \<delta> \<le> u_max\<close> .
    also have "... = ego2.s_stop" unfolding u_max_eq ego2.s_t_stop ego2.p_max_eq by (rule refl)
    finally show "other.s \<delta> \<le> ego2.s_stop" by auto
  next
    have "ego2.s_stop = u_max" unfolding ego2.s_t_stop ego2.p_max_eq u_max_eq by (rule refl)
    also have "... < other.s_stop" using assms by auto
    also have "... \<le> delayed_safe_distance.other.s_stop" using delayed_other_s_stop_eq by auto
    finally show "ego2.s_stop < delayed_safe_distance.other.s_stop" by auto
  qed

lemma delayed_other_t_stop_eq:
  assumes "\<delta> \<le> other.t_stop"
  shows "delayed_safe_distance.other.t_stop + \<delta> = other.t_stop"
  using assms decelerate_other
  unfolding delayed_safe_distance.other.t_stop_def other.t_stop_def other.s'_def
            movement.t_stop_def other.p'_def
  by (auto simp add:algebra_simps divide_simps)

lemma delayed_other_s_eq:
  assumes "0 \<le> t"
  shows "delayed_safe_distance.other.s t = other.s (t + \<delta>)"
proof (cases "\<delta> \<le> other.t_stop")
  assume 1: "\<delta> \<le> other.t_stop"
  have "t + \<delta> \<le> other.t_stop \<or> other.t_stop < t + \<delta>" by auto
  moreover
  { assume "t + \<delta> \<le> other.t_stop"
    hence "delayed_safe_distance.other.s t = delayed_safe_distance.other.p t"
      using delayed_other_t_stop_eq [OF 1] assms
      unfolding delayed_safe_distance.other.s_def by auto

    also have "... = other.p (t + \<delta>)"
      unfolding movement.p_def other.s_def other.s'_def other.p'_def
      using pos_react 1
      by (auto simp add: power2_eq_square divide_simps algebra_simps)

    also have "... = other.s (t + \<delta>)"
      unfolding other.s_def
      using assms pos_react \<open>t + \<delta> \<le> other.t_stop\<close> by auto

    finally have "delayed_safe_distance.other.s t = other.s (t + \<delta>)" by auto }

  moreover
  { assume "other.t_stop < t + \<delta>"
    hence "delayed_safe_distance.other.s t = delayed_safe_distance.other.p_max"
      using delayed_other_t_stop_eq [OF 1] assms delayed_safe_distance.other.t_stop_nonneg
      unfolding delayed_safe_distance.other.s_def by auto

    also have "... = other.p_max"
      unfolding movement.p_max_eq other.s_def other.s'_def other.p_def other.p'_def
      using pos_react 1 decelerate_other
      by (auto simp add:power2_eq_square divide_simps algebra_simps)

    also have "... = other.s (t + \<delta>)"
      unfolding other.s_def
      using assms pos_react \<open>other.t_stop < t + \<delta>\<close> by auto

    finally have "delayed_safe_distance.other.s t = other.s (t + \<delta>)" by auto }

  ultimately show ?thesis by auto
next
  assume "\<not> \<delta> \<le> other.t_stop"
  hence "other.t_stop < \<delta>" by auto
  hence "other.s' \<delta> = 0" and "other.s \<delta> = other.p_max"
    unfolding other.s'_def other.s_def using pos_react by auto
  hence "delayed_safe_distance.other.s t = delayed_safe_distance.other.p_max"
    unfolding delayed_safe_distance.other.s_def using assms decelerate_other
    by (auto simp add:movement.p_max_eq movement.p_def movement.t_stop_def)
  also have "... = other.p_max"
    unfolding movement.p_max_eq using \<open>other.s' \<delta> = 0\<close> \<open>other.s \<delta> = other.p_max\<close>
    using other.p_max_eq by auto
  also have "... = other.s (t + \<delta>)"
    unfolding other.s_def using pos_react assms \<open>other.t_stop < \<delta>\<close> by auto
  finally show "delayed_safe_distance.other.s t = other.s (t + \<delta>)" by auto
qed

lemma translate_collision_range:
  assumes "s\<^sub>o \<le> u_max"
  assumes "u_max < other.s_stop"
  shows "delayed_safe_distance.collision {0 ..} \<longleftrightarrow> collision_react {\<delta> ..}"
proof
  assume "delayed_safe_distance.collision {0 ..}"
  then obtain t where eq: "ego2.s t = delayed_safe_distance.other.s t" and "0 \<le> t"
    unfolding delayed_safe_distance.collision_def by auto

  have "ego2.s t = (ego2.s \<circ> \<tau>) (t + \<delta>)" unfolding comp_def \<tau>_def by auto
  also have "... = u (t + \<delta>)" unfolding u_def using \<open>0 \<le> t\<close> pos_react
    by (auto simp: \<tau>_def ego2.init_s)
  finally have left:"ego2.s t = u (t + \<delta>)" by auto

  have right: "delayed_safe_distance.other.s t = other.s (t + \<delta>)"
    using delayed_other_s_eq pos_react \<open>0 \<le> t\<close> by auto

  with eq and left have "u (t + \<delta>) = other.s (t + \<delta>)" by auto
  moreover have "\<delta> \<le> t + \<delta>" using \<open>0 \<le> t\<close> by auto
  ultimately show "collision_react {\<delta> ..}" unfolding collision_react_def by auto
next
  assume "collision_react {\<delta> ..}"
  hence "collision_react {\<delta> <..}" using collision_react_strict[OF assms] by simp
  then obtain t where eq: "u t = other.s t" and "\<delta> < t"
    unfolding collision_react_def by auto
  moreover hence "u t = (ego2.s \<circ> \<tau>) t" unfolding u_def using pos_react by auto
  moreover have "other.s t = delayed_safe_distance.other.s (t - \<delta>)"
    using delayed_other_s_eq \<open>\<delta> < t\<close> by auto
  ultimately have "ego2.s (t - \<delta>) = delayed_safe_distance.other.s (t - \<delta>)"
    unfolding comp_def \<tau>_def by auto
  with \<open>\<delta> < t\<close> show "delayed_safe_distance.collision {0 ..}"
    unfolding delayed_safe_distance.collision_def by auto
qed

theorem cond_3r_2:
  assumes "s\<^sub>o \<le> u_max"
  assumes "u_max < other.s_stop"
  assumes "other.s \<delta> \<le> u_max"
  shows "collision_react {0 ..} \<longleftrightarrow>
         (a\<^sub>o > a\<^sub>e \<and> other.s' \<delta> < v\<^sub>e \<and> other.s \<delta> -  ego.q \<delta> \<le> delayed_safe_distance.snd_safe_distance \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * other.s' \<delta> < 0)"
proof -
  have "collision_react {0 ..} \<longleftrightarrow> collision_react {\<delta> ..}" by (rule collision_after_delta[OF assms(1) assms(2)])
  also have "... \<longleftrightarrow> delayed_safe_distance.collision {0 ..}" by (simp add: translate_collision_range[OF assms(1) assms(2)])
  also have "... \<longleftrightarrow>  (a\<^sub>o > a\<^sub>e \<and> other.s' \<delta> < v\<^sub>e \<and> other.s \<delta> -  ego.q \<delta> \<le> delayed_safe_distance.snd_safe_distance \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * other.s' \<delta> < 0)"
    by (rule delayed_cond3'[OF assms(3) assms(2)])
  finally show "collision_react {0 ..} \<longleftrightarrow>  (a\<^sub>o > a\<^sub>e \<and> other.s' \<delta> < v\<^sub>e \<and> other.s \<delta> -  ego.q \<delta> \<le> delayed_safe_distance.snd_safe_distance \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * other.s' \<delta> < 0)"
    by auto
qed

lemma sd_2r_correct_for_3r_2:
  assumes "s\<^sub>o - s\<^sub>e > safe_distance_2r"
  assumes "other.s \<delta> \<le> u_max"
  assumes "\<not> (a\<^sub>o > a\<^sub>e \<and> other.s' \<delta> < v\<^sub>e \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * other.s' \<delta> < 0)"
  shows "no_collision_react {0..}"
proof -
  from assms have "s\<^sub>o - s\<^sub>e > v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o" unfolding safe_distance_2r_def by auto
  hence "s\<^sub>o - v\<^sub>o\<^sup>2 / 2 / a\<^sub>o > s\<^sub>e + v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e" by auto
  hence "s\<^sub>o - v\<^sub>o\<^sup>2 / a\<^sub>o + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o > s\<^sub>e + v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e" by auto
  hence "s\<^sub>o + v\<^sub>o * (- v\<^sub>o / a\<^sub>o) + 1/2 * a\<^sub>o * (-v\<^sub>o / a\<^sub>o)\<^sup>2 > s\<^sub>e + v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e"
    using other.p_def other.p_max_def other.p_max_eq other.t_stop_def by auto
  hence "other.s_stop > u_max" unfolding other.s_def using u_max_eq other.t_stop_def
    using ego.q_def other.p_def other.p_max_def other.s_def other.s_t_stop by auto
  thus ?thesis
    using assms(2) assms(3) collision_after_delta cond_1r delayed_cond3' translate_collision_range by linarith
qed

lemma sd2_at_most_sd4:
  assumes "a\<^sub>o > a\<^sub>e"
  shows "safe_distance_2r \<le> safe_distance_4r"
proof -
  have "a\<^sub>o \<noteq> 0" and "a\<^sub>e \<noteq> 0" and "a\<^sub>o - a\<^sub>e \<noteq> 0" and "0 < 2 * (a\<^sub>o - a\<^sub>e)" using hyps assms(1) by auto
  have "0 \<le> (- v\<^sub>e * a\<^sub>o + v\<^sub>o * a\<^sub>e + a\<^sub>o * a\<^sub>e * \<delta>) * (- v\<^sub>e * a\<^sub>o + v\<^sub>o * a\<^sub>e + a\<^sub>o * a\<^sub>e * \<delta>)"
    (is "0 \<le> (?l1 + ?l2 + ?l3) * ?r") by auto
  also have "... = v\<^sub>e\<^sup>2 * a\<^sub>o\<^sup>2 + v\<^sub>o\<^sup>2 * a\<^sub>e\<^sup>2 + a\<^sub>o\<^sup>2 * a\<^sub>e\<^sup>2 * \<delta>\<^sup>2 - 2 * v\<^sub>e * a\<^sub>o * v\<^sub>o * a\<^sub>e - 2 * a\<^sub>o\<^sup>2 * a\<^sub>e * \<delta> * v\<^sub>e + 2 * a\<^sub>o * a\<^sub>e\<^sup>2 * \<delta> * v\<^sub>o"
    (is "?lhs = ?rhs")
    by (auto simp add:algebra_simps power_def)
  finally have "0 \<le> ?rhs" by auto
  hence "(- v\<^sub>e\<^sup>2 * a\<^sub>o / a\<^sub>e - v\<^sub>o\<^sup>2 * a\<^sub>e / a\<^sub>o) * (a\<^sub>o * a\<^sub>e) \<le> (a\<^sub>o * a\<^sub>e * \<delta>\<^sup>2 - 2 * v\<^sub>e * v\<^sub>o - 2 * a\<^sub>o * \<delta> * v\<^sub>e + 2 * a\<^sub>e * \<delta> * v\<^sub>o) * (a\<^sub>o * a\<^sub>e)"
    by (auto simp add: algebra_simps power_def)
  hence "2 * v\<^sub>e * \<delta> * (a\<^sub>o - a\<^sub>e) - v\<^sub>e\<^sup>2 * a\<^sub>o / a\<^sub>e + v\<^sub>e\<^sup>2 + v\<^sub>o\<^sup>2 - v\<^sub>o\<^sup>2 * a\<^sub>e / a\<^sub>o \<le> v\<^sub>o\<^sup>2 + a\<^sub>o\<^sup>2 * \<delta>\<^sup>2 + v\<^sub>e\<^sup>2 + 2 * v\<^sub>o * \<delta> * a\<^sub>o - 2 * v\<^sub>e * v\<^sub>o - 2 * a\<^sub>o * \<delta> * v\<^sub>e - 2 * v\<^sub>o * \<delta> * a\<^sub>o + 2 * a\<^sub>e * \<delta> * v\<^sub>o - a\<^sub>o\<^sup>2 * \<delta>\<^sup>2 + a\<^sub>o * a\<^sub>e * \<delta>\<^sup>2 + 2 * v\<^sub>e * \<delta> * (a\<^sub>o - a\<^sub>e)"
    by (auto simp add: ego2.decel other.decel)
  hence "2 * v\<^sub>e * \<delta> * (a\<^sub>o - a\<^sub>e) - v\<^sub>e\<^sup>2 * a\<^sub>o / a\<^sub>e + v\<^sub>e\<^sup>2 + v\<^sub>o\<^sup>2 - v\<^sub>o\<^sup>2 * a\<^sub>e / a\<^sub>o \<le> (v\<^sub>o + \<delta> * a\<^sub>o - v\<^sub>e)\<^sup>2 - 2 * v\<^sub>o * \<delta> * a\<^sub>o + 2 * a\<^sub>e * \<delta> * v\<^sub>o - a\<^sub>o\<^sup>2 * \<delta>\<^sup>2 + a\<^sub>o * a\<^sub>e * \<delta>\<^sup>2 + 2 * v\<^sub>e * \<delta> * (a\<^sub>o - a\<^sub>e)"
    by (auto simp add: algebra_simps power_def)
  hence "v\<^sub>e * \<delta> * 2 * (a\<^sub>o - a\<^sub>e) - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e * 2 * a\<^sub>o + v\<^sub>e\<^sup>2 / 2 / a\<^sub>e * 2 * a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o * 2 * a\<^sub>o - v\<^sub>o\<^sup>2 / 2 / a\<^sub>o * 2 * a\<^sub>e \<le> (v\<^sub>o + \<delta> * a\<^sub>o - v\<^sub>e)\<^sup>2 - v\<^sub>o * \<delta> * 2 * a\<^sub>o - v\<^sub>o * \<delta> * 2 * -a\<^sub>e - a\<^sub>o * \<delta>\<^sup>2 / 2 * 2 * a\<^sub>o - a\<^sub>o * \<delta>\<^sup>2 / 2 * 2 * -a\<^sub>e + v\<^sub>e * \<delta> * 2 * (a\<^sub>o - a\<^sub>e)"
    (is "?lhs1 \<le> ?rhs1")
    by (simp add: \<open>a\<^sub>o \<noteq> 0\<close> \<open>a\<^sub>e \<noteq> 0\<close> power2_eq_square algebra_simps)
  hence "v\<^sub>e * \<delta> * 2 * (a\<^sub>o - a\<^sub>e) - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e * 2 * (a\<^sub>o - a\<^sub>e) + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o * 2 * (a\<^sub>o - a\<^sub>e) \<le> (v\<^sub>o + a\<^sub>o * \<delta> - v\<^sub>e)\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e) * 2 * (a\<^sub>o - a\<^sub>e) - v\<^sub>o * \<delta> * 2 * (a\<^sub>o - a\<^sub>e) - a\<^sub>o * \<delta>\<^sup>2 / 2 * 2 * (a\<^sub>o - a\<^sub>e) + v\<^sub>e * \<delta> * 2 *(a\<^sub>o - a\<^sub>e)"
    (is "?lhs2 \<le> ?rhs2")
  proof -
    assume "?lhs1 \<le> ?rhs1"
    have "?lhs1 = ?lhs2" by (auto simp add:field_simps)
    moreover
    have "?rhs1 = ?rhs2" using `a\<^sub>o - a\<^sub>e \<noteq> 0` by (auto simp add:field_simps)
    ultimately show ?thesis using `?lhs1 \<le> ?rhs1` by auto
  qed
  hence "(v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o) * 2 * (a\<^sub>o - a\<^sub>e) \<le> ((v\<^sub>o + a\<^sub>o * \<delta> - v\<^sub>e)\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e) - v\<^sub>o * \<delta> - 1/2 * a\<^sub>o * \<delta>\<^sup>2 + v\<^sub>e * \<delta>) * 2 *(a\<^sub>o - a\<^sub>e)"
    by (simp add: algebra_simps)
  hence "v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o \<le> (v\<^sub>o + a\<^sub>o * \<delta> - v\<^sub>e)\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e) - v\<^sub>o * \<delta> - 1/2 * a\<^sub>o * \<delta>\<^sup>2 + v\<^sub>e * \<delta>"
    using \<open>a\<^sub>o > a\<^sub>e\<close> real_mult_le_cancel_iff1[OF `0 < 2 * (a\<^sub>o - a\<^sub>e)`, of "(v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o)"
    "(v\<^sub>o + a\<^sub>o * \<delta> - v\<^sub>e)\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e) - v\<^sub>o * \<delta> - 1/2 * a\<^sub>o * \<delta>\<^sup>2 + v\<^sub>e * \<delta>"] semiring_normalization_rules(18)
    by (metis (no_types, lifting) real_mult_le_cancel_iff1)
  thus ?thesis using safe_distance_2r_def safe_distance_4r_def by auto
qed

lemma sd_4r_correct:
  assumes "s\<^sub>o - s\<^sub>e > safe_distance_4r"
  assumes "other.s \<delta> \<le> u_max"
  assumes "\<delta> \<le> other.t_stop"
  assumes "a\<^sub>o > a\<^sub>e"
  shows "no_collision_react {0..}"
proof -
  from assms have "s\<^sub>o - s\<^sub>e > (v\<^sub>o + a\<^sub>o * \<delta> - v\<^sub>e)\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e) - v\<^sub>o * \<delta> - 1/2 * a\<^sub>o * \<delta>\<^sup>2 + v\<^sub>e * \<delta>"
    unfolding safe_distance_4r_def by auto
  hence "s\<^sub>o + v\<^sub>o * \<delta> + 1/2 * a\<^sub>o * \<delta>\<^sup>2 - s\<^sub>e - v\<^sub>e * \<delta> > (v\<^sub>o + a\<^sub>o * \<delta> - v\<^sub>e)\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e)" by linarith
  hence "other.s \<delta> -  ego.q \<delta> > (other.s' \<delta> - v\<^sub>e)\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e)"
    using assms(3) ego.q_def other.p_def other.s_def other.p'_def other.s'_def pos_react by auto
  hence "other.s \<delta> -  ego.q \<delta> > delayed_safe_distance.snd_safe_distance"
    by (simp add: delayed_safe_distance.snd_safe_distance_def)
  hence c: "\<not> (other.s \<delta> -  ego.q \<delta> \<le> delayed_safe_distance.snd_safe_distance)" by linarith
  have "u_max < other.s_stop"
    unfolding u_max_eq other.s_t_stop other.p_max_eq ego.q_def using assms(1) sd2_at_most_sd4[OF assms(4)]
    unfolding safe_distance_4r_def safe_distance_2r_def by auto
  consider "s\<^sub>o \<le> u_max" | "s\<^sub>o > u_max" by linarith
  thus ?thesis
  proof (cases)
    case 1
    from cond_3r_2[OF this `u_max < other.s_stop` assms(2)]  show ?thesis
      using c by auto
  next
    case 2
    then show ?thesis using cond_1r by auto
  qed
qed

(*irrelevant since this safe_distance is unreachable in the checker*)
definition safe_distance_5r::real where "safe_distance_5r = v\<^sub>e\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e) + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o + v\<^sub>e * \<delta>"

lemma sd_5r_correct:
  assumes "s\<^sub>o - s\<^sub>e > safe_distance_5r"
  assumes "u_max < other.s_stop"
  assumes "other.s \<delta> \<le> u_max"
  assumes "\<delta> > other.t_stop"
  shows "no_collision_react {0..}"
proof -
  from assms have "s\<^sub>o - s\<^sub>e > v\<^sub>e\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e) + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o + v\<^sub>e * \<delta>"
    unfolding safe_distance_5r_def by auto
  hence "s\<^sub>o + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o - s\<^sub>e - v\<^sub>e * \<delta> > (0 - v\<^sub>e)\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e)"
    by (smt assms(2) assms(3) assms(4) other.s_def other.s_t_stop)
  hence "other.s \<delta> -  ego.q \<delta> > (other.s' \<delta> - v\<^sub>e)\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e)"
    using assms(2) assms(3) assms(4) other.s_def other.s_t_stop by auto
  hence "other.s \<delta> -  ego.q \<delta> > delayed_safe_distance.snd_safe_distance"
    by (simp add: delayed_safe_distance.snd_safe_distance_def)
  hence "\<not> (other.s \<delta> -  ego.q \<delta> \<le> delayed_safe_distance.snd_safe_distance)" by linarith
  thus ?thesis using assms(2) assms(3) cond_1r cond_3r_2 by linarith
qed

(*lemma sd_25:
  assumes "a\<^sub>o > a\<^sub>e"
  assumes "\<delta> > other.t_stop"
  shows "safe_distance_2r \<le> safe_distance_5r"
proof -
  from assms
  have "(a\<^sub>o - a\<^sub>e) > 0" using assms(1) by simp
  hence "- v\<^sub>e\<^sup>2 \<le> 0" by simp
  hence  "- v\<^sub>e\<^sup>2 * 2 * a\<^sub>o / 2 / a\<^sub>e \<le> 0"
    by (smt divide_le_0_iff mult_nonpos_nonpos other.decel real_sum_of_halves safe_distance.decelerate_ego safe_distance_axioms)
  hence "- v\<^sub>e\<^sup>2 * 2 * a\<^sub>o / 2 / a\<^sub>e +  v\<^sub>e\<^sup>2 \<le> v\<^sub>e\<^sup>2" by linarith
  hence "- v\<^sub>e\<^sup>2 / 2 / a\<^sub>e * 2 * a\<^sub>o - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e * (- 2 * a\<^sub>e) \<le> v\<^sub>e\<^sup>2" by simp
  hence "- v\<^sub>e\<^sup>2 / 2 / a\<^sub>e * (2 * a\<^sub>o - 2 * a\<^sub>e) \<le> v\<^sub>e\<^sup>2"
    proof -
      have f1: "a\<^sub>o * (2 * (- v\<^sub>e\<^sup>2 / 2 / a\<^sub>e)) - a\<^sub>e * - 2 * (v\<^sub>e\<^sup>2 / 2 / a\<^sub>e) \<le> v\<^sub>e\<^sup>2"
        by (metis \<open>- v\<^sub>e\<^sup>2 / 2 / a\<^sub>e * 2 * a\<^sub>o - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e * (- 2 * a\<^sub>e) \<le> v\<^sub>e\<^sup>2\<close> mult.commute)
      have f2: "\<And>r ra. - ((r::real) * ra) = ra * - r"
        by simp
      have "\<And>r ra rb. (r::real) * (ra * rb) = r * rb * ra"
        by simp
      then show ?thesis
        using f2 f1 by (metis (no_types) divide_minus_left left_diff_distrib mult.commute mult.left_commute mult_minus_right)
    qed
  hence "2 * (a\<^sub>o - a\<^sub>e) * (- v\<^sub>e\<^sup>2 / 2 / a\<^sub>e) \<le> 2 * (a\<^sub>o - a\<^sub>e)  * v\<^sub>e\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e)" by (simp add: mult.commute)
  hence "(a\<^sub>o - a\<^sub>e) * (- v\<^sub>e\<^sup>2 / 2 / a\<^sub>e) \<le> (a\<^sub>o - a\<^sub>e) * v\<^sub>e\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e)" using Real.real_mult_le_cancel_iff2 by linarith
  hence "- v\<^sub>e\<^sup>2 / 2 / a\<^sub>e \<le> v\<^sub>e\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e)"
    using \<open>0 < a\<^sub>o - a\<^sub>e\<close> real_mult_le_cancel_iff1 by blast
  hence "v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o \<le> v\<^sub>e\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e) + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o + v\<^sub>e * \<delta>" by linarith
  thus ?thesis using safe_distance_2r_def safe_distance_5r_def by linarith
qed *)

lemma translate_no_collision_range:
  "delayed_safe_distance.no_collision {0 ..} \<longleftrightarrow> no_collision_react {\<delta> ..}"
proof
  assume left: "delayed_safe_distance.no_collision {0 ..}"
  show "no_collision_react {\<delta> ..}"
  proof (unfold collision_react_def; simp; rule ballI)
    fix t::real
    assume "t \<in> {\<delta> ..}"
    hence "\<delta> \<le> t" by simp
    with pos_react have "0 \<le> t - \<delta>" by simp
    with left have ineq: "ego2.s (t - \<delta>) \<noteq> delayed_safe_distance.other.s (t - \<delta>)"
      unfolding delayed_safe_distance.collision_def by auto

    (* TODO: abstract this part. This is copied from  lemma translate_collision_range *)
    have "ego2.s (t - \<delta>) = (ego2.s \<circ> \<tau>) t" unfolding comp_def \<tau>_def by auto
    also have "... = u t" unfolding u_def using \<open>\<delta> \<le> t\<close> pos_react
      by (auto simp: \<tau>_def ego2.init_s)
    finally have "ego2.s (t - \<delta>) = u t" by auto

    moreover have "delayed_safe_distance.other.s (t - \<delta>) = other.s t"
      using delayed_other_s_eq pos_react \<open>\<delta> \<le> t\<close> by auto

    ultimately show "u t \<noteq> other.s t" using ineq by auto
  qed
next
  assume right:"no_collision_react {\<delta> ..}"
  show "delayed_safe_distance.no_collision {0 ..}"
  proof (unfold delayed_safe_distance.collision_def; simp; rule ballI)
    fix t ::real
    assume "t \<in> {0 ..}"
    hence "0 \<le> t" by auto
    hence "\<delta> \<le> t + \<delta>" by auto
    with right have ineq: "u (t + \<delta>) \<noteq> other.s (t + \<delta>)" unfolding collision_react_def by auto

    have "u (t + \<delta>) = ego2.s t" unfolding u_def comp_def \<tau>_def
      using \<open>0 \<le> t\<close> pos_react \<open>\<delta> \<le> t+ \<delta>\<close> by (auto simp add:ego2.init_s)
    moreover have "other.s (t + \<delta>) = delayed_safe_distance.other.s t"
      using delayed_other_s_eq[of t] using \<open>0 \<le> t\<close> by auto
    ultimately show "ego2.s t \<noteq> delayed_safe_distance.other.s t" using ineq by auto
  qed
qed

lemma delayed_cond1:
  assumes "other.s \<delta> > u_max"
  shows "delayed_safe_distance.no_collision {0 ..}"
proof -
  have "ego2.s_stop = u_max"  unfolding ego2.s_t_stop ego2.p_max_eq u_max_eq by auto
  also have "... < other.s \<delta>" using assms by simp
  finally have "ego2.s_stop < other.s \<delta>" by auto
  thus "delayed_safe_distance.no_collision {0 ..}" by (simp add: delayed_safe_distance.cond_1)
qed

theorem cond_3r_3:
  assumes "s\<^sub>o \<le> u_max"
  assumes "u_max < other.s_stop"
  assumes "other.s \<delta> > u_max"
  shows "no_collision_react {0 ..}"
proof -
  have eq: "{0 ..} = {0 .. \<delta>} \<union> {\<delta> ..}" using pos_react by auto
  show ?thesis unfolding eq
  proof (intro no_collision_union)
    show "no_collision_react {0 .. \<delta>}" by (rule no_collision_react_initially[OF assms(1) assms(2)])
  next
    have "delayed_safe_distance.no_collision {0 ..}" by (rule delayed_cond1[OF assms(3)])
    with translate_no_collision_range show "no_collision_react {\<delta> ..}" by auto
  qed
qed

lemma sd_2r_correct_for_3r_3:
  assumes "s\<^sub>o - s\<^sub>e > safe_distance_2r"
  assumes "other.s \<delta> > u_max"
  shows "no_collision_react {0..}"
proof -
  from assms have "s\<^sub>o - s\<^sub>e > v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o" unfolding safe_distance_2r_def by auto
  hence "s\<^sub>o - v\<^sub>o\<^sup>2 / 2 / a\<^sub>o > s\<^sub>e + v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e" by auto
  hence "s\<^sub>o - v\<^sub>o\<^sup>2 / a\<^sub>o + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o > s\<^sub>e + v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e" by auto
  hence "s\<^sub>o + v\<^sub>o * (- v\<^sub>o / a\<^sub>o) + 1/2 * a\<^sub>o * (-v\<^sub>o / a\<^sub>o)\<^sup>2 > s\<^sub>e + v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e"
    using other.p_def other.p_max_def other.p_max_eq other.t_stop_def by auto
  hence "other.s_stop > u_max" unfolding other.s_def using u_max_eq other.t_stop_def
    using ego.q_def other.p_def other.p_max_def other.s_def other.s_t_stop by auto
  thus ?thesis
    using assms(2) cond_1r cond_3r_3 by linarith
qed

lemma sd_3r_correct:
  assumes "s\<^sub>o - s\<^sub>e > safe_distance_3r"
  assumes "\<delta> \<le> other.t_stop"
  shows "no_collision_react {0 ..}"
proof -
  from assms have "s\<^sub>o - s\<^sub>e > v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e - v\<^sub>o * \<delta> - 1/2 * a\<^sub>o * \<delta>\<^sup>2" unfolding safe_distance_3r_def by auto
  hence "s\<^sub>o + v\<^sub>o * \<delta> + 1/2 * a\<^sub>o * \<delta>\<^sup>2 > s\<^sub>e + v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e" by auto
  hence "other.s \<delta> > u_max" using other.s_def u_max_eq assms(2) ego.q_def other.p_def pos_react by auto
  thus ?thesis using cond_1r cond_3r_3 delayed_other_s_stop_eq delayed_safe_distance.other.s0_le_s_stop by linarith
qed

lemma sd_2_at_least_sd_3:
  assumes "\<delta> \<le> other.t_stop"
  shows "safe_distance_3r \<ge> safe_distance_2r"
proof -
  from assms have "\<delta> = other.t_stop \<or> \<delta> < other.t_stop" by auto
  then have "safe_distance_3r = safe_distance_2r \<or> safe_distance_3r > safe_distance_2r"
  proof (rule Meson.disj_forward)
      assume "\<delta> = other.t_stop"
      hence "\<delta> = - v\<^sub>o / a\<^sub>o" unfolding other.t_stop_def by auto
      hence "- v\<^sub>o * \<delta> - 1/2 * a\<^sub>o * \<delta>\<^sup>2 = - v\<^sub>o  * other.t_stop - 1/2 * a\<^sub>o * other.t_stop\<^sup>2" by (simp add: movement.t_stop_def)
      thus "safe_distance_3r = safe_distance_2r"
        using other.p_def other.p_max_def other.p_max_eq safe_distance_2r_def safe_distance_3r_def by auto
    next
      assume "\<delta> < other.t_stop"
      hence "\<delta> < - v\<^sub>o / a\<^sub>o" unfolding other.t_stop_def by auto
      hence "0 < v\<^sub>o + a\<^sub>o * \<delta>"
        by (smt divide_right_mono_neg nonzero_mult_div_cancel_left other.decel)
      hence "0 < v\<^sub>o + 1/2 * a\<^sub>o * (\<delta> + other.t_stop)" by (auto simp add:field_simps other.t_stop_def)
      hence "0 > v\<^sub>o * (\<delta> - other.t_stop) + 1/2 * a\<^sub>o * (\<delta> + other.t_stop) * (\<delta> - other.t_stop)"
        by (smt \<open>\<delta> < other.t_stop\<close> linordered_field_class.sign_simps(35) linordered_field_class.sign_simps(45))
      hence " (\<delta> + other.t_stop) * (\<delta> - other.t_stop) = (\<delta>\<^sup>2 - other.t_stop\<^sup>2)"
        by (simp add: power2_eq_square square_diff_square_factored)
      hence "0 > v\<^sub>o * (\<delta> - other.t_stop) + 1/2 * a\<^sub>o * (\<delta>\<^sup>2 - other.t_stop\<^sup>2)"
        by (metis (no_types, hide_lams) \<open>v\<^sub>o * (\<delta> - other.t_stop) + 1 / 2 * a\<^sub>o * (\<delta> + other.t_stop) * (\<delta> - other.t_stop) < 0\<close> divide_divide_eq_left divide_divide_eq_right times_divide_eq_left)
      hence "0 > v\<^sub>o * \<delta> - v\<^sub>o * other.t_stop  + 1/2 * a\<^sub>o * \<delta>\<^sup>2 -  1/2 * a\<^sub>o * other.t_stop\<^sup>2 "
        by (simp add: linordered_field_class.sign_simps(38))
      hence "- v\<^sub>o * \<delta> - 1/2 * a\<^sub>o * \<delta>\<^sup>2 > - v\<^sub>o  * (- v\<^sub>o / a\<^sub>o) - 1/2 * a\<^sub>o * (- v\<^sub>o / a\<^sub>o)\<^sup>2"  by (smt movement.t_stop_def mult_minus_left)
      thus "safe_distance_3r > safe_distance_2r"
        using other.p_def other.p_max_def other.p_max_eq other.t_stop_def safe_distance_2r_def safe_distance_3r_def by auto
  qed
  thus ?thesis by auto
qed
end

subsubsection \<open>Designing Checker\<close>
(* checker function *)
definition rel_dist_to_stop :: "real \<Rightarrow> real \<Rightarrow> real" where
"rel_dist_to_stop v a \<equiv> - v\<^sup>2 / (2 * a)"
definition "rel_dist_to_stop_expr v a = Mult (Minus (Power (Var v) 2)) (Inverse (Mult (Num 2) (Var a)))"
definition "rel_dist_to_stop' p v a = approx p (rel_dist_to_stop_expr 0 1) [v, a]"
lemma rel_dist_to_stop': "interpret_floatarith (rel_dist_to_stop_expr 0 1) [v, a] = rel_dist_to_stop v a"
  by (simp add: rel_dist_to_stop_def rel_dist_to_stop_expr_def inverse_eq_divide)

definition first_safe_dist :: "real \<Rightarrow> real \<Rightarrow> real" where
"first_safe_dist v\<^sub>e a\<^sub>e \<equiv> rel_dist_to_stop v\<^sub>e a\<^sub>e"

definition second_safe_dist :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real" where
"second_safe_dist v\<^sub>e a\<^sub>e v\<^sub>o a\<^sub>o \<equiv> rel_dist_to_stop v\<^sub>e a\<^sub>e - rel_dist_to_stop v\<^sub>o a\<^sub>o"
definition "second_safe_dist_expr ve ae vo ao =
  Add (rel_dist_to_stop_expr ve ae) (Minus (rel_dist_to_stop_expr vo ao))"
definition "second_safe_dist' p v\<^sub>e a\<^sub>e v\<^sub>o a\<^sub>o = approx p (second_safe_dist_expr 0 1 2 3) [v\<^sub>e, a\<^sub>e, v\<^sub>o, a\<^sub>o]"
lemma second_safe_dist':
  "interpret_floatarith (second_safe_dist_expr 0 1 2 3) [v, a, v', a'] = second_safe_dist v a v' a'"
  by (simp add: second_safe_dist_def second_safe_dist_expr_def rel_dist_to_stop_def rel_dist_to_stop_expr_def inverse_eq_divide)

definition t_stop :: "real \<Rightarrow> real \<Rightarrow> real" where
"t_stop v a \<equiv> - v / a"
definition "t_stop_expr v a = Minus (Mult (Var v) (Inverse (Var a)))"

definition s_stop :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real" where
"s_stop s v a \<equiv> s + rel_dist_to_stop v a"

definition discriminant :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real" where
"discriminant s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<equiv> (v\<^sub>o - v\<^sub>e)\<^sup>2 - 2 * (a\<^sub>o - a\<^sub>e) * (s\<^sub>o - s\<^sub>e)"

definition suff_cond_safe_dist2 :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> bool" where
"suff_cond_safe_dist2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<equiv> let D2 = discriminant s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o in
                                             \<not> (a\<^sub>e < a\<^sub>o \<and> v\<^sub>o < v\<^sub>e \<and> 0 \<le> D2 \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o < sqrt D2)"

lemma less_sqrt_iff: "y \<ge> 0 \<Longrightarrow> x < sqrt y \<longleftrightarrow> (x \<ge> 0 \<longrightarrow> x\<^sup>2 < y)"
by (smt real_le_lsqrt real_less_rsqrt real_sqrt_ge_zero)

lemma suff_cond_safe_dist2_code[code]:
  "suff_cond_safe_dist2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o =
    (let D2 = discriminant s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o in
      (a\<^sub>e < a\<^sub>o \<longrightarrow> v\<^sub>o < v\<^sub>e \<longrightarrow> 0 \<le> D2 \<longrightarrow> (v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o \<ge> 0 \<and> (v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o)\<^sup>2 \<ge> D2)))"
  using real_sqrt_ge_zero real_less_rsqrt less_sqrt_iff
  by (auto simp: suff_cond_safe_dist2_def Let_def)

text \<open>
There are two expressions for safe distance. The first safe distance safe_dist1 is always valid.
Whenever the distance is bigger than safe_dist1, it is guarantee to be collision free.

The second one is safe_dist2. If the sufficient condition suff_cond_safe_dist2 is satisfied and
the distance is bigger than safe_dist2, it is guarantee to be collision free.
\<close>

definition "check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<longleftrightarrow> s\<^sub>o > s\<^sub>e \<and> 0 \<le> v\<^sub>e \<and> 0 \<le> v\<^sub>o \<and> a\<^sub>e < 0 \<and> a\<^sub>o < 0 "

(* TODO: get rid of check_precond: *)
lemma check_precond_safe_distance: "check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o = safe_distance a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o"
proof
  assume "safe_distance a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o"
  then interpret safe_distance a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o .
  show "check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o"
    by (auto simp: check_precond_def; fact)
qed (unfold_locales; auto simp: check_precond_def)

definition checker :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> bool" where
"checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<equiv> let distance = s\<^sub>o - s\<^sub>e;
                                precond = check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o;
                                safe_dist1 = first_safe_dist v\<^sub>e a\<^sub>e;
                                safe_dist2 = second_safe_dist v\<^sub>e a\<^sub>e v\<^sub>o a\<^sub>o;
                                cond2 = suff_cond_safe_dist2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o in
                                  precond \<and> (
                                    safe_dist1 < distance \<or>
                                   (safe_dist2 < distance \<and> distance \<le> safe_dist1 \<and> cond2))"

subsubsection \<open>prescriptive checker\<close>
text \<open>\label{sec:checkerp}\<close>

definition checker2 :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> bool" where
"checker2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<equiv> let distance = s\<^sub>o - s\<^sub>e;
                                precond = check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o;
                                safe_dist1 = first_safe_dist v\<^sub>e a\<^sub>e;
                                safe_dist2 = second_safe_dist v\<^sub>e a\<^sub>e v\<^sub>o a\<^sub>o;
                                safe_dist3 = - rel_dist_to_stop (v\<^sub>o - v\<^sub>e) (a\<^sub>o - a\<^sub>e) in
                             if \<not> precond then
                                False
                             else if distance > safe_dist1 then
                                True
                             else if a\<^sub>o > a\<^sub>e \<and> v\<^sub>o < v\<^sub>e \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o < 0 then
                                distance > safe_dist3
                             else
                                distance > safe_dist2"

thm
  safe_distance.cond_1
  safe_distance.cond_2
  safe_distance.cond_3'
definition checker3 :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> bool" where
"checker3 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<equiv> let distance = s\<^sub>o - s\<^sub>e;
                                precond = check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o;
                                s_stop_e = s\<^sub>e + rel_dist_to_stop v\<^sub>e a\<^sub>e;
                                s_stop_o = s\<^sub>o + rel_dist_to_stop v\<^sub>o a\<^sub>o in
                                precond \<and>
                                (s_stop_e < s\<^sub>o \<or>
                                (s\<^sub>o \<le> s_stop_e \<and> s_stop_e < s_stop_o \<and>
                                (\<not>(a\<^sub>o > a\<^sub>e \<and> v\<^sub>o < v\<^sub>e \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o < 0 \<and> distance * (a\<^sub>o - a\<^sub>e) \<le> (v\<^sub>o - v\<^sub>e)\<^sup>2 / 2))))"

theorem checker_eq_checker2: "checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<longleftrightarrow> checker2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o"
proof (cases "check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o")
  case False
  with checker_def checker2_def
  show ?thesis by auto
next
  case True
  with check_precond_def safe_distance_def
  have "safe_distance a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o"  by (simp add: check_precond_safe_distance)

  from this interpret safe_distance a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o by auto
  interpret ego: braking_movement a\<^sub>e v\<^sub>e s\<^sub>e by (unfold_locales; fact)
  interpret other: braking_movement a\<^sub>o v\<^sub>o s\<^sub>o by (unfold_locales; fact)

  from \<open>check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o\<close>  cond_3 cond_3'[symmetric] fst_leq_snd_safe_distance
  ego.s_t_stop ego.p_max_def ego.p_def ego.t_stop_def hyps other.s_t_stop other.p_max_def other.p_def
  other.t_stop_def checker2_def checker_def suff_cond_safe_dist2_def fst_safe_distance_def
  first_safe_dist_def snd_safe_distance_def second_safe_dist_def rel_dist_to_stop_def discriminant_def
  show ?thesis
  by (auto simp add:power_def Let_def split:if_splits)
qed

theorem checker2_eq_checker3:
  "checker2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<longleftrightarrow> checker3 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o"
  apply (auto simp: checker2_def checker3_def Let_def first_safe_dist_def not_less
    suff_cond_safe_dist2_def second_safe_dist_def rel_dist_to_stop_def check_precond_def)
proof goal_cases
  case 1
  then interpret safe_distance
    by unfold_locales auto
  from fst_leq_snd_safe_distance 1
  show ?case
    by (auto simp: fst_safe_distance_def snd_safe_distance_def)
next
  case 2
  then interpret safe_distance
    by unfold_locales auto
  from fst_leq_snd_safe_distance 2
  show ?case
    by (auto simp: fst_safe_distance_def snd_safe_distance_def divide_simps algebra_simps)
next
  case 3
  then interpret safe_distance
    by unfold_locales auto
  from fst_leq_snd_safe_distance 3
  show ?case
    by (auto simp: fst_safe_distance_def snd_safe_distance_def divide_simps algebra_simps)
qed

(* proof that the exact checker guarantee collision free *)
lemma aux_logic:
  assumes "a \<Longrightarrow> b"
  assumes "b \<Longrightarrow> a \<longleftrightarrow> c"
  shows "a \<longleftrightarrow> b \<and> c"
  using assms by blast

theorem soundness_correctness:
  "checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<longleftrightarrow> check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<and> safe_distance.no_collision a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o {0..}"
proof (rule aux_logic, simp add: checker_def Let_def)
  assume cp: "check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o"
  then have in_front': "s\<^sub>o > s\<^sub>e"
    and nonneg_vel_ego: "0 \<le> v\<^sub>e"
    and nonneg_vel_other: "0 \<le> v\<^sub>o"
    and decelerate_ego: "a\<^sub>e < 0"
    and decelerate_other: "a\<^sub>o < 0"
    by (auto simp: check_precond_def)

  from in_front' have in_front: "0 < s\<^sub>o - s\<^sub>e" by arith

  interpret safe_distance a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o by (unfold_locales; fact)
  interpret ego: braking_movement a\<^sub>e v\<^sub>e s\<^sub>e by (unfold_locales; fact)
  interpret other: braking_movement a\<^sub>o v\<^sub>o s\<^sub>o by (unfold_locales; fact)

  have "ego.p_max < s\<^sub>o \<or> other.p_max \<le> ego.p_max \<or> s\<^sub>o \<le> ego.p_max \<and> ego.p_max < other.p_max"
    by arith
  then show "checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o = safe_distance.no_collision a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o {0..}"
  proof (elim disjE)
    assume "ego.p_max < s\<^sub>o"
    then have "checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o"
      using \<open>a\<^sub>e < 0\<close> cp
      by (simp add: checker_def Let_def first_safe_dist_def rel_dist_to_stop_def ego.p_max_def
        ego.p_def ego.t_stop_def algebra_simps power2_eq_square)
    moreover
    have "no_collision {0..}"
      using \<open>ego.p_max < s\<^sub>o\<close>
      by (intro cond_1) (auto simp: ego.s_t_stop)
    ultimately show ?thesis by auto
  next
    assume "other.p_max \<le> ego.p_max"
    then have "\<not> checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o"
      using \<open>a\<^sub>e < 0\<close> \<open>a\<^sub>o < 0\<close> other.nonneg_vel
      by (auto simp add: checker_def Let_def first_safe_dist_def second_safe_dist_def
        rel_dist_to_stop_def movement.p_max_def
        movement.p_def movement.t_stop_def algebra_simps power2_eq_square)
         (smt divide_nonneg_neg mult_nonneg_nonneg)
    moreover have "collision {0..}"
      using \<open>other.p_max \<le> ego.p_max\<close>
      by (intro cond_2) (auto simp: other.s_t_stop ego.s_t_stop)
    ultimately show ?thesis by auto
  next
    assume H: "s\<^sub>o \<le> ego.p_max \<and> ego.p_max < other.p_max"
    then have "checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o = (\<not> (a\<^sub>e < a\<^sub>o \<and> v\<^sub>o < v\<^sub>e \<and> 0 \<le> D2 \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * v\<^sub>o < sqrt D2))"
      using \<open>a\<^sub>e < 0\<close> \<open>a\<^sub>o < 0\<close> cp
      by (simp add: checker_def Let_def first_safe_dist_def rel_dist_to_stop_def ego.p_max_def
        ego.p_def ego.t_stop_def algebra_simps power2_eq_square second_safe_dist_def
        suff_cond_safe_dist2_def discriminant_def not_less other.p_max_def other.p_def other.t_stop_def)
    also have "\<dots> = no_collision {0..}"
      using H
      unfolding Not_eq_iff
      by (intro cond_3[symmetric]) (auto simp: ego.s_t_stop other.s_t_stop)
    finally show ?thesis by auto
  qed
qed

subsubsection \<open>Theorem 5\<close>
text \<open>\label{sec:thm5}\<close>
theorem soundness_correctness2:
  "checker2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<longleftrightarrow> check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<and> safe_distance.no_collision a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o {0..}"
  unfolding soundness_correctness[symmetric] checker_eq_checker2 ..

subsubsection \<open>Checker extended with reaction time delay\<close>
text \<open>\label{sec:checker_react}\<close>
(* We define two checkers for different cases: one checker for the case that \<delta> \<le> other.t_stop (other.t_stop = - v\<^sub>o / a\<^sub>o) and a second checker for the case that \<delta> > other.t_stop *)
definition "check_precond_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<longleftrightarrow> s\<^sub>o > s\<^sub>e \<and> 0 \<le> v\<^sub>e \<and> 0 \<le> v\<^sub>o \<and> a\<^sub>e < 0 \<and> a\<^sub>o < 0 \<and> 0 < \<delta> \<and> \<delta> \<le> - v\<^sub>o / a\<^sub>o"

definition safe_distance0 where "safe_distance0 v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = v\<^sub>e * \<delta> - v\<^sub>o * \<delta> - a\<^sub>o * \<delta>\<^sup>2 / 2"
definition safe_distance_1r where "safe_distance_1r a\<^sub>e v\<^sub>e \<delta> = v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / a\<^sub>e / 2"
definition safe_distance_2r where "safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e + v\<^sub>o\<^sup>2 / 2 / a\<^sub>o"
definition safe_distance_4r where "safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> =
                               (v\<^sub>o + a\<^sub>o * \<delta> - v\<^sub>e)\<^sup>2 / 2 / (a\<^sub>o - a\<^sub>e) - v\<^sub>o * \<delta> - 1 / 2 * a\<^sub>o * \<delta>\<^sup>2 + v\<^sub>e * \<delta>"
definition safe_distance_3r where "safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> =
                                                      v\<^sub>e * \<delta> - v\<^sub>e\<^sup>2 / 2 / a\<^sub>e - v\<^sub>o * \<delta> - 1 / 2 * a\<^sub>o * \<delta>\<^sup>2"

definition checker_r1 :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> bool" where
  "checker_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<equiv> let distance = s\<^sub>o - s\<^sub>e;
				precond = check_precond_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>;
        vo_star = v\<^sub>o + a\<^sub>o * \<delta>;
        t_stop_o_star = - vo_star / a\<^sub>o;
        t_stop_e = - v\<^sub>e / a\<^sub>e;
        safe_dist0 = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>;
        safe_dist1 = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>;
        safe_dist2 = safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>;
        safe_dist3 = safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> in
   if \<not> precond then
      False
   else if distance > safe_dist0 \<or> distance > safe_dist3 then
      True
   else if (a\<^sub>o > a\<^sub>e \<and> vo_star < v\<^sub>e \<and> t_stop_e < t_stop_o_star) then
      distance > safe_dist2
   else
      distance > safe_dist1"

theorem checker_r1_correctness:
  "(checker_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<longleftrightarrow> check_precond_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..})"
proof
  assume asm: "checker_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
  have pre: "check_precond_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
  proof (rule ccontr)
    assume "\<not> check_precond_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
    with asm show "False" unfolding checker_r1_def Let_def by auto
  qed
  from pre have sdn': "safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>"
    by (unfold_locales) (auto simp add: check_precond_r1_def)
  interpret sdn: safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>
    rewrites "sdn.distance0 = safe_distance0 v\<^sub>e a\<^sub>o v\<^sub>o \<delta>" and
             "sdn.safe_distance_1r = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>" and
             "sdn.safe_distance_2r = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>" and
             "sdn.safe_distance_4r = safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>" and
             "sdn.safe_distance_3r = safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
  proof -
    from sdn' show "safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>" by auto
  next
    show "safe_distance_normal.distance0 v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance0 v\<^sub>e a\<^sub>o v\<^sub>o \<delta> "
      unfolding safe_distance_normal.distance0_def[OF sdn'] safe_distance0_def by auto
  next
    show "safe_distance_normal.safe_distance_1r a\<^sub>e v\<^sub>e \<delta> = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>"
      unfolding safe_distance_normal.safe_distance_1r_def[OF sdn'] safe_distance_1r_def by auto
  next
    show "safe_distance_normal.safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
      unfolding safe_distance_normal.safe_distance_2r_def[OF sdn'] safe_distance_2r_def by auto
  next
    show "safe_distance_normal.safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> "
      unfolding safe_distance_normal.safe_distance_4r_def[OF sdn'] safe_distance_4r_def by auto
  next
    show "safe_distance_normal.safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
      unfolding safe_distance_normal.safe_distance_3r_def[OF sdn'] safe_distance_3r_def by auto
  qed
  have "0 < \<delta>" and "\<delta> \<le> - v\<^sub>o / a\<^sub>o" using pre unfolding check_precond_r1_def by auto
  define so_delta where "so_delta = s\<^sub>o + v\<^sub>o * \<delta> + a\<^sub>o * \<delta>\<^sup>2 / 2"
  define q_e_delta where "q_e_delta \<equiv> s\<^sub>e + v\<^sub>e * \<delta>"
  define u_stop_e where "u_stop_e \<equiv> q_e_delta - v\<^sub>e\<^sup>2 / (2 * a\<^sub>e)"
  define vo_star where "vo_star = v\<^sub>o + a\<^sub>o * \<delta>"
  define t_stop_o_star where "t_stop_o_star \<equiv> - vo_star / a\<^sub>o"
  define t_stop_e where "t_stop_e = - v\<^sub>e / a\<^sub>e"
  define distance where "distance \<equiv> s\<^sub>o - s\<^sub>e"
  define distance0 where "distance0 = safe_distance0 v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
  define safe_dist0 where "safe_dist0 = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>"
  define safe_dist2 where "safe_dist2 \<equiv> safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
  define safe_dist1 where "safe_dist1 \<equiv> safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
  define safe_dist3 where "safe_dist3 = safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
  note abb = so_delta_def q_e_delta_def u_stop_e_def vo_star_def t_stop_o_star_def t_stop_e_def
             distance_def safe_dist2_def safe_dist1_def safe_dist0_def safe_dist3_def distance0_def
  consider "distance > safe_dist0" | "distance > safe_dist3" | "distance \<le> safe_dist0 \<and> distance \<le> safe_dist3"
    by linarith
  hence "sdn.no_collision_react {0..}"
  proof (cases)
    case 1
    then show ?thesis using sdn.sd_1r_correct unfolding  abb by auto
  next
    case 2
    hence pre2: "distance > distance0" using sdn.distance0_at_most_sd3r unfolding abb by auto
    hence "sdn.u \<delta> < sdn.other.s \<delta>" using pre unfolding sdn.u_def sdn.ego.q_def
      sdn.other.s_def sdn.other.t_stop_def sdn.other.p_def abb check_precond_r1_def sdn.distance0_def
      by auto
    from pre interpret sdr: safe_distance_no_collsion_delta a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>
      by (unfold_locales) (auto simp add:check_precond_r1_def `sdn.u \<delta> < sdn.other.s \<delta>`)
    show ?thesis using sdr.sd_3r_correct 2 pre unfolding check_precond_r1_def abb sdn.other.t_stop_def
      by auto
  next
    case 3
    hence "distance \<le> safe_dist3" by auto
    hence "sdn.other.s \<delta> \<le> sdn.u_max" using pre unfolding check_precond_r1_def sdn.other.s_def sdn.other.t_stop_def
      sdn.other.p_def sdn.u_max_eq sdn.ego.q_def abb sdn.safe_distance_3r_def by auto
    have " (a\<^sub>o > a\<^sub>e \<and> vo_star < v\<^sub>e \<and> t_stop_e < t_stop_o_star) \<or> \<not>  (a\<^sub>o > a\<^sub>e \<and> vo_star < v\<^sub>e \<and> t_stop_e < t_stop_o_star) "
      by auto
    moreover
    { assume cond: "(a\<^sub>o > a\<^sub>e \<and> vo_star < v\<^sub>e \<and> t_stop_e < t_stop_o_star)"
      with 3 pre have "distance > safe_dist2" using asm unfolding checker_r1_def
          Let_def abb by auto
      with sdn.distance0_at_most_sd4r have "distance > distance0" unfolding abb using cond by auto
      hence "sdn.u \<delta> < sdn.other.s \<delta>" using pre unfolding sdn.u_def sdn.ego.q_def
          sdn.other.s_def sdn.other.t_stop_def sdn.other.p_def abb check_precond_r1_def sdn.distance0_def
        by auto
      from pre interpret sdr: safe_distance_no_collsion_delta a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>
        by (unfold_locales) (auto simp add:check_precond_r1_def `sdn.u \<delta> < sdn.other.s \<delta>`)
      from sdr.sd_4r_correct[OF _ `sdn.other.s \<delta> \<le> sdn.u_max`] `distance > safe_dist2`
        have ?thesis using pre cond  unfolding check_precond_r1_def sdn.other.t_stop_def abb by auto }
    moreover
    { assume not_cond: "\<not>  (a\<^sub>o > a\<^sub>e \<and> vo_star < v\<^sub>e \<and> t_stop_e < t_stop_o_star)"
      with 3 pre have "distance > safe_dist1" using asm unfolding checker_r1_def
        Let_def abb by auto
      with sdn.dist0_sd2r_1 have "distance > distance0" using pre not_cond unfolding check_precond_r1_def
        sdn.other.t_stop_def sdn.other.s'_def sdn.other.p'_def abb by (auto simp add:field_simps)
      hence "sdn.u \<delta> < sdn.other.s \<delta>" using pre unfolding sdn.u_def sdn.ego.q_def
          sdn.other.s_def sdn.other.t_stop_def sdn.other.p_def abb check_precond_r1_def sdn.distance0_def
        by auto
      from pre interpret sdr: safe_distance_no_collsion_delta a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>
        by (unfold_locales) (auto simp add:check_precond_r1_def `sdn.u \<delta> < sdn.other.s \<delta>`)
      from sdr.sd_2r_correct_for_3r_2[OF _ `sdn.other.s \<delta> \<le> sdn.u_max`] not_cond `distance > safe_dist1`
        have ?thesis using pre unfolding abb sdn.other.s'_def check_precond_r1_def sdn.other.t_stop_def sdn.other.p'_def
        by (auto simp add:field_simps) }
    ultimately show ?thesis by auto
  qed
  with pre show " check_precond_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> sdn.no_collision_react {0..}" by auto
next
  assume "check_precond_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..}"
  hence pre: "check_precond_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>" and as2: "safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..}"
  by auto
  show "checker_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> "
  proof (rule ccontr)
    assume as1: "\<not> checker_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
    from pre have "0 < \<delta>" and "\<delta> \<le> - v\<^sub>o / a\<^sub>o" unfolding check_precond_r1_def by auto
    define so_delta where "so_delta = s\<^sub>o + v\<^sub>o * \<delta> + a\<^sub>o * \<delta>\<^sup>2 / 2"
    define q_e_delta where "q_e_delta \<equiv> s\<^sub>e + v\<^sub>e * \<delta>"
    define u_stop_e where "u_stop_e \<equiv> q_e_delta - v\<^sub>e\<^sup>2 / (2 * a\<^sub>e)"
    define vo_star where "vo_star \<equiv> v\<^sub>o + a\<^sub>o * \<delta>"
    define t_stop_o_star where "t_stop_o_star \<equiv> - vo_star / a\<^sub>o"
    define t_stop_e where "t_stop_e \<equiv> - v\<^sub>e / a\<^sub>e"
    define distance where "distance \<equiv> s\<^sub>o - s\<^sub>e"
    define distance0 where "distance0 \<equiv> safe_distance0 v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
    define safe_dist0 where "safe_dist0 \<equiv> safe_distance_1r a\<^sub>e v\<^sub>e \<delta>"
    define safe_dist2 where "safe_dist2 \<equiv> safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
    define safe_dist1 where "safe_dist1 \<equiv> safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
    define safe_dist3 where "safe_dist3 \<equiv> safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
    note abb = so_delta_def q_e_delta_def u_stop_e_def vo_star_def t_stop_o_star_def t_stop_e_def
               distance_def safe_dist2_def safe_dist1_def safe_dist0_def safe_dist3_def distance0_def
    from pre have sdn': "safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>"
      by (unfold_locales) (auto simp add: check_precond_r1_def)
    interpret sdn: safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>
      rewrites "sdn.distance0 = safe_distance0 v\<^sub>e a\<^sub>o v\<^sub>o \<delta>" and
               "sdn.safe_distance_1r = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>" and
               "sdn.safe_distance_2r = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>" and
               "sdn.safe_distance_4r = safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>" and
               "sdn.safe_distance_3r = safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
    proof -
      from sdn' show "safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>" by auto
    next
      show "safe_distance_normal.distance0 v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance0 v\<^sub>e a\<^sub>o v\<^sub>o \<delta> "
        unfolding safe_distance_normal.distance0_def[OF sdn'] safe_distance0_def by auto
    next
      show "safe_distance_normal.safe_distance_1r a\<^sub>e v\<^sub>e \<delta> = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>"
        unfolding safe_distance_normal.safe_distance_1r_def[OF sdn'] safe_distance_1r_def by auto
    next
      show "safe_distance_normal.safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
        unfolding safe_distance_normal.safe_distance_2r_def[OF sdn'] safe_distance_2r_def by auto
    next
      show "safe_distance_normal.safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> "
        unfolding safe_distance_normal.safe_distance_4r_def[OF sdn'] safe_distance_4r_def by auto
    next
      show "safe_distance_normal.safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
        unfolding safe_distance_normal.safe_distance_3r_def[OF sdn'] safe_distance_3r_def by auto
    qed
    have "\<not> distance > distance0 \<or>  distance > distance0" by auto
    moreover
    { assume "\<not> distance > distance0"
      hence "distance \<le> distance0" by auto
      with sdn.cond_3r_1' have "sdn.collision_react {0..\<delta>}" using pre unfolding check_precond_r1_def abb
        sdn.other.t_stop_def by auto
      with sdn.collision_react_subset have "sdn.collision_react {0..}" by auto
      with as2 have "False" by auto }
    moreover
    { assume if2: "distance > distance0"
      have "\<not> (distance > safe_dist0 \<or> distance > safe_dist3)"
      proof (rule ccontr)
        assume "\<not> \<not> (safe_dist0 < distance \<or> safe_dist3 < distance)"
        hence "(safe_dist0 < distance \<or> safe_dist3 < distance)" by auto
        with as1 show "False" using pre if2 unfolding checker_r1_def Let_def abb
          by auto
      qed
      hence if31: "distance \<le> safe_dist0" and if32: "distance \<le> safe_dist3" by auto
      have "sdn.u \<delta> < sdn.other.s \<delta>" using if2 pre unfolding sdn.u_def sdn.ego.q_def
          sdn.other.s_def sdn.other.t_stop_def sdn.other.p_def abb check_precond_r1_def sdn.distance0_def
          by auto
      from pre interpret sdr: safe_distance_no_collsion_delta a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>
        by (unfold_locales) (auto simp add:check_precond_r1_def `sdn.u \<delta> < sdn.other.s \<delta>`)
      have " s\<^sub>o \<le> sdn.u_max" using if31 unfolding sdn.u_max_eq sdn.ego.q_def abb
        sdn.safe_distance_1r_def by auto
      have "sdn.other.s \<delta> \<le> sdn.u_max" using if32 pre unfolding sdn.other.s_def check_precond_r1_def
        sdn.other.t_stop_def sdn.other.p_def sdn.u_max_eq sdn.ego.q_def abb sdn.safe_distance_3r_def
        by auto
      consider "(a\<^sub>o > a\<^sub>e \<and> vo_star < v\<^sub>e \<and> t_stop_e < t_stop_o_star)" |
               "\<not> (a\<^sub>o > a\<^sub>e \<and> vo_star < v\<^sub>e \<and> t_stop_e < t_stop_o_star)" by auto
      hence "False"
      proof (cases)
        case 1
        hence rest_conjunct:"(a\<^sub>e < a\<^sub>o \<and> sdn.other.s' \<delta> < v\<^sub>e \<and> v\<^sub>e - a\<^sub>e / a\<^sub>o * sdn.other.s' \<delta> < 0)"
          using pre unfolding check_precond_r1_def unfolding sdn.other.s'_def sdn.other.t_stop_def
          sdn.other.p'_def abb by (auto simp add:field_simps)
        from 1 have "distance \<le> safe_dist2" using as1 pre if2 if31 if32 unfolding checker_r1_def
          Let_def abb by auto
        hence cond_f: "sdn.other.s \<delta> - sdn.ego.q \<delta> \<le> sdr.delayed_safe_distance.snd_safe_distance"
          using pre unfolding check_precond_r1_def sdn.other.s_def sdn.other.t_stop_def sdn.other.p_def
          sdn.ego.q_def sdr.delayed_safe_distance.snd_safe_distance_def using sdn.other.s'_def[of "\<delta>"]
          unfolding sdn.other.t_stop_def sdn.other.p'_def abb sdn.safe_distance_4r_def
          by auto
        have "distance > safe_dist1 \<or> distance \<le> safe_dist1" by auto
        moreover
        { assume "distance > safe_dist1"
          hence "sdn.u_max < sdn.other.s_stop" unfolding sdn.u_max_eq sdn.ego.q_def sdn.other.s_t_stop
              sdn.other.p_max_eq abb sdn.safe_distance_2r_def by (auto simp add:field_simps)
          from sdr.cond_3r_2[OF `s\<^sub>o \<le> sdn.u_max` this `sdn.other.s \<delta> \<le> sdn.u_max`]
          have "sdn.collision_react {0..}" using cond_f rest_conjunct by auto
          with as2 have "False" by auto }
        moreover
        { assume "distance \<le> safe_dist1"
          hence "sdn.u_max \<ge> sdn.other.s_stop" unfolding sdn.u_max_eq sdn.ego.q_def sdn.other.s_t_stop
              sdn.other.p_max_eq abb sdn.safe_distance_2r_def by (auto simp add:field_simps)
          with sdn.cond_2r[OF this] have "sdn.collision_react {0..}" by auto
          with as2 have "False" by auto }
        ultimately show ?thesis by auto
      next
        case 2
        hence "distance \<le> safe_dist1" using as1 pre if2 if31 if32 unfolding checker_r1_def
          Let_def abb by auto
        hence "sdn.u_max \<ge> sdn.other.s_stop" unfolding sdn.u_max_eq sdn.ego.q_def sdn.other.s_t_stop
          sdn.other.p_max_eq abb sdn.safe_distance_2r_def by (auto simp add:field_simps)
        with sdn.cond_2r[OF this] have "sdn.collision_react {0..}" by auto
        with as2 show "False" by auto
      qed }
    ultimately show "False" by auto
  qed
qed

definition "check_precond_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<longleftrightarrow> s\<^sub>o > s\<^sub>e \<and> 0 \<le> v\<^sub>e \<and> 0 \<le> v\<^sub>o \<and> a\<^sub>e < 0 \<and> a\<^sub>o < 0 \<and> 0 < \<delta> \<and> \<delta> > - v\<^sub>o / a\<^sub>o"
definition safe_distance0_2 where "safe_distance0_2 v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = v\<^sub>e * \<delta> + 1 / 2 * v\<^sub>o\<^sup>2 / a\<^sub>o"

definition checker_r2 :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> bool" where
  "checker_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<equiv> let distance = s\<^sub>o - s\<^sub>e;
				precond = check_precond_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>;
        safe_dist0 = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>;
        safe_dist1 = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> in
   if \<not> precond then
      False
   else if distance > safe_dist0 then
      True
   else
      distance > safe_dist1"

theorem checker_r2_correctness:
  "(checker_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<longleftrightarrow> check_precond_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..})"
proof
  assume asm: "checker_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
  have pre: "check_precond_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
  proof (rule ccontr)
    assume "\<not> check_precond_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
      with asm show "False" unfolding checker_r2_def Let_def by auto
    qed
      from pre have sdn': "safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>"
    by (unfold_locales) (auto simp add: check_precond_r2_def)
  interpret sdn: safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>
    rewrites "sdn.distance0_2 = safe_distance0_2 v\<^sub>e a\<^sub>o v\<^sub>o \<delta>" and
             "sdn.safe_distance_1r = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>" and
             "sdn.safe_distance_2r = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
  proof -
    from sdn' show "safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>" by auto
  next
    show "safe_distance_normal.distance0_2 v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance0_2 v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
      unfolding safe_distance_normal.distance0_2_def[OF sdn'] safe_distance0_2_def by auto
  next
    show "safe_distance_normal.safe_distance_1r a\<^sub>e v\<^sub>e \<delta> = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>"
      unfolding safe_distance_normal.safe_distance_1r_def[OF sdn'] safe_distance_1r_def by auto
  next
    show "safe_distance_normal.safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
      unfolding safe_distance_normal.safe_distance_2r_def[OF sdn'] safe_distance_2r_def by auto
  qed
  have "0 < \<delta>" and "\<delta> > - v\<^sub>o / a\<^sub>o" using pre unfolding check_precond_r2_def by auto
  define distance where "distance \<equiv> s\<^sub>o - s\<^sub>e"
  define distance0_2 where "distance0_2 = safe_distance0_2 v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
  define safe_dist0 where "safe_dist0 = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>"
  define safe_dist1 where "safe_dist1 \<equiv> safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
  note abb = distance_def safe_dist1_def safe_dist0_def distance0_2_def
  consider "distance > safe_dist0" | "distance \<le> safe_dist0"
    by linarith
  hence "sdn.no_collision_react {0..}"
  proof (cases)
    case 1
    then show ?thesis using sdn.sd_1r_correct unfolding abb by auto
  next
    case 2
    hence "(s\<^sub>o \<le> sdn.u_max)" using distance_def safe_dist0_def sdn.sd_1r_eq by linarith
    with 2 pre have "distance > safe_dist1" using asm unfolding checker_r2_def Let_def abb by auto
    with sdn.dist0_sd2r_2 have "distance > distance0_2" using abb \<open>- v\<^sub>o / a\<^sub>o < \<delta>\<close> by auto
    hence "sdn.u \<delta> < sdn.other.s \<delta>" using abb sdn.distance0_2_eq \<open>\<delta> > - v\<^sub>o / a\<^sub>o\<close> sdn.other.t_stop_def by auto
    have "sdn.u_max < sdn.other.s \<delta>" using abb sdn.sd2r_eq  \<open>\<delta> > - v\<^sub>o / a\<^sub>o\<close> sdn.other.t_stop_def `distance > safe_dist1` by auto
    from pre interpret sdr: safe_distance_no_collsion_delta a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>
        by (unfold_locales) (auto simp add:check_precond_r2_def `sdn.u \<delta> < sdn.other.s \<delta>`)
    from sdr.sd_2r_correct_for_3r_3[OF] `distance > safe_dist1` `sdn.u \<delta> < sdn.other.s \<delta>` `sdn.u_max < sdn.other.s \<delta>`
       show ?thesis using pre unfolding abb sdn.other.s'_def check_precond_r2_def sdn.other.t_stop_def sdn.other.p'_def
            by (auto simp add:field_simps)
  qed
  with pre show " check_precond_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> sdn.no_collision_react {0..}" by auto
next
  assume "check_precond_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..}"
  hence pre: "check_precond_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>" and as2: "safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..}"
    by auto
  show "checker_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
  proof (rule ccontr)
    assume as1: "\<not> checker_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
    from pre have "0 < \<delta>" and "\<delta> > - v\<^sub>o / a\<^sub>o" unfolding check_precond_r2_def by auto
    define distance where "distance \<equiv> s\<^sub>o - s\<^sub>e"
    define distance0_2 where "distance0_2 = safe_distance0_2 v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
    define safe_dist0 where "safe_dist0 = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>"
    define safe_dist1 where "safe_dist1 \<equiv> safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
    note abb = distance_def safe_dist1_def safe_dist0_def distance0_2_def
    from pre have sdn': "safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>"
      by (unfold_locales) (auto simp add: check_precond_r2_def)
   interpret sdn: safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>
    rewrites "sdn.distance0_2 = safe_distance0_2 v\<^sub>e a\<^sub>o v\<^sub>o \<delta>" and
             "sdn.safe_distance_1r = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>" and
             "sdn.safe_distance_2r = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
    proof -
      from sdn' show "safe_distance_normal a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>" by auto
    next
      show "safe_distance_normal.distance0_2 v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance0_2 v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
        unfolding safe_distance_normal.distance0_2_def[OF sdn'] safe_distance0_2_def by auto
    next
      show "safe_distance_normal.safe_distance_1r a\<^sub>e v\<^sub>e \<delta> = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>"
        unfolding safe_distance_normal.safe_distance_1r_def[OF sdn'] safe_distance_1r_def by auto
    next
      show "safe_distance_normal.safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>"
        unfolding safe_distance_normal.safe_distance_2r_def[OF sdn'] safe_distance_2r_def by auto
    qed
    have "\<not> distance > distance0_2 \<or>  distance > distance0_2" by auto
    moreover
    { assume "\<not> distance > distance0_2"
      hence "distance \<le> distance0_2" by auto
      with sdn.cond_3r_1'_2 have "sdn.collision_react {0..\<delta>}" using pre unfolding check_precond_r2_def abb sdn.other.t_stop_def by auto
      with sdn.collision_react_subset have "sdn.collision_react {0..}" by auto
      with as2 have "False" by auto }
    moreover
    { assume if2: "distance > distance0_2"
      have "\<not> (distance > safe_dist0)"
      proof (rule ccontr)
        assume "\<not> \<not> (safe_dist0 < distance)"
        hence "(safe_dist0 < distance)" by auto
        with as1 show "False" using pre if2 unfolding checker_r2_def Let_def abb by auto
      qed
      hence if3: "distance \<le> safe_dist0" by auto
      with pre have "distance \<le> safe_dist1" using as1 unfolding checker_r2_def Let_def abb by auto

      have "sdn.u \<delta> < sdn.other.s \<delta>" using abb if2 sdn.distance0_2_eq \<open>\<delta> > - v\<^sub>o / a\<^sub>o\<close> sdn.other.t_stop_def by auto
      from pre interpret sdr: safe_distance_no_collsion_delta a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta>
          by (unfold_locales) (auto simp add:check_precond_r2_def `sdn.u \<delta> < sdn.other.s \<delta>`)
      have "sdn.u_max \<ge> sdn.other.s \<delta>" using abb sdn.sd2r_eq  \<open>\<delta> > - v\<^sub>o / a\<^sub>o\<close> sdn.other.t_stop_def `distance \<le> safe_dist1` by auto
      with `\<delta> > - v\<^sub>o / a\<^sub>o` have "sdn.u_max \<ge> sdn.other.s_stop" by (smt movement.t_stop_def sdn.other.s_mono sdn.other.t_stop_nonneg)
      hence "sdn.collision_react {0..}" using sdn.cond_2r by auto
      with as2 have "False" by auto }
    ultimately show "False" by auto
  qed
qed

(* combine the two checkers into one*)
definition "check_precond_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<longleftrightarrow> s\<^sub>o > s\<^sub>e \<and> 0 \<le> v\<^sub>e \<and> 0 \<le> v\<^sub>o \<and> a\<^sub>e < 0 \<and> a\<^sub>o < 0 \<and> 0 < \<delta>"
definition checker_r :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> bool" where
  "checker_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<equiv> let distance = s\<^sub>o - s\<^sub>e;
				precond = check_precond_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>;
        vo_star = v\<^sub>o + a\<^sub>o * \<delta>;
        t_stop_o_star = - vo_star / a\<^sub>o;
        t_stop_e = - v\<^sub>e / a\<^sub>e;
        t_stop_o = - v\<^sub>o / a\<^sub>o;
        safe_dist0 = safe_distance_1r a\<^sub>e v\<^sub>e \<delta>;
        safe_dist1 = safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>;
        safe_dist2 = safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>;
        safe_dist3 = safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta> in
   if \<not> precond then
      False
   else if distance > safe_dist0 then
      True
   else if \<delta> \<le> t_stop_o \<and> distance > safe_dist3 then
      True
   else if \<delta> \<le> t_stop_o \<and> (a\<^sub>o > a\<^sub>e \<and> vo_star < v\<^sub>e \<and> t_stop_e < t_stop_o_star) then
      distance > safe_dist2
   else
      distance > safe_dist1"

theorem checker_eq_1:
  "checker_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> \<delta> \<le> - v\<^sub>o / a\<^sub>o  \<longleftrightarrow> checker_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
proof -
  have "checker_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> \<delta> \<le> - v\<^sub>o / a\<^sub>o \<longleftrightarrow> check_precond_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>
    \<and> (s\<^sub>o - s\<^sub>e > safe_distance_1r a\<^sub>e v\<^sub>e \<delta>
        \<or> s\<^sub>o - s\<^sub>e > safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>
        \<or> (((a\<^sub>o > a\<^sub>e \<and> v\<^sub>o + a\<^sub>o * \<delta> < v\<^sub>e \<and> - v\<^sub>e / a\<^sub>e < - (v\<^sub>o + a\<^sub>o * \<delta>) / a\<^sub>o) \<longrightarrow> s\<^sub>o - s\<^sub>e > safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>)
            \<and> (\<not> (a\<^sub>o > a\<^sub>e \<and> v\<^sub>o + a\<^sub>o * \<delta> < v\<^sub>e \<and> - v\<^sub>e / a\<^sub>e < - (v\<^sub>o + a\<^sub>o * \<delta>) / a\<^sub>o) \<longrightarrow> s\<^sub>o - s\<^sub>e > safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>)))
    \<and> \<delta> \<le> - v\<^sub>o / a\<^sub>o" using checker_r_def by metis
  also have "... \<longleftrightarrow> check_precond_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>
    \<and> (s\<^sub>o - s\<^sub>e > safe_distance_1r a\<^sub>e v\<^sub>e \<delta>
        \<or> s\<^sub>o - s\<^sub>e > safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>
        \<or> (((a\<^sub>o > a\<^sub>e \<and> v\<^sub>o + a\<^sub>o * \<delta> < v\<^sub>e \<and> - v\<^sub>e / a\<^sub>e < - (v\<^sub>o + a\<^sub>o * \<delta>) / a\<^sub>o) \<longrightarrow> s\<^sub>o - s\<^sub>e > safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>)
            \<and> (\<not> (a\<^sub>o > a\<^sub>e \<and> v\<^sub>o + a\<^sub>o * \<delta> < v\<^sub>e \<and> - v\<^sub>e / a\<^sub>e < - (v\<^sub>o + a\<^sub>o * \<delta>) / a\<^sub>o) \<longrightarrow> s\<^sub>o - s\<^sub>e > safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>)))"
    by (auto simp add:check_precond_r_def check_precond_r1_def)
  also have "... \<longleftrightarrow> checker_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>" by (metis checker_r1_def)
  finally show ?thesis by auto
qed

theorem checker_eq_2:
  "checker_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> \<delta> > - v\<^sub>o / a\<^sub>o \<longleftrightarrow> checker_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>"
proof -
  have "checker_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> \<delta> > - v\<^sub>o / a\<^sub>o \<longleftrightarrow> check_precond_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> (\<not> check_precond_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<or>
   s\<^sub>o - s\<^sub>e > safe_distance_1r a\<^sub>e v\<^sub>e \<delta> \<or>
   (\<delta> \<le> - v\<^sub>o / a\<^sub>o \<and> s\<^sub>o - s\<^sub>e > safe_distance_3r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>) \<or>
   (\<delta> \<le> - v\<^sub>o / a\<^sub>o \<and> a\<^sub>o > a\<^sub>e \<and> v\<^sub>o + a\<^sub>o * \<delta> < v\<^sub>e \<and> - v\<^sub>e / a\<^sub>e < - (v\<^sub>o + a\<^sub>o * \<delta>) / a\<^sub>o \<and> s\<^sub>o - s\<^sub>e > safe_distance_4r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>) \<or>
   s\<^sub>o - s\<^sub>e > safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>) \<and> \<delta> > - v\<^sub>o / a\<^sub>o" unfolding checker_r_def Let_def if_splits by auto
  also have
   "... \<longleftrightarrow> check_precond_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>
   \<and> (s\<^sub>o - s\<^sub>e > safe_distance_1r a\<^sub>e v\<^sub>e \<delta> \<or> s\<^sub>o - s\<^sub>e > safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>)
   \<and> \<delta> > - v\<^sub>o / a\<^sub>o"  by (auto simp add:HOL.disjE)
  also have
    "... \<longleftrightarrow> check_precond_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>
   \<and> (s\<^sub>o - s\<^sub>e > safe_distance_1r a\<^sub>e v\<^sub>e \<delta> \<or> s\<^sub>o - s\<^sub>e > safe_distance_2r a\<^sub>e v\<^sub>e a\<^sub>o v\<^sub>o \<delta>)"
    by (auto simp add:check_precond_r_def check_precond_r2_def)
  also have "... \<longleftrightarrow> checker_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>" by (auto simp add:checker_r2_def Let_def if_splits)
  thus ?thesis using calculation by auto
qed

theorem checker_r_correctness:
  "(checker_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<longleftrightarrow> check_precond_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..})"
proof -
  have "checker_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<longleftrightarrow> (checker_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> \<delta> \<le> - v\<^sub>o / a\<^sub>o) \<or> (checker_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> \<delta> > - v\<^sub>o / a\<^sub>o)" by auto
  also have "... \<longleftrightarrow> checker_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<or> checker_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta>" using checker_eq_1 checker_eq_2 by auto
  also have "... \<longleftrightarrow> (check_precond_r1 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..})
      \<or> (check_precond_r2 s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..})"
    using checker_r1_correctness checker_r2_correctness by auto
  also have "... \<longleftrightarrow> (\<delta> \<le> - v\<^sub>o / a\<^sub>o \<and> check_precond_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..})
      \<or> (\<delta> > - v\<^sub>o / a\<^sub>o \<and> check_precond_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..})"
    by (auto simp add:check_precond_r_def check_precond_r1_def check_precond_r2_def)
  also have "... \<longleftrightarrow> check_precond_r s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<delta> \<and> safe_distance_normal.no_collision_react a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o \<delta> {0..}"
    by auto
  finally show ?thesis by auto
qed

subsection \<open>serialize printing\<close>

consts print::"String.literal \<Rightarrow> unit"
consts integer_to_string::"integer \<Rightarrow> String.literal"
consts concat_string::"String.literal \<Rightarrow> String.literal \<Rightarrow> String.literal" (infixr "@s" 65)

definition "int_to_string x = integer_to_string (integer_of_int x)"
code_printing
  constant print \<rightharpoonup> (SML) "TextIO.print"
| constant integer_to_string \<rightharpoonup> (SML) "IntInf.toString"
| constant concat_string \<rightharpoonup> (SML) "String.^ ((_), (_))"
| constant String.explode \<rightharpoonup> (SML) "String.explode"

class "show" = fixes "show"::"'a \<Rightarrow> String.literal"

instantiation nat::"show"
begin
definition "show_nat n = (int_to_string (int n))"
instance proof qed
end

instantiation int::"show"
begin
definition "show_int i = int_to_string i"
instance proof qed
end

instantiation float::"show"
begin
definition "show_float f = (show (mantissa f) @s STR ''*2^('' @s show (exponent f)) @s STR '')''"
instance proof qed
end

subsection \<open>approximate checker\<close>

lemma checker2_def': "checker2 a b c d e f =
  (let distance = d - a;
    precond = check_precond a b c d e f;
    safe_dist1 = first_safe_dist b c;
    safe_dist2 = second_safe_dist b c e f;
    C = c < f \<and> e < b \<and> b * f > c * e;
    P1 = (e - b)\<^sup>2 < 2 * distance * (f - c);
    P2 = - b\<^sup>2 / c + e\<^sup>2 / f < 2 * distance
    in precond \<and>
      (safe_dist1 < distance \<or>
      safe_dist1 \<ge> distance \<and> (C \<and> P1 \<or> \<not>C \<and> P2)))"
  unfolding checker2_def
  by (auto simp: Let_def algebra_simps divide_simps check_precond_def second_safe_dist_def
    rel_dist_to_stop_def)

lemma power2_less_sqrt_iff: "(x::real)\<^sup>2 < y \<longleftrightarrow> (y \<ge> 0 \<and> abs x < sqrt y)"
  apply (auto simp: real_less_rsqrt abs_real_def less_sqrt_iff)
  apply (meson le_less le_less_trans not_less power2_less_0)+
  done

schematic_goal checker_form: "interpret_form ?x ?y \<Longrightarrow> checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o"
  unfolding checker_eq_checker2 checker2_eq_checker3 checker3_def check_precond_def first_safe_dist_def second_safe_dist_def
    suff_cond_safe_dist2_def Let_def t_stop_def s_stop_def
    rel_dist_to_stop_def
    discriminant_def
    not_le not_less
    de_Morgan_conj
    de_Morgan_disj
    power2_less_sqrt_iff
  apply (tactic \<open>(Reification.tac @{context} @{thms interpret_form.simps interpret_floatarith.simps interpret_floatarith_divide interpret_floatarith_diff}) NONE 1\<close>)
  apply assumption
  done

definition "print_width l u f = (let _ = print (show (u - l) @s STR ''\<newline>'') in f)"

definition "checker' p s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o = approx_form p
           (Conj (Conj (Less (Var (Suc (Suc 0))) (Var (Suc (Suc (Suc 0)))))
                   (Conj (LessEqual (Var (Suc (Suc (Suc (Suc (Suc (Suc (Suc 0)))))))) (Var (Suc (Suc (Suc (Suc (Suc 0)))))))
                     (Conj (LessEqual (Var (Suc (Suc (Suc (Suc (Suc (Suc (Suc 0)))))))) (Var (Suc (Suc (Suc (Suc (Suc (Suc 0))))))))
                       (Conj (Less (Var 0) (Var (Suc (Suc (Suc (Suc (Suc (Suc (Suc 0)))))))))
                         (Less (Var (Suc 0)) (Var (Suc (Suc (Suc (Suc (Suc (Suc (Suc 0)))))))))))))
             (Disj (Less (Add (Var (Suc (Suc 0)))
                           (Mult (Minus (Power (Var (Suc (Suc (Suc (Suc (Suc 0)))))) 2)) (Inverse (Mult (Var (Suc (Suc (Suc (Suc 0))))) (Var 0)))))
                     (Var (Suc (Suc (Suc 0)))))
               (Conj (LessEqual (Var (Suc (Suc (Suc 0))))
                       (Add (Var (Suc (Suc 0)))
                         (Mult (Minus (Power (Var (Suc (Suc (Suc (Suc (Suc 0)))))) 2)) (Inverse (Mult (Var (Suc (Suc (Suc (Suc 0))))) (Var 0))))))
                 (Conj (Less (Add (Var (Suc (Suc 0)))
                               (Mult (Minus (Power (Var (Suc (Suc (Suc (Suc (Suc 0)))))) 2)) (Inverse (Mult (Var (Suc (Suc (Suc (Suc 0))))) (Var 0)))))
                         (Add (Var (Suc (Suc (Suc 0))))
                           (Mult (Minus (Power (Var (Suc (Suc (Suc (Suc (Suc (Suc 0))))))) 2))
                             (Inverse (Mult (Var (Suc (Suc (Suc (Suc 0))))) (Var (Suc 0)))))))
                   (Disj (LessEqual (Var (Suc 0)) (Var 0))
                     (Disj (LessEqual (Var (Suc (Suc (Suc (Suc (Suc 0)))))) (Var (Suc (Suc (Suc (Suc (Suc (Suc 0))))))))
                       (Disj (LessEqual (Var (Suc (Suc (Suc (Suc (Suc (Suc (Suc 0))))))))
                               (Add (Var (Suc (Suc (Suc (Suc (Suc 0))))))
                                 (Minus (Mult (Mult (Var 0) (Inverse (Var (Suc 0)))) (Var (Suc (Suc (Suc (Suc (Suc (Suc 0)))))))))))
                         (Less (Mult (Power (Add (Var (Suc (Suc (Suc (Suc (Suc (Suc 0))))))) (Minus (Var (Suc (Suc (Suc (Suc (Suc 0)))))))) 2)
                                 (Inverse (Var (Suc (Suc (Suc (Suc 0)))))))
                           (Mult (Add (Var (Suc (Suc (Suc 0)))) (Minus (Var (Suc (Suc 0))))) (Add (Var (Suc 0)) (Minus (Var 0))))))))))))
  (map Some [a\<^sub>e, a\<^sub>o, s\<^sub>e, s\<^sub>o, (Float 2 0, Float 2 0),v\<^sub>e, v\<^sub>o, (Float 0 1, Float 0 1)]) (replicate 8 0)"

lemma less_Suc_iff_disj: "i < Suc x \<longleftrightarrow> i = x \<or> i < x"
  by auto

lemma checker':
  assumes "a \<in> {real_of_float al .. real_of_float au}"
  assumes "b \<in> {real_of_float bl .. real_of_float bu}"
  assumes "c \<in> {real_of_float cl .. real_of_float cu}"
  assumes "d \<in> {real_of_float dl .. real_of_float du}"
  assumes "e \<in> {real_of_float el .. real_of_float eu}"
  assumes "f \<in> {real_of_float fl .. real_of_float fu}"
  assumes chk: "checker' p (al, au) (bl, bu) (cl, cu) (dl, du) (el, eu) (fl, fu)"
  shows "checker a b c d e f"
  apply (rule checker_form)
  apply (rule approx_form_aux)
  apply (rule chk[unfolded checker'_def])
  using assms(1-6)
  by (auto simp: bounded_by_def less_Suc_iff_disj)

subsubsection\<open>Theorem 6\<close>
text \<open>\label{sec:thm6}\<close>
lemma
  assumes "a \<in> {real_of_float al .. real_of_float au}"
  assumes "b \<in> {real_of_float bl .. real_of_float bu}"
  assumes "c \<in> {real_of_float cl .. real_of_float cu}"
  assumes "d \<in> {real_of_float dl .. real_of_float du}"
  assumes "e \<in> {real_of_float el .. real_of_float eu}"
  assumes "f \<in> {real_of_float fl .. real_of_float fu}"
  assumes chk: "checker' p (al, au) (bl, bu) (cl, cu) (dl, du) (el, eu) (fl, fu)"
  shows checker'_precond: "check_precond a b c d e f"
    and checker'_no_collision: "safe_distance.no_collision c b a f e d  {0..}"
  unfolding atomize_conj
  apply (subst soundness_correctness[symmetric])
  using checker'[OF assms]
  by (auto simp: checker_def Let_def)

subsection \<open>a more direct (?) approach\<close>

lemma "x \<in> {-2 .. 0::real} \<longrightarrow> x * (x + 2) > -4.1"
  by (approximation 40)

definition symbolic_checker :: "real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> real \<Rightarrow> bool" where
"symbolic_checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<equiv>
  let
    e_stop = - v\<^sub>e / a\<^sub>e;
    o_stop = - v\<^sub>o / a\<^sub>o
  in
    check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<and>
    (\<not>quadroot_in 0 (min e_stop o_stop) (1/2 * (a\<^sub>o - a\<^sub>e)) (v\<^sub>o - v\<^sub>e) (s\<^sub>o - s\<^sub>e) \<and>
    \<not>quadroot_in e_stop o_stop (1/2 * a\<^sub>o) v\<^sub>o (s\<^sub>o - movement.p a\<^sub>e v\<^sub>e s\<^sub>e e_stop) \<and>
    \<not>quadroot_in o_stop e_stop (1/2 * a\<^sub>e) v\<^sub>e (s\<^sub>e - movement.p a\<^sub>o v\<^sub>o s\<^sub>o o_stop))"

theorem symbolic_soundness_correctness:
  "symbolic_checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<longleftrightarrow> check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o \<and> safe_distance.no_collision a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o {0..}"
proof -
  {
    assume c: "check_precond s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o"
    then interpret safe_distance a\<^sub>e v\<^sub>e s\<^sub>e a\<^sub>o v\<^sub>o s\<^sub>o
      by (simp add: check_precond_safe_distance)
    have "symbolic_checker s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o = no_collision {0..}"
      using c
      unfolding symbolic_checker symbolic_checker_def ego.s_t_stop other.s_t_stop ego.p_max_def other.p_max_def
      by (auto simp: Let_def movement.t_stop_def)
  }
  then show ?thesis
    by (auto simp: symbolic_checker_def Let_def)
qed

subsection \<open>Checking using global optimizaition\<close>

definition "parabola a b c x = Add c (Mult x (Add b (Mult x a)))"

definition "check_precond_form s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o =
  Conj (Less (Var s\<^sub>e) (Var s\<^sub>o))
  (Conj (LessEqual (Num 0) (Var v\<^sub>e))
    (Conj (LessEqual (Num 0) (Var v\<^sub>o))
      (Conj (Less (Var a\<^sub>e) (Num 0)) (Less (Var a\<^sub>o) (Num 0)))))"

lemma interpret_parabola:
  "interpret_floatarith (parabola (Var 0) (Var 1) (Var 2) (Var 3)) [a, b, c, x] =
    a * x\<^sup>2 + b * x + c"
  by (simp add: parabola_def algebra_simps power2_eq_square)

definition "nroot_in_form a b x f =
  (let nonzero = (\<lambda>x. Less (Num 0) (Abs x))
  in (Bound (Var x) a b (nonzero f)))"

lemma "interpret_form (nroot_in_form a b x f) xs \<longleftrightarrow>
  \<not>(root_in (interpret_floatarith a xs) (interpret_floatarith b xs) (\<lambda>s. interpret_floatarith f (xs[x:=s])))"
  unfolding nroot_in_form_def Let_def
  unfolding interpret_form.simps interpret_floatarith.simps
  oops

lemma
  "(\<forall>t. (t \<in> A \<longrightarrow> P t) \<and> (t \<in> B \<longrightarrow> Q t)) \<longleftrightarrow> (\<forall>t \<in> A. P t) \<and> (\<forall>t \<in> B. Q t)"
  by (auto)

definition
  checker_form where
  "checker_form s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o t =
    (let
      e_stop = Minus (Mult (Var v\<^sub>e) (Inverse (Var a\<^sub>e)));
      o_stop = Minus (Mult (Var v\<^sub>o) (Inverse (Var a\<^sub>o)));
      nonzero = (\<lambda>x. Less (Num 0) (Abs x));
      half = (\<lambda>x. Mult (Inverse (Num 2)) x);
      minus = (\<lambda>x y. Add x (Minus y));
      minusv = (\<lambda>x y. minus (Var x) (Var y));
      mov_p = (\<lambda>a v s t. parabola (half (Var a)) (Var v) (Var s) t)
    in Conj (check_precond_form s\<^sub>e v\<^sub>e a\<^sub>e s\<^sub>o v\<^sub>o a\<^sub>o)
      (Conj
        (Bound (Var t) (Num 0) (Min e_stop o_stop)
          (nonzero (parabola (half (minusv a\<^sub>o a\<^sub>e)) (minusv v\<^sub>o v\<^sub>e) (minusv s\<^sub>o s\<^sub>e) (Var t))))
      (Conj
        (Bound (Var t) e_stop o_stop
          (nonzero (parabola (half (Var a\<^sub>o)) (Var v\<^sub>o) (minus (Var s\<^sub>o) (mov_p a\<^sub>e v\<^sub>e s\<^sub>e e_stop)) (Var t))))
        (Bound (Var t) o_stop e_stop
          (nonzero (parabola (half (Var a\<^sub>e)) (Var v\<^sub>e) (minus (Var s\<^sub>e) (mov_p a\<^sub>o v\<^sub>o s\<^sub>o o_stop)) (Var t)))))))"

lemma "interpret_form (check_precond_form i j k l m n) xs =
  check_precond (xs ! i) (xs ! j) (xs ! k) (xs ! l) (xs ! m) (xs ! n)"
  by (auto simp: check_precond_form_def check_precond_def)

lemma "interpret_form (checker_form 0 1 2 3 4 5 6) [se, ve, ae, so, vo, ao, t] =
  symbolic_checker se ve ae so vo ao"
  apply (auto simp: checker_form_def Let_def )
  unfolding symbolic_checker_def Let_def
  oops

end