Углубление · Логика Хоара ← Глава II
Углубление к главе II

Логика Хоара: доказательство программ.

Как доказать, что программа верна, не запуская её на всех входах? Логика Хоара отвечает тройкой {P} C {Q}: если до выполнения истинно предусловие P и команда C завершилась, после истинно постусловие Q. Сердце метода — инвариант цикла. Это прямой мост от логики к корректности.

{P} C {Q}тройка
инвариантсердце цикла
→ типымост к VII
HOARE{P} C {Q} пред · пост⊢ {P} C {Q} до — программа — после
№ 00Тройка

{P} C {Q} — контракт выполнения

Запись $\{P\}\ C\ \{Q\}$ читается так: если перед командой $C$ истинно предусловие $P$ и $C$ завершается, то после неё истинно постусловие $Q$. Это контракт: что требуется на входе и что гарантируется на выходе.

$\{\,x \ge 0\,\}\quad y := \sqrt{x}\quad\{\,y\cdot y = x \wedge y \ge 0\,\}$

Доказательство корректности — это вывод: показать, что из $P$ через шаги $C$ логически получается $Q$, по правилам для каждой конструкции языка.

Доказать программу — значит вывести её постусловие из предусловия. — идея Хоара
⊢
Правила вывода

По одной конструкции за раз

У каждой конструкции — своё правило. Присваивание, последовательность, ветвление, цикл. Собирая их, доказывают всю программу.

:=Присваивание

$\{Q[x:=e]\}\ x:=e\ \{Q\}$ — чтобы после было $Q$, до должно быть $Q$ с подстановкой нового значения. Работаем «справа налево».

;Последовательность

Из $\{P\}\,C_1\,\{R\}$ и $\{R\}\,C_2\,\{Q\}$ следует $\{P\}\,C_1;C_2\,\{Q\}$ — промежуточное условие $R$ склеивает шаги.

⌥Ветвление

В каждой ветви if к предусловию добавляется условие (или его отрицание); обе ветви должны привести к одному $Q$.

↺Цикл

$\dfrac{\{I\wedge b\}\ C\ \{I\}}{\{I\}\ \textbf{while}\ b\ \{I\wedge\neg b\}}$ — если тело сохраняет инвариант $I$, то после цикла верны $I$ и отрицание условия.

↺
Инвариант цикла

То, что верно на каждом витке

Инвариант — свойство, истинное перед циклом и сохраняемое каждой итерацией. Он — сердце доказательства: связывает «до», «во время» и «после» цикла одной формулой.

INVARIANSI сохраняется вход: Iвыход: I ∧ ¬b старт · I телохранит I I ∧ ¬bпосле пока b — снова ¬b — выход
Инвариант I держится на входе и после каждой итерации. На выходе верны I и ¬b — из них выводят постусловие.

Пример: сумма чисел от 0 до n−1. Инвариант — «sum равна сумме первых i чисел». Он верен в начале (i=0, sum=0), сохраняется телом и на выходе (i=n) даёт нужный результат:

# инвариант I: sum = 0 + 1 + ... + (i-1)
i = 0; sum = 0
while i < n do # I сохраняется
  sum = sum + i
  i = i + 1
end
# I ∧ ¬(i<n) ⟹ sum = 0+...+(n-1)
№ 04Мост к типам

От троек — к типам-теоремам

Логика Хоара доказывает программу снаружи: пишем код, затем доказываем тройку. Соответствие Карри-Ховарда из главы VII идёт дальше — встраивает утверждение прямо в тип, и тогда доказательством служит сама программа, а проверку ведёт компилятор. Это два пути к одному: программа, корректность которой установлена не испытанием, а выводом.

Обе идеи — продолжение главы о логике: корректность есть теорема, а теорему доказывают.

Корректность — это теорема; разница лишь в том, доказываем мы её о программе или самим типом. — линия курса
№ 05Связи

Куда дальше