Theory RealTimeDeque_Dequeue_Proof

section "Dequeue Proofs"

theory RealTimeDeque_Dequeue_Proof
imports Deque RealTimeDeque_Aux States_Proof
begin
 
lemma list_deqL' [simp]: "invar deque; listL deque  []; deqL' deque = (x, deque')
    x # listL deque' = listL deque"
proof(induction deque arbitrary: x rule: deqL'.induct)
  case (4 left right length_right)

  then obtain left' where pop_left[simp]: "Idle.pop left = (x, left')"
    by(auto simp: Let_def split: if_splits stack.splits prod.splits idle.splits)

  then obtain stack_left' length_left' 
    where left'[simp]: "left' = idle.Idle stack_left' length_left'"
    using idle.exhaust by blast

  from 4 have invar_left': "invar left'"
    using Idle_Proof.invar_pop[of left]
    by auto

  then have size_left' [simp]: "size stack_left' = length_left'"
    by auto

  have size_left'_size_left [simp]: "size stack_left' = (size left) - 1"
    using Idle_Proof.size_pop_sub[of left x left']
    by auto

  show ?case
  proof(cases "3 * length_left'  length_right")
    case True
    with 4 pop_left show ?thesis
      using Idle_Proof.pop_list[of left x left']
      by auto
  next
    case False
    note Start_Rebalancing = False

    then show ?thesis
    proof(cases "length_left'  1")
      case True
      let ?big = "Big1 (Current [] 0 right (size right - Suc length_left')) 
                           right [] (size right - Suc length_left')"
      let ?small = "Small1 (Current [] 0 stack_left' (Suc (2 * length_left'))) stack_left' []"
      let ?states = "States Left ?big ?small"

      from 4 Start_Rebalancing True invar_left' have invar: "invar ?states"
        by(auto simp: Let_def rev_take rev_drop)

      with 4 Start_Rebalancing True invar_left'
      have "States_Aux.listL ?states = tl (Idle_Aux.list left) @ rev (Stack_Aux.list right)"
        using pop_list_tl'[of left x left'] 
        by (auto simp del: take_rev_def)
    
      with invar 
      have "States_Aux.listL ((step^^6) ?states) = 
            tl (Idle_Aux.list left) @ rev (Stack_Aux.list right)"
        using step_n_listL[of ?states 6]
        by presburger
      
      with 4 Start_Rebalancing True show ?thesis 
        by(auto simp: Let_def)
    next
      case False
      from False Start_Rebalancing 4 have [simp]:"size left = 1"
        using size_left' size_left'_size_left by auto
        
      with False Start_Rebalancing 4 have [simp]: "Idle_Aux.list left = [x]"
        by(induction left)(auto simp: length_one_hd split: stack.splits)

      obtain right1 right2 where "right = Stack right1 right2"
        using Stack_Aux.list.cases by blast

      with False Start_Rebalancing 4 show ?thesis 
        by(induction right1 right2 rule: small_deque.induct) auto
    qed 
  qed
next
  case (5 big small)

  then have start_invar: "invar (States Left big small)"
    by auto

  from 5 have small_invar: "invar small"
    by auto

  from 5 have small_size: "0 < size small"
    by auto

  with 5(3) obtain small' where pop: "Small.pop small = (x, small')"
    by(cases small)
      (auto simp: Let_def split: states.splits direction.splits state_splits prod.splits)

  let ?states_new = "States Left big small'"
  let ?states_stepped = "(step^^4) ?states_new"

  have invar: "invar ?states_new"
    using pop start_invar small_size invar_pop_small[of Left big small x small']
    by auto

  have "x # Small_Aux.list_current small' = Small_Aux.list_current small"
    using small_invar small_size pop Small_Proof.pop_list_current[of small x small'] by auto
    
  then have listL: 
      "x # States_Aux.listL ?states_new = 
       Small_Aux.list_current small @ rev (Big_Aux.list_current big)"
    using invar small_size Small_Proof.pop_list_current[of small x small'] 5(1)
    by auto      

  from invar have "invar ?states_stepped"
    using invar_step_n by blast

  then have states_listL_list_current [simp]: "x # States_Aux.listL ?states_stepped = 
                Small_Aux.list_current small @ rev (Big_Aux.list_current big)"
    using States_Proof.step_n_listL invar listL by metis

  then have "listL (deqL (Rebal (States Left big small))) = States_Aux.listL ?states_stepped"
    by(auto simp: Let_def pop split: prod.splits direction.splits states.splits state_splits)

  then have states_listL_list_current: 
      "x # listL (deqL (Rebal (States Left big small))) =
       Small_Aux.list_current small @ rev (Big_Aux.list_current big)"
    by auto

  with 5(1) have "listL (Rebal (States Left big small)) = 
                  Small_Aux.list_current small @ rev (Big_Aux.list_current big)"
    by auto

  with states_listL_list_current 
  have "x # listL (deqL (Rebal (States Left big small))) = 
        listL (Rebal (States Left big small))"
    by auto

  with 5 show ?case by auto
next
  case (6 big small)
  then have start_invar: "invar (States Right big small)"
    by auto

  from 6 have big_invar: "invar big"
    by auto

  from 6 have big_size: "0 < size big"
    by auto

  with 6(3) obtain big' where pop: "Big.pop big = (x, big')"
    by(cases big)
      (auto simp: Let_def split: prod.splits direction.splits states.splits state_splits)

  let ?states_new = "States Right big' small"
  let ?states_stepped = "(step^^4) ?states_new"

  have invar: "invar ?states_new"
    using pop start_invar big_size invar_pop_big[of Right big small]
    by auto

  have big_list_current: "x # Big_Aux.list_current big' = Big_Aux.list_current big"
    using big_invar big_size pop by auto
    
  then have listL: 
    "x # States_Aux.listL ?states_new = 
     Big_Aux.list_current big @ rev (Small_Aux.list_current small)"
    proof(cases "States_Aux.lists ?states_new")
      case (Pair bigs smalls)
      with invar big_list_current show ?thesis
        using app_rev[of smalls bigs]
        by(auto split: prod.splits)
    qed

  from invar have four_steps: "invar ?states_stepped"
    using invar_step_n by blast

  then have [simp]: 
      "x # States_Aux.listL ?states_stepped = 
       Big_Aux.list_current big @ rev (Small_Aux.list_current small)"
    using States_Proof.step_n_listL[of ?states_new 4] invar listL
    by auto

  then have "listL (deqL (Rebal (States Right big small))) = 
              States_Aux.listL ?states_stepped"
    by(auto simp: Let_def pop split: prod.splits direction.splits states.splits state_splits)

  then have listL_list_current: 
      "x # listL (deqL (Rebal (States Right big small))) = 
       Big_Aux.list_current big @ rev (Small_Aux.list_current small)"
    by auto

  with 6(1) have "listL (Rebal (States Right big small)) = 
                  Big_Aux.list_current big @ rev (Small_Aux.list_current small)"
    using invar_list_big_first[of "States Right big small"] by fastforce

  with listL_list_current have 
    "x # listL (deqL (Rebal (States Right big small))) = 
     listL (Rebal (States Right big small))"
    by auto

  with 6 show ?case by auto
qed auto

lemma list_deqL [simp]:
    "invar deque; listL deque  []  listL (deqL deque) = tl (listL deque)"
  using cons_tl[of "fst (deqL' deque)" "listL (deqL deque)" "listL deque"]
  by(auto split: prod.splits)

lemma list_firstL [simp]:
    "invar deque; listL deque  []  firstL deque = hd (listL deque)"
  using cons_hd[of "fst (deqL' deque)" "listL (deqL deque)" "listL deque"] 
  by(auto split: prod.splits)

lemma invar_deqL:
    "invar deque; ¬ is_empty deque  invar (deqL deque)"
proof(induction deque rule: deqL'.induct)
  case (4 left right length_right)
  then obtain x left' where pop_left[simp]: "Idle.pop left = (x, left')"
    by fastforce

  then obtain stack_left' length_left' 
    where left'[simp]: "left' = idle.Idle stack_left' length_left'"
    using idle.exhaust by blast

  from 4 have invar_left': "invar left'" "invar left"
    using Idle_Proof.invar_pop by fastforce+

  have [simp]: "size stack_left' = size left - 1" 
    by (metis Idle_Proof.size_pop_sub left' pop_left size_idle.simps)

  have [simp]: "length_left' = size left - 1" 
    using invar_left' by auto

  from 4 have list: "x # Idle_Aux.list left' = Idle_Aux.list left"
    using Idle_Proof.pop_list[of left x left']
    by auto

  show ?case 
  proof(cases "length_right  3 * size left'")
    case True
    with 4 invar_left' show ?thesis
      by(auto simp: Stack_Proof.size_empty[symmetric])
  next
    case False
    note Start_Rebalancing = False
    then show ?thesis 
    proof(cases "1  size left'")
      case True
      let ?big = 
        "Big1 
            (Current [] 0 right (size right - Suc length_left')) 
            right [] (size right - Suc length_left')"
      let ?small = "Small1 (Current [] 0 stack_left' (Suc (2 * length_left'))) stack_left' []"
      let ?states = "States Left ?big ?small"

      from 4 Start_Rebalancing True invar_left' 
      have invar: "invar ?states"
        by(auto simp: Let_def rev_take rev_drop)

      then have invar_stepped: "invar ((step^^6) ?states)"
        using invar_step_n by blast

      from 4 Start_Rebalancing True 
      have remaining_steps: "6 < remaining_steps ?states"
        by auto

      then have remaining_steps_end: "0 < remaining_steps ((step^^6) ?states)"
        by(simp only: remaining_steps_n_steps_sub[of ?states 6] invar)

      from 4 Start_Rebalancing True  
      have size_ok': "size_ok' ?states (remaining_steps ?states - 6)"
        by auto
         
      then have size_ok: "size_ok ((step^^6) ?states)"
        using invar remaining_steps size_ok_steps by blast

      from True Start_Rebalancing 4 show ?thesis
        using remaining_steps_end size_ok invar_stepped
        by(auto simp: Let_def)
    next
      case False
      from False Start_Rebalancing 4 have [simp]: "size left = 1"
        by auto
        
      with False Start_Rebalancing 4 have [simp]: "Idle_Aux.list left = [x]"  
        using list[symmetric]
        by(auto simp: list Stack_Proof.list_empty_size)
     
      obtain right1 right2 where "right = Stack right1 right2"
        using Stack_Aux.list.cases by blast

      with False Start_Rebalancing 4 show ?thesis 
        by(induction right1 right2 rule: small_deque.induct) auto
    qed
  qed
next
  case (5 big small)
  
  obtain x small' where small' [simp]: "Small.pop small = (x, small')"
    by fastforce

  let ?states = "States Left big small'"
  let ?states_stepped = "(step^^4) ?states"

  obtain big_stepped small_stepped where stepped [simp]: 
       "?states_stepped = States Left big_stepped small_stepped"
     by (metis remaining_steps_states.cases step_n_same)

  from 5 have invar: "invar ?states"
    using invar_pop_small[of Left big small x small']
    by auto

  then have invar_stepped: "invar ?states_stepped"
    using invar_step_n by blast

  show ?case
  proof(cases "4 < remaining_steps ?states")
    case True

    then have remaining_steps: "0 < remaining_steps ?states_stepped"
      using invar remaining_steps_n_steps_sub[of ?states 4]
      by simp

    from True have size_ok: "size_ok ?states_stepped"
      using step_4_pop_small_size_ok[of Left big small x small'] 5(1)
      by auto

    from remaining_steps size_ok invar_stepped show ?thesis
      by(cases big_stepped; cases small_stepped) (auto simp: Let_def split!: common_state.split)
  next
    case False
    then have remaining_steps_stepped: "remaining_steps ?states_stepped = 0"
      using invar by(auto simp del: stepped)

    then obtain small_current small_idle big_current big_idle where idle [simp]: "
      States Left big_stepped small_stepped = 
      States Left 
          (Big2 (common_state.Idle big_current big_idle))
          (Small3 (common_state.Idle small_current small_idle))
      "
      using remaining_steps_idle' invar_stepped remaining_steps_stepped
      by fastforce

    have size_new_small : "1 < size_new small" 
      using 5 by auto

    have [simp]: "size_new small = Suc (size_new small')" 
      using 5 by auto

    have [simp]: "size_new small' = size_new small_stepped"
      using invar step_n_size_new_small stepped
      by metis

    have [simp]: "size_new small_stepped = size small_idle" 
      using idle invar_stepped
      by(cases small_stepped) auto

    have [simp]: "¬is_empty small_idle"
      using size_new_small
      by (simp add: Idle_Proof.size_not_empty)

    have [simp]: "size_new big = size_new big_stepped"
      by (metis invar step_n_size_new_big stepped)

    have [simp]: "size_new big_stepped = size big_idle" 
      using idle invar_stepped
      by(cases big_stepped) auto
      
    have "0 < size big_idle" 
      using 5 by auto
  
    then have [simp]: "¬is_empty big_idle"
      by (auto simp: Idle_Proof.size_not_empty)

    have [simp]: "size small_idle  3 * size big_idle"
      using 5 by auto

    have [simp]: "size big_idle  3 * size small_idle"
      using 5 by auto

    show ?thesis
      using invar_stepped by auto 
  qed
next
  case (6 big small)
  
  obtain x big' where big' [simp]: "Big.pop big = (x, big')"
    by fastforce

  let ?states = "States Right big' small"
  let ?states_stepped = "(step^^4) ?states"

  obtain big_stepped small_stepped where stepped [simp]: 
       "?states_stepped = States Right big_stepped small_stepped"
     by (metis remaining_steps_states.cases step_n_same)

  from 6 have invar: "invar ?states"
    using invar_pop_big[of Right big small x big']
    by auto

  then have invar_stepped: "invar ?states_stepped"
    using invar_step_n by blast

  show ?case
  proof(cases "4 < remaining_steps ?states")
    case True

    then have remaining_steps: "0 < remaining_steps ?states_stepped"
      using invar remaining_steps_n_steps_sub[of ?states 4]
      by simp

    from True have size_ok: "size_ok ?states_stepped"
      using step_4_pop_big_size_ok[of Right big small x big'] 6(1)
      by auto

    from remaining_steps size_ok invar_stepped show ?thesis
      by(cases big_stepped; cases small_stepped) (auto simp: Let_def split!: common_state.split)
  next
    case False
    then have remaining_steps_stepped: "remaining_steps ?states_stepped = 0"
      using invar by(auto simp del: stepped)

    then obtain small_current small_idle big_current big_idle where idle [simp]: "
      States Right big_stepped small_stepped = 
      States Right 
          (Big2 (common_state.Idle big_current big_idle))
          (Small3 (common_state.Idle small_current small_idle))
      "
      using remaining_steps_idle' invar_stepped remaining_steps_stepped
      by fastforce

    have size_new_big : "1 < size_new big" 
      using 6 by auto

    have [simp]: "size_new big = Suc (size_new big')" 
      using 6 by auto

    have [simp]: "size_new big' = size_new big_stepped"
      using invar step_n_size_new_big stepped
      by metis

    have [simp]: "size_new big_stepped = size big_idle" 
      using idle invar_stepped
      by(cases big_stepped) auto

    have [simp]: "¬is_empty big_idle"
      using size_new_big
      by (simp add: Idle_Proof.size_not_empty)

    have [simp]: "size_new small = size_new small_stepped"
      by (metis invar step_n_size_new_small stepped)

    have [simp]: "size_new small_stepped = size small_idle" 
      using idle invar_stepped
      by(cases small_stepped) auto
      
    have "0 < size small_idle" 
      using 6 by auto
  
    then have [simp]: "¬is_empty small_idle"
      by (auto simp: Idle_Proof.size_not_empty)

    have [simp]: "size big_idle  3 * size small_idle"
      using 6 by auto

    have [simp]: "size small_idle  3 * size big_idle"
      using 6 by auto

    show ?thesis
      using invar_stepped by auto 
  qed
qed auto

end