(* Temporal notions for discrete time *)

Infix "^" := Cons.(* increase clocks of states   *) 
 
  Notation SPath := (Stream S) (only parsing).CoInductive ForAllS (P : Stream S -> Prop) : Stream S -> Prop :=
      forallS :
        forall (x : Stream S) (s : S),
        P (s ^ x) -> ForAllS P x -> ForAllS P (s ^ x).CoInductive ForAllS (P : Stream S -> Prop) : Stream S -> Prop :=
      forallS :
        forall (x : Stream S) (s : S),
        P (s ^ x) -> ForAllS P x -> ForAllS P (s ^ x).Inductive ExistsS (P : Stream S -> Prop) : Stream S -> Prop :=
    | Here : forall x : Stream S, P x -> ExistsS P x
    | Further :
        forall (x : Stream S) (s : S), ExistsS P x -> ExistsS P (s ^ x).Inductive ExistsS (P : Stream S -> Prop) : Stream S -> Prop :=
    | Here : forall x : Stream S, P x -> ExistsS P x
    | Further :
        forall (x : Stream S) (s : S), ExistsS P x -> ExistsS P (s ^ x).Inductive ExistsS (P : Stream S -> Prop) : Stream S -> Prop :=
    | Here : forall x : Stream S, P x -> ExistsS P x
    | Further :
        forall (x : Stream S) (s : S), ExistsS P x -> ExistsS P (s ^ x).(* Ejecution traces *)
  
  CoInductive isTrace : Stream S -> Prop :=
    | isTraceTick :
        forall (x : Stream S) (s : S),
        inv (inc s tick) ->
        isTrace (inc s tick ^ x) -> isTrace (s ^ inc s tick ^ x)
    | isTraceDisc :
        forall (x : Stream S) (s1 s2 : S) (l : Label),
        tr s1 l s2 -> inv s2 -> isTrace (s2 ^ x) -> isTrace (s1 ^ s2 ^ x).(* Ejecution traces *)
  
  CoInductive isTrace : Stream S -> Prop :=
    | isTraceTick :
        forall (x : Stream S) (s : S),
        inv (inc s tick) ->
        isTrace (inc s tick ^ x) -> isTrace (s ^ inc s tick ^ x)
    | isTraceDisc :
        forall (x : Stream S) (s1 s2 : S) (l : Label),
        tr s1 l s2 -> inv s2 -> isTrace (s2 ^ x) -> isTrace (s1 ^ s2 ^ x).(* Ejecution traces *)
  
  CoInductive isTrace : Stream S -> Prop :=
    | isTraceTick :
        forall (x : Stream S) (s : S),
        inv (inc s tick) ->
        isTrace (inc s tick ^ x) -> isTrace (s ^ inc s tick ^ x)
    | isTraceDisc :
        forall (x : Stream S) (s1 s2 : S) (l : Label),
        tr s1 l s2 -> inv s2 -> isTrace (s2 ^ x) -> isTrace (s1 ^ s2 ^ x).Definition isTraceFrom (Sini : S) (x : Stream S) :=
    Sini = hd x /\ isTrace x.(* operator Until *)

  Inductive Until (P Q : Stream S -> Prop) : Stream S -> Prop :=
    | UntilFurther :
        forall (s : S) (x : Stream S),
        P (s ^ x) -> Until P Q x -> Until P Q (s ^ x)
    | UntilHere : forall x : Stream S, Q x -> Until P Q x.(* operator Until *)

  Inductive Until (P Q : Stream S -> Prop) : Stream S -> Prop :=
    | UntilFurther :
        forall (s : S) (x : Stream S),
        P (s ^ x) -> Until P Q x -> Until P Q (s ^ x)
    | UntilHere : forall x : Stream S, Q x -> Until P Q x.(* operator Until *)

  Inductive Until (P Q : Stream S -> Prop) : Stream S -> Prop :=
    | UntilFurther :
        forall (s : S) (x : Stream S),
        P (s ^ x) -> Until P Q x -> Until P Q (s ^ x)
    | UntilHere : forall x : Stream S, Q x -> Until P Q x.Inductive EX_Until (Sini : S) (P Q : Stream S -> Prop) : Prop :=
      ExUntil :
        forall x : Stream S,
        isTraceFrom Sini x -> Until P Q x -> EX_Until Sini P Q.Inductive EX_Until (Sini : S) (P Q : Stream S -> Prop) : Prop :=
      ExUntil :
        forall x : Stream S,
        isTraceFrom Sini x -> Until P Q x -> EX_Until Sini P Q.Definition FA_Until (Sini : S) (P Q : Stream S -> Prop) :=
    forall x : Stream S, isTraceFrom Sini x -> Until P Q x.(* Init => FA[] P *)

  Definition Always (Sini : S) (P : Stream S -> Prop) :=
    forall x : Stream S, isTraceFrom Sini x -> ForAllS P x.(* Init => FA<> P *)

  Definition Inevitable (Sini : S) (P : Stream S -> Prop) :=
    forall x : Stream S, isTraceFrom Sini x -> ExistsS P x.(* Init => EX<> P *)

  Inductive Posible (Sini : S) (P : Stream S -> Prop) : Prop :=
      posible :
        forall x : Stream S,
        isTraceFrom Sini x -> ExistsS P x -> Posible Sini P.(* Init => EX<> P *)

  Inductive Posible (Sini : S) (P : Stream S -> Prop) : Prop :=
      posible :
        forall x : Stream S,
        isTraceFrom Sini x -> ExistsS P x -> Posible Sini P.(* Init => EX[] P *)

  Inductive SafePath (Sini : S) (P : Stream S -> Prop) : Prop :=
      safePath :
        forall x : Stream S,
        isTraceFrom Sini x -> ForAllS P x -> SafePath Sini P.(* Init => EX[] P *)

  Inductive SafePath (Sini : S) (P : Stream S -> Prop) : Prop :=
      safePath :
        forall x : Stream S,
        isTraceFrom Sini x -> ForAllS P x -> SafePath Sini P.

(* Specifications: *)
Theorem Equiv1 : forall (Sini : S) (P : Stream S -> Prop), Posible Sini P <-> EX_Until Sini (fun _ : Stream S => True) P.
Theorem Equiv2 : forall (Sini : S) (P : Stream S -> Prop), Inevitable Sini P <-> FA_Until Sini (fun _ : Stream S => True) P.
Lemma ConsTrace : forall (s1 s2 : S) (x z : Stream S), isTraceFrom s2 z -> isTraceFrom s1 (s1 ^ s2 ^ x) -> isTraceFrom s1 (s1 ^ z).
Lemma notPosible : forall (P : Stream S -> Prop) (s1 : S), ~ Posible s1 P -> forall (z : Stream S) (s2 : S), isTraceFrom s1 (s1 ^ s2 ^ z) -> ~ Posible s2 P.
Theorem Equiv3 : forall (Sini : S) (P : Stream S -> Prop), Always Sini P <-> ~ Posible Sini (fun s : Stream S => ~ P s).
Lemma not_EX : forall (P : Stream S -> Prop) (x : Stream S) (s : S), ~ ExistsS P (s ^ x) -> ~ ExistsS P x.
Theorem Equiv4 : forall (Sini : S) (P : Stream S -> Prop), SafePath Sini P <-> ~ Inevitable Sini (fun s : Stream S => ~ P s).
Theorem Mon_I_S : forall (x : Stream S) (Pg Pp : Stream S -> Prop), ForAllS Pg x -> (forall s : Stream S, Pg s -> Pp s) -> ForAllS Pp x.
Theorem Conj_S : forall (x : Stream S) (P1 P2 : Stream S -> Prop), ForAllS P1 x -> ForAllS P2 x -> ForAllS (fun s : Stream S => P1 s /\ P2 s) x.
Theorem Mon_I_EX_S : forall (x : Stream S) (Pg Pp : Stream S -> Prop), ExistsS Pg x -> (forall s : Stream S, Pg s -> Pp s) -> ExistsS Pp x.
Theorem OneStep_EX : forall (x : Stream S) (P : Stream S -> Prop), ExistsS P x -> forall s : S, ExistsS P (s ^ x).