Library OracleLanguages.Imp.Oracles.SeqAssoc


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 :=
  | UnfoldSeq
  | FoldSeq.

  Inductive _cont_mod :=
  | ExtraUnfoldLeft
  | ExtraUnfoldRight.

  Definition _genv := unit.

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

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

  Definition _step (_ : _genv) (S : _state) : option _state :=
    match S with
    | 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 m km') ⇒
        match m with
        | UnfoldSeq
          perform_n_m_steps 2 1 S₁ S₂ (CmdMod Id::ContMod ExtraUnfoldRight::km')
        | FoldSeq
          perform_n_m_steps 1 2 S₁ S₂ (CmdMod Id::ContMod ExtraUnfoldLeft::km')
        end
      | Some (SpecialContStep m km') ⇒
        match m with
        | ExtraUnfoldLeft
          step υ S₁ >>= λ S₁',
          Some (State S₁' S₂ (CmdMod Id::CmdMod Id::km'))
        | ExtraUnfoldRight
          step υ S₂ >>= λ S₂',
          Some (State S₁ S₂' (CmdMod Id::CmdMod Id::km'))
        end
      end
    end.

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

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

  Definition unfold_seq c :=
    match c with
    | Seq (Seq c₁ c₂) c₃
      ret (Seq c₁ (Seq c₂ c₃))
    | _None
    end.

  Definition fold_seq c :=
    match c with
    | Seq c₁ (Seq c₂ c₃) ⇒
      ret (Seq (Seq c₁ c₂) c₃)
    | _None
    end.

  Fixpoint apply_cmd_mod c m {struct 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 UnfoldSequnfold_seq c
    | LeafMod FoldSeqfold_seq c
    end.

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

  Inductive km_invariant : list (cont_mod mod _cont_mod) cont cont Prop :=
  | empty_cont_mod : km_invariant [] [] []
  | extra_unfold_left_inv :
       c₁ c₂ km k₁ k₂,
        km_invariant km k₁ k₂
        km_invariant (ContMod ExtraUnfoldLeft::km)
                     ((Seq c₁ c₂)::k₁)
                     (c₁::c₂::k₂)
  | extra_unfold_right_inv :
       c₁ c₂ km k₁ k₂,
        km_invariant km k₁ k₂
        km_invariant (ContMod ExtraUnfoldRight::km)
                     (c₁::c₂::k₁)
                     ((Seq c₁ c₂)::k₂)
  | cmd_cont : c c' m km k₁ k₂,
      apply_cmd_mod c m = Some c'
      km_invariant km k₁ k₂
      km_invariant (CmdMod m::km) (c::k₁) (c'::k₂).

  Definition leaf_mod_of_cmds (c₁ c₂ : cmd) : option mod :=
    match unfold_seq c₁ >>= λ c₁',
          if beq_cmd c₁' c₂ then
            Some UnfoldSeq
          else
            None
    with
    | Some mSome m
    | None
      fold_seq c₁ >>= λ c₁',
      if beq_cmd c₁' c₂ then
        Some FoldSeq
      else
        None
    end.

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

  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 seqassoc_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.