Семантика предикатного трансформатора была введена Эдсгером Дейкстрой в его основополагающей статье « Охраняемые команды, неопределенность и формальный вывод программ ». Они определяют семантику императивной парадигмы программирования , назначая каждому оператору в этом языке соответствующий предикатный трансформатор : общую функцию между двумя предикатами в пространстве состояний оператора. В этом смысле семантика предикатного трансформатора является разновидностью денотационной семантики . Фактически, в охраняемых командах Дейкстра использует только один вид предикатного трансформатора: хорошо известные слабейшие предусловия (см. ниже).
Более того, семантика предикатного трансформатора является переформулировкой логики Флойда–Хоара . В то время как логика Хоара представлена как дедуктивная система , семантика предикатного трансформатора (либо по слабейшим предусловиям , либо по сильнейшим постусловиям , см. ниже) является полной стратегией построения допустимых выводов логики Хоара. Другими словами, они предоставляют эффективный алгоритм для сведения проблемы проверки тройки Хоара к проблеме доказательства формулы первого порядка . Технически, семантика предикатного трансформатора выполняет своего рода символическое исполнение утверждений в предикаты: исполнение выполняется назад в случае слабейших предусловий или вперед в случае сильнейших постусловий.
Для утверждения S и постусловия R слабейшее предусловие — это предикат Q такой, что для любого предусловия P , тогда и только тогда . Другими словами, это «самое свободное» или наименее ограничительное требование, необходимое для гарантии того, что R выполняется после S . Уникальность легко следует из определения: если и Q, и Q' являются слабейшими предусловиями, то по определению так и так , и таким образом . Мы часто используем для обозначения слабейшего предусловия для утверждения S относительно постусловия R .
Мы используем T для обозначения предиката, который везде истинен, и F для обозначения предиката, который везде ложен. Мы не должны, по крайней мере, концептуально путать себя с булевым выражением, определенным некоторым синтаксисом языка, который также может содержать true и false как булевы скаляры. Для таких скаляров нам нужно выполнить приведение типа, так что у нас будет T = predicate(true) и F = predicate(false). Такое продвижение часто выполняется небрежно, поэтому люди склонны считать T истинным, а F — ложным.
Ниже мы приводим два эквивалентных слабейших предварительных условия для оператора присваивания. В этих формулах есть копия R , где свободные вхождения x заменяются на E. Следовательно, здесь выражение E неявно приводится к допустимому термину базовой логики: таким образом, это чистое выражение, полностью определенное, завершающееся и без побочных эффектов.
При условии, что E хорошо определено, мы просто применяем так называемое правило одной точки к версии 1. Тогда
Первая версия позволяет избежать потенциального дублирования x в R , тогда как вторая версия проще, когда x встречается не более одного раза в R. Первая версия также раскрывает глубокую двойственность между слабейшим предусловием и сильнейшим постусловием (см. ниже).
Пример допустимого расчета wp (с использованием версии 2) для присваиваний с целочисленной переменной x :
Это означает, что для того, чтобы постусловие x > 10 было истинным после присваивания, предусловие x > 15 должно быть истинным до присваивания. Это также «слабейшее предусловие», поскольку это «слабейшее» ограничение на значение x , которое делает x > 10 истинным после присваивания.
Например,
Например:
Оставив на мгновение вопрос о завершении, мы можем определить правило для самого слабого либерального предварительного условия , обозначаемого wlp , используя предикат INV , называемый Loop INV ariant , который обычно предоставляется программистом:
Чтобы показать полную корректность, мы также должны показать, что цикл завершается. Для этого мы определяем обоснованное отношение на пространстве состояний, обозначенное как ( wfs , <) и определяем вариантную функцию vf , так что мы имеем:
Неформально, в приведенном выше соединении трех формул:
Однако, соединение этих трех не является необходимым условием. Точно, у нас есть
На самом деле, защищенный командный язык Дейкстры (GCL) является расширением простого императивного языка, данного до сих пор с недетерминированными утверждениями. Действительно, GCL стремится быть формальной нотацией для определения алгоритмов. Недетерминированные утверждения представляют выбор, оставленный для фактической реализации (в эффективном языке программирования): свойства, доказанные на недетерминированных утверждениях, гарантируются для всех возможных вариантов реализации. Другими словами, слабейшие предварительные условия недетерминированных утверждений гарантируют
Обратите внимание, что определения слабейшего предусловия, данные выше (в частности, для цикла while ), сохраняют это свойство.
Выборка представляет собой обобщение оператора if :
Здесь, когда два охранника и одновременно истинны, то выполнение этого оператора может запустить любой из связанных операторов или .
Повторение — это обобщение оператора while аналогичным образом.
Исчисление уточнения расширяет GCL с помощью понятия утверждения спецификации . Синтаксически мы предпочитаем записывать утверждение спецификации как
который определяет вычисление, которое начинается в состоянии, удовлетворяющем pre , и гарантированно заканчивается в состоянии, удовлетворяющем post, изменяя только x . Мы называем логическую константу, используемую для помощи в спецификации. Например, мы можем определить вычисление, которое увеличивает x на 1 как
Другим примером является вычисление квадратного корня целого числа.
Утверждение спецификации выглядит как примитив в том смысле, что оно не содержит других утверждений. Однако оно очень выразительно, поскольку pre и post являются произвольными предикатами. Его самое слабое предварительное условие следующее.
Он сочетает в себе синтаксическую идею Моргана с идеей резкости Бийлсмы, Мэтьюза и Уилтинка. [1] Главное преимущество этого — возможность определения wp для goto L и других операторов перехода. [2]
Формализация операторов перехода, таких как goto L, занимает очень долгий и ухабистый процесс. Распространенное мнение, похоже, указывает на то, что оператор goto может быть аргументирован только операционально. Вероятно, это связано с неспособностью распознать, что goto L на самом деле является чудом (т. е. нестрогим) и не следует придуманному Дейкстрой Закону Исключенного Чуда, как он есть сам по себе. Но он имеет чрезвычайно простой операциональный вид с точки зрения самого слабого предварительного условия, что было неожиданно. Мы определяем
Для goto L выполнение передает управление метке L , в которой должно выполняться самое слабое предварительное условие. То, как wpL упоминается в правиле, не следует воспринимать как большой сюрприз. Это просто для некоторого Q, вычисленного к этой точке. Это похоже на любые правила wp, использующие составляющие операторы для задания определений wp, хотя goto L кажется примитивом. Правило не требует уникальности для мест, где wpL выполняется в программе, поэтому теоретически оно позволяет одной и той же метке появляться в нескольких местах, пока самое слабое предварительное условие в каждом месте является тем же wpL. Оператор goto может перейти в любое из таких мест. Это фактически оправдывает то, что мы могли бы размещать одни и те же метки в одном и том же месте несколько раз, как , что то же самое, что и . Кроме того, это не подразумевает никаких правил области действия, таким образом, позволяя, например, перейти в тело цикла. Рассчитаем wp следующей программы S, в которой есть переход в тело цикла.
wp(do x > 0 → L: x := x-1 od; if x < 0 → x := -x; goto L ⫿ x ≥ 0 → skip fi, post) = {правила последовательного состава и чередования} wp(сделать x > 0 → L: x := x-1 od, (x<0 ∧ wp(x := -x; перейти к L, post)) ∨ (x ≥ 0 ∧ post) = {последовательная композиция, goto, правила назначения} wp(сделать x > 0 → L: x := x-1 od, x<0 ∧ wpL(x ← -x) ∨ x≥0 ∧ post) = {правило повторения} самое сильное решение Z: [ Z ≡ x > 0 ∧ wp(L: x := x-1, Z) ∨ x < 0 ∧ wpL(x ← -x) ∨ x=0 ∧ post ] = { правило присваивания, найдено wpL = Z(x ← x-1) } самое сильное решение Z: [ Z ≡ x > 0 ∧ Z(x ← x-1) ∨ x < 0 ∧ Z(x ← x-1) (x ← -x) ∨ x=0 ∧ пост] = {подстановка} самое сильное решение Z:[ Z ≡ x > 0 ∧ Z(x ← x-1) ∨ x < 0 ∧ Z(x ← -x-1) ∨ x=0 ∧ пост ] = {решить уравнение приближенным методом} пост(x ← 0)
Поэтому,
wp(S, пост) = пост(x ← 0).
Важным вариантом самого слабого предусловия является самое слабое либеральное предусловие , которое дает самое слабое условие, при котором S либо не завершается, либо устанавливает R. Поэтому оно отличается от wp тем, что не гарантирует завершения. Следовательно, оно соответствует логике Хоара в частичной корректности: для языка утверждений, данного выше, wlp отличается от wp только в while-loop , не требуя варианта (см. выше).
Если S — утверждение, а R — предусловие ( предикат начального состояния), то — их сильнейшее постусловие : оно подразумевает любое постусловие, которому удовлетворяет конечное состояние любого выполнения S, для любого начального состояния, удовлетворяющего R. Другими словами, тройка Хоара доказуема в логике Хоара тогда и только тогда, когда выполняется следующий предикат:
Обычно, наиболее сильные-постусловия используются в частичной корректности. Следовательно, мы имеем следующее соотношение между наиболее слабыми-либеральными-предусловиями и наиболее сильными-постусловиями:
Например, по заданию у нас есть:
Выше логическая переменная y представляет собой начальное значение переменной x . Следовательно,
В последовательности видно, что sp работает вперед (тогда как wp работает назад):
Лесли Лэмпорт предложил win и sin в качестве предикатных трансформаторов для параллельного программирования . [3]
В этом разделе представлены некоторые характерные свойства предикатных трансформаторов. [4] Ниже S обозначает предикатный трансформатор (функцию между двумя предикатами в пространстве состояний), а P — предикат. Например, S(P) может обозначать wp(S,P) или sp(S,P) . Мы сохраняем x как переменную пространства состояний.
Предикатные трансформаторы интереса ( wp , wlp и sp ) являются монотонными . Предикатный трансформатор S является монотонным тогда и только тогда, когда:
Это свойство связано с правилом следствия логики Хоара .
Предикатный трансформатор S является строгим тогда и только тогда:
Например, wp искусственно сделан строгим, тогда как wlp, как правило, нет. В частности, если утверждение S не может быть завершено, то является выполнимым. Мы имеем
Действительно, T является допустимым инвариантом этого цикла.
Нестрогие, но монотонные или конъюнктивные предикатные трансформаторы называются чудесными и также могут использоваться для определения класса программных конструкций, в частности, операторов перехода, которые Дейкстру волновали меньше всего. Эти операторы перехода включают прямой goto L, break и continue в цикле и операторы return в теле процедуры, обработку исключений и т. д. Оказывается, что все операторы перехода являются исполняемыми чудесами, [5] т. е. они могут быть реализованы, но не строгими.
Предикатный трансформатор S завершается , если:
На самом деле эта терминология имеет смысл только для строгих предикатных трансформаторов: действительно, является слабейшим предусловием, гарантирующим завершение S.
Кажется, было бы более уместно назвать это свойство неабортирующим : при полной корректности непрерывание является абортом, тогда как при частичной корректности — нет.
Предикатный трансформатор S является конъюнктивным тогда и только тогда:
Это имеет место , даже если оператор S недетерминирован как оператор выбора или оператор спецификации.
Предикатный трансформатор S является дизъюнктивным тогда и только тогда:
Это, как правило, не тот случай, когда S недетерминирован. Действительно, рассмотрим недетерминированное утверждение S, выбирающее произвольное логическое значение. Это утверждение дано здесь как следующее утверждение выбора :
Тогда сводится к формуле .
Следовательно, сводится к тавтологии
Между тем, формула сводится к неверному предложению .
В семантике предикатных трансформаторов выражения ограничены терминами логики (см. выше). Однако это ограничение кажется слишком сильным для большинства существующих языков программирования, где выражения могут иметь побочные эффекты (вызов функции, имеющей побочный эффект), не могут завершаться или прерываться (например, деление на ноль ). Существует много предложений по расширению слабейших предусловий или сильнейших постусловий для языков императивных выражений и, в частности, для монад .
Среди них теория типов Хоара объединяет логику Хоара для языка, подобного Haskell , логику разделения и теорию типов . [9] В настоящее время эта система реализована в виде библиотеки Coq под названием Ynot . [10] В этом языке оценка выражений соответствует вычислениям сильнейших постусловий .
Вероятностные предикатные преобразователи являются расширением предикатных преобразователей для вероятностных программ . Действительно, такие программы имеют множество применений в криптографии (сокрытие информации с использованием некоторого рандомизированного шума), распределенных системах (нарушение симметрии). [11]