Module Safe

From Coq Require Import String Morphisms Permutation.
From Coq Require Import Datatypes List.
Import List.ListNotations.
Open Scope list_scope.

From Velus Require Import Common.
From Velus Require Import CommonList.
From Velus Require Import CommonTyping.
From Velus Require Import Environment.
From Velus Require Import FunctionalEnvironment.
From Velus Require Import Operators.
From Velus Require Import CoindStreams.
From Velus Require Import Clocks.
From Velus Require Import Lustre.StaticEnv.
From Velus Require Import Lustre.LSyntax Lustre.LTyping Lustre.LClocking Lustre.LSemantics Lustre.LOrdered.

From Velus Require Import Lustre.Denot.Cpo.
Require Import CommonDS SDfuns SD CheckOp OpErr Restr CommonList2 ResetMask.


Module Type LDENOTSAFE
       (Import Ids : IDS)
       (Import Op : OPERATORS)
       (Import 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 Typ : LTYPING Ids Op OpAux Cks Senv Syn)
       (Import Restr : LRESTR Ids Op OpAux Cks Senv Syn)
       (Import Cl : LCLOCKING Ids Op OpAux Cks Senv Syn)
       (Import Lord : LORDERED Ids Op OpAux Cks Senv Syn)
       (Import Den : SD Ids Op OpAux Cks Senv Syn Lord)
       (Import Ckop : CHECKOP Ids Op OpAux Cks Senv Syn)
       (Import OpErr : OP_ERR Ids Op OpAux Cks Senv Syn Typ Restr Lord Den Ckop).

Lemma typeof_same :
  forall es ty,
    Forall (fun e => typeof e = [ty]) es ->
    Forall (eq ty) (typesof es).
Proof.

Theorem find_node_in_nodes :
  forall {PSyn Prefs} (G : @global PSyn Prefs),
    forall f n,
      find_node f G = Some n ->
      In n (nodes G).
Proof.

Theorem find_node_name :
  forall {PSyn Prefs} (G : @global PSyn Prefs),
    forall f n,
      find_node f G = Some n ->
      f = n_name n.
Proof.

Lemma wc_env_in :
  forall {PSyn Prefs} (G : @global PSyn Prefs),
  forall f (n : node),
    wc_global G ->
    find_node f G = Some n ->
    wc_env (List.map (fun '(x, (_, ck, _)) => (x, ck)) (n_in n)).
Proof.

Section Static_env_node.

  Lemma NoDup_senv :
    forall {PSyn Prefs} (nd : @node PSyn Prefs),
      NoDupMembers (senv_of_ins (n_in nd) ++ senv_of_decls (n_out nd)).
  Proof.

  Lemma Ty_senv :
    forall {PSyn Prefs} (n : @node PSyn Prefs),
    forall x ty,
      HasType (senv_of_ins (n_in n)) x ty ->
      In (x,ty) (List.map (fun '(x, (ty, _, _)) => (x, ty)) (n_in n)).
  Proof.

  Lemma HasType_ins_app :
    forall {PSyn Prefs} (n : @node PSyn Prefs),
    forall Γ x ty,
      NoDupMembers (senv_of_ins (n_in n) ++ Γ) ->
      In x (List.map fst (n_in n)) ->
      HasType (senv_of_ins (n_in n) ++ Γ) x ty ->
      HasType (senv_of_ins n.(n_in)) x ty.
  Proof.

  Lemma HasClock_ins_app :
    forall {PSyn Prefs} (n : @node PSyn Prefs),
    forall Γ x ck,
      NoDupMembers (senv_of_ins (n_in n) ++ Γ) ->
      In x (List.map fst (n_in n)) ->
      HasClock (senv_of_ins (n_in n) ++ Γ) x ck ->
      HasClock (senv_of_ins n.(n_in)) x ck.
  Proof.

  Lemma HasClock_senv :
    forall {PSyn Prefs} (n : @node PSyn Prefs),
    forall x ck,
      HasClock (senv_of_ins (n_in n)) x ck ->
      In (x,ck) (List.map (fun '(x, (_, ck, _)) => (x, ck)) (n_in n)).
  Proof.

  Lemma HasType_app_r :
    forall l1 l2 x ty,
      HasType l2 x ty ->
      HasType (l1 ++ l2) x ty.
  Proof.

  Lemma HasClock_app_r :
    forall l1 l2 x ty,
      HasClock l2 x ty ->
      HasClock (l1 ++ l2) x ty.
  Proof.

  Lemma HasType_app_l :
    forall l1 l2 x ty,
      HasType l1 x ty ->
      HasType (l1 ++ l2) x ty.
  Proof.

  Lemma HasClock_app_l :
    forall l1 l2 x ty,
      HasClock l1 x ty ->
      HasClock (l1 ++ l2) x ty.
  Proof.

  Lemma In_HasType' :
    forall x l, In x (List.map fst l) ->
           exists ty, HasType (senv_of_decls l) x ty.
  Proof.

  Lemma In_HasClock :
    forall x l, In x (List.map fst l) ->
           exists ck, HasClock (senv_of_decls l) x ck.
  Proof.

  Lemma senv_HasClock' :
    forall l x ty ck i o,
      In (x,(ty,ck,i,o)) l ->
      HasClock (senv_of_decls l) x ck.
  Proof.

End Static_env_node.


Safety properties of synchronous streams


Section Safe_DS.

  Context {A : Type}.

  Definition safe_DS : DS (sampl A) -> Prop :=
    DSForall (fun v => match v with err _ => False | _ => True end).

  Definition safe_ty : DS (sampl A) -> Prop :=
    DSForall (fun v => match v with err error_Ty => False | _ => True end).

  Definition safe_cl : DS (sampl A) -> Prop :=
    DSForall (fun v => match v with err error_Cl => False | _ => True end).

  Definition safe_op : DS (sampl A) -> Prop :=
    DSForall (fun v => match v with err error_Op => False | _ => True end).

  Lemma safe_DS_compose :
    forall s, safe_ty s ->
         safe_cl s ->
         safe_op s ->
         safe_DS s.
  Proof.

  Lemma safe_DS_decompose :
    forall s, safe_DS s ->
         safe_ty s /\ safe_cl s /\ safe_op s.
  Proof.

End Safe_DS.


Section SDfuns_safe.

  Context {PSyn : list decl -> block -> Prop}.
  Context {Prefs : PS.t}.

  Variables
    (Γ : static_env)
    (G : @global PSyn Prefs)
    (ins : list ident)
    (envG : Dprodi FI)
    (envI : DS_prod SI)
    (bs : DS bool)
    (env : DS_prod SI).

  Definition sample (k : enumtag) (x : sampl value) (c : bool) : bool :=
    match x with
    | pres (Venum e) => (k =? e) && c
    | _ => false
    end.

  Fixpoint denot_clock ck : DS bool :=
    match ck with
    | Cbase => bs
    | Con ck x (_, k) =>
        let sx := denot_var ins envI env x in
        let cks := denot_clock ck in
        ZIP (sample k) sx cks
    end.

A stream of values of type ty
  Definition ty_DS (ty : type) (s : DS (sampl value)) : Prop :=
    DSForall_pres (fun v => wt_value v ty) s.

  Add Parametric Morphism : ty_DS
      with signature eq ==> @Oeq (DS (sampl value)) ==> iff as ty_DS_Morph.
  Proof.

A stream that respects its clock (≃ alignment). Because the stream might not yet be fully computed, we use an inequality. This predicate holds in the denotational model because the computation of an expression denotation implicitly depends on the clock stream, and thus cannot exceed it. See safe_exp below.
  Definition cl_DS (ck : clock) (s : DS (sampl value)) :=
    AC s <= denot_clock ck.

Global well-formedness hypothesis on the environment
  Definition wf_env :=
    forall x ty ck,
      HasType Γ x ty ->
      HasClock Γ x ck ->
      let s := denot_var ins envI env x in
      ty_DS ty s
      /\ cl_DS ck s
      /\ safe_DS s.

  Definition ty_env :=
    (forall x ty, HasType Γ x ty -> ty_DS ty (denot_var ins envI env x)).
  Definition cl_env :=
    (forall x ck, HasClock Γ x ck -> cl_DS ck (denot_var ins envI env x)).
  Definition ef_env :=
    (forall x ty, HasType Γ x ty -> safe_DS (denot_var ins envI env x)).

  Lemma wf_env_decompose : (ty_env /\ cl_env /\ ef_env) <-> wf_env.
  Proof.

Quelques résultats du type : qui peut le plus, peut le moins

  Lemma ty_DS_le :
    forall ty x y,
      x <= y ->
      ty_DS ty y ->
      ty_DS ty x.
  Proof.

  Lemma cl_DS_le :
    forall ck x y,
      x <= y ->
      cl_DS ck y ->
      cl_DS ck x.
  Proof.

  Lemma safe_DS_le :
    forall {A} (x y : DS (sampl A)),
      x <= y ->
      safe_DS y ->
      safe_DS x.
  Proof.

  Lemma Forall2_ty_DS_le :
    forall n tys (xs ys : nprod n),
      xs <= ys ->
      Forall2 ty_DS tys (list_of_nprod ys) ->
      Forall2 ty_DS tys (list_of_nprod xs).
  Proof.

  Lemma Forall2_cl_DS_le :
    forall n cks (xs ys : nprod n),
      xs <= ys ->
      Forall2 cl_DS cks (list_of_nprod ys) ->
      Forall2 cl_DS cks (list_of_nprod xs).
  Proof.

  Lemma forall_safe_le :
    forall {A} n (xs ys : @nprod (DS (sampl A)) n),
      xs <= ys ->
      forall_nprod safe_DS ys ->
      forall_nprod safe_DS xs.
  Proof.

Faits sur sconst


  Lemma cl_sconst :
    forall c bs', bs' <= bs -> cl_DS Cbase (sconst c bs').
  Proof.

  Lemma ty_sconst :
    forall v ty,
      wt_value v ty ->
      ty_DS ty (sconst v bs).
  Proof.

  Lemma safe_sconst :
    forall A (c:A), safe_DS (sconst c bs).
  Proof.

Faits sur sunop


  Lemma ty_sunop :
    forall op s ty tye,
      type_unop op tye = Some ty ->
      ty_DS tye s ->
      ty_DS ty (sunop (fun v => sem_unop op v tye) s).
  Proof.

  Lemma safe_ty_sunop :
    forall op s ty tye,
      type_unop op tye = Some ty ->
      ty_DS tye s ->
      safe_ty s ->
      safe_ty (sunop (fun v => sem_unop op v tye) s).
  Proof.

  Lemma safe_cl_sunop :
    forall op s tye,
      safe_cl s ->
      safe_cl (sunop (fun v => sem_unop op v tye) s).
  Proof.

  Lemma safe_op_sunop :
    forall op s tye,
      safe_op s ->
      DSForall_pres (fun v => sem_unop op v tye <> None) s ->
      safe_op (sunop (fun v => sem_unop op v tye) s).
  Proof.

  Lemma cl_sunop :
    forall op s ck tye,
      cl_DS ck s ->
      DSForall_pres (fun v => sem_unop op v tye <> None) s ->
      cl_DS ck (sunop (fun v => sem_unop op v tye) s).
  Proof.

Faits sur sbinop


  Lemma ty_sbinop :
    forall op s1 s2 ty tye1 tye2,
      type_binop op tye1 tye2 = Some ty ->
      ty_DS tye1 s1 ->
      ty_DS tye2 s2 ->
      ty_DS ty (sbinop (fun v1 v2 => sem_binop op v1 tye1 v2 tye2) s1 s2).
  Proof.

  Lemma safe_ty_sbinop :
    forall op s1 s2 tye1 tye2,
      safe_ty s1 ->
      safe_ty s2 ->
      safe_ty (sbinop (fun v1 v2 => sem_binop op v1 tye1 v2 tye2) s1 s2).
  Proof.

  Lemma safe_cl_sbinop :
    forall op s1 s2 tye1 tye2 ck,
      safe_cl s1 ->
      safe_cl s2 ->
      cl_DS ck s1 ->
      cl_DS ck s2 ->
      safe_cl (sbinop (fun v1 v2 => sem_binop op v1 tye1 v2 tye2) s1 s2).
  Proof.

  Lemma safe_op_sbinop :
    forall op s1 s2 tye1 tye2,
      safe_op s1 ->
      safe_op s2 ->
      DSForall_2pres
        (fun v1 v2 => sem_binop op v1 tye1 v2 tye2 <> None) (ZIP pair s1 s2) ->
      safe_op (sbinop (fun v1 v2 => sem_binop op v1 tye1 v2 tye2) s1 s2).
  Proof.

  Lemma cl_sbinop :
    forall op s1 s2 ck tye1 tye2,
      cl_DS ck s1 ->
      cl_DS ck s2 ->
      DSForall_2pres
        (fun v1 v2 => sem_binop op v1 tye1 v2 tye2 <> None) (ZIP pair s1 s2) ->
      cl_DS ck (sbinop (fun v1 v2 => sem_binop op v1 tye1 v2 tye2) s1 s2).
  Proof.

Faits sur fby1/fby


  Lemma ty_fby1 :
    forall ty b ov xs ys,
      (match ov with Some v => wt_value v ty | _ => True end) ->
      ty_DS ty xs ->
      ty_DS ty ys ->
      ty_DS ty (fby1s b ov xs ys).
  Proof.

  Lemma ty_fby :
    forall ty xs ys,
      ty_DS ty xs ->
      ty_DS ty ys ->
      ty_DS ty (fby xs ys).
  Proof.

  Lemma cl_fby1 :
    forall {A} cs v (xs ys : DS (sampl A)),
      safe_DS xs ->
      AC xs <= cs ->
      safe_DS ys ->
      AC ys <= cs ->
      AC (fby1 (Some v) xs ys) <= cs.
  Proof.

  Lemma cl_fby :
    forall ck xs ys,
      safe_DS xs /\ cl_DS ck xs ->
      safe_DS ys /\ cl_DS ck ys ->
      cl_DS ck (fby xs ys).
  Proof.

  Lemma safe_fby1 :
    forall {A} v cs (xs ys : DS (sampl A)),
      safe_DS xs ->
      AC xs <= cs ->
      safe_DS ys ->
      AC ys <= cs ->
      safe_DS (fby1 (Some v) xs ys).
  Proof.

  Lemma safe_fby :
    forall ck xs ys,
      safe_DS xs /\ cl_DS ck xs ->
      safe_DS ys /\ cl_DS ck ys ->
      safe_DS (fby xs ys).
  Proof.


Faits sur swhenv


  Lemma ty_swhenv :
    forall ty xs tx tn k cs,
      k < length tn ->
      ty_DS ty xs ->
      ty_DS (Tenum tx tn) cs ->
      ty_DS ty (swhenv k xs cs).
  Proof.

  Lemma cl_swhenv :
    forall xs ck x ty k,
      let cs := denot_var ins envI env x in
      safe_DS xs /\ cl_DS ck xs
      /\ safe_DS cs /\ cl_DS ck cs ->
      cl_DS (Con ck x (ty, k)) (swhenv k xs cs).
  Proof.

  Lemma safe_swhenv :
    forall k tx tn ck xs cs,
      ty_DS (Tenum tx tn) cs
      /\ safe_DS xs /\ cl_DS ck xs
      /\ safe_DS cs /\ cl_DS ck cs ->
      safe_DS (swhenv k xs cs).
  Proof.

Faits sur smergev


  Lemma zip_ac_le :
    forall A B (f : sampl A -> bool -> B) (X : DS (sampl A)) Y,
      AC X <= Y ->
      ZIP f X Y <= ZIP f X (AC X).
  Proof.

  Lemma ty_smergev :
    forall ty tx tn l cs np,
      ty_DS (Tenum tx tn) cs ->
      forall_nprod (ty_DS ty) np ->
      ty_DS ty (smergev l cs np).
  Proof.

  Definition value_belongs (l : list enumtag) (v : sampl value) :=
    match v with
    | pres (Venum v) => In v l
    | abs => True
    | _ => False
    end.

  Lemma cl_smergev_ :
    forall x tx ck l np,
      let cs := denot_var ins envI env x in
      NoDup l ->
      l <> [] ->
      DSForall (value_belongs l) cs ->
      cl_DS ck cs ->
      forall_nprod safe_DS np ->
      Forall2 (fun i s => cl_DS (Con ck x (tx,i)) s) l (list_of_nprod np) ->
      cl_DS ck (smergev l cs np).
  Proof.

  Lemma ty_belongs :
    forall tid tn xs,
      safe_DS xs ->
      ty_DS (Tenum tid tn) xs ->
      DSForall (value_belongs (seq 0 (length tn))) xs.
  Proof.

  Lemma Permutation_belongs :
    forall l l',
      Permutation l l' ->
      forall v,
        (value_belongs l v <-> value_belongs l' v).
  Proof.

  Lemma cl_smergev :
    forall x tid tn ck l np,
      let cs := denot_var ins envI env x in
      l <> [] ->
      Permutation l (seq 0 (length tn)) ->
      safe_DS cs ->
      ty_DS (Tenum tid tn) cs ->
      cl_DS ck cs ->
      Forall2 (fun i s => safe_DS s /\ cl_DS (Con ck x (Tenum tid tn,i)) s) l (list_of_nprod np) ->
      cl_DS ck (smergev l cs np).
  Proof.

  Lemma safe_smergev_ :
    forall x tx ck l np,
      let cs := denot_var ins envI env x in
      NoDup l ->
      l <> [] ->
      DSForall (value_belongs l) cs ->
      cl_DS ck cs ->
      forall_nprod safe_DS np ->
      Forall2 (fun i s => cl_DS (Con ck x (tx,i)) s) l (list_of_nprod np) ->
      safe_DS (smergev l cs np).
  Proof.

  Lemma safe_smergev :
    forall x tid tn ck l np,
      let cs := denot_var ins envI env x in
      l <> [] ->
      Permutation l (seq 0 (length tn)) ->
      safe_DS cs ->
      ty_DS (Tenum tid tn) cs ->
      cl_DS ck cs ->
      Forall2 (fun i s => safe_DS s /\ cl_DS (Con ck x (Tenum tid tn,i)) s) l (list_of_nprod np) ->
      safe_DS (smergev l cs np).
  Proof.


Faits sur scasev


  Lemma ty_scasev :
    forall ty tx tn l cs np,
      ty_DS (Tenum tx tn) cs ->
      forall_nprod (ty_DS ty) np ->
      ty_DS ty (scasev l cs np).
  Proof.

  Lemma cl_scasev_ :
    forall ck l cs np,
      l <> [] ->
      DSForall (value_belongs l) cs ->
      cl_DS ck cs ->
      forall_nprod safe_DS np ->
      forall_nprod (cl_DS ck) np ->
      cl_DS ck (scasev l cs np).
  Proof.

  Lemma cl_scasev :
    forall tid tn ck l cs np,
      l <> [] ->
      Permutation l (seq 0 (length tn)) ->
      safe_DS cs ->
      ty_DS (Tenum tid tn) cs ->
      cl_DS ck cs ->
      forall_nprod (fun s => safe_DS s /\ cl_DS ck s) np ->
      cl_DS ck (scasev l cs np).
  Proof.

  Lemma safe_scasev_ :
    forall ck l cs np,
      l <> [] ->
      DSForall (value_belongs l) cs ->
      cl_DS ck cs ->
      forall_nprod safe_DS np ->
      forall_nprod (cl_DS ck) np ->
      safe_DS (scasev l cs np).
  Proof.

  Lemma safe_scasev :
    forall tid tn ck l cs np,
      l <> [] ->
      Permutation l (seq 0 (length tn)) ->
      safe_DS cs ->
      ty_DS (Tenum tid tn) cs ->
      cl_DS ck cs ->
      forall_nprod (fun s => safe_DS s /\ cl_DS ck s) np ->
      safe_DS (scasev l cs np).
  Proof.


Faits sur scase_defv


  Lemma ty_scase_defv_ :
    forall ty tx tn l cs ds np,
      ty_DS (Tenum tx tn) cs ->
      ty_DS ty ds ->
      forall_nprod (ty_DS ty) np ->
      ty_DS ty (scase_defv l cs (nprod_cons ds np)).
  Proof.

  Corollary ty_scase_defv :
    forall ty tx tn l cs dnp,
      ty_DS (Tenum tx tn) cs ->
      forall_nprod (ty_DS ty) dnp ->
      ty_DS ty (scase_defv l cs dnp).
  Proof.

  Lemma cl_scase_defv_ :
    forall tx tn ck l cs ds np,
      l <> [] ->
      ty_DS (Tenum tx tn) cs ->
      safe_DS cs ->
      cl_DS ck cs ->
      safe_DS ds ->
      cl_DS ck ds ->
      forall_nprod safe_DS np ->
      forall_nprod (cl_DS ck) np ->
      cl_DS ck (scase_defv l cs (nprod_cons ds np)).
  Proof.

  Corollary cl_scase_defv :
    forall tid tn ck l cs dnp,
      l <> [] ->
      ty_DS (Tenum tid tn) cs ->
      safe_DS cs ->
      cl_DS ck cs ->
      forall_nprod (fun s => safe_DS s /\ cl_DS ck s) dnp ->
      cl_DS ck (scase_defv l cs dnp).
  Proof.

  Lemma safe_scase_defv_ :
    forall tx tn ck l cs ds np,
      l <> [] ->
      ty_DS (Tenum tx tn) cs ->
      safe_DS cs ->
      cl_DS ck cs ->
      safe_DS ds ->
      cl_DS ck ds ->
      forall_nprod safe_DS np ->
      forall_nprod (cl_DS ck) np ->
      safe_DS (scase_defv l cs (nprod_cons ds np)).
  Proof.

  Corollary safe_scase_defv :
    forall tid tn ck l cs dnp,
      l <> [] ->
      safe_DS cs ->
      ty_DS (Tenum tid tn) cs ->
      cl_DS ck cs ->
      forall_nprod (fun s => safe_DS s /\ cl_DS ck s) dnp ->
      safe_DS (scase_defv l cs dnp).
  Proof.


Résultats généraux sur les expressions


  Lemma Forall_ty_exp :
    forall es,
      Forall (fun e => Forall2 ty_DS (typeof e) (list_of_nprod (denot_exp G ins e envG envI env))) es ->
      Forall2 ty_DS (typesof es) (list_of_nprod (denot_exps G ins es envG envI env)).
  Proof.

  Lemma Forall_cl_exp :
    forall es,
      Forall (fun e => Forall2 cl_DS (clockof e) (list_of_nprod (denot_exp G ins e envG envI env))) es ->
      Forall2 cl_DS (clocksof es) (list_of_nprod (denot_exps G ins es envG envI env)).
  Proof.

  Lemma Forall_ty_expss :
    forall (es : list (enumtag * list exp)) n,
      Forall (fun es => length (annots (snd es)) = n) es ->
      Forall (fun l => Forall (fun e => Forall2 ty_DS (typeof e) (list_of_nprod (denot_exp G ins e envG envI env))) l) (List.map snd es) ->
      Forall2 (fun tys (ss : nprod n) => Forall2 ty_DS tys (list_of_nprod ss))
        (List.map typesof (List.map snd es)) (list_of_nprod (denot_expss G ins es n envG envI env)).
  Proof.

  Lemma Forall_cl_expss :
    forall (es : list (enumtag * list exp)) n,
      Forall (fun es => length (annots (snd es)) = n) es ->
      Forall (fun l => Forall (fun e => Forall2 cl_DS (clockof e) (list_of_nprod (denot_exp G ins e envG envI env))) l) (List.map snd es) ->
      Forall2 (fun cls (ss : nprod n) => Forall2 cl_DS cls (list_of_nprod ss))
        (List.map clocksof (List.map snd es)) (list_of_nprod (denot_expss G ins es n envG envI env)).
  Proof.

End SDfuns_safe.

Global Add Parametric Morphism ins : (denot_clock ins)
    with signature @Oeq (DS_prod SI) ==> @Oeq (DS bool) ==> @Oeq (DS_prod SI) ==> @eq clock ==> @Oeq (DS bool)
      as denot_clock_morph.
Proof.

Global Add Parametric Morphism Γ ins : (wf_env Γ ins)
       with signature @Oeq (DS_prod SI) ==> @Oeq (DS bool) ==> @Oeq (DS_prod SI) ==> iff
         as wf_env_morph.
Proof.

Faits sur denot_var et denot_clock


Lemma app_denot_var :
  forall ins envI1 envI2 env1 env2 x,
    app (denot_var ins envI1 env1 x) (denot_var ins envI2 env2 x)
    == denot_var ins (APP_env envI1 envI2) (APP_env env1 env2) x.
Proof.

Lemma rem_denot_var :
  forall ins envI env x,
    rem (denot_var ins envI env x)
    == denot_var ins (REM_env envI) (REM_env env) x.
Proof.

Lemma rem_denot_clock :
  forall ins envI bs env ck,
    rem (denot_clock ins envI bs env ck)
    == denot_clock ins (REM_env envI) (rem bs) (REM_env env) ck.
Proof.

Lemma denot_clock_app :
  forall ins envI1 envI2 bs1 bs2 env1 env2 ck,
    denot_clock ins (APP_env envI1 envI2) (app bs1 bs2) (APP_env env1 env2) ck
    == app (denot_clock ins envI1 bs1 env1 ck) (denot_clock ins envI2 bs2 env2 ck).
Proof.


Faits sur wf_env


Lemma wf_env_rem :
  forall Γ ins envI bs env,
    wf_env Γ ins envI bs env ->
    wf_env Γ ins (REM_env envI) (rem bs) (REM_env env).
Proof.

Lemma wf_env_APP_ :
  forall Γ ins envI1 envI2 bs1 bs2 env1 env2,
    wf_env Γ ins envI1 bs1 env1 ->
    wf_env Γ ins envI2 bs2 env2 ->
    wf_env Γ ins (APP_env envI1 envI2) (app bs1 bs2) (APP_env env1 env2).
Proof.

Corollary wf_env_APP :
  forall Γ ins envI bs env1 env2,
    wf_env Γ ins envI bs env1 ->
    wf_env Γ ins (REM_env envI) (rem bs) env2 ->
    wf_env Γ ins envI bs (APP_env env1 env2).
Proof.

Section wf_var.

wf_env n'étant pas un prédicat co-inductif, il est impossible de raisonner directement dessus avec la tactique cofix. (Typiquement, pour "attendre" un Con sur le flot de la condition de reset). On introduit donc le prédicat co-inductif wf_var et on montre qu'il est équivalent à wf_env s'il tient pour chaque variable de l'environment (cf. wfv_wfe et wfe_wfv).

  CoInductive wf_var ty ck ins : DS_prod SI -> DS bool -> DS_prod SI -> DS (sampl value) -> Prop :=
  | wfvEps :
    forall envI bs env s,
      wf_var ty ck ins envI bs env s ->
      wf_var ty ck ins envI bs env (Eps s)
  | wfvCon :
    forall envI bs env x s,
      wf_var ty ck ins (REM_env envI) (rem bs) (REM_env env) s ->
      first (AC (cons x s)) <= first (denot_clock ins envI bs env ck) ->
      (match x with
       | pres v => wt_value v ty
       | abs => True
       | err _ => False
       end) ->
      wf_var ty ck ins envI bs env (cons x s).

  Global Add Parametric Morphism ty ck ins : (wf_var ty ck ins)
         with signature @Oeq (DS_prod SI) ==> @Oeq (DS bool) ==>
                          @Oeq (DS_prod SI) ==> @Oeq (DS (sampl value)) ==> Basics.impl
           as wfv_morph.
  Proof.

  Lemma wfv_spec1 :
    forall ins envI bs env,
    forall ty ck xs,
      wf_var ty ck ins envI bs env xs ->
      ty_DS ty xs /\ safe_DS xs.
  Proof.

  Lemma wfv_spec2 :
    forall ins envI bs env,
    forall ty ck xs,
      wf_var ty ck ins envI bs env xs ->
      cl_DS ins envI bs env ck xs.
  Proof.

  Lemma wfv_wfe :
    forall Γ ins envI bs env,
      (forall x ty ck,
          HasType Γ x ty ->
          HasClock Γ x ck ->
          let s := denot_var ins envI env x in
          wf_var ty ck ins envI bs env s) ->
      wf_env Γ ins envI bs env.
  Proof.

  Lemma wfe_wfv_ :
    forall ins envI bs env,
    forall ty ck s,
      ty_DS ty s /\ cl_DS ins envI bs env ck s /\ safe_DS s ->
      wf_var ty ck ins envI bs env s.
  Proof.

  Lemma wfe_wfv :
    forall Γ ins envI bs env,
      wf_env Γ ins envI bs env ->
      (forall x ty ck,
          HasType Γ x ty ->
          HasClock Γ x ck ->
          let s := denot_var ins envI env x in
          wf_var ty ck ins envI bs env s).
  Proof.

  Lemma wf_var_bot:
    forall ty ck ins envI bs env,
      wf_var ty ck ins envI bs env 0.
  Proof.

  Lemma wf_env_bot :
    forall Γ ins bs,
      wf_env Γ ins 0 bs 0.
  Proof.

End wf_var.


Continuous alternatives of denot_var and denot_clock, sometimes useful to deal with the ordering properties

Section Cont_alt.

  Definition denot_var_C ins x : DS_prod SI -C-> DS_prod SI -C-> DS (sampl value) :=
    curry (if mem_ident x ins
           then PROJ _ x @_ FST _ _
           else PROJ _ x @_ SND _ _).

  Fact denot_var_eq :
    forall ins x envI env,
      denot_var ins envI env x = denot_var_C ins x envI env.
  Proof.

  Fixpoint denot_clock_C ins ck : DS_prod SI -C-> DS bool -C-> DS_prod SI -C-> DS bool :=
    curry (curry match ck with
    | Cbase => SND _ _ @_ FST _ _
    | Con ck x (_, k) =>
        let sx := (denot_var_C ins x @2_ FST _ _ @_ FST _ _) (SND _ _) in
        let cks := (denot_clock_C ins ck @3_ FST _ _ @_ FST _ _)
                     (SND _ _ @_ FST _ _) (SND _ _) in
        (ZIP (sample k) @2_ sx) cks
    end).

  Fact denot_clock_eq :
    forall ins envI bs env ck,
      denot_clock ins envI bs env ck = denot_clock_C ins ck envI bs env.
  Proof.

End Cont_alt.


Section Admissibility.

  Lemma admissible_and3 :
  forall T U V (D:cpo) (P Q : T -> U -> V -> D -> Prop),
    admissible (fun d => forall x y z, P x y z d) ->
    admissible (fun d => forall x y z, Q x y z d) ->
    admissible (fun d => forall x y z, P x y z d /\ Q x y z d).
  Proof.

  Lemma wf_env_admissible :
    forall Γ ins envI bs,
      admissible (wf_env Γ ins envI bs).
  Proof.

  Lemma wf_env_admissible_ins :
    forall Γ ins bs env,
      admissible (fun envI => wf_env Γ ins envI bs env).
  Proof.

End Admissibility.


Section SubClock.

CStr.sub_clock avec une notion de préfixe : le flot de gauche est plus long que celui de droite par ex : T T T F T F T T est sub_clock de F T F F T ⊥ T T T F T F ⊥ n'est pas sub_clock de F T F F T F T
  CoInductive sub_clock : relation (DS bool) :=
  | ScEps : forall x y,
      sub_clock x y -> sub_clock x (Eps y)
  | ScCon : forall a b s t x,
      sub_clock s t ->
      decomp a s x ->
      Bool.le b a ->
      sub_clock x (cons b t).

  Lemma le_sub_clock :
    forall x y,
      x <= y ->
      sub_clock y x.
  Proof.

  Lemma sub_clock_decomp :
    forall a s x y,
      decomp a s x ->
      sub_clock y x ->
      exists b t, decomp b t y /\ Bool.le a b /\ sub_clock t s.
  Proof.

  Lemma sub_clock_trans : forall x y z,
      sub_clock x y ->
      sub_clock y z ->
      sub_clock x z.
  Proof.

  Lemma sub_clock_Oeq_compat :
    forall x y z t,
      x == y ->
      z == t ->
      sub_clock x z ->
      sub_clock y t.
  Proof.

  Global Add Parametric Morphism : sub_clock
      with signature (@Oeq (DS bool)) ==> (@Oeq (DS bool)) ==> iff
        as sub_clock_morph.
  Proof.

  Lemma sub_clock_refl : forall s, sub_clock s s.
  Proof.

  Lemma sub_clock_antisym :
    forall x y,
      sub_clock x y ->
      sub_clock y x ->
      x == y.
  Proof.

  Lemma sub_clock_le :
    forall bs xs ys,
      xs <= ys ->
      sub_clock bs ys ->
      sub_clock bs xs.
  Proof.

  Lemma sub_clock_sample :
    forall bs cs xs k,
      sub_clock bs cs ->
      sub_clock bs (ZIP (sample k) xs cs).
  Proof.

  Lemma sub_clock_bs :
    forall ins envI bs env ck,
      sub_clock bs (denot_clock ins envI bs env ck).
  Proof.

  Lemma sub_clock_orb :
    forall bs xs ys,
      sub_clock bs xs ->
      sub_clock bs ys ->
      sub_clock bs (ZIP orb xs ys).
  Proof.

  Lemma orb_sub_clock :
    forall bs xs ys,
      sub_clock bs ys ->
      xs <= bs ->
      ZIP orb xs ys <= bs.
  Proof.

End SubClock.


Traitement de l'horloge de base


Lemma sub_clock_bss :
  forall l bs (env : DS_prod SI),
    l <> [] ->
    (forall x, In x l -> sub_clock bs (AC (env x))) ->
    sub_clock bs (bss l env).
Proof.

Lemma bss_sub :
  forall l (env : DS_prod SI) bs,
    (exists x, In x l /\ (AC (env x) <= bs)) ->
    (forall x, In x l -> sub_clock bs (AC (env x))) ->
    bss l env <= bs.
Proof.

Lemma bss_le_bs :
  forall {PSyn Prefs} (n : @node PSyn Prefs),
  forall env bs,
    let Γ := senv_of_ins (n_in n) ++ senv_of_decls (n_out n) in
    wc_env (List.map (fun '(x, (_, ck, _)) => (x, ck)) (n_in n)) ->
    cl_env Γ (idents (n_in n)) env bs 0 ->
    bss (idents (n_in n)) env <= bs.
Proof.


Section Node_safe.

  Context {PSyn : list decl -> block -> Prop}.
  Context {Prefs : PS.t}.

  Variables
    (G : @global PSyn Prefs)
    (envG : Dprodi FI).

  Hypothesis
    (WCG : wc_global G).


  Hypothesis Hnode :
    forall f n,
      find_node f G = Some n ->
      let ins := List.map fst n.(n_in) in
      let Γ := senv_of_ins (n_in n) ++ senv_of_decls (n_out n) in
      forall bs envI,
        bss ins envI <= bs ->
        wf_env Γ ins envI bs 0 ->
        wf_env Γ ins envI bs (envG f envI).

  Lemma basilus_nclockus :
    forall ins envI env e,
      let ss := denot_exp G ins e envG envI env in
      Forall2 (fun nc s => match snd nc with
                        | Some x => denot_var ins envI env x = s
                        | None => True end)
        (nclockof e) (list_of_nprod ss).
  Proof.

  Corollary nclocksof_sem :
    forall ins envI env es,
      let ss := denot_exps G ins es envG envI env in
      Forall2 (fun nc s => match snd nc with
                        | Some x => denot_var ins envI env x = s
                        | None => True end)
        (nclocksof es) (list_of_nprod ss).
  Proof.


Traitement des instanciations de nœuds


  Lemma Wi_match_ss :
    forall ins envI env env',
    forall bck sub,
    forall (n : @node PSyn Prefs) nn (ss : nprod nn) ncks,
      let ckins := List.map (fun '(x, (_, ck, _)) => (x, ck)) n.(n_in) in
      Forall2 (WellInstantiated bck sub) ckins ncks ->
      Forall2 (fun nc s => match snd nc with
                        | Some x => denot_var ins envI env x = s
                        | None => True
                        end) ncks (list_of_nprod ss) ->
      forall x y ck,
        sub x = Some y ->
        In (x, ck) ckins ->
        denot_var (idents (n_in n)) (env_of_np (idents (n_in n)) ss) env' x =
          denot_var ins envI env y.
  Proof.

  Lemma denot_clock_inst_ins :
    forall ins envI bs env,
    forall bck sub,
    forall ncks (n: @node PSyn Prefs) nn (ss : nprod nn),
      let ckins := List.map (fun '(x, (_, ck, _)) => (x, ck)) n.(n_in) in
      wc_env ckins ->
      Forall2 (WellInstantiated bck sub) ckins ncks ->
      Forall2 (cl_DS ins envI bs env) (List.map fst ncks) (list_of_nprod ss) ->
      Forall2 (fun nc s => match snd nc with
                        | Some x => denot_var ins envI env x = s
                        | None => True
                        end) ncks (list_of_nprod ss) ->
      forall env' ck x ck',
        In (x, ck) ckins ->
        instck bck sub ck = Some ck' ->
        denot_clock (idents (n_in n)) (env_of_np (List.map fst (n_in n)) ss)
          (denot_clock ins envI bs env bck) env' ck
        = denot_clock ins envI bs env ck'.
  Proof.

  Lemma cl_env_inst :
    forall ins envI bs env,
    forall bck sub,
    forall ncks (n : @node PSyn Prefs) nn (ss : nprod nn),
      let ckins := List.map (fun '(x, (_, ck, _)) => (x, ck)) n.(n_in) in
      wc_env ckins ->
      Forall2 (WellInstantiated bck sub) ckins ncks ->
      Forall2 (fun nc s => match snd nc with
                        | Some x => denot_var ins envI env x = s
                        | None => True
                        end) ncks (list_of_nprod ss) ->
      Forall2 (cl_DS ins envI bs env) (List.map fst ncks) (list_of_nprod ss) ->
      cl_env (senv_of_ins (n_in n) ++ senv_of_decls (n_out n)) (idents (n_in n)) (env_of_np (idents (n_in n)) ss) (denot_clock ins envI bs env bck) 0.
  Proof.

  Lemma ef_env_inst :
    forall (n : @node PSyn Prefs) (ss : nprod (length (n_in n))),
      forall_nprod safe_DS ss ->
      ef_env (senv_of_ins (n_in n) ++ senv_of_decls (n_out n)) (idents (n_in n))
        (env_of_np (idents (n_in n)) ss) 0.
  Proof.

  Lemma ty_env_inst :
    forall tys (n : @node PSyn Prefs) nn (ss : nprod nn),
      Forall2 (fun (et : type) '(_, (t, _, _)) => et = t) tys (n_in n) ->
      Forall2 ty_DS tys (list_of_nprod ss) ->
      ty_env (senv_of_ins (n_in n) ++ senv_of_decls (n_out n)) (idents (n_in n))
        (env_of_np (idents (n_in n)) ss) 0.
  Proof.

  Lemma inst_ty_env :
    forall tys (n : @node PSyn Prefs) envI env,
      Forall2 (fun a '(_, (t, _, _, _)) => a = t) tys (n_out n) ->
      ty_env (senv_of_ins (n_in n) ++ senv_of_decls (n_out n)) (idents (n_in n)) envI env ->
      Forall2 ty_DS tys (list_of_nprod (np_of_env (List.map fst (n_out n)) env)).
  Proof.

  Lemma inst_ef_env :
    forall (n : @node PSyn Prefs) envI env,
      ef_env (senv_of_ins (n_in n) ++ senv_of_decls (n_out n)) (idents (n_in n)) envI env ->
      forall_nprod safe_DS (np_of_env (List.map fst (n_out n)) env).
  Proof.

  Lemma inst_cl_env :
    forall ins envI bs env env',
    forall bck sub,
    forall (a : list ann) (n : @node PSyn Prefs) nn (ss : nprod nn) ncks,
      let ckins := List.map (fun '(x, (_, ck, _)) => (x, ck)) n.(n_in) in
      let ckouts := List.map (fun '(x, (_, ck, _, _)) => (x, ck)) n.(n_out) in
      wc_env ckins ->
      wc_env (ckins ++ ckouts) ->
      Forall2 (WellInstantiated bck sub) ckouts (List.map (fun '(_, ck) => (ck, None)) a) ->
      Forall2 (WellInstantiated bck sub) ckins ncks ->
      cl_env (senv_of_ins (n_in n) ++ senv_of_decls (n_out n)) (idents (n_in n)) (env_of_np (idents (n_in n)) ss) (denot_clock ins envI bs env bck) env' ->
      Forall2 (cl_DS ins envI bs env) (List.map fst ncks) (list_of_nprod ss) ->
      Forall2 (fun nc s => match snd nc with
                        | Some x => denot_var ins envI env x = s
                        | None => True
                        end) ncks (list_of_nprod ss) ->
      Forall2 (cl_DS ins envI bs env) (List.map snd a) (list_of_nprod (np_of_env (List.map fst (n_out n)) env')).
  Proof.

À partir de flots bien formés, construire un environnement d'entrées bien formé.
  Lemma safe_inst_in :
    forall ins envI bs env,
    forall es (n : @node PSyn Prefs) bck sub nn (ss : nprod nn),
      nn = length (n_in n) ->
      Forall2 (fun (et : type) '(_, (t, _, _)) => et = t) (typesof es) (n_in n) ->
      Forall2 (WellInstantiated bck sub) (List.map (fun '(x, (_, ck, _)) => (x, ck)) (n_in n)) (nclocksof es) ->
      wc_env (List.map (fun '(x, (_, ck, _)) => (x, ck)) (n_in n)) ->
      Forall2 ty_DS (typesof es) (list_of_nprod ss) ->
      Forall2 (cl_DS ins envI bs env) (List.map fst (nclocksof es)) (list_of_nprod ss) ->
      forall_nprod safe_DS ss ->
      Forall2 (fun nc s =>
               match snd nc with
               | Some x => denot_var ins envI env x = s
               | None => True
               end) (nclocksof es) (list_of_nprod ss) ->
      wf_env (senv_of_ins (n_in n) ++ senv_of_decls (n_out n)) (idents (n_in n)) (env_of_np (idents (n_in n)) ss)
        (denot_clock ins envI bs env bck) 0.
  Proof.


Traitement du reset


  Lemma denot_clock_ins :
    forall ins bs envI env1 env2 ck,
      (forall y, Is_free_in_clock y ck -> In y ins) ->
      denot_clock ins envI bs env1 ck == denot_clock ins envI bs env2 ck.
  Proof.

  Lemma clock_ins_stable :
    forall (n : @node PSyn Prefs) x ck,
      wc_node G n ->
      let Γ := senv_of_ins (n_in n) ++ senv_of_decls (n_out n) in
      let ins := List.map fst (n_in n) in
      HasClock Γ x ck ->
      In x ins ->
      (forall y, Is_free_in_clock y ck -> In y ins).
  Proof.

FIXME: on voudrait généraliser (envG f) pour sortir de la section Node_safe, se concentrer sur la fonction de reset (sans Hnode, Γ, etc.) et obtenir un résultat du genre : Lemma safe_sreset : forall (f : DS_prod SI -C-> DS_prod SI) Γ ins envI bs rs, (forall bs envI, bss ins envI <= bs -> wf_env Γ ins envI bs 0 -> wf_env Γ ins envI bs (f envI)) -> bss ins envI <= bs -> safe_DS rs -> wf_env Γ ins envI bs 0 -> wf_env Γ ins envI bs (sreset f rs envI). Malheureusement ça semble impossible car il faut des propriétés du type (wc_env Γ) et on ne peut les obtenir que dans un nœud bien cadencé.

Ici on utilise l'hypothèse de section Hnode à chaque fois que la condition de reset rs est activée.
  Lemma safe_sreset :
    forall f n envI bs rs,
      find_node f G = Some n ->
      let ins := List.map fst (n_in n) in
      let Γ := senv_of_ins (n_in n) ++ senv_of_decls (n_out n) in
      bss (List.map fst (n_in n)) envI <= bs ->
      wf_env Γ ins envI bs 0 ->
      wf_env Γ ins envI bs (sreset (envG f) rs envI).
  Proof.


  Ltac find_specialize_in H :=
    repeat multimatch goal with
      | [ v : _ |- _ ] => specialize (H v)
      end.

  Lemma safe_exp_ :
    forall Γ ins envI bs env,
    wf_env Γ ins envI bs env ->
    bss ins envI <= bs ->
    forall (e : exp),
      wt_exp G Γ e ->
      wc_exp G Γ e ->
      no_rte_exp G ins envG envI env e ->
      let ss := denot_exp G ins e envG envI env in
      Forall2 ty_DS (typeof e) (list_of_nprod ss)
      /\ Forall2 (cl_DS ins envI bs env) (clockof e) (list_of_nprod ss)
      /\ forall_nprod safe_DS ss.
  Proof.

  Corollary safe_exp :
    forall Γ ins envI bs env,
    wf_env Γ ins envI bs env ->
    bss ins envI <= bs ->
    forall (e : exp),
      wt_exp G Γ e ->
      wc_exp G Γ e ->
      no_rte_exp G ins envG envI env e ->
      let ss := denot_exp G ins e envG envI env in
      forall_nprod safe_DS ss.
  Proof.

  Lemma safe_exps_ :
    forall Γ ins envI bs env,
    wf_env Γ ins envI bs env ->
    bss ins envI <= bs ->
    forall (es : list exp),
      Forall (wt_exp G Γ) es ->
      Forall (wc_exp G Γ) es ->
      Forall (no_rte_exp G ins envG envI env) es ->
      let ss := denot_exps G ins es envG envI env in
      Forall2 ty_DS (typesof es) (list_of_nprod ss)
      /\ Forall2 (cl_DS ins envI bs env) (clocksof es) (list_of_nprod ss)
      /\ forall_nprod safe_DS ss.
  Proof.

  Corollary safe_exps :
    forall Γ ins envI bs env,
    wf_env Γ ins envI bs env ->
    bss ins envI <= bs ->
    forall (es : list exp),
      Forall (wt_exp G Γ) es ->
      Forall (wc_exp G Γ) es ->
      Forall (no_rte_exp G ins envG envI env) es ->
      let ss := denot_exps G ins es envG envI env in
      forall_nprod safe_DS ss.
  Proof.


Terrible cas des appels de nœuds aux sorties dépendantes. Il ne rentre pas dans le cadre de safe_exp car on n'a pas l'hypothèse wc_exp G Γ (Eapp f es er anns). De toute façon, le résultat de safe_exp ne serait pas correct ici. Par ex. soit f de signature f (t :: ⋅) returns (c :: ⋅, y :: ⋅ on c) et l'équation b :: ⋅, x :: ⋅ on b = f(t); Alors par Hnode le deuxième flot, correspondant à celui de y dans l'environnement interne de f respecte bien l'horloge on c, mais pas on b dans l'environnement de l'appelant. On va donc montrer la préservation de cl_DS mais seulement dans l'environnement (env') dans lequel les variables b et x ont été mises à jour, soit à la fin d'un tour de denot_node.
  Lemma safe_Eapp_dep :
    forall Γ ins envI bs env,
    forall xs f es er anns n bck sub,
      wf_env Γ ins envI bs env ->
      bss ins envI <= bs ->
      Forall (wt_exp G Γ) es ->
      Forall (wc_exp G Γ) es ->
      Forall (no_rte_exp G ins envG envI env) es ->
      Forall (wt_exp G Γ) er ->
      Forall (wc_exp G Γ) er ->
      Forall (no_rte_exp G ins envG envI env) er ->
      find_node f G = Some n ->
      NoDup (xs ++ ins) ->
      Forall (fun e => typeof e = [bool_velus_type]) er ->
      wc_env (List.map (fun '(x, (_, ck, _)) => (x, ck)) n.(n_in)) ->
      wc_env (List.map (fun '(x, (_, ck, _)) => (x, ck)) n.(n_in) ++ List.map (fun '(x, (_, ck, _, _)) => (x, ck)) n.(n_out)) ->
      Forall2 (fun (et : type) '(_, (t, _, _)) => et = t) (typesof es) (n_in n) ->
      Forall2 (fun a '(_, (t, _, _, _)) => fst a = t) anns n.(n_out) ->
      Forall2 (WellInstantiated bck sub) (List.map (fun '(x, (_, ck, _)) => (x, ck)) (n_in n)) (nclocksof es) ->
      Forall3 (fun xck ck2 x2 => WellInstantiated bck sub xck (ck2, Some x2)) (List.map (fun '(x, (_, ck, _, _)) => (x, ck)) n.(n_out)) (List.map snd anns) xs ->
      forall env',
      env <= env' ->
      let ss := denot_exp G ins (Eapp f es er anns) envG envI env in
      Forall2 (fun x (s : DS (sampl value)) => s <= env' x) xs (list_of_nprod ss) ->
      Forall2 ty_DS (List.map fst anns) (list_of_nprod ss)
      /\ Forall2 (cl_DS ins envI bs env') (List.map snd anns) (list_of_nprod ss)
      /\ forall_nprod safe_DS ss.
  Proof.

  Lemma denot_blocks_equs :
    forall {PSyn Prefs} (G : @global PSyn Prefs),
    forall ins envG envI env blks,
      Forall (wl_block G) blks ->
      NoDup (flat_map get_defined blks) ->
      let env' := denot_blocks G ins blks envG envI env in
      Forall (fun blk =>
                match blk with
                | Beq (xs,es) =>
                    Forall2 (fun x (s : DS _) => s == PROJ _ x env')
                      xs (list_of_nprod (denot_exps G ins es envG envI env))
                | _ => True
                end
        ) blks.
  Proof.

  Lemma safe_node :
    forall n envI env bs,
      let ins := List.map fst n.(n_in) in
      let Γ := senv_of_ins (n_in n) ++ senv_of_decls (n_out n) ++ get_locals (n_block n) in
      bss (List.map fst (n_in n)) envI <= bs ->
      env <= denot_node G n envG envI env ->
      wc_node G n ->
      wt_node G n ->
      no_rte_node G ins envG envI env n ->
      wf_env Γ ins envI bs env ->
      wf_env Γ ins envI bs (denot_node G n envG envI env).
  Proof.

End Node_safe.


Deuxième partie : montrer que wf_env est préservé


Section Rev.

Dans la suite on souhaite utiliser fixp_ind pour établir un résultat sur l'environnement env := FIXP (denot_equation ...). Or pour appliquer safe_exp on a besoin de no_rte_exp, qui est supposé prouvé pour env. fixp_inv2 permet de transporter cette hypothèse à chaque itération du point fixe. Il faut cependant montrer qu'elle est admissible "en arrière" :
Definition admissible_rev (D:cpo)(P:D->Type) :=
  forall f : natO -m> D, P (lub f) -> (forall n, P (f n)).

Lemma fixp_inv2 : forall (D:cpo) (F:D -m> D) (P P' Q : D -> Prop),
    (forall x, P' x -> P x) ->
    admissible P ->
    admissible_rev _ Q ->
    Q (fixp F) ->
    P' 0 ->
    (forall x, P' x -> Q x -> P' (F x)) ->
    P (fixp F).
Proof.

Lemma fixp_inv2_le : forall (D:cpo) (F:D -m> D) (P Q : D -> Prop),
    admissible P ->
    admissible_rev _ Q ->
    Q (fixp F) ->
    P 0 ->
    (forall x, P x -> x <= F x -> Q x -> P (F x)) ->
    P (fixp F).
Proof.

Lemma denot_clock_le :
  forall ins envI bs env env' ck ,
    env <= env' ->
    denot_clock ins envI bs env ck <=
      denot_clock ins envI bs env' ck.
Proof.

Lemma oc_node_admissible_rev :
  forall {PSyn Prefs} (G : @global PSyn Prefs),
  forall ins envG envI n,
    admissible_rev _ (fun env => no_rte_node G ins envG envI env n).
Proof.

End Rev.

Lemma wf_env_loc :
  forall {PSyn Prefs} (n : @node PSyn Prefs),
  forall envI bs env,
    wf_env (senv_of_ins (n_in n)
                   ++ senv_of_decls (n_out n)
                   ++ get_locals (n_block n)) (List.map fst (n_in n)) envI bs env ->
    wf_env (senv_of_ins (n_in n)
                   ++ senv_of_decls (n_out n)) (List.map fst (n_in n)) envI bs env.
Proof.

Lemma wf_env_0_ext :
  forall {PSyn Prefs} (n : @node PSyn Prefs),
  forall envI bs,
    wf_env (senv_of_ins (n_in n)
                   ++ senv_of_decls (n_out n)) (List.map fst (n_in n)) envI bs 0 ->
    wf_env (senv_of_ins (n_in n)
                   ++ senv_of_decls (n_out n)
                   ++ get_locals (n_block n)) (List.map fst (n_in n)) envI bs 0.
Proof.

Theorem noerrors_prog :
  forall {PSyn Prefs} (G : @global PSyn Prefs),
    wt_global G ->
    wc_global G ->
    no_rte_global G ->
    forall f n envI,
      find_node f G = Some n ->
      let ins := List.map fst n.(n_in) in
      let Γ := senv_of_ins (n_in n) ++ senv_of_decls (n_out n) ++ get_locals (n_block n) in
      forall bs, bss ins envI <= bs ->
      wf_env Γ ins envI bs 0 ->
      wf_env Γ ins envI bs (denot_global G f envI).
Proof.


the same theorem but with the weaker no_rte_node_main hypothesis
Theorem noerrors_prog_main :
  forall {PSyn Prefs} (G : @global PSyn Prefs),
    wt_global G ->
    wc_global G ->
    forall f n envI,
      no_rte_global_main G f envI ->
      find_node f G = Some n ->
      let ins := List.map fst n.(n_in) in
      let Γ := senv_of_ins (n_in n) ++ senv_of_decls (n_out n) ++ get_locals (n_block n) in
      forall bs, bss ins envI <= bs ->
      wf_env Γ ins envI bs 0 ->
      wf_env Γ ins envI bs (denot_global G f envI).
Proof.


As a consequence of clock typing correctness, we prove that the absences of inputs and outputs are aligned
Section Abs_aligned.

Lemma denot_clock_abs :
  forall ins ck,
    let abs_env := fun _ : ident => DS_const abs in
    denot_clock ins abs_env (DS_const false) abs_env ck == DS_const false.
Proof.

Lemma wf_env_abs_ins :
  forall Γ ins,
    (forall x ck, HasClock Γ x ck -> In x ins -> (forall y, Is_free_in_clock y ck -> In y ins)) ->
    wf_env Γ ins (fun _ : ident => DS_const abs) (DS_const false) 0.
Proof.

Lemma wf_env_smask0 :
  forall Γ ins envI bs k rs,
    (forall x ck, HasClock Γ x ck -> In x ins -> (forall y, Is_free_in_clock y ck -> In y ins)) ->
    wf_env Γ ins envI bs 0 ->
    wf_env Γ ins
      (smask_env k rs envI)
      (MAP bool_of_sbool (smask k rs (MAP pres bs)))
      0.
Proof.

Lemma bss_abs :
  forall I A l,
    @bss I A l abs_env == DS_const false.
Proof.

Lemma denot_clock_bs_abs :
  forall ins envI env ck,
    denot_clock ins envI (DS_const false) env ck <= DS_const false.
Proof.

Lemma AC_le_abss :
  forall A (xs : DS (sampl A)),
    safe_DS xs ->
    AC xs <= DS_const false ->
    xs <= abss.
Proof.


Theorem wf_alignLE :
  forall {PSyn Prefs} (G : @global PSyn Prefs),
    restr_global G ->
    forall f n,
    find_node f G = Some n ->
    forall envI,
    let ins := List.map fst (n_in n) in
    let Γ := senv_of_ins (n_in n) ++ senv_of_decls (n_out n) ++ get_locals (n_block n) in
    wf_env Γ ins envI (bss ins envI) (denot_global G f envI) ->
    abs_alignLE envI (denot_global G f envI).
Proof.

End Abs_aligned.


End LDENOTSAFE.

Module LdenotsafeFun
       (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)
       (Typ : LTYPING Ids Op OpAux Cks Senv Syn)
       (Restr : LRESTR Ids Op OpAux Cks Senv Syn)
       (Cl : LCLOCKING Ids Op OpAux Cks Senv Syn)
       (Lord : LORDERED Ids Op OpAux Cks Senv Syn)
       (Den : SD Ids Op OpAux Cks Senv Syn Lord)
       (Ckop : CHECKOP Ids Op OpAux Cks Senv Syn)
       (OpErr : OP_ERR Ids Op OpAux Cks Senv Syn Typ Restr Lord Den Ckop)
<: LDENOTSAFE Ids Op OpAux Cks Senv Syn Typ Restr Cl Lord Den Ckop OpErr.
  Include LDENOTSAFE Ids Op OpAux Cks Senv Syn Typ Restr Cl Lord Den Ckop OpErr.
End LdenotsafeFun.