Require Export ZArith.
(*Require Export Bmc.Logic.*)
Open Scope nat_scope.
Set Implicit Arguments.
(**)
Definition state : Type := Z.
Definition sseq : Type := nat -> state.
Definition nth (n : nat) (ss : sseq) : state :=
ss n.
Notation "ss .[ n ] " := (nth n ss)
(at level 0).
Definition skipn (n : nat) (ss : sseq) : sseq :=
fun i => ss (i+n).
(**)
Definition trans : Type := state -> state -> Prop.
Definition prop : Type := state -> Prop.
Fixpoint path (T : trans) (ss : sseq) (o len : nat) : Prop :=
match len with
| O => True
| S len' => path T ss o len' /\ T ss.[o+len'] ss.[o+len]
end.
Fixpoint invariance (P : prop) (ss : sseq) (len : nat) : Prop :=
match len with
| O => P ss.[0]
| S len' => invariance P ss len' /\ P ss.[len]
end.
Fixpoint no_loop' (ss : sseq) (o m n : nat) : Prop :=
match n with
| O => ss.[o+m] <> ss.[o]
| S n' => no_loop' ss o m n' /\ ss.[o+m] <> ss.[o+n]
end.
Fixpoint no_loop (ss : sseq) (o k : nat) : Prop :=
match k with
| O => True
| S k' => no_loop' ss o k k' /\ no_loop ss o k'
end.
Definition loop (ss : sseq) (o m n : nat) : Prop :=
exists i, i <= n /\ ss.[o+m] = ss.[o+i].
Definition loop_free (T : trans) (ss : sseq) (o k: nat) : Prop :=
path T ss o k /\ no_loop ss o k.
Definition lasso_fwd (I : prop) (T : trans) (k : nat) : Prop :=
forall ss : sseq,
I ss.[0] -> ~loop_free T ss 0 k.
Definition lasso_bwd (T : trans) (P : prop) (k: nat) : Prop :=
forall ss : sseq,
loop_free T ss 0 k -> P ss.[k].
Definition lasso_bwd' (T : trans) (P : prop) (k: nat) : Prop :=
forall ss : sseq,
~P ss.[k] -> ~loop_free T ss 0 k.
Definition prop_nth_init (I : prop) (T : trans) (P : prop) (n : nat) : Prop :=
forall ss : sseq,
I ss.[0] -> path T ss 0 n -> P ss.[n].
Fixpoint safety_nth (I : prop) (T : trans) (P : prop) (n : nat) : Prop :=
match n with
| O => prop_nth_init I T P n
| S n' => safety_nth I T P n' /\ prop_nth_init I T P n
end.
Definition prop_nth_init_lf  (I : prop) (T : trans) (P : prop) (n : nat) : Prop :=
forall ss : sseq,
I ss.[0] -> loop_free T ss 0 n -> P ss.[n].
Fixpoint safety_nth_offset (P : prop) (ss : sseq) (o n: nat) : Prop :=
match n with
| O => True
| S n' => safety_nth_offset P ss o n' /\ P ss.[o+n']
end.
(**)

Lemma bounded_safety :
forall (i k : nat) (I : prop) (T : trans) (P : prop),
i <= k -> safety_nth I T P k -> prop_nth_init I T P i.