UP | HOME

Termination problem

How to proof a program will stop and give us an answer? This big question leads halting problem, but not the end. Even though we cannot get a result for arbitrary program, get this information for certain kind of program might still useful. However, even this simpler question is still hard. For example, the following program will stop(roughly speak).

for (int a=0; a<10; a++) {
}

What if we add a printf statement as loop body? The answer is subtle, it depends on how do we use printf, because printf in fact is a turing machine. In real life, as a creator of analysis tool, we might say let's ignore weird usage. Hence, the printf terminated, and we back to the loop structure. We know the above terminated, but how do we know? Because stop condition is bigger than initial value when a get increased. To inference on these condition, one must know how to extract information from program. There have many ways to represent a program, here I will assume just a proper abstract syntax tree and related tools existed. Then getting the information is simple:

for (int a = <init>; a < <stop>; a++)

Our checker can be like

(define (ok? init stop)
  (<= init stop))

What!? That simple? Yes, that simple, and useless. The code is useless because there has more form of loop. For example, control variable can get decreased.

for (int a = <init>; a > <stop>; a--)

To handle this also, the checker turns to

(define (ok? init stop step)
  (case step
   [(--) (>= init stop)]
   [(++) (<= init stop)]
   [else #f]))

1. Recursion

Even the step mode have infinite pattern, however. Which means this way has infinite thing to do. The point is recursion is isomorphic to iteration, hence, we rewrite program as the following.

let rec loop : int -> unit =
  fun a ->
  match a with
  | 0 -> ()
  | n -> loop (n - 1)

2. Inductive

To prove such program stop, is still hard, finding base case and induction case need manual work. We need something to restrict the possible input. For numberic, we can write:

type nat =
  | zero
  | suc nat

With type nat, the recursion be rewrote to:

let rec loop : nat -> unit =
  fun a ->
  match a with
  | zero -> ()
  | suc (n) -> loop n

The definition like type this kind, called inductive family. Turns out, we can see it's a lattice. Hence, termination problem is finding a process corresponding to a lattice, and inductive family is just a limited, full connected version. Anyway, now proving termination is finding every recursive point is an induction case, suc (n) to loop n so it's smaller on recursion then it's induction.

Date: 2022-10-02 Sun 00:00

Author: Lîm Tsú-thuàn