Tools to analyze (and design!) algorithms.
Program statements can be treated as "predicate transformers": If a statement S executed in the state P causes the state to change to Q, we will write {P} S {Q}. (Note that very often one would "reverse engineer" this: we know our goal Q, we suspect that we will reach it by executing S; what should the pre-condition P be? Once we answer that question, we may want to find out how to establish P, and so on.)
Basic program statements are, among others, an assignment (of the form "<variable>:=<expression>") and "the while loop" of the standard form
while Cond
do Body;
(do distinguish between "executing the loop" -- until Cond becomes false, if ever -- and "executing the Body".)
The notion of an invariant is "a predicate that remains true when the Body of the loop is executed while Cond is true". To see how executing the loop changes the state of computation, we assume that the initial state is expressed by the predicate P which evaluates to true before the loop is executed; any invariant Inv that we may want to define should be implied by P (which we will denote P => Inv). Since Inv remains invariant during execution of the Body when the condition is true, we can write {Inv and Cond} Body {Inv}. Finally, we call our invariant useful if, upon exiting the loop, we reach a state in which Q evaluates to true.
These three conditions form a "check-list" of an invariant proof
of {P}while Cond
do Body{Q}
(i) Initialization: P => Inv
(ii) Maintenance: {Inv and Cond} Body {Inv}
(iii) Final: ¬ Cond and Inv => Q
The above proves only partial correctness of the loop, as the termination question has not been considered. Often, total correctness proof is achieved by establishing a termination function t that takes integral values and is decreased by execution of the body of the loop in the state in which condition evaluates to true:
(iv) {t=t0 and Cond}B{t<t0}
A useful such function will imply the eventual falsification of the looop condition:
(v) t<0 => ¬ Cond
An example of loop invariant used in a Minimum Weight Spanning Tree iterative algorithm implemented as a loop coloring edges of a graph is:
at any point, there is a MWST containing all the blue edges and
none of the red edges.
We will see next how coloring rules implement such a loop:
while there are uncolored edges do {apply Red or Blue coloring rule}
Deterministic and non-deterministic finite automata
In the second part of the course, we will discuss abstract complexity of problems, where the main question can be couched as whether deterministic and non-deterministic models of computation yield similar time complexity. Actually, that is a fancy way of expressing the hope that problems solvable in exponential time (as a function of the input size) can also be solved in polynomial time. The conventional wisdom is no.
Just to give you a flavor of non-deterministic computation, we introduced the notion of finite automaton, where the input causes state transition, eventually leading to (or not) an accepting state. The crucial assumption is that the number of states is finite (hence the name). Depending on whether the transition function d is deterministic, ie., d: Q x S -> Q (where Q is the set of states and S is the set of inputs, both finite), or non-deterministic, represented by d: Q x S -> Powerset(Q).
("Powerset(Q)" stands for the set of all subsets of Q and represents the non-deterministic choice of transition "we can move to q1, or q2, or ...")
Finite automaton is often represented by its state diagram which is a directed graph where each vertex represents a state, and an arc <p,q> is labeled a iff there is a transition from p to q upon reading input a. In a deterministic automaton, there is a unique arc labeled by a given input character from each state. In a non-deterministic automaton, there may be several such arcs, leading to the subset of states indicated by the transition function.
The set of input strings causing a transition from the initial state to an accepting state is called the language recognized by the automaton. For a no-deterministic automaton, it is required that at least one such transition is possible to accepted the input string. It is somewhat surprising that the set of languages recognized by both types of automata is the same (and called regular languages). This and similar models have profound significance for compilation of programming languages.