Перейти к содержанию

Логика Хоара

Материал из Мегавики — свободной энциклопедии

Логика Хоара (англ. Hoare logic, также Floyd—Hoare logic, или Hoare rules) — формальная система с набором логических правил, предназначенных для доказательства корректности[англ.] компьютерных программ. Была предложена в 1969 году английским учёным в области информатики и математической логики Хоаром, позже развита самим Хоаром и другими исследователями.[1] Первоначальная идея была предложена в работе Флойда, который опубликовал похожую систему[2] в применении к блок-схемам (англ. flowchart).

Тройки Хоара[править]

Основной характеристикой логики Хоара является тройка Хоара (англ. Hoare triple). Тройка описывает, как выполнение фрагмента кода изменяет состояние вычисления. Тройка Хоара имеет следующий вид:

{P}C{Q}

где P и Q являются утверждениями (англ. assertions), а C — командой. P называется предусловием (антецедент), а Q — постусловием (консеквент). Если предусловие выполняется, команда делает верным постусловие. Утверждения являются формулами логики предикатов.

В логике Хоара есть аксиомы и правила вывода для всех конструкций простого императивного языка программирования. В дополнение к этим конструкциям, описанным в оригинальной работе Хоара, Хоаром и другими исследователями были разработаны правила и для остальных конструкций: одновременного выполнения, вызова процедуры, перехода и указателя.

Основная идея Хоара — дать для каждой конструкции императивного языка пред- и постусловие, записанное в виде логической формулы. Поэтому и возникает в названии тройка — предусловие, конструкция языка, постусловие.

  • Ясно, что для пустого оператора пред- и постусловия совпадают.
  • Для оператора присваивания в постусловии кроме предусловия должен учитываться факт, что значение переменной стало другим.
  • Для составного оператора (в Python это отступы, в C это {}) имеем цепочку пред- и постусловий . В результате для составного оператора можно оставить первое предусловие и последнее постусловие.
  • Правило вывода говорит, что можно усилить пред и ослабить постусловие, если нам это понадобится. Нет смысла сохранять всю программу какое-то утверждение, которое не помогает решить поставленную задачу.
  • Оператор ветвления или просто if. Его условно можно разбить на две ветки: then и else. Если к предусловию добавить истинность логического условия (то, что стоит под if), то после выполнения ветки then должно следовать постусловие. Аналогично, если к предусловию добавить отрицание логического условия (то, что стоит под if), то после выполнения ветки else должно следовать постусловие
  • Оператор цикла. Это самое нетривиальное и сложное, поскольку цикл может выполняться много раз и даже не закончиться. Чтобы решить проблему возможного многократного повтора тела цикла вводят инвариант цикла. Инвариант цикла — это то, что истинно перед его выполнением, истинно после каждого выполнения тела цикла и, следовательно, истинно и после его окончания. Предусловие для оператора цикла — это просто его инвариант цикла. Если истинно условие продолжения цикла (то, что стоит под while), то после выполнения тела цикла должна следовать истинность инвариант цикла. В результате, после окончания цикла имеем в качестве постусловия истинность инвариант цикла и отрицание условия продолжения цикла.
  • Оператора цикла с полной корректностью. Для этого к предыдущему пункту добавляют ограничивающую функцию, с помощью которой легко доказать, что цикл будет выполняться ограниченное число раз. На неё накладывают условия, что она всегда >=0, строго убывает после каждого выполнения тела цикла и в точности = 0, когда цикл заканчивается.

Правильно работающую программу можно написать очень многими способами, и во многих случаях она будет эффективной. Эта неоднозначность усложняет программирование. Для этого вводят стиль. Но этого оказывается мало. Для многих программ (например, связанных косвенно с жизнью человека) нужно доказать и их корректность. Оказалось, что доказательство корректности делает программу дороже на порядок (примерно в 10 раз).[источник не указан 3211 дней]

Частичная и полная корректность[править]

В стандартной логике Хоара может быть доказана только частичная корректность, так как завершение программы нужно доказывать отдельно. Также в логике Хоара не может быть выражено правило не использования избыточных частей программы. «Интуитивное» понимание тройки Хоара можно выразить так: если P имеет место до выполнения C, то либо имеет место Q, либо C никогда не завершится. Действительно, если C не завершается, никакого «после» нет, поэтому Q может быть любым утверждением. Более того, мы можем выбрать Q со значением «ложь», чтобы показать, что C никогда не завершится.

Полная корректность также может быть доказана с использованием расширенной версии правила для оператора While.

Правила[править]

Аксиома пустого оператора[править]

Правило для пустого оператора утверждает, что оператор skip (пустой оператор) не меняет состояния программы, поэтому утверждение, верное до skip, остаётся верным после его выполнения.

{P} skip {P}

Аксиома оператора присваивания[править]

Аксиома оператора присваивания утверждает, что после присваивания, значение любого предиката относительно правой части присваивания не меняется с заменой правой на левую часть:

{P[E/x]} x:=E {P}

Здесь P[E/x] означает выражение P в котором все вхождения свободной переменной x заменены выражением E.

Смысл аксиомы присваивания заключается в том, что истинность {P[E/x]} эквивалентна {P} после выполнения присваивания. Таким образом, если {P[E/x]} имело значение «истина» до присваивания, согласно аксиоме присваивания {P} будет иметь значение «истина» после присваивания. И наоборот, если {P[E/x]} было равно «ложь» до оператора присваивания, {P} должно быть равно «ложь» после.

Примеры корректных троек:

  • {x+1=43} y:=x+1 {y=43}
  • {x+1N} x:=x+1 {xN}

Аксиома присваивания в формулировке Хоара не применима, когда более одного идентификатора ссылаются на одно и то же значение. Например,

{y=3} x:=2 {y=3}

является неверным утверждением, если x и y ссылаются на одну и ту же переменную, так как никакое предусловие не может обеспечить, чтобы y было равно 3 после того, как x присвоено 2.

Правило композиции[править]

Правило композиции Хоара применяется к последовательному выполнению программ S и T, где S выполняется до T, что записывается как S;T.

{P} S {Q} , {Q} T {R}{P} S;T {R}

Например, рассмотрим два экземпляра аксиомы присваивания:

{x+1=43} y:=x+1 {y=43}

и

{y=43} z:=y {z=43}

Согласно правилу композиции, мы получаем:

{x+1=43} y:=x+1;z:=y {z=43}

Правило условного оператора[править]

{BP} S {Q} , {¬BP} T {Q}{P} if B then S else T endif {Q}

Правило вывода[править]

P P , {P} S {Q} , Q Q{P } S {Q}

Правило оператора цикла[править]

{PB} S {P}{P} while B do S done {¬BP}

Здесь P является инвариантом цикла.

Правило оператора цикла с полной корректностью[править]

<is well-founded,[PBt=z] S [Pt<z][P] while B do S done [¬BP]

В этом правиле, кроме сохранения инварианта цикла, доказывается завершение цикла при помощи терма, называемого переменной цикла (здесь t), значение которого строго уменьшается согласно отношению полной фундированности (well-founded relation) "<" с каждой итерацией. При этом условие B должно подразумевать, что t не является минимальным элементом своей области определения, в противном случае посылка данного правила будет ложной. Поскольку отношение "<" является полностью фундированным, каждый шаг цикла определяется уменьшающимися членами конечного линейно упорядоченного множества.

В записи данного правила используются квадратные, а не фигурные скобки, для того чтобы обозначить полную корректность правила. (Это один из вариантов обозначения полной корректности.)

Примеры[править]

Пример 1
{x+1=43} y:=x+1 {y=43} — на основании аксиомы присваивания.
Поскольку (x+1=43x=42), на основании правила вывода получаем:
{x=42} y:=x+1 {y=43x=42}
Пример 2
{x+1N} x:=x+1 {xN} — на основании аксиомы присваивания.
Если x и N целые, то (x<N)(x+1N), и на основании правила вывода получаем:
{x<N} x:=x+1 {xN}

См. также[править]

Ссылки[править]

  1. C. A. R. Hoare. «An axiomatic basis for computer programming Архивная копия от 17 июля 2011 на Wayback Machine». Communications of the ACM, 12(10):576—580,583 October 1969. doi:10.1145/363235.363259
  2. R. W. Floyd. «Assigning meanings to programs. Архивировано 9 декабря 2008 года.  (недоступная ссылка с 13-05-2013 [4870 дней] — история)» (недоступная ссылка) Proceedings of the American Mathematical Society Symposia on Applied Mathematics. Vol. 19, pp. 19-31. 1967.

Литература[править]