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.
(**)
(**)
(**)
Local Lemma split_no_loop_latter'' :
forall (ss : sseq) (i j k : nat),
no_loop' ss i (S k) (S j) <->
ss.[(i + (S k))] <> ss.[i] /\
no_loop' ss (S i) k j.
Local Lemma split_no_loop_latter' : forall (ss : sseq) (j i : nat),
no_loop ss i (S j) -> no_loop ss (S i) j.

Lemma split_loop_free : forall  (ss : sseq) (T : trans) (i j : nat),
loop_free T ss 0 (i+j) ->
loop_free T ss 0 i /\ loop_free T ss i j.