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:=Dneg; out:=Σ2 |}::
{| nxt:=St0; dir:=Dneg; out:=Σ3 |}::
{| nxt:=St0; dir:=Dpos; out:=Σ0 |}::
{| nxt:=St0; dir:=Dpos; out:=Σ1 |}::
{| nxt:=St0; dir:=Dpos; out:=Σ2 |}::
{| nxt:=St0; dir:=Dpos; out:=Σ3 |}::
{| nxt:=St1; dir:=Dneg; out:=Σ0 |}::
{| nxt:=St1; dir:=Dneg; out:=Σ1 |}::
{| nxt:=St1; dir:=Dneg; out:=Σ2 |}::
{| nxt:=St1; dir:=Dneg; out:=Σ3 |}::
{| nxt:=St1; dir:=Dpos; out:=Σ0 |}::
{| nxt:=St1; dir:=Dpos; out:=Σ1 |}::
{| nxt:=St1; dir:=Dpos; out:=Σ2 |}::
{| nxt:=St1; dir:=Dpos; out:=Σ3 |}::
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 St0 Σ2) (tm St0 Σ3)
(tm St1 Σ0) (tm St1 Σ1) (tm St1 Σ2) (tm St1 Σ3).
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.