Library programming_machine
Require Import listaux.
Require Import Omega.
Inductive value:Type:=
|value_none: value
|value_nat: nat->value
|value_listnat: list nat -> value
.
Inductive variable:Type:=
|var_argument : nat->variable
|var_scope : nat->variable
.
Inductive unioperation:Type:=
|unioperation_len : unioperation
.
Inductive binoperation:Type:=
|binoperation_plus : binoperation
|binoperation_minus : binoperation
|binoperation_lt : binoperation
|binoperation_and : binoperation
|binoperation_get : binoperation
.
Inductive expression:Type:=
|exp_variable: variable->expression
|exp_constant: value->expression
|exp_unioperation: unioperation->expression->expression
|exp_binoperation: binoperation->expression->expression->expression
.
Inductive statement:Type:=
|statement_assignment : variable->expression ->statement
|statement_listset : variable -> expression -> expression -> statement
.
Inductive program:Type:=
|program_nil : program
|program_cons : statement -> program -> program
|program_loop : loop -> program -> program
with loop:Type:=
|loop_intro : expression -> program -> loop
.
Definition memory:= ((list value)*(list value))%type.
Definition variable_value (m:memory) (var:variable) : value :=
let (argument,scope):=m in
match var with
|var_argument n => nth n argument value_none
|var_scope n => nth n scope value_none
end.
Definition cast_value_bool (v:value):bool:=
match v with
|value_none => false
|value_nat n => match n with O=>false|S p=>true end
|value_listnat l => match l with nil=>false|cons _ _=>true end
end.
Fixpoint expression_value (m:memory) (e:expression) {struct e} : value :=
match e with
|exp_variable var => variable_value m var
|exp_constant val => val
|exp_unioperation op e =>
let v:=expression_value m e in
match op with
| unioperation_len =>
match v with
|value_none => value_none
|value_nat _ => value_none
|value_listnat l => value_nat (length l)
end
end
|exp_binoperation op e1 e2 =>
let v1:=expression_value m e1 in
let v2:=expression_value m e2 in
match op with
|binoperation_plus =>
match v1 with
|value_nat n1 =>
match v2 with
|value_nat n2 => value_nat (n1+n2)
|_ => value_none
end
|_ => value_none
end
|binoperation_minus =>
match v1 with
|value_nat n1 =>
match v2 with
|value_nat n2 => value_nat (n1-n2)
|_ => value_none
end
|_ => value_none
end
|binoperation_lt =>
match v1 with
|value_nat n1 =>
match v2 with
|value_nat n2 =>
match le_lt_dec n2 n1 with
|left _ => value_nat 0
|right _ => value_nat 1
end
|_ => value_none
end
|_ => value_none
end
|binoperation_and =>
if (andb (cast_value_bool v1) (cast_value_bool v2))
then value_nat 1
else value_nat 0
|binoperation_get =>
match v1 with
|value_listnat l =>
match v2 with
|value_nat n => value_nat (nth n l 0)
|_ => value_none
end
|_ => value_none
end
end
end.
Definition statement_execute (ST:statement) (mem:memory):memory:=
let (argument,scope):=mem in
match ST with
|statement_assignment var exp =>
match var with
|var_scope p => (argument,setandraise p scope (expression_value mem exp) value_none)
|var_argument p => (setandraise p argument (expression_value mem exp) value_none,scope)
end
|statement_listset var exppos exp =>
match var with
|var_scope p => match nth p scope value_none with
|value_none => mem
|value_nat _ => mem
|value_listnat l =>
match (expression_value mem exp) with
|value_none => mem
|value_nat vn => match expression_value mem exppos with
|value_none => mem
|value_nat pos =>
(argument,
setandraise p scope (value_listnat(setandraise pos l vn O)) value_none
)
|value_listnat _ => mem
end
|value_listnat _ => mem
end
end
|var_argument p => mem
end
end.
Fixpoint execute (P:program) (mem:memory) (limit:nat) {struct limit}: (nat*memory):=
match limit with
|O=> (O,mem)
|S plimit=>
match P with
|program_nil => (1,mem)
|program_cons ST P' =>
let m:=statement_execute ST mem
in let (n',m'):=execute P' m plimit in
(match n' with O=>0|S _=> S n' end,m')
|program_loop L P' =>
let (n,m):= loop_execute L mem plimit in
match n with
|O=>(0,m)
|S _ => let (n',m'):=(execute P' m plimit) in
(match n' with O=>0|S _=>n'+n end,m')
end
end
end
with loop_execute (L:loop) (mem:memory) (limit:nat) {struct limit}: (nat*memory):=
match limit with
|O => (O,mem)
|S plimit=>
match L with
loop_intro e P =>
let val:=expression_value mem e in
match cast_value_bool(val) with
|true => let (n1,m1):=execute P mem plimit in
match n1 with
|O=>(0,m1)
|S_=>
let (n2,m2):=loop_execute L m1 plimit in
match n2 with
|O=>(0,m2)
|S_=> (n1+n2,m2)
end
end
|false => (1,mem)
end
end
end
.
Eval compute in
execute
(program_cons
(statement_assignment (var_scope 3) (exp_constant (value_nat 5)))
program_nil
)
(nil, nil)
1000.
Theorem infinity: exists P:program, forall (mem:memory) (limit:nat),
let (n,m):=execute P mem limit in n=0.
Proof.
exists (program_loop
(loop_intro (exp_constant (value_nat 1)) program_nil) program_nil).
intros.
destruct limit. simpl. auto.
revert mem. simpl.
induction limit. simpl. auto.
intros.
simpl.
destruct (execute program_nil mem limit) as [n1 m1].
specialize(IHlimit m1).
destruct limit. simpl. destruct n1;auto.
set(X:=loop_execute _ _ _) in IHlimit|-*.
simpl in X.
destruct X.
destruct n. destruct n1;auto.
simpl in IHlimit. inversion IHlimit.
Qed.
Theorem loop_nil: forall (E:expression) (mem:memory) (limit:nat),
loop_execute (loop_intro E program_nil) mem limit=
match limit with
|O=>(0,mem)
|S _=>
match cast_value_bool(expression_value mem E) with
|true => (0,mem)
|false => (1,mem)
end
end.
Proof.
intros. induction limit. simpl. auto.
simpl.
destruct(cast_value_bool (expression_value mem E));auto.
set(X:=execute program_nil mem limit).
destruct limit. simpl in *|-*. auto.
simpl in X. unfold X. rewrite IHlimit. auto.
Qed.
Scheme program_loop_rect := Induction for program Sort Type
with loop_program_rect := Induction for loop Sort Type.
Theorem program_rect_expanded: forall (P : program -> Type)
(IHnil:P program_nil)
(IHcons: forall (ST : statement) (p : program), P p ->
P (program_cons ST p))
(IHloop:forall (Le:expression) (Lp : program) (p : program),
P p -> P Lp ->
P (program_loop (loop_intro Le Lp) p) ),
forall p : program, P p.
Proof.
intros.
set(PL:=fun L:loop=> match L with loop_intro Le Lp =>P Lp end).
assert(R:=program_loop_rect P PL). apply R;clear R.
+ exact IHnil.
+ intros. apply IHcons. exact X.
+ intros. destruct l. apply IHloop;auto.
+ simpl. auto.
Qed.