Section TNF.
Fixpoint list_nat_sum(ls:list nat):nat :=
match ls with
| nil => O
| h::t => h+(list_nat_sum t)
end.
Definition isHaltTrans(tr:option (Trans Σ)):nat :=
match tr with
| Some _ => 0
| None => 1
end.
Definition CountHaltTrans tm :=
list_nat_sum (map (fun s=>list_nat_sum (map (fun i => isHaltTrans (tm s i)) Σ_list)) St_list).
Ltac destruct_and :=
match goal with
| H:?A/\?B |- _ => destruct H
end.
Record TNF_Node := {
TNF_tm: TM Σ;
TNF_cnt: nat;
TNF_ptr: St;
}.
Definition TNF_Node_WF(x:TNF_Node):Prop :=
let (tm,cnt,ptr) := x in
cnt = CountHaltTrans tm /\
cnt <> 0 /\
UnusedState_ptr tm ptr.
Definition Trans_list:=
{| nxt:=St0; dir:=Dneg; out:=Σ0 |}::
{| nxt:=St0; dir:=Dneg; out:=Σ1 |}::
{| nxt:=St0; dir:=Dpos; out:=Σ0 |}::
{| nxt:=St0; dir:=Dpos; out:=Σ1 |}::
{| nxt:=St1; dir:=Dneg; out:=Σ0 |}::
{| nxt:=St1; dir:=Dneg; out:=Σ1 |}::
{| nxt:=St1; dir:=Dpos; out:=Σ0 |}::
{| nxt:=St1; dir:=Dpos; out:=Σ1 |}::
{| nxt:=St2; dir:=Dneg; out:=Σ0 |}::
{| nxt:=St2; dir:=Dneg; out:=Σ1 |}::
{| nxt:=St2; dir:=Dpos; out:=Σ0 |}::
{| nxt:=St2; dir:=Dpos; out:=Σ1 |}::
{| nxt:=St3; dir:=Dneg; out:=Σ0 |}::
{| nxt:=St3; dir:=Dneg; out:=Σ1 |}::
{| nxt:=St3; dir:=Dpos; out:=Σ0 |}::
{| nxt:=St3; dir:=Dpos; out:=Σ1 |}::
{| nxt:=St4; dir:=Dneg; out:=Σ0 |}::
{| nxt:=St4; dir:=Dneg; out:=Σ1 |}::
{| nxt:=St4; dir:=Dpos; out:=Σ0 |}::
{| nxt:=St4; dir:=Dpos; out:=Σ1 |}::
nil.
Definition St_leb s1 s2 :=
Nat.leb (St_to_nat s2) (St_to_nat s1).
Definition TM_simplify tm :=
makeTM
(tm St0 Σ0) (tm St0 Σ1)
(tm St1 Σ0) (tm St1 Σ1)
(tm St2 Σ0) (tm St2 Σ1)
(tm St3 Σ0) (tm St3 Σ1)
(tm St4 Σ0) (tm St4 Σ1).
Definition TM_upd' tm s i tr :=
TM_simplify (TM_upd Σ Σ_eqb tm s i tr).
Definition TNF_Node_upd(x:TNF_Node) s i tr:=
let (tm,cnt,ptr):=x in
{|
TNF_tm:=TM_upd' tm s i (Some tr);
TNF_cnt:=Nat.pred cnt;
TNF_ptr:=(if St_eqb ptr (nxt _ tr) then (St_suc ptr) else ptr)
|}.
Definition TNF_Node_expand(x:TNF_Node) s i:=
let (tm,cnt,ptr):=x in
if Nat.eqb cnt 1 then nil else
map (TNF_Node_upd x s i)
(filter (fun tr => St_leb ptr (nxt _ tr)) Trans_list).
Hypothesis BB:nat.
Ltac nat_eq_dec s1 s2 :=
eq_dec nat_eqb_spec Nat.eqb s1 s2.
Ltac St_le_dec s1 s2 :=
eq_dec St_leb_spec St_leb s1 s2.
Definition TNF_Node_HTUB(x:TNF_Node):Prop :=
let (tm,_,_):=x in
HaltTimeUpperBound _ BB (InitES Σ Σ0) (LE _ tm).
Inductive HaltDecideResult :=
| Result_Halt(s:St)(i:Σ)
| Result_NonHalt
| Result_Unknown
.
Definition HaltDecider := TM Σ -> HaltDecideResult.
Definition HaltDecider_WF(f:HaltDecider) :=
forall tm,
match f tm with
| Result_Halt s i => exists n t, HaltsAt _ tm n (InitES Σ Σ0) /\ Steps _ tm n (InitES Σ Σ0) (s,t) /\ t Z0 = i /\ n<=BB
| Result_NonHalt => ~HaltsFromInit Σ Σ0 tm
| Result_Unknown => True
end.
Definition HaltDecider_cons(f g:HaltDecider):HaltDecider :=
fun tm =>
let res := f tm in
match res with
| Result_Unknown => g tm
| _ => res
end.
Definition HaltDecider_nil:HaltDecider := fun _ => Result_Unknown.
Fixpoint HaltDecider_list(f:list HaltDecider):HaltDecider :=
match f with
| nil => HaltDecider_nil
| h::t => HaltDecider_cons h (HaltDecider_list t)
end.
Definition SearchQueue :=
((list TNF_Node)*(list TNF_Node))%type.
Definition SearchQueue_WF (q:SearchQueue) x0:=
let (q1,q2):=q in
(forall x, In x (q1++q2) -> TNF_Node_WF x) /\
((forall x, In x (q1++q2) -> TNF_Node_HTUB x) -> TNF_Node_HTUB x0).
Definition SearchQueue_upd(q:SearchQueue)(f:HaltDecider) :=
match q with
| (h::t,q2) =>
match f (TNF_tm h) with
| Result_Halt s i => ((TNF_Node_expand h s i)++t,q2)
| Result_NonHalt => (t,q2)
| Result_Unknown => (t,h::q2)
end
| _ => q
end.
Definition SearchQueue_upd_bfs(q:SearchQueue)(f:HaltDecider) :=
match q with
| (h::t,q2) =>
match f (TNF_tm h) with
| Result_Halt s i => (t,(TNF_Node_expand h s i)++q2)
| Result_NonHalt => (t,q2)
| Result_Unknown => (t,h::q2)
end
| _ => q
end.
Definition SearchQueue_reset(q:SearchQueue):SearchQueue :=
match q with
| (q1,q2) => (q1++q2,nil)
end.
Definition SearchQueue_init(x0:TNF_Node):SearchQueue := (x0::nil,nil).
Definition SearchQueue_init_spec(x0:TNF_Node):
TNF_Node_WF x0 ->
SearchQueue_WF (SearchQueue_init x0) x0.
Fixpoint SearchQueue_upds q f (n:nat) :=
match (fst q) with
| nil => q
| _ =>
match n with
| O => SearchQueue_upd q f
| S n0 => SearchQueue_upds (SearchQueue_upds q f n0) f n0
end
end.
Fixpoint SearchQueue_upds_bfs q f (n:nat) :=
match n with
| O => q
| S n0 => SearchQueue_upd_bfs (SearchQueue_upds_bfs q f n0) f
end.
Definition SearchQueue_bfs q f :=
SearchQueue_reset (SearchQueue_upds_bfs q f (length (fst q))).

Lemma SearchQueue_bfs_spec q x0 f:
SearchQueue_WF q x0 ->
HaltDecider_WF f ->
SearchQueue_WF (SearchQueue_bfs q f) x0.