Module VelusWorld
From compcert Require Import common.Errors.
From compcert Require Import common.Events.
From compcert Require Import common.Behaviors.
From compcert Require Import common.Determinism.
From compcert Require Import common.Smallstep.
From Velus Require Import Common.
From Velus Require Import Ident.
From Velus Require Import CoindStreams.
From Velus Require Import Traces.
From Velus Require Import ObcToClight.Interface.
Import Op.
From Velus Require Import Velus.
From Velus Require Import Instantiator.
Import L.
Import CIStr.
From Coq Require Import Permutation.
From Coq Require Import String.
From Coq Require Import List.
Import List.ListNotations.
Open Scope stream_scope.
An execution environment (“World”)
Abstract Definition of World
Definition state :=
list (
ident *
Stream value).
Definition update_assoc_ident [
A] (
x :
ident) (
vs :
A) '(
y,
ys) : (
ident *
A) :=
if ident_eqb x y then (
y,
vs)
else (
y,
ys).
Definition get (
s :
state) (
x :
ident) :
option (
eventval *
state) :=
match assoc_ident x s with
|
None =>
None
|
Some (
Cons v vs) =>
Some (
eventval_of_value v,
map (
update_assoc_ident x vs)
s)
end.
CoFixpoint stream_world (
s :
state) :
world :=
World (
fun evname evargs =>
None)
(
fun chunk id ofs =>
option_map (
fun z => (
fst z,
stream_world (
snd z))) (
get s id))
(
fun chunk id ofs v =>
Some (
stream_world s)).
Lemma stream_world_deterministic:
forall P si,
sem_deterministic (
world_sem (
Asm.semantics P) (
stream_world si)).
Proof.
Lemma stream_world_behaves_deterministic:
forall P si,
forall beh1 beh2 :
program_behavior,
program_behaves (
world_sem (
Asm.semantics P) (
stream_world si))
beh1 ->
program_behaves (
world_sem (
Asm.semantics P) (
stream_world si))
beh2 ->
same_behaviors beh1 beh2.
Proof.
Properties of update_assoc_ident
Section UpdateAssocIdent.
Context {
A :
Type}.
Lemma update_assoc_ident_inv:
forall x sx (
s :
list (
ident *
A)),
map fst (
map (
update_assoc_ident x sx)
s) =
map fst s.
Proof.
induction s as [|(
y, ?)
s]; [
reflexivity|].
simpl;
rewrite IHs.
destruct (
ident_eqb x y);
reflexivity.
Qed.
Lemma map_update_assoc_ident:
forall z zs (
s :
list (
ident *
A)),
~
InMembers z s ->
map (
update_assoc_ident z zs)
s =
s.
Proof.
Lemma update_assoc_ident_not_In:
forall x xs (
ins :
list A)
s,
~
In x xs ->
map (
update_assoc_ident x s) (
combine xs ins) =
combine xs ins.
Proof.
induction xs as [|
y xs]; [
reflexivity|].
intros ins s Hni.
apply not_in_cons in Hni as [
Hne Hni].
destruct ins as [|
i ins]; [
reflexivity|].
apply (
IHxs ins s)
in Hni.
simpl.
rewrite Hni.
now apply ident_eqb_neq in Hne as ->.
Qed.
Lemma update_assoc_ident_not_eq:
forall x y vs (
s :
list (
ident *
A)),
x <>
y ->
assoc_ident (
prefix_glob x) (
map (
update_assoc_ident (
prefix_glob y)
vs)
s)
=
assoc_ident (
prefix_glob x)
s.
Proof.
End UpdateAssocIdent.
Instantiate the World for a particular program
Preliminary Definitions: consume and adv_stream_state
Definition consume (
s :
state) (
x :
ident) :
state :=
match assoc_ident (
prefix_glob x)
s with
|
None =>
s
|
Some (
Cons _
vs) =>
map (
update_assoc_ident (
prefix_glob x)
vs)
s
end.
Lemma consume_nil:
forall x,
consume []
x = [].
Proof.
Lemma consume_cons:
forall s x z zs,
NoDupMembers ((
z,
zs) ::
s) ->
consume ((
z,
zs) ::
s)
x =
(
if ident_eqb (
prefix_glob x)
z then (
z,
Streams.tl zs)
else (
z,
zs)) ::
consume s x.
Proof.
Lemma get_consume:
forall st x,
get st (
prefix_glob x) =
option_map
(
fun s => (
eventval_of_value (
Streams.hd s),
consume st x))
(
assoc_ident (
prefix_glob x)
st).
Proof.
Lemma InMembers_consume:
forall x s c,
NoDupMembers s ->
InMembers x s <->
InMembers x (
consume s c).
Proof.
Lemma NoDupMembers_consume:
forall s x,
NoDupMembers s <->
NoDupMembers (
consume s x).
Proof.
Lemma consume_commute:
forall s x y,
NoDupMembers s ->
x <>
y ->
consume (
consume s x)
y =
consume (
consume s y)
x.
Proof.
Lemma assoc_ident_not_consumed:
forall x xs,
~
In x xs ->
forall s,
assoc_ident (
prefix_glob x) (
fold_left consume xs s)
=
assoc_ident (
prefix_glob x)
s.
Proof.
Lemma fold_left_consume_cons:
forall e cs s,
~
In (
fst e) (
map prefix_glob cs) ->
NoDupMembers (
e ::
s) ->
fold_left consume cs (
e ::
s) =
e ::
fold_left consume cs s.
Proof.
Function adv_stream_state (
n :
nat) (
cs :
list ident) (
s :
state) :
state :=
match n with
| 0 =>
List.fold_left consume cs s
|
S n =>
adv_stream_state n cs
(
List.map (
fun xs => (
fst xs,
Streams.tl (
snd xs)))
s)
end.
Lemma adv_stream_state_drop:
forall cs n s,
adv_stream_state n cs s
=
fold_left consume cs (
map (
fun xs => (
fst xs,
Str_nth_tl n (
snd xs)))
s).
Proof.
induction n;
intro s;
simpl.
-
assert (
map (
fun xs => (
fst xs,
snd xs))
s =
s)
as ->
by (
induction s as [|(
x1,
x2)
s];
simpl;
auto).
reflexivity.
-
now rewrite IHn,
map_map;
simpl.
Qed.
Lemma adv_stream_state_map:
forall s cs,
NoDupMembers s ->
NoDup cs ->
forall n,
adv_stream_state n cs s
=
map (
fun xs => (
fst xs,
Str_nth_tl
(
if mem_ident (
fst xs) (
map prefix_glob cs)
then S n else n)
(
snd xs)))
s.
Proof.
Lemma consume_next:
forall x xs n si,
~
InMembers x xs ->
NoDupMembers xs ->
NoDupMembers si ->
consume (
adv_stream_state n (
idents xs)
si)
x
=
adv_stream_state n (
x ::
idents xs)
si.
Proof.
intros x xs n;
revert xs;
induction n.
-
simpl.
induction xs as [|
y xs]; [
reflexivity|].
intros s Hni Hndxs Hnds.
inv Hndxs.
apply NotInMembers_cons in Hni as (
Hni &
Hnd).
simpl.
rewrite consume_commute;
auto.
rewrite <-
IHxs;
auto.
now apply NoDupMembers_consume.
-
simpl.
intros xs si Hni Hndxs Hnds.
rewrite IHn;
auto.
apply NoDupMembers_map;
auto.
Qed.
Instantiate the world for Lustre programs
Section VelusWorld.
Context {
PSyn :
list decl ->
block ->
Prop} {
prefs :
PS.t}.
Variable (
G : @
global PSyn prefs).
Function init_stream_state (
f :
ident) (
ins :
list (
Stream value)) :
state :=
match find_node f G with
|
Some node =>
combine (
map (
Basics.compose prefix_glob fst) (@
n_in PSyn prefs node))
ins
|
None => []
end.
Definition velus_world (
f :
ident) (
ins :
list (
Stream value)) :
world
:=
stream_world (
init_stream_state f ins).
Definition nth_stream_state (
f :
ident) (
ins :
list (
Stream value))
(
n :
nat) (
cs :
list ident) :
state :=
adv_stream_state n cs (
init_stream_state f ins).
Lemma NoDupMembers_init_stream_state:
forall f ins,
NoDupMembers (
init_stream_state f ins).
Proof.
Lemma nth_stream_state_permutation:
forall f n ins xs,
NoDup xs ->
forall xs',
Permutation xs xs' ->
nth_stream_state f ins n xs =
nth_stream_state f ins n xs'.
Proof.
Lemma assoc_ident_nth_stream_state:
forall f ins n,
forall (
node: @
node PSyn prefs),
find_node f G =
Some node ->
forall xs x,
InMembers x node.(
n_in) ->
~
In x xs ->
assoc_ident (
prefix_glob x) (
nth_stream_state f ins n xs)
=
assoc_ident x (
combine (
map fst node.(
n_in)) (
List.map (
Str_nth_tl n)
ins)).
Proof.
Corollary consume_next_nth_stream_state:
forall f ins n x xs,
~
InMembers x xs ->
NoDupMembers xs ->
consume (
nth_stream_state f ins n (
idents xs))
x
=
nth_stream_state f ins n (
x ::
idents xs).
Proof.
Lemma nth_stream_state_next:
forall (
node: @
node PSyn prefs)
f ins,
find_node f G =
Some node ->
forall Len_ins:
Datatypes.length ins =
Datatypes.length node.(
n_in),
forall n,
nth_stream_state f ins n (
idents node.(
n_in))
=
nth_stream_state f ins (
S n) [].
Proof.
Lemma velus_world_forever_reactive:
forall P,
single_events P ->
forall f ins outs (
node: @
node PSyn prefs),
find_node f G =
Some node ->
forall Len_ins:
Datatypes.length ins =
Datatypes.length node.(
n_in),
forall Len_outs:
Datatypes.length outs =
Datatypes.length node.(
n_out),
forall s n,
Forever_reactive P s
(
trace_node node ins outs Len_ins Len_outs n) ->
Forever_reactive (
world_sem P (
velus_world f ins))
(
s,
stream_world (
nth_stream_state f ins n []))
(
trace_node node ins outs Len_ins Len_outs n).
Proof.
intros P SE f ins outs node FN Len_ins Len_outs.
cofix CI.
intros *
FR.
rewrite trace_node_step in FR.
apply CompCertLib.inv_forever_reactive with (1:=
SE)
in FR as (
s' &
Hstar &
FR).
rewrite trace_node_step.
apply forever_reactive_intro
with (
s2 := (
s',
stream_world (
nth_stream_state f ins (
S n) []))).
-
clear CI FR.
apply CompCertLib.single_events_star_split with (1:=
SE)
in Hstar
as (
sl &
Hload &
Hstore).
eapply star_trans with (
s2:=(
sl,
stream_world (
nth_stream_state f ins (
S n) [])));
[| |
reflexivity].
+
rewrite <-
nth_stream_state_next with (1:=
FN) (2:=
Len_ins).
assert (
Datatypes.length ins
=
Datatypes.length (
idfst (
idfst (
n_in node))))
as Hlen
by (
rewrite Len_ins;
now repeat rewrite length_idfst).
clear Hstore Len_outs outs Len_ins s'.
pose proof (
assoc_ident_nth_stream_state _
ins n _
FN)
as Hinv.
pose proof (
eq_refl node.(
n_in))
as Hn.
revert Hn Hinv Hload Hlen.
generalize node.(
n_in)
at 2 3 4 5 7
as xs.
generalize ins at 2 3 4 10
as xins.
intros xins xs Hn.
pose proof Hn as Hn'.
rewrite <- (
app_nil_l xs)
in Hn.
assert ([] =
idents [])
as Hids by reflexivity.
revert Hids Hn.
generalize ([] :
list (
ident * (
type *
Cks.clock *
ident)))
at 1 2
as xs'.
intros xs' Hids Hn.
repeat rewrite length_idfst.
setoid_rewrite Hn' at 1;
clear Hn'.
rewrite Hn.
setoid_rewrite Hids;
clear Hids.
pose proof (
NoDupMembers_n_in node)
as Hnd;
rewrite Hn in Hnd.
clear Hn.
revert SE xs' xins s sl Hnd.
clear.
intro SE.
induction xs as [|[
x [[
xty xck]
xid]]
xs].
*
intros xs' xins.
unfold load_events.
intros s s' Hin Hinv Hstar Hlen.
eapply CompCertLib.star_world_sem with (1:=
Hstar).
simpl;
rewrite app_nil_r,
map2_nil_r;
now constructor.
*
intros xs' xins s s' Hnd Hinv Hstar Hlen.
destruct xins as [|
xi xins];
inv Hlen.
simpl in Hstar.
change (
Star P s ([
load_event_of_value (
tr_Stream xi n) (
x,
xty)]
**
load_events (
tr_Streams xins n) (
idfst (
idfst xs)))
s')
in Hstar.
apply CompCertLib.single_events_star_split with (1:=
SE)
in Hstar
as (
s'' &
Hstar1 &
Hstar2).
rewrite <-
Permutation_middle,
app_comm_cons in Hnd.
eapply IHxs in Hstar2;
eauto;
clear IHxs.
2:{
clear Hstar1 Hstar2.
intros ys y Hyin Hyni;
simpl.
assert (
y <>
x)
as Hyx.
{
intro;
subst.
simpl in Hnd;
rewrite Permutation_middle in Hnd.
apply NoDupMembers_app_r in Hnd.
now inv Hnd. }
rewrite Hinv;
simpl;
auto.
rewrite assoc_ident_cons2;
auto.
}
assert (
Permutation (
idents (
xs' ++ (
x, (
xty,
xck,
xid)) ::
xs))
(
idents ((
x, (
xty,
xck,
xid)) ::
xs' ++
xs)))
as Hperm
by (
now rewrite Permutation_middle).
assert (
NoDup (
idents (
xs' ++ (
x, (
xty,
xck,
xid)) ::
xs)))
as Hnd'
by (
rewrite Hperm;
unfold idents;
now apply fst_NoDupMembers).
rewrite (
nth_stream_state_permutation _ _ _ _
Hnd' _
Hperm).
match goal with
| |-
star _ _ _ (
load_events ?
ii ?
xx) _ =>
change (
load_events ?
ii ?
xx)
with ([
load_event_of_value (
tr_Stream xi n) (
x,
xty)]
++
load_events (
tr_Streams xins n) (
idfst (
idfst xs)))
end.
rewrite app_comm_cons.
eapply star_trans
with (2:=
Hstar2) (
t1:=[
load_event_of_value (
tr_Stream xi n) (
x,
xty)]);
auto.
apply CompCertLib.star_world_sem with (1:=
Hstar1);
clear Hstar1 Hstar2.
simpl.
apply possible_trace_cons
with (
w2:=
stream_world (
nth_stream_state f ins n (
x ::
idents xs'))).
2:
now constructor.
constructor;
simpl.
rewrite get_consume.
assert (~
In x (
idents xs')).
{
unfold idents in Hnd';
apply fst_NoDupMembers in Hnd'.
rewrite <-
Permutation_middle in Hnd'.
apply NoDupMembers_cons_inv in Hnd' as (
Hnd' & _).
apply NotInMembers_app in Hnd' as (_ &
Hnd').
now rewrite fst_InMembers in Hnd'. }
rewrite Hinv;
simpl;
auto.
rewrite assoc_ident_cons1.
destruct (
Str_nth_tl n xi)
as [
v vs]
eqn:
Hxi.
unfold tr_Stream,
Str_nth;
rewrite Hxi;
simpl.
apply NoDupMembers_app_l in Hnd;
inv Hnd.
rewrite consume_next_nth_stream_state;
auto.
+
generalize (
nth_stream_state f ins (
S n) [])
as w;
intros w.
assert (
Datatypes.length outs
=
Datatypes.length (
idfst (
idfst (
idfst (
n_out node)))))
as Hlen
by (
rewrite Len_outs;
now repeat rewrite length_idfst).
revert Hstore Hlen.
generalize (
idfst (
idfst (
idfst (
n_out node))))
as xs.
clear Hload Len_ins FN s Len_outs.
intro xs;
revert xs outs sl s'.
induction xs as [|
x xs];
intros outs s s' Hstar Hout.
*
unfold store_events in *.
rewrite map2_nil_r in *.
eauto using CompCertLib.star_world_sem,
possible_trace.
*
destruct outs as [|
o outs];
inv Hout.
change (
Star P s ([
store_event_of_value (
tr_Stream o n)
x]
**
store_events (
tr_Streams outs n)
xs)
s')
in Hstar.
apply CompCertLib.single_events_star_split with (1:=
SE)
in Hstar
as (
s'' &
Hstar1 &
Hstar2).
apply IHxs in Hstar2;
auto.
apply star_trans
with (2:=
Hstar2) (
t1:=[
store_event_of_value (
tr_Stream o n)
x]);
auto.
apply CompCertLib.star_world_sem with (1:=
Hstar1).
apply possible_trace_cons with (
w2:=
stream_world w);
eauto using possible_trace,
possible_event.
-
clear CI Hstar FR s s'.
unfold tr_Streams at 1.
pose proof node.(
n_ingt0)
as Hgt0.
destruct node.(
n_in); [
inv Hgt0|
clear Hgt0].
destruct ins; [
inv Len_ins|].
inversion 1.
-
now apply (
CI _ _
FR).
Qed.
Lemma velus_world_behaves:
forall P main,
single_events P ->
forall ins outs node,
find_node main G =
Some node ->
forall Len_ins:
Datatypes.length ins =
Datatypes.length node.(
n_in),
forall Len_outs:
Datatypes.length outs =
Datatypes.length node.(
n_out),
program_behaves P
(
Reacts (
trace_node node ins outs Len_ins Len_outs 0)) ->
program_behaves (
world_sem P (
velus_world main ins))
(
Reacts (
trace_node node ins outs Len_ins Len_outs 0)).
Proof.
Lemma asm_and_velus_world_deterministic:
forall P main ins beh1 beh2,
program_behaves (
world_sem (
Asm.semantics P) (
velus_world main ins))
beh1 ->
program_behaves (
world_sem (
Asm.semantics P) (
velus_world main ins))
beh2 ->
same_behaviors beh1 beh2.
Proof.
Corollary react_in_asm_and_velus_world_never_goes_wrong:
forall P main ins t,
program_behaves (
world_sem (
Asm.semantics P) (
velus_world main ins)) (
Reacts t) ->
~
exists t',
program_behaves (
world_sem (
Asm.semantics P) (
velus_world main ins)) (
Goes_wrong t').
Proof.
End VelusWorld.