Module NClocking

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

From Velus Require Import Common.
From Velus Require Import Operators Environment.
From Velus Require Import Clocks.
From Velus Require Import Fresh.
From Velus Require Import StaticEnv.
From Velus Require Import Lustre.LSyntax Lustre.LClocking.
From Velus Require Import Lustre.Normalization.Normalization.
From Velus Require Import Lustre.SubClock.SCClocking.

Preservation of Typing through Normalization


Module Type NCLOCKING
       (Import Ids : IDS)
       (Import Op : OPERATORS)
       (OpAux : OPERATORS_AUX Ids Op)
       (Import Cks : CLOCKS Ids Op OpAux)
       (Import Senv : STATICENV Ids Op OpAux Cks)
       (Import Syn : LSYNTAX Ids Op OpAux Cks Senv)
       (Import Clo : LCLOCKING Ids Op OpAux Cks Senv Syn)
       (Import Norm : NORMALIZATION Ids Op OpAux Cks Senv Syn).

  Module Import SCC := SCClockingFun Ids Op OpAux Cks Senv Syn Clo SC. Import SC.

  Import Fresh Fresh.Facts Fresh.Tactics.

Rest of clockof preservation (started in Normalization.v)


  Fact unnest_reset_clockof : forall G vars e e' eqs' st st',
      wc_exp G vars e ->
      numstreams e = 1 ->
      unnest_reset (unnest_exp G true) e st = (e', eqs', st') ->
      clockof e' = clockof e.
  Proof.

  Corollary mmap2_unnest_exp_clocksof'' : forall G vars is_control es es' eqs' st st',
      Forall (wc_exp G vars) es ->
      mmap2 (unnest_exp G is_control) es st = (es', eqs', st') ->
      Forall2 (fun e ck => clockof e = [ck]) (concat es') (clocksof es).
  Proof.

  Corollary mmap2_unnest_exp_clocksof''' : forall G vars is_control ck es es' eqs' st st',
      Forall (wc_exp G vars) es ->
      Forall (eq ck) (clocksof es) ->
      mmap2 (unnest_exp G is_control) es st = (es', eqs', st') ->
      Forall (fun e => clockof e = [ck]) (concat es').
  Proof.

  Corollary mmap2_mmap2_unnest_exp_clocksof1 : forall G vars is_control ck x tx es es' eqs' st st',
      Forall (fun es => Forall (wc_exp G vars) (snd es)) es ->
      Forall (fun '(i, es) => Forall (eq (Con ck x (tx, i))) (clocksof es)) es ->
      mmap2 (fun '(i, es) => bind2 (mmap2 (unnest_exp G is_control) es) (fun es' eqs' => ret (i, concat es', concat eqs'))) es st = (es', eqs', st') ->
      Forall (fun '(i, es) => Forall (fun e => clockof e = [Con ck x (tx, i)]) es) es'.
  Proof.

  Corollary mmap2_mmap2_unnest_exp_clocksof2 : forall G vars is_control ck (es : list (enumtag * _)) es' eqs' st st',
      Forall (fun es => Forall (wc_exp G vars) (snd es)) es ->
      Forall (fun es => Forall (eq ck) (clocksof (snd es))) es ->
      mmap2 (fun '(i, es) => bind2 (mmap2 (unnest_exp G is_control) es) (fun es' eqs' => ret (i, concat es', concat eqs'))) es st = (es', eqs', st') ->
      Forall (fun es => Forall (fun e => clockof e = [ck]) (snd es)) es'.
  Proof.

  Corollary mmap2_unnest_exp_clocksof :
    forall G vars is_control es es' eqs' st st',
      Forall (wc_exp G vars) es ->
      mmap2 (unnest_exp G is_control) es st = (es', eqs', st') ->
      clocksof (concat es') = clocksof es.
  Proof.
  Local Hint Resolve mmap2_unnest_exp_clocksof : norm.

  Corollary unnest_exps_clocksof : forall G vars es es' eqs' st st',
      Forall (wc_exp G vars) es ->
      unnest_exps G es st = (es', eqs', st') ->
      clocksof es' = clocksof es.
  Proof.

  Fact fby_iteexp_clockof : forall e0 e ann es' eqs' st st',
      fby_iteexp e0 e ann st = (es', eqs', st') ->
      clockof es' = [(snd ann)].
  Proof.

  Fact unnest_fby_clocksof : forall anns e0s es,
      length e0s = length anns ->
      length es = length anns ->
      clocksof (unnest_fby e0s es anns) = List.map snd anns.
  Proof.

  Fact unnest_merge_clocksof : forall tys x tx es nck,
      clocksof (unnest_merge (x, tx) es tys nck) = List.map (fun _ => nck) tys.
  Proof.

  Fact unnest_case_clocksof : forall tys c es d nck,
      clocksof (unnest_case c es d tys nck) = List.map (fun _ => nck) tys.
  Proof.

  Fact unnest_rhs_clockof: forall G vars e es' eqs' st st',
      wc_exp G vars e ->
      unnest_rhs G e st = (es', eqs', st') ->
      clocksof es' = clockof e.
  Proof.

  Corollary unnest_rhss_clocksof: forall G vars es es' eqs' st st',
      Forall (wc_exp G vars) es ->
      unnest_rhss G es st = (es', eqs', st') ->
      clocksof es' = clocksof es.
  Proof.

nclockof is also preserved by unnest_exp


  Fact unnest_merge_clockof : forall ckid es tys ck,
      Forall (fun e => clockof e = [ck]) (unnest_merge ckid es tys ck).
  Proof.

  Fact unnest_case_clockof : forall e es d tys ck,
      Forall (fun e => clockof e = [ck]) (unnest_case e es d tys ck).
  Proof.

  Fact unnest_when_nclocksof : forall ckid k es tys ck,
      length es = length tys ->
      nclocksof (unnest_when ckid k es tys ck) = map (fun _ => (ck, None)) tys.
  Proof.

  Fact unnest_merge_nclocksof : forall tx tys es ck,
      nclocksof (unnest_merge tx es tys ck) = map (fun _ => (ck, None)) tys.
  Proof.

  Fact unnest_case_nclocksof : forall e tys es d ck,
      nclocksof (unnest_case e es d tys ck) = map (fun _ => (ck, None)) tys.
  Proof.

  Lemma idents_for_anns_nclocksof : forall anns ids st st',
      idents_for_anns anns st = (ids, st') ->
      nclocksof (map (fun '(x, ann0) => Evar x ann0) ids) = map (fun '(x, (_, ck)) => (ck, Some x)) ids.
  Proof.

  Fact unnest_exp_nclocksof : forall G vars e is_control es' eqs' st st',
      wc_exp G vars e ->
      unnest_exp G is_control e st = (es', eqs', st') ->
      Forall2 (fun '(ck1, o1) '(ck2, o2) => ck1 = ck2 /\ LiftO True (fun x1 => o2 = Some x1) o1) (nclockof e) (nclocksof es').
  Proof with

  Corollary mmap2_unnest_exp_nclocksof : forall G vars es is_control es' eqs' st st',
      Forall (wc_exp G vars) es ->
      mmap2 (unnest_exp G is_control) es st = (es', eqs', st') ->
      Forall2 (fun '(ck1, o1) '(ck2, o2) => ck1 = ck2 /\ LiftO True (fun x1 => o2 = Some x1) o1) (nclocksof es) (nclocksof (concat es')).
  Proof with

  Lemma unnest_noops_exp_nclocksof : forall ck e e' eqs' st st',
      normalized_lexp e ->
      unnest_noops_exp ck e st = (e', eqs', st') ->
      Forall2 (fun '(ck1, o1) '(ck2, o2) => ck1 = ck2 /\ LiftO True (fun x1 => o2 = Some x1) o1) (nclockof e) (nclockof e').
  Proof.

  Fact unnest_noops_exps_nclocksof : forall cks es es' eqs' st st',
      Forall normalized_lexp es ->
      length cks = length es ->
      unnest_noops_exps cks es st = (es', eqs', st') ->
      Forall2 (fun '(ck1, o1) '(ck2, o2) => ck1 = ck2 /\ LiftO True (fun x1 => o2 = Some x1) o1) (nclocksof es) (nclocksof es').
  Proof.

  Fact unnest_noops_exps_nclocksof2 : forall G vars cks es es2 es' eqs2 eqs' st st2 st3 st',
      (forall x, ~IsLast vars x) ->
      Forall (wc_exp G vars) es ->
      length cks = length (annots es) ->
      mmap2 (unnest_exp G false) es st = (es2, eqs2, st2) ->
      unnest_noops_exps cks (concat es2) st3 = (es', eqs', st') ->
      Forall2 (fun '(ck1, o1) '(ck2, o2) => ck1 = ck2 /\ LiftO True (fun x1 => o2 = Some x1) o1) (nclocksof es) (nclocksof es').
  Proof.

A few additional things


  Fact idents_for_anns_incl_ck : forall anns ids st st',
    idents_for_anns anns st = (ids, st') ->
    forall x ty ck, In (x, (ty, ck)) ids -> HasClock (st_senv st') x ck.
  Proof.

  Ltac solve_incl :=
    match goal with
    | H : wc_clock ?l1 ?cl |- wc_clock ?l2 ?cl =>
      eapply wc_clock_incl; [|eauto]; intros
    | H : wc_exp ?G ?l1 ?e |- wc_exp ?G ?l2 ?e =>
      eapply wc_exp_incl; [| |eauto]; intros
    | H : wc_equation ?G ?l1 ?eq |- wc_equation ?G ?l2 ?eq =>
      eapply wc_equation_incl; [| |eauto]; intros
    | H : wc_block ?G ?l1 ?eq |- wc_block ?G ?l2 ?eq =>
      eapply wc_block_incl; [| |eauto]; intros
    | H : In ?i ?l1 |- In ?i ?l2 =>
      assert (incl l1 l2) by repeat solve_incl; eauto
    | |- incl (st_anns ?st1) (st_anns _) =>
        eapply st_follows_incl; repeat solve_st_follows
    | |- incl ?l1 ?l1 => reflexivity
    | |- incl ?l1 (?l1 ++ ?l2) =>
      eapply incl_appl; reflexivity
    | |- incl (?l1 ++ ?l2) (?l1 ++ ?l3) => apply incl_appr'
    | |- incl ?l1 (?l2 ++ ?l3) => eapply incl_appr
    | |- incl ?l1 (?a::?l2) => eapply incl_tl
    | |- incl _ _ => apply incl_map
    | H : HasClock ?l1 ?x ?ty |- HasClock ?l2 ?x ?ty =>
        eapply HasClock_incl; [|eauto]
    | H : IsLast ?l1 ?x |- IsLast ?l2 ?x =>
        eapply IsLast_incl; [|eauto]
    end; auto.

Preservation of clocking through first pass


  Import Permutation.

  Fact fresh_ident_wc_env : forall pref hint vars ty ck id (st st': fresh_st pref _),
      wc_env (idck (vars++st_senv st)) ->
      wc_clock (idck (vars++st_senv st)) ck ->
      fresh_ident hint (ty, ck) st = (id, st') ->
      wc_env (idck (vars++st_senv st')).
  Proof.

  Fact idents_for_anns_wc_env : forall vars anns ids st st',
      wc_env (idck (vars++st_senv st)) ->
      Forall (wc_clock (idck (vars++st_senv st))) (map snd anns) ->
      idents_for_anns anns st = (ids, st') ->
      wc_env (idck (vars++st_senv st')).
  Proof with

  Fact hd_default_wc_exp {PSyn prefs} : forall (G : @global PSyn prefs) vars es,
      Forall (wc_exp G vars) es ->
      wc_exp G vars (hd_default es).
  Proof.
  Local Hint Resolve hd_default_wc_exp : norm.

  Section unnest_node_wc.
    Variable G1 : @global nolocal local_prefs.
    Variable G2 : @global nolocal norm1_prefs.

    Fact idents_for_anns_wc : forall vars anns ids st st',
        idents_for_anns anns st = (ids, st') ->
        Forall (wc_exp G2 (vars++st_senv st')) (List.map (fun '(x, ann) => Evar x ann) ids).
    Proof.

    Fact mmap2_wc {pref A B} :
      forall vars (k : A -> Fresh pref (list exp * list equation) B) a es' eqs' st st',
        mmap2 k a st = (es', eqs', st') ->
        (forall st st' a es eqs', k a st = (es, eqs', st') -> st_follows st st') ->
        Forall (fun a => forall es' eqs' st0 st0',
                    k a st0 = (es', eqs', st0') ->
                    st_follows st st0 ->
                    st_follows st0' st' ->
                    Forall (wc_exp G2 vars) es' /\
                    Forall (wc_equation G2 vars) eqs') a ->
        Forall (wc_exp G2 vars) (concat es') /\
        Forall (wc_equation G2 vars) (concat eqs').
    Proof with

    Fact mmap2_wc' {pref A B} :
      forall vars (k : A -> Fresh pref (enumtag * list exp * list equation) B) a es' eqs' st st',
        mmap2 k a st = (es', eqs', st') ->
        (forall st st' a es eqs', k a st = (es, eqs', st') -> st_follows st st') ->
        Forall (fun a => forall n es' eqs' st0 st0',
                    k a st0 = (n, es', eqs', st0') ->
                    st_follows st st0 ->
                    st_follows st0' st' ->
                    Forall (wc_exp G2 vars) es' /\
                    Forall (wc_equation G2 vars) eqs') a ->
        Forall (wc_exp G2 vars) (concat (map snd es')) /\
        Forall (wc_equation G2 vars) (concat eqs').
    Proof with

    Fact unnest_fby_wc_exp : forall vars e0s es anns,
        Forall (wc_exp G2 vars) e0s ->
        Forall (wc_exp G2 vars) es ->
        Forall2 (fun e0 a => clockof e0 = [a]) e0s (map snd anns) ->
        Forall2 (fun e a => clockof e = [a]) es (map snd anns) ->
        Forall (wc_exp G2 vars) (unnest_fby e0s es anns).
    Proof.

    Fact unnest_arrow_wc_exp : forall vars e0s es anns,
        Forall (wc_exp G2 vars) e0s ->
        Forall (wc_exp G2 vars) es ->
        Forall2 (fun e0 a => clockof e0 = [a]) e0s (map snd anns) ->
        Forall2 (fun e a => clockof e = [a]) es (map snd anns) ->
        Forall (wc_exp G2 vars) (unnest_arrow e0s es anns).
    Proof.

    Fact unnest_when_wc_exp : forall vars ckid tx ck b ty es tys,
        length es = length tys ->
        HasClock vars ckid ck ->
        Forall (wc_exp G2 vars) es ->
        Forall (fun e => clockof e = [ck]) es ->
        Forall (wc_exp G2 vars) (unnest_when (ckid, tx) b es tys (Con ck ckid (ty, b))).
    Proof.

    Fact unnest_merge_wc_exp : forall vars ckid tx ck es tys,
        HasClock vars ckid ck ->
        es <> [] ->
        Forall (fun es => length (snd es) = length tys) es ->
        Forall (fun es => Forall (wc_exp G2 vars) (snd es)) es ->
        Forall (fun '(i, es) => Forall (fun e => clockof e = [Con ck ckid (tx, i)]) es) es ->
        Forall (wc_exp G2 vars) (unnest_merge (ckid, tx) es tys ck).
    Proof.

    Fact unnest_case_wc_exp : forall vars e ck es d tys,
        wc_exp G2 vars e ->
        clockof e = [ck] ->
        es <> [] ->
        Forall (fun es => length (snd es) = length tys) es ->
        Forall (fun es => Forall (wc_exp G2 vars) (snd es)) es ->
        Forall (fun es => Forall (fun e => clockof e = [ck]) (snd es)) es ->
        LiftO True (fun d => length (clocksof d) = length tys) d ->
        LiftO True (Forall (wc_exp G2 vars)) d ->
        LiftO True (Forall (fun e => clockof e = [ck])) d ->
        Forall (wc_exp G2 vars) (unnest_case e es d tys ck).
    Proof.

    Fact unnest_reset_wc : forall vars e e' eqs' st st' ck,
        (forall x, ~IsLast vars x) ->
        (forall es' eqs' st0',
            st_follows st0' st' ->
            unnest_exp G1 true e st = (es', eqs', st0') ->
            Forall (wc_exp G2 (vars++st_senv st0')) es' /\
            Forall (wc_equation G2 (vars++st_senv st0')) eqs') ->
        wc_exp G1 (vars++st_senv st) e ->
        clockof e = [ck] ->
        unnest_reset (unnest_exp G1 true) e st = (e', eqs', st') ->
        clockof e' = [ck] /\
        wc_exp G2 (vars++st_senv st') e' /\
        Forall (wc_equation G2 (vars++st_senv st')) eqs'.
    Proof.

    Fact unnest_resets_wc : forall vars es es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        Forall (fun e => forall es' eqs' st0 st0',
                    unnest_exp G1 true e st0 = (es', eqs', st0') ->
                    st_follows st st0 ->
                    st_follows st0' st' ->
                    Forall (wc_exp G2 (vars++st_senv st0')) es' /\
                    Forall (wc_equation G2 (vars++st_senv st0')) eqs') es ->
        Forall (wc_exp G1 (vars++st_senv st)) es ->
        Forall (fun e => exists ck, clockof e = [ck]) es ->
        mmap2 (unnest_reset (unnest_exp G1 true)) es st = (es', eqs', st') ->
        Forall (fun e => exists ck, clockof e = [ck]) es' /\
        Forall (wc_exp G2 (vars++st_senv st')) es' /\
        Forall (wc_equation G2 (vars++st_senv st')) (concat eqs').
    Proof.

    Lemma unnest_noops_exps_wc : forall vars cks es es' eqs' st st' ,
        length es = length cks ->
        Forall normalized_lexp es ->
        Forall (fun e => numstreams e = 1) es ->
        Forall (wc_exp G2 (vars++st_senv st)) es ->
        unnest_noops_exps cks es st = (es', eqs', st') ->
        Forall (wc_exp G2 (vars++st_senv st')) es' /\
        Forall (wc_equation G2 (vars++st_senv st')) eqs'.
    Proof.

    Hypothesis Hiface : global_iface_incl G1 G2.

    Fact unnest_exp_wc : forall vars e is_control es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_exp G1 (vars++st_senv st) e ->
        unnest_exp G1 is_control e st = (es', eqs', st') ->
        Forall (wc_exp G2 (vars++st_senv st')) es' /\
        Forall (wc_equation G2 (vars++st_senv st')) eqs'.
    Proof with

    Corollary mmap2_unnest_exp_wc : forall vars is_control es es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        Forall (wc_exp G1 (vars++st_senv st)) es ->
        mmap2 (unnest_exp G1 is_control) es st = (es', eqs', st') ->
        Forall (wc_exp G2 (vars++st_senv st')) (concat es') /\
        Forall (wc_equation G2 (vars++st_senv st')) (concat eqs').
    Proof.

    Corollary unnest_exps_wc : forall vars es es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        Forall (wc_exp G1 (vars++st_senv st)) es ->
        unnest_exps G1 es st = (es', eqs', st') ->
        Forall (wc_exp G2 (vars++st_senv st')) es' /\
        Forall (wc_equation G2 (vars++st_senv st')) eqs'.
    Proof.

    Corollary mmap2_mmap2_unnest_exp_wc : forall vars is_control (es: list (enumtag * _)) es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        Forall (fun es => Forall (wc_exp G1 (vars++st_senv st)) (snd es)) es ->
        mmap2 (fun '(i, es) => bind2 (mmap2 (unnest_exp G1 is_control) es) (fun es' eqs' => ret (i, concat es', concat eqs'))) es st = (es', eqs', st') ->
        Forall (fun es => Forall (wc_exp G2 (vars++st_senv st')) (snd es)) es' /\
        Forall (wc_equation G2 (vars++st_senv st')) (concat eqs').
    Proof.

    Fact unnest_rhs_wc : forall vars e es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_exp G1 (vars++st_senv st) e ->
        unnest_rhs G1 e st = (es', eqs', st') ->
        Forall (wc_exp G2 (vars++st_senv st')) es' /\
        Forall (wc_equation G2 (vars++st_senv st')) eqs'.
    Proof with

    Corollary unnest_rhss_wc : forall vars es es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        Forall (wc_exp G1 (vars++st_senv st)) es ->
        unnest_rhss G1 es st = (es', eqs', st') ->
        Forall (wc_exp G2 (vars++st_senv st')) es' /\
        Forall (wc_equation G2 (vars++st_senv st')) eqs'.
    Proof.

    Fact unnest_equation_wc_eq : forall vars e eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_equation G1 (vars++st_senv st) e ->
        unnest_equation G1 e st = (eqs', st') ->
        Forall (wc_equation G2 (vars++st_senv st')) eqs'.
    Proof with

    Lemma unnest_block_wc : forall vars d blocks' st st',
        (forall x, ~IsLast vars x) ->
        wc_block G1 (vars++st_senv st) d ->
        unnest_block G1 d st = (blocks', st') ->
        Forall (wc_block G2 (vars++st_senv st')) blocks'.
    Proof.

    Corollary unnest_blocks_wc : forall vars blocks blocks' st st',
        (forall x, ~IsLast vars x) ->
        Forall (wc_block G1 (vars++st_senv st)) blocks ->
        unnest_blocks G1 blocks st = (blocks', st') ->
        Forall (wc_block G2 (vars++st_senv st')) blocks'.
    Proof with

The produced environment is also well-clocked


    Hypothesis HwcG1 : wc_global G1.
    Hypothesis HwcG2 : wc_global G2.

    Fact unnest_reset_wc_env : forall vars e e' eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_env (idck (vars++st_senv st)) ->
        (forall es' eqs' st0',
            unnest_exp G1 true e st = (es', eqs', st0') ->
            st_follows st0' st' ->
            wc_env (idck (vars++st_senv st0'))) ->
        wc_exp G1 (vars ++ st_senv st) e ->
        unnest_reset (unnest_exp G1 true) e st = (e', eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Fact mmap2_wc_env {A A1 A2 : Type} :
      forall vars (k : A -> Unnesting.FreshAnn (A1 * A2)) a a1s a2s st st',
        wc_env (idck (vars++st_senv st)) ->
        mmap2 k a st = (a1s, a2s, st') ->
        (forall st st' a es a2s, k a st = (es, a2s, st') -> st_follows st st') ->
        Forall (fun a => forall a1s a2s st0 st0',
                    wc_env (idck (vars++st_senv st0)) ->
                    k a st0 = (a1s, a2s, st0') ->
                    st_follows st st0 ->
                    st_follows st0' st' ->
                    wc_env (idck (vars++st_senv st0'))) a ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Corollary unnest_resets_wc_env : forall vars es es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_env (idck (vars++st_senv st)) ->
        Forall (fun e => forall es' eqs' st0 st0',
                    wc_env (idck (vars++st_senv st0)) ->
                    unnest_exp G1 true e st0 = (es', eqs', st0') ->
                    st_follows st st0 ->
                    st_follows st0' st' ->
                    wc_env (idck (vars++st_senv st0'))) es ->
        Forall (wc_exp G1 (vars ++ st_senv st)) es ->
        mmap2 (unnest_reset (unnest_exp G1 true)) es st = (es', eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Lemma unnest_noops_exps_wc_env : forall vars cks es es' eqs' st st' ,
        length es = length cks ->
        Forall normalized_lexp es ->
        Forall (fun e => numstreams e = 1) es ->
        Forall (wc_exp G2 (vars++st_senv st)) es ->
        wc_env (idck (vars++st_senv st)) ->
        unnest_noops_exps cks es st = (es', eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof.

    Fact unnest_exp_wc_env : forall vars e is_control es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_env (idck (vars++st_senv st)) ->
        wc_exp G1 (vars++st_senv st) e ->
        unnest_exp G1 is_control e st = (es', eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Corollary mmap2_unnest_exp_wc_env : forall vars es is_control es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_env (idck (vars++st_senv st)) ->
        Forall (wc_exp G1 (vars++st_senv st)) es ->
        mmap2 (unnest_exp G1 is_control) es st = (es', eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof.

    Corollary unnest_exps_wc_env : forall vars es es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_env (idck (vars++st_senv st)) ->
        Forall (wc_exp G1 (vars++st_senv st)) es ->
        unnest_exps G1 es st = (es', eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Fact unnest_rhs_wc_env : forall vars e es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_env (idck (vars++st_senv st)) ->
        wc_exp G1 (vars++st_senv st) e ->
        unnest_rhs G1 e st = (es', eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Corollary unnest_rhss_wc_env : forall vars es es' eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_env (idck (vars++st_senv st)) ->
        Forall (wc_exp G1 (vars++st_senv st)) es ->
        unnest_rhss G1 es st = (es', eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Fact unnest_equation_wc_env : forall vars e eqs' st st',
        (forall x, ~IsLast vars x) ->
        wc_env (idck (vars++st_senv st)) ->
        wc_equation G1 (vars++st_senv st) e ->
        unnest_equation G1 e st = (eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Lemma unnest_block_wc_env : forall vars d blocks' st st' ,
        (forall x, ~IsLast vars x) ->
        wc_env (idck (vars++st_senv st)) ->
        wc_block G1 (vars++st_senv st) d ->
        unnest_block G1 d st = (blocks', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof.

    Corollary unnest_blocks_wc_env : forall vars blocks blocks' st st' ,
        (forall x, ~IsLast vars x) ->
        wc_env (idck (vars++st_senv st)) ->
        Forall (wc_block G1 (vars++st_senv st)) blocks ->
        unnest_blocks G1 blocks st = (blocks', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Lemma unnest_node_wc : forall n,
        wc_node G1 n ->
        wc_node G2 (unnest_node G1 n).
    Proof with

  End unnest_node_wc.

  Lemma unnest_global_wc : forall G,
      wc_global G ->
      wc_global (unnest_global G).
  Proof.

Preservation of clocking through second pass


  Section normfby_node_wc.
    Variable G1 : @global nolocal norm1_prefs.
    Variable G2 : @global nolocal norm2_prefs.

    Hypothesis Hiface : global_iface_incl G1 G2.
    Local Hint Resolve iface_incl_wc_exp : norm.

    Fact fby_iteexp_wc_exp : forall vars e0 e ty ck e' eqs' st st' ,
        wc_exp G1 (vars++st_senv st) e0 ->
        wc_exp G1 (vars++st_senv st) e ->
        clockof e0 = [ck] ->
        clockof e = [ck] ->
        fby_iteexp e0 e (ty, ck) st = (e', eqs', st') ->
        wc_exp G2 (vars++st_senv st') e'.
    Proof with

    Fact arrow_iteexp_wc_exp : forall vars e0 e ty ck e' eqs' st st' ,
        wc_exp G1 (vars++st_senv st) e0 ->
        wc_exp G1 (vars++st_senv st) e ->
        clockof e0 = [ck] ->
        clockof e = [ck] ->
        arrow_iteexp e0 e (ty, ck) st = (e', eqs', st') ->
        wc_exp G2 (vars++st_senv st') e'.
    Proof with

    Fact init_var_for_clock_wc_env : forall vars ck id eqs' st st' ,
        wc_env (idck (vars++st_senv st)) ->
        wc_clock (idck (vars++st_senv st)) ck ->
        init_var_for_clock ck st = (id, eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Fact fby_iteexp_wc_env : forall vars e0 e ty ck es' eqs' st st' ,
        wc_env (idck (vars++st_senv st)) ->
        wc_clock (idck (vars++st_senv st)) ck ->
        fby_iteexp e0 e (ty, ck) st = (es', eqs', st') ->
        wc_env (idck (vars++st_senv st')).
    Proof with

    Fact init_var_for_clock_wc_eq : forall vars ck id eqs' st st' ,
        wc_clock (idck (vars++st_senv st)) ck ->
        init_var_for_clock ck st = (id, eqs', st') ->
        Forall (wc_equation G2 (vars++st_senv st')) eqs'.
    Proof with

    Fact normalized_lexp_wc_exp_clockof : forall vars e,
        normalized_lexp e ->
        wc_env (idck vars) ->
        wc_exp G2 vars e ->
        Forall (wc_clock (idck vars)) (clockof e).
    Proof with

    Fact fby_iteexp_wc_eq : forall vars e0 e ty ck e' eqs' st st' ,
        normalized_lexp e0 ->
        wc_env (idck (vars++st_senv st)) ->
        wc_exp G1 (vars++st_senv st) e0 ->
        wc_exp G1 (vars++st_senv st) e ->
        clockof e0 = [ck] ->
        clockof e = [ck] ->
        fby_iteexp e0 e (ty, ck) st = (e', eqs', st') ->
        Forall (wc_equation G2 (vars++st_senv st')) eqs'.
    Proof with

    Fact normfby_equation_wc : forall vars to_cut eq eqs' st st' ,
        unnested_equation G1 eq ->
        wc_env (idck (vars++st_senv st)) ->
        wc_equation G1 (vars++st_senv st) eq ->
        normfby_equation to_cut eq st = (eqs', st') ->
        (Forall (wc_equation G2 (vars++st_senv st')) eqs' /\ wc_env (idck (vars++st_senv st'))).
    Proof with

    Fact normfby_block_wc : forall vars to_cut d blocks' st st' ,
        unnested_block G1 d ->
        wc_env (idck (vars++st_senv st)) ->
        wc_block G1 (vars++st_senv st) d ->
        normfby_block to_cut d st = (blocks', st') ->
        Forall (wc_block G2 (vars++st_senv st')) blocks' /\ wc_env (idck (vars++st_senv st')).
    Proof.

    Corollary normfby_blocks_wc : forall vars to_cut blocks blocks' st st' ,
        Forall (unnested_block G1) blocks ->
        wc_env (idck (vars++st_senv st)) ->
        Forall (wc_block G1 (vars++st_senv st)) blocks ->
        normfby_blocks to_cut blocks st = (blocks', st') ->
        Forall (wc_block G2 (vars++st_senv st')) blocks' /\ wc_env (idck (vars++st_senv st')).
    Proof.

    Lemma normfby_node_wc : forall n,
        unnested_node G1 n ->
        wc_node G1 n ->
        wc_node G2 (normfby_node n).
    Proof.

  End normfby_node_wc.

  Lemma normfby_global_wc : forall G,
      unnested_global G ->
      wc_global G ->
      wc_global (normfby_global G).
  Proof.

Conclusion


  Lemma normalize_global_wc : forall G,
      wc_global G ->
      wc_global (normalize_global G).
  Proof.

End NCLOCKING.

Module NClockingFun
       (Ids : IDS)
       (Op : OPERATORS)
       (OpAux : OPERATORS_AUX Ids Op)
       (Cks : CLOCKS Ids Op OpAux)
       (Senv : STATICENV Ids Op OpAux Cks)
       (Syn : LSYNTAX Ids Op OpAux Cks Senv)
       (Clo : LCLOCKING Ids Op OpAux Cks Senv Syn)
       (Norm : NORMALIZATION Ids Op OpAux Cks Senv Syn)
       <: NCLOCKING Ids Op OpAux Cks Senv Syn Clo Norm.
  Include NCLOCKING Ids Op OpAux Cks Senv Syn Clo Norm.
End NClockingFun.