Module CSCorrectness

From Coq Require Import List.
Import List.ListNotations.
Open Scope list_scope.
From Coq Require Import Setoid Morphisms.

From Velus Require Import Common.
From Velus Require Import Operators Environment.
From Velus Require Import FunctionalEnvironment.
From Velus Require Import Clocks.
From Velus Require Import CoindStreams IndexedStreams.
From Velus Require Import CoindIndexed.
From Velus Require Import Fresh.
From Velus Require Import Lustre.StaticEnv.
From Velus Require Import Lustre.LSyntax Lustre.LOrdered Lustre.LTyping Lustre.LClocking Lustre.LSemantics Lustre.LClockedSemantics.
From Velus Require Import Lustre.SubClock.SCCorrectness.
From Velus Require Import Lustre.ClockSwitch.ClockSwitch.
From Velus Require Import Lustre.ClockSwitch.CSClocking.

Module Type CSCORRECTNESS
       (Import Ids : IDS)
       (Import Op : OPERATORS)
       (Import OpAux : OPERATORS_AUX Ids Op)
       (Import Cks : CLOCKS Ids Op OpAux)
       (Import CStr : COINDSTREAMS Ids Op OpAux Cks)
       (Import Senv : STATICENV Ids Op OpAux Cks)
       (Import Syn : LSYNTAX Ids Op OpAux Cks Senv)
       (Import Ty : LTYPING Ids Op OpAux Cks Senv Syn)
       (Import Cl : LCLOCKING Ids Op OpAux Cks Senv Syn)
       (Import Ord : LORDERED Ids Op OpAux Cks Senv Syn)
       (Import Sem : LSEMANTICS Ids Op OpAux Cks Senv Syn Ord CStr)
       (Import LCS : LCLOCKEDSEMANTICS Ids Op OpAux Cks Senv Syn Cl Ord CStr Sem)
       (Import CS : CLOCKSWITCH Ids Op OpAux Cks Senv Syn).

  Module Import SCT := SCCorrectnessFun Ids Op OpAux Cks CStr Senv Syn Cl Ord Sem LCS SC. Import SC.

  Module Clocking := CSClockingFun Ids Op OpAux Cks Senv Syn Cl CS.
  Module Import CIStr := CoindIndexedFun Ids Op OpAux Cks CStr IStr.

  Import Fresh Facts Tactics List.

  Section switch_block.
    Variable G1 : @global noauto auto_prefs.
    Variable G2 : @global noswitch switch_prefs.

    Hypothesis HwcG1 : wc_global G1.
    Hypothesis HGref : global_sem_refines G1 G2.

    Import Permutation.
    Import Fresh Facts Tactics List.

    Lemma sem_clock_Con_when Hi bs' bs : forall ck xc tx tn e sc,
        wt_stream sc (Tenum tx tn) ->
        slower sc bs ->
        sem_var Hi xc sc ->
        sem_clock Hi bs' ck (abstract_clock sc) ->
        sem_clock Hi bs' (Con ck xc (Tenum tx tn, e)) (fwhenb e bs sc).
    Proof.

    Lemma when_free_sem Hi' bs' : forall x y ty ck cx tx tn e sc vs,
        sem_var Hi' (Var cx) sc ->
        wt_stream sc (Tenum tx tn) ->
        sem_var Hi' (Var x) vs ->
        abstract_clock vsabstract_clock sc ->
        sem_var Hi' (Var y) (fwhenv e vs sc) ->
        sem_block_ck G2 Hi' bs' (when_free x y ty ck cx (Tenum tx tn) e).
    Proof.

    Lemma merge_when {A} : forall c vs (brs : list (enumtag * A)) tx tn,
        wt_stream c (Tenum tx tn) ->
        abstract_clock vsabstract_clock c ->
        Permutation (map fst brs) (seq 0 (length tn)) ->
        merge c (map (fun '(k, _) => (k, fwhenv k vs c)) brs) vs.
    Proof.

    Lemma merge_defs_sem Hi Hi' bs' : forall sub x ty ck xc tx tn subs c vs,
        Permutation (map fst subs) (seq 0 (length tn)) ->
        (forall x0 y vs, Env.find x0 sub = Some y -> sem_var Hi (Var x0) vs -> sem_var Hi' (Var y) vs) ->
        (forall x0 vs, Env.find x0 sub = None -> sem_var Hi (Var x0) vs -> sem_var Hi' (Var x0) vs) ->
        sem_var Hi' (Var xc) c ->
        wt_stream c (Tenum tx tn) ->
        sem_var Hi (Var x) vs ->
        abstract_clock vsabstract_clock c ->
        Forall (fun '(k, sub) => sem_var Hi' (Var (rename_var sub x)) (fwhenv k vs c)) subs ->
        sem_block_ck G2 Hi' bs' (merge_defs sub x ty ck xc (Tenum tx tn) subs).
    Proof.

    Definition st_senv {pref} (st: fresh_st pref _) := senv_of_tyck (st_anns st).

    Lemma cond_eq_sem envty : forall Hi bs e ty ck vs x xcs eqs' st st',
        Forall (AtomOrGensym auto_prefs) (map fst envty) ->
        dom_ub Hi (envty ++ st_senv st) ->
        sem_exp_ck G2 Hi bs e [vs] ->
        sem_clock (var_history Hi) bs ck (abstract_clock vs) ->
        cond_eq e ty ck st = (x, xcs, eqs', st') ->
        exists Hi',
          sem_var (Hi + Hi') (Var x) vs
          /\ Forall (sem_equation_ck G2 (Hi + Hi') bs) eqs'
          /\ HiHi + Hi'
          /\ (forall x, FEnv.In (Var x) Hi' <-> In x (map fst xcs))
          /\ (forall x, ~FEnv.In (Last x) Hi')
          /\ sc_vars (senv_of_tyck xcs) (Hi + Hi') bs.
    Proof.

    Lemma new_idents_sem {A} Γty frees defs bck tx tn xc :
      forall Hi1 Hi2 bs' (branches : list (enumtag * A)) xs sc st st',
        Forall (AtomOrGensym auto_prefs) (map fst Γty) ->
        dom_ub Hi2ty ++ st_senv st) ->
        sem_var Hi2 (Var xc) sc ->
        sem_clock (var_history Hi2) bs' bck (abstract_clock sc) ->
        wt_stream sc (Tenum tx tn) ->
        Forall (fun '(x, _) => forall vs, sem_var Hi1 (Var x) vs -> abstract_clock vsabstract_clock sc) (frees++defs) ->
        mmap
          (fun '(k, _) =>
             bind (new_idents bck xc (Tenum tx tn) k frees)
                  (fun nfrees =>
                     bind (new_idents bck xc (Tenum tx tn) k defs)
                          (fun ndefs => ret (k, Env.from_list (map (fun '(x, y2, _) => (x, y2)) (nfrees ++ ndefs)), nfrees, ndefs)))) branches st = (xs, st') ->
        exists Hi',
          Hi2Hi2 + Hi'
          /\ (forall x, FEnv.In (Var x) Hi' <-> InMembers x (flat_map (fun '(_, _, nfrees, ndefs) => (map (fun '(_, x, (ty, ck)) => (x, (ty, ck, xH, @None (exp * ident)))) (nfrees++ndefs))) xs))
          /\ (forall x, ~FEnv.In (Last x) Hi')
          /\ Forall (fun '(k, sub, _, _) => (forall x y vs, Env.find x sub = Some y -> sem_var Hi1 (Var x) vs -> sem_var (Hi2 + Hi') (Var y) (fwhenv k vs sc))) xs
          /\ sc_vars (flat_map (fun '(_, _, nfrees, ndefs) => (map (fun '(_, x, (ty, ck)) => (x, Build_annotation ty ck xH None)) (nfrees++ndefs))) xs) (Hi2 + Hi') bs'.
    Proof.

    Fact switch_blocks_sem' : forall bck sub Γty Γck Hi Hi' bs bs' blks blks' st st',
        Forall
          (fun blk => forall bck sub Γty Γck Hi Hi' bs bs' blk' st st',
               (forall x, ~IsLast Γty x) ->
               (forall x, ~IsLast Γck x) ->
               (forall x, Env.In x sub -> InMembers x Γck) ->
               (forall x y, Env.find x sub = Some y -> exists (n : ident) (hint : option ident), y = gensym switch hint n) ->
               (forall x y vs, Env.find x sub = Some y -> sem_var Hi (Var x) vs -> sem_var Hi' (Var y) vs) ->
               (forall x vs, Env.find x sub = None -> sem_var Hi (Var x) vs -> sem_var Hi' (Var x) vs) ->
               incl (map fst Γck) (map fst Γty) ->
               NoDupMembers Γty ->
               NoDupMembers Γck ->
               Forall (AtomOrGensym auto_prefs) (map fst Γty) ->
               dom_ub Hi Γty ->
               dom_lb Hi Γck ->
               sc_vars Γck Hi bs ->
               dom_ub Hi' (Γty ++ st_senv st) ->
               sem_clock (var_history Hi') bs' bck bs ->
               noauto_block blk ->
               NoDupLocals (map fst Γty) blk ->
               GoodLocals auto_prefs blk ->
               wt_block G1 Γty blk ->
               wc_block G1 Γck blk ->
               sem_block_ck G1 Hi bs blk ->
               switch_block Γck bck sub blk st = (blk', st') ->
               sem_block_ck G2 Hi' bs' blk') blks ->
        (forall x, ~IsLast Γty x) ->
        (forall x, ~IsLast Γck x) ->
        (forall x, Env.In x sub -> InMembers x Γck) ->
        (forall x y, Env.find x sub = Some y -> exists (n : ident) (hint : option ident), y = gensym switch hint n) ->
        (forall x y vs, Env.find x sub = Some y -> sem_var Hi (Var x) vs -> sem_var Hi' (Var y) vs) ->
        (forall x vs, Env.find x sub = None -> sem_var Hi (Var x) vs -> sem_var Hi' (Var x) vs) ->
        incl (map fst Γck) (map fst Γty) ->
        NoDupMembers Γty ->
        NoDupMembers Γck ->
        Forall (AtomOrGensym auto_prefs) (map fst Γty) ->
        dom_ub Hi Γty ->
        dom_lb Hi Γck ->
        sc_vars Γck Hi bs ->
        dom_ub Hi' (Γty ++ st_senv st) ->
        sem_clock (var_history Hi') bs' bck bs ->
        Forall noauto_block blks ->
        Forall (NoDupLocals (map fst Γty)) blks ->
        Forall (GoodLocals auto_prefs) blks ->
        Forall (wt_block G1 Γty) blks ->
        Forall (wc_block G1 Γck) blks ->
        Forall (sem_block_ck G1 Hi bs) blks ->
        mmap (switch_block Γck bck sub) blks st = (blks', st') ->
        Forall (sem_block_ck G2 Hi' bs') blks'.
    Proof.

    Lemma switch_scope_sem {A} P_na P_nd P_good P_wt P_wc P_sem1 f_switch (P_sem2: _ -> _ -> Prop) :
      forall locs (blk: A) bck sub Γty Γck Hi Hi' bs bs' s' st st',
        (forall x, ~IsLast Γty x) ->
        (forall x, ~IsLast Γck x) ->
        (forall x, Env.In x sub -> InMembers x Γck) ->
        (forall x y, Env.find x sub = Some y -> exists (n : ident) (hint : option ident), y = gensym switch hint n) ->
        (forall x y vs, Env.find x sub = Some y -> sem_var Hi (Var x) vs -> sem_var Hi' (Var y) vs) ->
        (forall x vs, Env.find x sub = None -> sem_var Hi (Var x) vs -> sem_var Hi' (Var x) vs) ->
        incl (map fst Γck) (map fst Γty) ->
        NoDupMembers Γty ->
        NoDupMembers Γck ->
        Forall (AtomOrGensym auto_prefs) (map fst Γty) ->
        dom_ub Hi Γty ->
        dom_lb Hi Γck ->
        sc_vars Γck Hi bs ->
        dom_ub Hi' (Γty ++ st_senv st) ->
        sem_clock (var_history Hi') bs' bck bs ->
        noauto_scope P_na (Scope locs blk) ->
        NoDupScope P_nd (map fst Γty) (Scope locs blk) ->
        GoodLocalsScope P_good auto_prefs (Scope locs blk) ->
        wt_scope P_wt G1 Γty (Scope locs blk) ->
        wc_scope P_wc G1 Γck (Scope locs blk) ->
        sem_scope_ck (sem_exp_ck G1) P_sem1 Hi bs (Scope locs blk) ->
        switch_scope f_switch Γck bck sub (Scope locs blk) st = (s', st') ->
        (forall Γty Γck Hi Hi' blk' st st',
            (forall x, ~IsLast Γty x) ->
            (forall x, ~IsLast Γck x) ->
            (forall x, Env.In x sub -> InMembers x Γck) ->
            (forall x y, Env.find x sub = Some y -> exists (n : ident) (hint : option ident), y = gensym switch hint n) ->
            (forall x y vs, Env.find x sub = Some y -> sem_var Hi (Var x) vs -> sem_var Hi' (Var y) vs) ->
            (forall x vs, Env.find x sub = None -> sem_var Hi (Var x) vs -> sem_var Hi' (Var x) vs) ->
            incl (map fst Γck) (map fst Γty) ->
            NoDupMembers Γty ->
            NoDupMembers Γck ->
            Forall (AtomOrGensym auto_prefs) (map fst Γty) ->
            dom_ub Hi Γty ->
            dom_lb Hi Γck ->
            sc_vars Γck Hi bs ->
            dom_ub Hi' (Γty ++ st_senv st) ->
            sem_clock (var_history Hi') bs' bck bs ->
            P_na blk ->
            P_nd (map fst Γty) blk ->
            P_good blk ->
            P_wt Γty blk ->
            P_wc Γck blk ->
            P_sem1 Hi blk ->
            f_switch Γck blk st = (blk', st') ->
            P_sem2 Hi' blk') ->
        sem_scope_ck (sem_exp_ck G2) P_sem2 Hi' bs' s'.
    Proof.

    Ltac inv_branch :=
      match goal with
      | _ => (Syn.inv_branch || Ty.inv_branch || Cl.inv_branch || Sem.inv_branch || LCS.inv_branch)
      end.

    Lemma change_last : forall Γ Hi Hi',
        (forall x, ~IsLast Γ x) ->
        dom_ub Hi Γ ->
        (forall x vs, sem_var Hi (Last x) vs -> sem_var Hi' (Last x) vs).
    Proof.

    Lemma switch_block_sem : forall blk bck sub Γty Γck Hi Hi' bs bs' blk' st st',
        (forall x, ~IsLast Γty x) ->
        (forall x, ~IsLast Γck x) ->
        (forall x, Env.In x sub -> InMembers x Γck) ->
        (forall x y, Env.find x sub = Some y -> exists (n : ident) (hint : option ident), y = gensym switch hint n) ->
        (forall x y vs, Env.find x sub = Some y -> sem_var Hi (Var x) vs -> sem_var Hi' (Var y) vs) ->
        (forall x vs, Env.find x sub = None -> sem_var Hi (Var x) vs -> sem_var Hi' (Var x) vs) ->
        incl (map fst Γck) (map fst Γty) ->
        NoDupMembers Γty ->
        NoDupMembers Γck ->
        Forall (AtomOrGensym auto_prefs) (map fst Γty) ->
        dom_ub Hi Γty ->
        dom_lb Hi Γck ->
        sc_vars Γck Hi bs ->
        dom_ub Hi' (Γty ++ st_senv st) ->
        sem_clock (var_history Hi') bs' bck bs ->
        noauto_block blk ->
        NoDupLocals (map fst Γty) blk ->
        GoodLocals auto_prefs blk ->
        wt_block G1 Γty blk ->
        wc_block G1 Γck blk ->
        sem_block_ck G1 Hi bs blk ->
        switch_block Γck bck sub blk st = (blk', st') ->
        sem_block_ck G2 Hi' bs' blk'.
    Proof.

  End switch_block.

  Lemma switch_node_sem G1 G2 : forall f n ins outs,
      global_sem_refines G1 G2 ->
      CommonTyping.wt_program wt_node {| types := G1.(types); externs := G1.(externs); nodes := n :: G1.(nodes) |} ->
      wc_global (Global G1.(types) G1.(externs) (n::G1.(nodes))) ->
      Ordered_nodes (Global G1.(types) G1.(externs) (n::G1.(nodes))) ->
      Ordered_nodes (Global G2.(types) G2.(externs) ((switch_node n)::G2.(nodes))) ->
      sem_node_ck (Global G1.(types) G1.(externs) (n::G1.(nodes))) f ins outs ->
      sem_node_ck (Global G2.(types) G2.(externs) ((switch_node n)::G2.(nodes))) f ins outs.
  Proof with

  Lemma switch_global_refines : forall G,
      wt_global G ->
      wc_global G ->
      global_sem_refines G (switch_global G).
  Proof with

  Theorem switch_global_sem : forall G f ins outs,
      wt_global G ->
      wc_global G ->
      sem_node_ck G f ins outs ->
      sem_node_ck (switch_global G) f ins outs.
  Proof.

End CSCORRECTNESS.

Module CSCorrectnessFun
       (Ids : IDS)
       (Op : OPERATORS)
       (OpAux : OPERATORS_AUX Ids Op)
       (Cks : CLOCKS Ids Op OpAux)
       (CStr : COINDSTREAMS Ids Op OpAux Cks)
       (Senv : STATICENV Ids Op OpAux Cks)
       (Syn : LSYNTAX Ids Op OpAux Cks Senv)
       (Ty : LTYPING Ids Op OpAux Cks Senv Syn)
       (Clo : LCLOCKING Ids Op OpAux Cks Senv Syn)
       (Lord : LORDERED Ids Op OpAux Cks Senv Syn)
       (Sem : LSEMANTICS Ids Op OpAux Cks Senv Syn Lord CStr)
       (LCS : LCLOCKEDSEMANTICS Ids Op OpAux Cks Senv Syn Clo Lord CStr Sem)
       (CS : CLOCKSWITCH Ids Op OpAux Cks Senv Syn)
       <: CSCORRECTNESS Ids Op OpAux Cks CStr Senv Syn Ty Clo Lord Sem LCS CS.
  Include CSCORRECTNESS Ids Op OpAux Cks CStr Senv Syn Ty Clo Lord Sem LCS CS.
End CSCorrectnessFun.