Two questions haunt every serious program. Is it fast enough? — will it still finish when the input is a million times bigger? And is it right? — not "did it pass the tests", but is it guaranteed to produce the correct answer on every input the specification allows? This master's-level course takes both questions to graduate depth, and shows that they are two faces of the same discipline: reasoning rigorously about what a computation does and what it costs.
The first half — complexity analysis — builds the machinery for measuring cost: asymptotics and recurrences, amortised and probabilistic analysis, the complexity classes P, NP, the polynomial hierarchy and PSPACE, NP-completeness and the art of reductions, and — when a problem is provably intractable — approximation, parameterised and exact-exponential algorithms, and matching lower bounds. The second half — correctness — builds the machinery for proof: Hoare logic and loop invariants, weakest preconditions and the guarded-command calculus, termination and total correctness, type soundness and the Curry–Howard correspondence, separation logic, and the automatic verification of temporal properties by model checking.
It assumes an undergraduate grounding in