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.

Lemma HaltDecider_cons_spec(f g:HaltDecider):
HaltDecider_WF f ->
HaltDecider_WF g ->
HaltDecider_WF (HaltDecider_cons f g).