Library OracleLanguages.Imp.Oracles.SwapAssign


Require Import Common.
Require Import Imp.Lang.
Require Import ProgrammingLanguage.
Require Import OracleLanguage.
Require Import OracleHelpers.

Module Make
       (Var_as_DT : UsualDecidableTypeOrig)
       (Import Lang : ImpProgrammingLanguage Var_as_DT)
       (Import OracleHelpers : ImpOracleHelpers Var_as_DT Lang).
  Inductive mod :=
  | Swap.

  Inductive _cont_mod :=
  | SwapCont.

  Definition _genv := unit.

  Inductive _state : Type :=
  | Stuck : state state _state
  | State : state state list (cont_mod mod _cont_mod) _state.

  Definition perform_n_steps
             (n : nat) (S₁ S₂ : state)
             (km' : list (cont_mod mod _cont_mod)) : option _state :=
    
    match step υ S₁, step υ S₂ with
    | None, None
      None
    | _, _
      match nsteps' υ n S₁, nsteps' υ n S₂ with
      | (S₁', 0), (S₂', 0)
        
        Some (State S₁' S₂' km')
      | (S₁', S _), (S₂', S _)
        
        Some (Stuck S₁' S₂')
      | _, _
        
        None
      end
    end.

  Definition _step (_ : _genv) (S : _state) : option _state :=
    match S with
    | Stuck S₁ S₂
      None
    | State S₁ S₂ km
      match step_helper S₁ S₂ km with
      | None
        None
      | Some StuckStep
        None
      | Some (GenericStep S₁' S₂' km') ⇒
        Some (State S₁' S₂' km')
      | Some (SpecialCmdStep _ km') ⇒
        perform_n_steps 1 S₁ S₂ ((ContMod SwapCont)::km')
      | Some (SpecialContStep _ km') ⇒
        perform_n_steps 2 S₁ S₂ km'
      end
    end.

  Definition _left_state (S : _state) : ProgrammingLanguage.state imp_language :=
    match S with
    | Stuck S₁ _ | State S₁ _ _
      S₁
    end.

  Definition _right_state (S : _state) : ProgrammingLanguage.state imp_language :=
    match S with
    | Stuck _ S₂ | State _ S₂ _
      S₂
    end.

  Definition swap_assignments c :=
    match c with
    | Seq (Assign x e) (Assign y e') ⇒
      ret (Seq (Assign y e') (Assign x e))
    | _None
    end.

  Fixpoint apply_cmd_mod c m :=
    match m with
    | IdSome c
    | RecMod m₁ m₂
      match c with
      | Seq c₁ c₂
        apply_cmd_mod c₁ m₁ >>= λ c₁',
        apply_cmd_mod c₂ m₂ >>= λ c₂',
        Some (Seq c₁' c₂')
      | ITE b c₁ c₂
        apply_cmd_mod c₁ m₁ >>= λ c₁',
        apply_cmd_mod c₂ m₂ >>= λ c₂',
        Some (ITE b c₁' c₂')
      | While b c
        apply_cmd_mod c m₁ >>= λ c',
        Some (While b c')
      | Skip | Assign _ _ | Assert _
        None
      end
    | LeafMod Swapswap_assignments c
    end.

  Lemma apply_cmd_mod_id:
     c, apply_cmd_mod c Id = Some c.

  Definition assign_indep' c :=
    match c with
    | Seq (Assign x e) (Assign y e') ⇒
      if In_exp_var_dec x e' then
        false
      else
        if In_exp_var_dec y e then
          false
        else
          negb (MFacts.eqb x y)
    | _false
    end.

  Fixpoint assign_indep m c :=
    match m with
    | Idtrue
    | LeafMod Swap
      assign_indep' c
    | RecMod m₁ m₂
      match c with
      | Seq c₁ c₂ | ITE _ c₁ c₂assign_indep m₁ c₁ && assign_indep m₂ c₂
      | While _ c₁assign_indep m₁ c₁
      | Skip | Assign _ _ | Assert _false
      end
    end.

  Inductive km_invariant : list (cont_mod mod _cont_mod) cont cont Prop :=
  | empty_cont_mod : km_invariant [] [] []
  | cont_mod_inv :
       x₁ e₁ x₂ e₂ km k₁ k₂,
        x₁ x₂
        (¬ In_exp_var x₁ e₂)
        (¬ In_exp_var x₂ e₁)
        km_invariant km k₁ k₂
        km_invariant (ContMod SwapCont::km)
                     (Assign x₁ e₁::Assign x₂ e₂::k₁)
                     (Assign x₂ e₂::Assign x₁ e₁::k₂)
  | cmd_cont : c c' m km k₁ k₂,
      assign_indep m c = true
      apply_cmd_mod c m = Some c'
      km_invariant km k₁ k₂
      km_invariant (CmdMod m::km) (c::k₁) (c'::k₂).

  Definition _invariant (_ : _genv) (S : _state) : Prop :=
    match S with
    | Stuck S₁ S₂step υ S₁ = None step υ S₂ = None
    | State (k₁, s₁) (k₂, s₂) km
      km_invariant km k₁ k₂ M.Equal s₁ s₂
    end.

  Lemma eval_exp_add_neq:
     s x v e,
      (¬ In_exp_var x e)
      eval_exp s e = eval_exp (M.add x v s) e.

  Lemma eval_exp_add_neq':
     s₁ s₂ x v e,
      M.Equal s₁ s₂
      (¬ In_exp_var x e)
      eval_exp s₁ e = eval_exp (M.add x v s₂) e.

  Lemma map_swap_add_neq:
     {X : Type} s₁ s₂ x y (v₁ v₂ : X),
      M.Equal s₁ s₂
      x y
      M.Equal (M.add x v₁ (M.add y v₂ s₁)) (M.add y v₂ (M.add x v₁ s₂)).

  Lemma _invariant_1:
     genv os os',
      _invariant genv os
      _step genv os = Some os'
      _invariant genv os'.
  Lemma _prediction_soundness :
     genv os os',
      _invariant genv os
      _step genv os = Some os'
       n₁ n₂,
        opt_state_eq (nsteps υ n₁ (_left_state os))
                       (Some (_left_state os'))
         opt_state_eq (nsteps υ n₂ (_right_state os))
                       (Some (_right_state os'))
         n₁ + n₂ > 0.

  Lemma _prediction_completeness :
     genv os,
      _invariant genv os
      _step genv os = None
      step υ (_left_state os) = None
       step υ (_right_state os) = None.
  Definition swapassign_oracle : oracle_language imp_language imp_language :=
    {|
      oracle_state := _state;
      oracle_genv := unit;
      oracle_step := _step;
      left_state := _left_state;
      right_state := _right_state;
      left_genv := λ _, υ;
      right_genv := λ _, υ;
      invariant := _invariant;
      invariant_1 := _invariant_1;
      prediction_soundness := _prediction_soundness;
      prediction_completeness := _prediction_completeness
    |}.
End Make.