再帰の基本
algorithmfoundationundergraduatelecture
data/lecture/information/algorithm/foundation/computational-complexity-basics.lecture.n.md
1導入
この講義では、再帰算法を、同種の小さい入力に対する結果から元の入力に対する結果を構成する方法として説明する。設計に必要な基底条件、再帰段階、停止尺度を定義し、停止性と正当性を区別して証明する。さらに、呼出しスタックによる実行過程と計算量を解説する。
2再帰算法の構成要素
再帰算法とは、ある入力に対する計算の途中で、同一の算法を別の入力に適用する算法である。この適用を再帰呼出しという。
基底条件とは、再帰呼出しを実行せずに結果を直接返す条件である。再帰段階とは、基底条件を満たさない入力を小さい同種の入力へ変換し、その再帰呼出しの結果から元の結果を構成する規則である。
停止尺度とは、各入力に非負整数を対応させ、各再帰呼出しで厳密に減少する量である。この量は再帰呼出しが無限に継続しないことを証明するために使用する。
3階乗の再帰的定義
n\in\mathbb{Z}_{\geq 0} に対する階乗を次で定義する。
0!=1,\qquad n!=n(n-1)!\quad(n\geq 1).
関数 \operatorname{fact}(n) の仕様を「n\in\mathbb{Z}_{\geq0} を受け取り、n! を返す」とする。この仕様に対する再帰算法は次のように記述できる。
fact(n):
if n = 0:
return 1
return n * fact(n - 1)
n=0 が基底条件であり、n\geq1 における n\operatorname{fact}(n-1) の計算が再帰段階である。停止尺度には \mu(n)=n を採用する。
4停止性
n=0 なら再帰呼出しを実行せずに終了する。n\geq1 なら、再帰呼出しの入力は n-1 であり、
0\leq\mu(n-1)=n-1<n=\mu(n)
が成立する。したがって、非負整数である停止尺度は各再帰呼出しで厳密に減少する。非負整数の厳密減少列は無限に継続しないため、有限回の呼出しの後に n=0 へ到達する。よって \operatorname{fact}(n) はすべての n\in\mathbb{Z}_{\geq0} で停止する。
5正当性
停止性は「計算が終了する」ことを保証するが、「返値が仕様を満たす」ことは別に証明する必要がある。n に関する数学的帰納法を用いる。
- 基底段階:n=0 では、算法は 1 を返す。0!=1 であるため、返値は正しい。
- 帰納段階:n\geq1 とし、\operatorname{fact}(n-1)=(n-1)! を帰納法の仮定とする。算法の返値は n\operatorname{fact}(n-1) であるから、仮定と階乗の定義により
n\operatorname{fact}(n-1)=n(n-1)!=n!
となる。
したがって、すべての n\in\mathbb{Z}_{\geq0} について \operatorname{fact}(n)=n! が成立する。基底条件と再帰段階は、それぞれ帰納法の基底段階と帰納段階に対応する。
6呼出しスタック
呼出しフレームとは、一回の関数呼出しに必要な引数、局所変数、復帰位置などを保持する記録である。呼出しスタックとは、未完了の呼出しフレームを後入先出しの順序で保持するスタックである。
\operatorname{fact}(3) の実行では、\operatorname{fact}(3)、\operatorname{fact}(2)、\operatorname{fact}(1)、\operatorname{fact}(0) の順にフレームが積まれる。基底条件が 1 を返した後、逆順に復帰して 1、2、6 を構成する。したがって、再帰呼出しの深さは同時に保持するフレーム数を決定する。
7計算量
ここでは、各算術演算の費用を \Theta(1) とする単位費用 RAM モデルを採用し、算術演算回数を評価する。任意精度整数のビット演算量を評価する場合、n! の桁数と乗算算法の費用を別途考慮する必要がある。
このモデルでは、\operatorname{fact}(n) は n>0 の各入力について一回の再帰呼出しと定数時間の乗算を実行する。時間計算量 T(n) は
T(0)=\Theta(1),\qquad T(n)=T(n-1)+\Theta(1)
を満たすため、T(n)=\Theta(n) である。最大の呼出深度は n+1 であり、各フレームが定数量の領域を使用するため、呼出しスタックの補助空間計算量は \Theta(n) である。
8設計と検証の手順
- 入力と返値の仕様を明示する。
- 再帰呼出しを要しない基底条件を定める。
- 小さい同種の入力から結果を構成する再帰段階を定める。
- 各再帰呼出しで厳密に減少する停止尺度を提示し、停止性を証明する。
- 帰納法などにより正当性を証明する。
- 再帰呼出しの回数と最大深度から時間・空間計算量を評価する。
data/lecture/information/algorithm/foundation/sorting-basics.lecture.n.md
Recursion Basics
data/lecture/information/algorithm/foundation/computational-complexity-basics.lecture.n.md
1Introduction
This lecture explains a recursive algorithm as a method that constructs the result for an input from the result for a smaller input of the same kind. It defines the base case, recursive step, and termination measure needed for the design, and proves termination and correctness separately. It also explains the execution process through the call stack and analyzes its complexity.
2Components of a Recursive Algorithm
A recursive algorithm is an algorithm that applies itself to another input during a computation. Such an application is a recursive call.
A base case is a condition under which the algorithm returns a result directly without making a recursive call. A recursive step transforms an input that does not satisfy a base case into a smaller input of the same kind and constructs the original result from the result of the recursive call.
A termination measure assigns a nonnegative integer to every input and strictly decreases in every recursive call. It is used to prove that recursive calls cannot continue indefinitely.
3Recursive Definition of Factorial
For n\in\mathbb{Z}_{\geq0}, factorial is defined by
0!=1,\qquad n!=n(n-1)!\quad(n\geq1).
The specification of \operatorname{fact}(n) is: given n\in\mathbb{Z}_{\geq0}, return n!. A recursive algorithm satisfying this specification is
fact(n):
if n = 0:
return 1
return n * fact(n - 1)
The condition n=0 is the base case, and the computation of n\operatorname{fact}(n-1) for n\geq1 is the recursive step. We choose \mu(n)=n as the termination measure.
4Termination
If n=0, the algorithm terminates without a recursive call. If n\geq1, the recursive call receives n-1, and
0\leq\mu(n-1)=n-1<n=\mu(n).
Thus, the nonnegative-integer termination measure strictly decreases in every recursive call. A strictly decreasing sequence of nonnegative integers cannot be infinite, so the computation reaches n=0 after finitely many calls. Therefore, \operatorname{fact}(n) terminates for every n\in\mathbb{Z}_{\geq0}.
5Correctness
Termination guarantees that the computation ends, but it does not by itself guarantee that the return value satisfies the specification. We prove the latter claim by induction on n.
- Base case: for n=0, the algorithm returns 1. Since 0!=1, the return value is correct.
- Inductive step: let n\geq1 and assume \operatorname{fact}(n-1)=(n-1)!. The algorithm returns n\operatorname{fact}(n-1). By the inductive hypothesis and the definition of factorial,
n\operatorname{fact}(n-1)=n(n-1)!=n!.
Therefore, \operatorname{fact}(n)=n! for every n\in\mathbb{Z}_{\geq0}. The base case and recursive step correspond respectively to the base case and inductive step of the proof.
6Call Stack
A stack frame is a record containing the arguments, local variables, return location, and other information required by one function call. The call stack stores the stack frames of unfinished calls in last-in, first-out order.
During the evaluation of \operatorname{fact}(3), frames for \operatorname{fact}(3), \operatorname{fact}(2), \operatorname{fact}(1), and \operatorname{fact}(0) are pushed in that order. After the base case returns 1, the calls return in reverse order and construct 1, 2, and 6. Consequently, the recursive-call depth determines the number of frames stored simultaneously.
7Complexity
We use the unit-cost RAM model, in which every arithmetic operation costs \Theta(1), and count arithmetic operations. An analysis of arbitrary-precision bit complexity must instead account for the number of bits in n! and the cost of the multiplication algorithm.
In this model, for each input with n>0, \operatorname{fact}(n) makes one recursive call and performs a constant-time multiplication. Its time complexity satisfies
T(0)=\Theta(1),\qquad T(n)=T(n-1)+\Theta(1),
so T(n)=\Theta(n). The maximum call depth is n+1. Because each frame uses a constant amount of storage, the auxiliary-space complexity of the call stack is \Theta(n).
8Design and Verification Procedure
- State the specification of the input and return value.
- Define a base case that requires no recursive call.
- Define a recursive step that constructs the result from a smaller input of the same kind.
- Provide a termination measure that strictly decreases in every recursive call, and prove termination.
- Prove correctness, for example by induction.
- Evaluate time and space complexity from the number of recursive calls and the maximum call depth.
data/lecture/information/algorithm/foundation/sorting-basics.lecture.n.md