Module InftyProof

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

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

From Velus Require Import Lustre.Denot.Cpo.
Require Import SDfuns SD Restr Infty CommonList2.

Import List.

Module Type LDENOTINF
       (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 LCA : LCAUSALITY Ids Op OpAux Cks Senv Syn)
       (Import Lord : LORDERED Ids Op OpAux Cks Senv Syn)
       (Import Restr : LRESTR Ids Op OpAux Cks Senv Syn)
       (Import Den : SD Ids Op OpAux Cks Senv Syn Lord).

  Section Top.

  Hypothesis HasCausInj :
    forall Γ x cx, HasCaus Γ x cx -> cx = x.

  Lemma HasCausRefl : forall Γ x, IsVar Γ x -> HasCaus Γ x x.
  Proof.

First we show that a well-formed node receiving streams of length n outputs streams of length n.
  Section Node_n.

  Context {PSyn : list decl -> block -> Prop}.
  Context {Prefs : PS.t}.
  Variables
    (G : @global PSyn Prefs)
    (envG : Dprodi FI).

  Fact idcaus_map :
    forall l : list (ident * (type * clock * ident)),
      map snd (idcaus l) = map fst l.
  Proof.

  Fact idcaus_of_decls_map :
    forall l : list (ident * (type * clock * ident * option ident)),
      Forall (fun '(_, (_, _, _, o)) => o = None) l ->
      map fst l = map snd (idcaus_of_decls l).
  Proof.

  Fact map_fst_idcaus_decls : forall l,
      Forall (fun '(_, (_, _, _, o)) => o = None) l ->
      map fst (idcaus_of_senv (senv_of_decls l)) = map fst l.
  Proof.


Invariants pour l'induction causale
  Definition P_var (n : nat) (env : DS_prod SI) (x : ident) : Prop :=
    is_ncons n (PROJ _ x env).

  Definition P_vars (n : nat) (env : DS_prod SI) (cxs : list ident) : Prop :=
    forall x, In x cxs -> P_var n env x.

  Definition P_exp (n : nat) ins envI env (e : exp) (k : nat) : Prop :=
    let ss := denot_exp G ins e envG envI env in
    is_ncons n (get_nth k errTy ss).

  Hypothesis Hnode :
    forall (n : nat) (f : ident) (nd : node) (envI : DS_prod SI),
      find_node f G = Some nd ->
      (P_vars n envI (map fst (n_in nd))) ->
      (P_vars n (envG f envI) (map fst (n_out nd))).


  Global Add Parametric Morphism n : (P_var n) with signature
      Oeq (O := DS_prod SI) ==> eq ==> iff as P_var_morph.
  Proof.

  Global Add Parametric Morphism n : (P_vars n) with signature
      Oeq (O := DS_prod SI) ==> eq ==> iff as P_vars_morph.
  Proof.

  Lemma P_vars_In :
    forall n env xs x,
      P_vars n env xs ->
      In x xs ->
      P_var n env x.
  Proof.

  Lemma P_var_S :
    forall n env x,
      P_var (S n) env x ->
      P_var n env x.
  Proof.

  Lemma P_vars_S :
    forall n env xs,
      P_vars (S n) env xs ->
      P_vars n env xs.
  Proof.

  Lemma P_vars_O :
    forall env xs,
      P_vars O env xs.
  Proof.

  Lemma P_vars_app_l :
    forall n env xs ys,
      P_vars n env (xs ++ ys) ->
      P_vars n env ys.
  Proof.

  Lemma P_vars_app_r :
    forall n env xs ys,
      P_vars n env (xs ++ ys) ->
      P_vars n env xs.
  Proof.

  Lemma P_exps_k : forall n es ins envI env k,
      P_exps (P_exp n ins envI env) es k ->
      is_ncons n (get_nth k errTy (denot_exps G ins es envG envI env)).
  Proof.

  Lemma P_expss_k : forall n (ess : list (enumtag * list exp)) ins envI env k m,
      Forall (fun es => length (annots (snd es)) = m) ess ->
      Forall (fun es => P_exps (P_exp n ins envI env) es k) (map snd ess) ->
      forall_nprod (fun np => is_ncons n (get_nth k errTy np))
        (denot_expss G ins ess m envG envI env).
  Proof.

  Lemma P_exps_impl :
    forall Q (P_exp : exp -> nat -> Prop) es k,
      Forall Q es ->
      P_exps (fun e k => Q e -> P_exp e k) es k ->
      P_exps P_exp es k.
  Proof.

  Lemma Forall_P_exps :
    forall (P_exp : exp -> nat -> Prop) es k,
      Forall (fun e => forall k, k < numstreams e -> P_exp e k) es ->
      k < list_sum (map numstreams es) ->
      P_exps P_exp es k.
  Proof.

  Lemma Forall_P_expss :
    forall (P_exp : exp -> nat -> Prop) (ess : list (enumtag * list exp)) k m,
      Forall (Forall (fun e => forall k, k < numstreams e -> P_exp e k)) (map snd ess) ->
      Forall (fun es => length (annots (snd es)) = m) ess ->
      k < m ->
      Forall (fun es => P_exps P_exp es k) (map snd ess).
  Proof.

  Lemma is_ncons_sbools_of :
    forall n m (np : nprod m),
      forall_nprod (is_ncons n) np ->
      is_ncons n (sbools_of np).
  Proof.

  Ltac solve_err :=
    try (rewrite annots_numstreams in *; congruence)
    ; try (repeat (rewrite get_nth_const; [|simpl; cases]);
         match goal with
         | |- is_cons (nrem _ (Cpo_streams_type.map _ _)) =>
             apply (is_ncons_map _ _ _ _ (S _)); auto 1
         | _ => idtac
         end;
         now (apply is_ncons_DS_const || apply is_consn_DS_const)).

  Lemma P_vars_env_of_np :
    forall n l m (mp : nprod m),
      forall_nprod (is_ncons n) mp ->
      P_vars n (env_of_np l mp) l.
  Proof.

  Lemma P_vars_app :
    forall n X Y l,
      P_vars 1 X l ->
      P_vars n Y l ->
      P_vars (S n) (APP_env X Y) l.
  Proof.

  Lemma P_vars_1 :
    forall n X l,
      P_vars (S n) X l ->
      P_vars 1 X l.
  Proof.

  Lemma is_cons_sreset_aux :
    forall (f:DS_prod SI -C-> DS_prod SI) ins outs R X Y,
      (forall envI, P_vars 1 envI ins -> P_vars 1 (f envI) outs) ->
      is_cons R ->
      P_vars 1 X ins ->
      P_vars 1 Y outs ->
      P_vars 1 (sreset_aux f R X Y) outs.
  Proof.

  Lemma is_ncons_sreset :
    forall (f:DS_prod SI -C-> DS_prod SI) ins outs R X,
      (forall n envI, P_vars n envI ins -> P_vars n (f envI) outs) ->
      forall n,
        is_ncons n R ->
        P_vars n X ins ->
        P_vars n (sreset f R X) outs.
  Proof.

  Lemma is_ncons_bss :
    forall n (env : DS_prod SI) l,
      P_vars n env l ->
      is_ncons n (bss l env).
  Proof.

  Lemma exp_n :
    forall Γ n e ins envI env k,
      P_vars n envI ins ->
      k < numstreams e ->
      restr_exp e ->
      wl_exp G e ->
      wx_exp Γ e ->
      (forall x cx, HasCaus Γ x cx -> ~ In x ins -> P_var n env cx) ->
      P_exp n ins envI env e k.
  Proof.

  Lemma exps_n :
    forall Γ n es ins envI env k,
      P_vars n envI ins ->
      k < list_sum (map numstreams es) ->
      Forall restr_exp es ->
      Forall (wl_exp G) es ->
      Forall (wx_exp Γ) es ->
      (forall x cx, HasCaus Γ x cx -> ~ In x ins -> P_var n env cx) ->
      P_exps (P_exp n ins envI env) es k.
  Proof.

  Lemma exp_S :
    forall Γ n e ins envI env k,
      P_vars (S n) envI ins ->
      k < numstreams e ->
      (forall x, Is_used_inst Γ x k e -> ~ In x ins -> P_var (S n) env x) ->
      restr_exp e ->
      wl_exp G e ->
      wx_exp Γ e ->
      (forall x cx, HasCaus Γ x cx -> ~ In x ins -> P_var n env cx) ->
      P_exp (S n) ins envI env e k.
  Proof.

  Corollary exps_S :
    forall Γ n es ins envI env k,
      P_vars (S n) envI ins ->
      k < list_sum (map numstreams es) ->
      (forall x, Is_used_inst_list Γ x k es -> ~ In x ins -> P_var (S n) env x) ->
      Forall restr_exp es ->
      Forall (wl_exp G) es ->
      Forall (wx_exp Γ) es ->
      (forall x cx, HasCaus Γ x cx -> ~ In x ins -> P_var n env cx) ->
      P_exps (P_exp (S n) ins envI env) es k.
  Proof.

  Lemma P_var_inside_blocks :
    forall Γ ins envI env blks x n,
      Forall restr_block blks ->
      Forall (wl_block G) blks ->
      Forall (wx_block Γ) blks ->
      P_vars (S n) envI ins ->
      (forall x cx : ident, HasCaus Γ x cx -> ~ In x ins -> P_var n env cx) ->
      (forall y, Exists (depends_on Γ x y) blks -> ~ In y ins -> P_var (S n) env y) ->
      Exists (Syn.Is_defined_in (Var x)) blks ->
      P_var (S n) (denot_blocks G ins blks envG envI env) x.
  Proof.

  Lemma HasCaus_In :
    forall x cx Γ,
      HasCaus Γ x cx ->
      In x (map fst Γ).
  Proof.

  Lemma locals_restr_blocks :
    forall (blks : list block),
      Forall restr_block blks ->
      flat_map idcaus_of_locals blks = [].
  Proof.

  Lemma get_idcaus_locals :
    forall (nd : @node PSyn Prefs),
      restr_node nd ->
      map fst (get_locals (n_block nd)) = map snd (idcaus_of_locals (n_block nd)).
  Proof.

  Lemma nin_defined :
    forall (n : @node PSyn Prefs),
    forall vars blks x,
      n_block n = Blocal (Scope vars blks) ->
      In x (List.map fst (senv_of_decls (n_out n) ++ senv_of_decls vars)) ->
      List.Exists (Syn.Is_defined_in (Var x)) blks.
  Proof.

L'étape d'induction pour P_var sur les nœuds, qui utilise exp_S.
  Lemma denot_S :
    forall nd envI n,
      restr_node nd ->
      wl_node G nd ->
      wx_node nd ->
      node_causal nd ->
      P_vars (S n) envI (map fst (n_in nd)) ->
      P_vars n (FIXP _ (denot_node G nd envG envI)) (map fst (n_out nd) ++ map fst (get_locals (n_block nd))) ->
      P_vars (S n) (FIXP _ (denot_node G nd envG envI)) (map fst (n_out nd) ++ map fst (get_locals (n_block nd))).
  Proof.

  Theorem denot_n :
    forall nd envI n,
      restr_node nd ->
      wl_node G nd ->
      wx_node nd ->
      node_causal nd ->
      P_vars n envI (map fst (n_in nd)) ->
      P_vars n (FIXP _ (denot_node G nd envG envI)) (map fst (n_out nd) ++ map fst (get_locals (n_block nd))).
  Proof.

  End Node_n.


Using the well-ordered property of programs, show that all nodes receiving streams of length n outputs streams of length n.

  Theorem denot_global_n :
    forall {PSyn Prefs} (G : @global PSyn Prefs),
    forall n f nd envI,
      restr_global G ->
      wt_global G ->
      Forall node_causal (nodes G) ->
      find_node f G = Some nd ->
      P_vars n envI (map fst (n_in nd)) ->
      P_vars n (denot_global G f envI) (map fst (n_out nd) ++ map fst (get_locals (n_block nd))).
  Proof.

  End Top.

Section MOVE_ME.

Lemma inf_dom_env_of_np :
  forall l m (mp : nprod m),
    forall_nprod (@infinite _) mp ->
    infinite_dom (env_of_np l mp) l.
Proof.


End MOVE_ME.

Maintenant on passe à l'infini

Lemma infinite_P_vars :
  forall env l, infinite_dom env l <-> (forall n, P_vars n env l).
Proof.

Theorem denot_inf :
  forall (HasCausInj : forall Γ x cx, HasCaus Γ x cx -> cx = x),
  forall {PSyn Prefs} (G : @global PSyn Prefs),
    restr_global G ->
    wt_global G ->
    Forall node_causal (nodes G) ->
    forall f nd envI,
      find_node f G = Some nd ->
      infinite_dom envI (List.map fst (n_in nd)) ->
      infinite_dom (denot_global G f envI) (List.map fst (n_out nd) ++ map fst (get_locals (n_block nd))).
Proof.

Lemma sbools_ofs_inf :
  forall n (np : nprod n),
    forall_nprod (@infinite _) np ->
    infinite (sbools_of np).
Proof.

Une fois l'infinité des flots obtenue, on peut l'utiliser pour prouver l'infinité des expressions.
Lemma infinite_exp :
  forall {PSyn Prefs} (G : @global PSyn Prefs),
  forall ins envI (envG : Dprodi FI) env,
    (forall f nd envI,
        find_node f G = Some nd ->
        infinite_dom envI (List.map fst (n_in nd)) ->
        infinite_dom (envG f envI) (List.map fst (n_out nd))) ->
    infinite (bss ins envI) ->
    forall Γ, (forall x, IsVar Γ x -> infinite (denot_var ins envI env x)) ->
    forall e, restr_exp e -> wx_exp Γ e -> wl_exp G e ->
    forall_nprod (@infinite _) (denot_exp G ins e envG envI env).
Proof.

Corollary infinite_exps :
  forall {PSyn Prefs} (G : @global PSyn Prefs),
  forall ins (envG : Dprodi FI) envI env,
    (forall f nd envI,
        find_node f G = Some nd ->
        infinite_dom envI (List.map fst (n_in nd)) ->
        infinite_dom (envG f envI) (List.map fst (n_out nd))) ->
    infinite (bss ins envI) ->
    forall Γ, (forall x, IsVar Γ x -> infinite (denot_var ins envI env x)) ->
    forall es, Forall restr_exp es -> Forall (wx_exp Γ) es -> Forall (wl_exp G) es ->
    forall_nprod (@infinite _) (denot_exps G ins es envG envI env).
Proof.

Corollary infinite_expss :
  forall {PSyn Prefs} (G : @global PSyn Prefs),
  forall ins (envG : Dprodi FI) envI env,
    (forall f nd envI,
        find_node f G = Some nd ->
        infinite_dom envI (List.map fst (n_in nd)) ->
        infinite_dom (envG f envI) (List.map fst (n_out nd))) ->
    infinite (bss ins envI) ->
    forall Γ, (forall x, IsVar Γ x -> infinite (denot_var ins envI env x)) ->
    forall I (ess : list (I * list exp)) n,
    Forall (Forall restr_exp) (map snd ess) ->
    Forall (fun es => Forall (wx_exp Γ) (snd es)) ess ->
    Forall (fun es => Forall (wl_exp G) (snd es)) ess ->
    Forall (fun es => length (annots (snd es)) = n) ess ->
    forall_nprod (forall_nprod (@infinite _)) (denot_expss G ins ess n envG envI env).
Proof.

End LDENOTINF.

Module LDenotInfFun
       (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)
       (LCA : LCAUSALITY Ids Op OpAux Cks Senv Syn)
       (Lord : LORDERED Ids Op OpAux Cks Senv Syn)
       (Restr : LRESTR Ids Op OpAux Cks Senv Syn)
       (Den : SD Ids Op OpAux Cks Senv Syn Lord)
<: LDENOTINF Ids Op OpAux Cks Senv Syn Typ LCA Lord Restr Den.
  Include LDENOTINF Ids Op OpAux Cks Senv Syn Typ LCA Lord Restr Den.
End LDenotInfFun.