Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
AlgStr / Библиотека / ЛЕКЦИИ / PZ00 / Логические спецификации.doc
Скачиваний:
32
Добавлен:
23.03.2015
Размер:
93.18 Кб
Скачать

Логические спецификации

(или введение в верификацию программ)

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

Анализ программ, не содержащих ветвлений

Для доказательства правильности программ мы будем использовать формулы полной корректности. Каждая такая формула включает в себя два предиката – предусловие и постусловие, а также сегмент программы. Областью предикатов является набор всевозможных состояний переменных программы, получаемых в ходе вычислений.

Формула полной корректности имеет вид

{P} S1;S2;…Sn {Q}

и утверждает , что если состояние процесса вычислений перед выполнением операторов S1;S2;…Sn удовлетворяет предусловию P, то выполнение операторов S1;S2;…Sn гарантирует выполнение постусловия {Q}. Разумеется, если в начальном состоянии предусловие ложно, то вся формула истинна. Это аналогично правилу логики, утверждающему , что

(FALSE  P)  TRUE.

Видно, что пара предикатов в этих формулах очень напоминает тело спецификации процедуры: предусловие похоже на Requires, а постусловие – на Effects.

Например.

{TRUE}

X:=0; Y:=1;

{Y > X}

Как это доказать? Используя смысл операции присваивания, видно, что выполнение двух операторов присваивания даст значения переменным Y=1 и X=0. Из теории целых чисел известно, что 1 > 0, ч.т.д.

Что мы использовали:

  1. порядок вычислений в программе (управляющий поток);

  2. смысл оператора присваивания (:=);

  3. значение операции > для целых чисел.

Основной прием доказательства можно сформулировать следующим образом:

  1. Локализация всех путей между двумя предикатами.

  2. Для каждого пути выполняется проход назад от конечного предиката до обнаружения производного предиката P, который должен быть истинен по отношению к первому оператору в данном пути, если при этом был истинен конечный предикат.

  3. Информация о типах значений переменных, входящих в предикаты, используется для установления того факта, что предусловие для каждого пути включает производный предикат P.

Это доказательство можно расписать более подробно. Проход назад через второе присваивание с исходной посылкой Y > X упрощает данный фрагмент программы до следующего

{ TRUE }

X:=0;

{1 > X },

а дальнейший проход дает

TRUE  1 > 0,

которое упрощается до TRUE, следуя правилам логики целых чисел.

В построении этого доказательства мы воспользовались следующим правилом (аксиомой) присваивания:

Пусть Р есть любой предикат, а E - есть выражение свободное от побочных эффектов: тогда если Р истинен после присваивания X := E, то Р с E, подставленным во все свободные вхождения X (т.е. вхождения не связанные квантором) перед этим присваиванием, должен быть истинен.

Или другими словами:

Для того, чтобы P было верным после выполнения X:=E (где E – выражение) достаточно, чтобы P[E  X] (т.е. свойство P после замены всех вхождений X на E) было верно изначально или кратко

{ P[E  X]} X:=E {P}.

Это означает, что предикат P, в котором E подставлено во все свободные вхождения X, есть самое слабое предусловие, обеспечивающее истинность P после присваивания X:=P.

Кажется несколько странным выполнение прохода назад по программе. Но преимущество этого способа заключается в том, что таким образом мы последовательно достигаем поставленной цели: на каждом шаге, зная, что мы хотим удостовериться в правильном выполнении каждого фрагмента программы, мы вычисляем то, что должно быть истинным по отношению к данному шагу. По достижении начала программы мы получаем самое слабое условие, выполнение которого достаточно для подтверждения истинности постусловия (“самое слабое” в том смысле, что его включает в себя любое другое достаточное предусловие). Мы завершаем доказательство, показывая, что исходное предусловие включает в себя полученное нами самое слабое предусловие.

Если двигаться вперед, то необходимо начать с того, что предполагается истинным в начале выполнения программы, и вычислить то, что должно быть истинным по завершении данной части. Достигнув, таким образом, конца программы, мы будем иметь самое сильное постусловие, вытекающее из исходного предусловия (“самое сильное” в том смысле, что оно предполагает выполнение любых других значимых постусловий). В этом случае мы завершаем доказательство, если покажем, что это самое строгое постусловие включает в себя необходимое постусловие.

Проблема здесь заключается в том, что при просмотре программы вперед у на отсутствует метод последовательного исключения незначимой информации. Это приводит к накоплению множества утверждений, являющихся истинными, но не имеющими никакого отношения к доказательству.

Эти два метода доказательства можно проиллюстрировать с помощью следующих рисунков:

Достаточное предусловие (P)

Необходимое

постусловие (Q)

S1; S2; … Sn

Самое слабое предусловие

Рис. 1 . Проход назад.

Достаточное предусловие (P) Самое сильное постусловие

S1; S2; … Sn

Необходимое

постусловие (Q)

Рис. 2. Проход вперед.

Мы видим, что предусловие и постусловие аналогичны предложениям Requires и Effects в спецификациях процедур. Но между ними есть существенное различие. В спецификациях процедуры предикат Effects имеет дело с двумя состояниями: до и после обращения. Когда мы ссылаемся на значение формального параметра, то рассматриваем его (порой неявно) как имеющий префикс пре- и пост-. В формуле полной корректности каждый предикат относится только к одному состоянию. Это порождает небольшую проблему, возникающую при необходимости установления связи между начальными и конечными значенгиями.

Например, рассмотрим формулу полной корректности, утверждающую, что оператор X:=X+1 приводит к увеличению X на 1. Необходимо, чтобы постусловие ссылалось как к начальному, так и к конечному значению X. Для этого введем в предусловие новую переменную X0 и считая, что она имеет такое же значение как и X. Запишем

{ X0=X } X:=X+1 {X>X0 }

Для доказательства продвинем предикат X > X0 через оператор присваивания:

X+1>X0.

Учтем, что X0=X, получим

X0+1>X0 или 1>0,

что упрощается до TRUE.

Рассмотрим несколько примеров доказательства.

Пример 1. Необходимо доказать формулу полной корректности

{ X>n } X:=X+1 {X>n+1 } (1)

Доказательство. Продвинем предикат {X>n+1 } через оператор присваивания. Получим самое слабое предусловие {X+1>n+1 } или {X>n }. Как видим самое слабое предусловие не шире (в точности совпадает) достаточного предусловия. Формула доказана.

Пример 2. Доказать

{0<X<1} X:=1/X+Y {X>Y+1}. (2)

Доказательство. Продвинем предикат {X>Y+1} через оператор присваивания. Получим самое слабое предусловие {1/X+Y>Y+1}. Теперь докажем, что достаточное предуслове включает (из него следует) самое слабое предусловие. Т.е. нам надо доказать тождественную истинность формулы

(0<X<1)  (1/X+Y>Y+1)

Заметим, что (0<X<1)  (1/X>1).

Добавив к обеим частям неравенства по Y, получим

(0<X<1)  (1/X>1)  (1/X+Y>Y+1)

ч.т.д.

Аксиома последовательного выполнения.