From Coq Require Import Classical Lia Arith.
Require Import semantics.
Connections with a simple form of denotational semantics.
Inductive result :
Type :=
|
Bottom:
result
|
Error:
result
|
Result:
term ->
result.
Definition step (
rec:
term ->
result) (
a:
term) :
result :=
match a with
|
Var v =>
Error
|
Const n =>
Result (
Const n)
|
Fun v b =>
Result (
Fun v b)
|
App b c =>
match rec b with
|
Bottom =>
Bottom
|
Error =>
Error
|
Result vb =>
match rec c with
|
Bottom =>
Bottom
|
Error =>
Error
|
Result vc =>
match vb with
|
Fun x d =>
rec (
subst x vc d)
|
_ =>
Error
end
end
end
end.
Fixpoint compute (
n:
nat) :
term ->
result :=
match n with
|
O => (
fun a =>
Bottom)
|
S n1 =>
step (
compute n1)
end.
Definition evaluates (
a:
term) (
r:
result) :
Prop :=
exists n,
forall m,
n <=
m ->
compute m a =
r.
Lemma evaluates_unique:
forall a r1 r2,
evaluates a r1 ->
evaluates a r2 ->
r1 =
r2.
Proof.
intros a r1 r2 [
n1 C1] [
n2 C2].
rewrite <- (
C1 (
max n1 n2))
by lia.
rewrite <- (
C2 (
max n1 n2))
by lia.
auto.
Qed.
Inductive result_le:
result ->
result ->
Prop :=
|
result_le_refl:
forall r,
result_le r r
|
result_le_bot:
forall r,
result_le Bottom r.
Lemma step_increasing:
forall (
rec1 rec2:
term ->
result),
(
forall a,
result_le (
rec1 a) (
rec2 a)) ->
(
forall a,
result_le (
step rec1 a) (
step rec2 a)).
Proof.
intros. destruct a; simpl; try constructor.
generalize (H a1); intro; inversion H0; try constructor.
destruct (rec1 a1); try constructor.
generalize (H a2); intro; inversion H2; try constructor.
destruct (rec1 a2); try constructor.
destruct t; auto || constructor.
Qed.
Lemma compute_increasing:
forall n1 n2 a,
n1 <=
n2 ->
result_le (
compute n1 a) (
compute n2 a).
Proof.
induction n1;
simpl;
intros.
constructor.
destruct n2.
lia.
simpl.
apply step_increasing.
intros.
apply IHn1.
lia.
Qed.
Lemma evaluates_total:
forall a,
exists r,
evaluates a r.
Proof.
intro.
elim (
classic (
forall n,
compute n a =
Bottom));
intros.
-
exists Bottom, 0;
intros;
auto.
-
apply not_all_ex_not in H.
destruct H as [
n EQ].
exists (
compute n a),
n;
intros.
generalize (
compute_increasing _ _ a H);
intro.
inversion H0.
auto.
congruence.
Qed.
Lemma evaluates_limsup:
forall a r n,
evaluates a r ->
result_le (
compute n a)
r.
Proof.
intros a r n [
m COMP].
assert (
n <=
m \/
m <=
n)
by lia.
elim H;
intros.
rewrite <- (
COMP m)
by lia.
apply compute_increasing;
lia.
rewrite <- (
COMP n)
by auto.
constructor.
Qed.
Lemma evaluates_compute_either:
forall a r n,
evaluates a r ->
compute n a =
Bottom \/
compute n a =
r.
Proof.
Lemma compute_converges:
forall n a v,
compute n a =
Result v ->
evaluates a (
Result v).
Proof.
intros.
exists n.
intros.
generalize (
compute_increasing n m a H0);
rewrite H;
intro.
inversion H1;
auto.
Qed.
Lemma compute_gets_stuck:
forall n a,
compute n a =
Error ->
evaluates a Error.
Proof.
intros.
exists n.
intros.
generalize (
compute_increasing n m a H0);
rewrite H;
intro.
inversion H1;
auto.
Qed.
Lemma compute_diverges:
forall a,
evaluates a Bottom ->
forall n,
compute n a =
Bottom.
Proof.
Lemma converges_eval:
forall a v,
evaluates a (
Result v) ->
eval a v.
Proof.
assert (
forall n a v,
compute n a =
Result v ->
eval a v).
{
induction n;
intros until v;
destruct a;
simpl;
try congruence;
intro.
-
inversion H.
constructor.
-
inversion H.
constructor.
-
destruct (
compute n a1)
eqn:
COMP1;
try congruence.
destruct (
compute n a2)
eqn:
COMP2;
try congruence.
destruct t;
try congruence.
econstructor;
eauto.
}
intros a v [
n COMP].
apply H with n.
apply COMP.
lia.
Qed.
Lemma eval_converges:
forall a v,
eval a v ->
evaluates a (
Result v).
Proof.
induction 1.
-
apply compute_converges with 1.
reflexivity.
-
apply compute_converges with 1.
reflexivity.
-
destruct IHeval1 as [
n1 A1].
destruct IHeval2 as [
n2 A2].
destruct IHeval3 as [
n3 A3].
apply compute_converges with (
S (
max n1 (
max n2 n3))).
simpl.
rewrite A1 by lia.
rewrite A2 by lia.
apply A3;
lia.
Qed.
Lemma diverges_evalinf:
forall a,
evaluates a Bottom ->
evalinf a.
Proof.
cofix COINDHYP;
intros.
generalize (
compute_diverges a H);
intro.
destruct a;
try (
generalize (
H0 1);
simpl;
congruence).
destruct (
evaluates_total a1)
as [
r1 EVAL1].
elim EVAL1;
intros n1 COMP1.
destruct r1.
-
apply evalinf_app_l.
auto.
-
generalize (
H0 (
S n1));
simpl.
rewrite COMP1.
congruence.
auto.
-
destruct (
evaluates_total a2)
as [
r2 EVAL2].
elim EVAL2;
intros n2 COMP2.
destruct r2.
+
apply evalinf_app_r with t.
apply converges_eval;
auto.
auto.
+
generalize (
H0 (
S (
max n1 n2)));
simpl.
rewrite COMP1 by lia.
rewrite COMP2 by lia.
congruence.
+
assert (
exists x,
exists b,
t =
Fun x b).
{
generalize (
H0 (
S (
max n1 n2)));
simpl.
rewrite COMP1 by lia.
rewrite COMP2 by lia.
destruct t;
intros;
try congruence.
exists v;
exists t;
auto.
}
destruct H1 as [
x [
b EQ]].
subst t.
apply evalinf_app_f with x b t0.
apply converges_eval;
auto.
apply converges_eval;
auto.
apply COINDHYP.
exists (
max n1 n2);
intros.
generalize (
H0 (
S m)).
simpl.
rewrite COMP1 by lia.
rewrite COMP2 by lia.
auto.
Qed.
Lemma evalinf_diverges:
forall a,
evalinf a ->
evaluates a Bottom.
Proof.