Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
НПО - ПОИТ (Бахтизин).doc
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
5 Мб
Скачать
☆

9.2. Метод индуктивных утверждений

9.2.1. Общие сведения

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

Общими для различных методов верификации ПО является представление программ в виде схемы алгоритма, с каждой дугой которой соотносится некоторый предикат, называемый утверждением (рис. 9.1).

Если Pi есть утверждение, связанное с входящей дугой оператора V, а Pj – утверждение, связанное с исходящей дугой того же оператора, то тогда необходимо доказать правильность следующего оператора: если Pi истинно и если оператор V выполнен, то утверждение Pj истинно. Такие теоремы имеют следующий вид: Pi→Pj.

Обычный метод их доказательства сводится, например, к тому, чтобы показать, что Pj истинно всякий раз, когда Pi истинно, т.е. для доказательства всей теоремы необходимо доказать, например, истинность Pj. Подобный процесс может быть повторен для каждого оператора программы.

На рис. 9.2 приведена схема алгоритма некоторой программы с предикатами P1 и Pn.

На данном рисунке P1 – утверждение, непосредственно предшествующее входному оператору программы (начальное утверждение), а Pn – утверждение, соответствующее выходному оператору программы (конечное утверждение).

Тогда оператор «если P1 истинно и программа выполнена, то Pn истинно», представляет собой теорему, доказательство которой устанавливает правильность того, что ПО соответствует своим спецификациям (т.е. теорема имеет вид P1→Pn). Таким образом, доказательство правильности программ сводится к доказательству теорем методами исчисления предикатов.

Одним из известных методов доказательства правильности программ является метод индуктивных утверждений, предложенный Флойдом.

Данный метод применим для доказательства правильности или корректности схем алгоритмов. В понятии корректности программ можно выделить два аспекта:

  1. Частичная корректность.

  2. Завершаемость.

Частичная корректность подразумевает соответствие программы своей спецификации.

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

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

9.2.2. Последовательность шагов по доказательству корректности схем алгоритмов программ

Пример.

Рассмотрим определение результата деления двух натуральных чисел А и В в виде пары чисел «частное» и «остаток», не используя операции умножения и деления.

Обозначим:

СН – частное;

АА – остаток (текущий);

А – делимое;

В – делитель;

R – конечный остаток от деления.

Схема алгоритма деления приведена на рис. 9.3.

Представим алгоритм, приведённый на рис. 9.3, в форме, принятой при верификации программ (рис. 9.4). На рис. 9.4 «←» обозначает операцию присваивания.

Рис. 9.3. Пример алгоритма деления натуральных чисел

Рис. 9.4. Представление алгоритма в форме, принятой при верификации программ

Обычно при доказательстве правильности (корректности) операторы ввода-вывода игнорируется.

Шаги по доказательству корректности программ выглядят следующим образом.

  1. На схеме алгоритма выделяем точки разреза. Всегда будет нулевая точка лежащая на дуге исходящей из вершины “начало” и точки, на каждой дуге ведущей к вершине “конец” алгоритма. Кроме того, вводятся точки разреза как минимум на каждый цикл по одной точке.

  2. На алгоритме выделяем множество путей, при этом путь должен обладать следующими свойствами:

    1. путь должен начинаться и заканчиваться в точке разреза;

    2. путь не должен содержать других точек разреза;

    3. множество всех выделенных путей должно покрывать все ветви алгоритма, т.к. в данной схеме алгоритма 3 ветви, то выделяем 3 следующих пути:

α01 = {«0», 2, «1»};

α11 = {«1», 3, 4, «1»};

α12 = {«1», 3, 5, «2»}.

  1. Формулируем предикаты, т.е. с каждой точкой разреза связывается предикат или некоторое индуктивное утверждение. Назначение предиката состоит в том, чтобы описать соотношение между переменными в этой точке. Это индуктивное утверждение должно обладать тем свойством, что всякий раз, когда исполнение программы достигает данной точки, предикат должен быть истинным для текущих значений входящих в него переменных в данной точке. Входной предикат связывается с начальной точкой разреза программы, а выходной с конечной точкой разреза. Применительно к рассматриваемому примеру (см. рис. 9.4):

Р0: А, В – натуральные числа;

Р1: АА = А – СН * ВВ;

Р2: С = (A – R) / В,

где: АА – это текущий остаток в цикле;

СН – текущее частное;

ВВ – делитель;

R – конечный остаток от деления.

Входное утверждение Р0 (входной предикат) описывает все необходимые входные условия для нашего алгоритма. Выходное утверждение Р2 (выходной предикат) описывает связь выхода с входом, т.е. ожидаемый результат. Предикат Р1 вводится таким образом, чтобы он отражал основные свойства цикла.

  1. Формулируем условия прохождения пути:

α01: W01 = истина;

α11: W11 = AA ≥ BB;

α12: W12 = AA < BB.

  1. Строим для каждого пути αij, ведущего из точки разреза i в точку j, некоторое верификационное условие

α01: [P0 ^ W01]→[P1]; (9.1)

α11: [P1 ^ W11]→[P1]; (9.2)

α12: [P1 ^ W12]→[P2]. (9.3)

Cуть метода заключается в демонстрации того, что из входного утверждения P0 и преобразование выполняемого на данном пути следует утверждение, сформулированное в конце пути, например в точке “1” и так вплоть до выходного утверждения P2.

  1. Доказательство корректности верификационных условий. Все три условия имеют вид p→q. Обычный метод доказательства таких утверждений сводится к тому, чтобы показать, что q истинно всякий раз, когда истинно p , т.е. нужно доказать истинность q при условии истинности p.

Докажем истинность предложения (9.1) для пути α01:

Подставляем в предикат P1 значения переменных после выполнения блока 2 схемы алгоритма (рис 9.4):

А = А – 0 * В следовательно А = А (истинно).

Таким образом, всё предложение истинно. Докажем истинность предложения (9.2) для пути α11:

Чтобы доказать истинность предиката в конце пути (точка разреза «1»), достаточно доказать:

    1. истинность P1 при первом попадании в точку «1»;

    2. истинность P1(n+1) при условии, что справедливо P1(n), где n – параметр цикла.

Таким образом, необходимо доказать истинность предложения

P1(n) → P1(n+1),

т.е. при условии, что P1(n) – истинно, доказать, что P1(n+1) – истинно, и таким образом, P1(n) будет истинным для любого значения n.

Докажем истинность предиката P1 при первом попадании в точку разреза «1», т.е. докажем истинность предложения (9.4):

Таким образом, истинность предложения (9.4) на первой итерации доказана.

Пусть P1 истинно на n-й итерации:

AA – n*BB = A – (CH+n)*BB.

Докажем истинность на (n+1)-ой итерации:

AA – (n+1)*BB = A – (CH+n+1)*BB;

AA – n*BB – BB = A – (CH+n)*BB – BB;

AA – n*BB = A – (CH+n)*BB.

Таким образом, истинность на (n+1)-ой итерации доказана, и таким образом, предложение (9.4) истинно для любого n в рамках ограничений предложения (9.4).

Докажем истинность предложения (9.3) на пути α12:

Подставляем в предикат P2 значения переменных после выполнения блока 5 схемы алгоритма (см. рис. 9.4):

CH = (A – AA)/B;

AA = A – CH*B.

Так как B ≡ BB (нигде не менялось), то получаем предикат P1, истинность которого доказана (по условию):

AA = A – CH*BB.

Поэтому предложение (9.3) истинно.

Данный подход позволяет обнаруживать ошибки. Например, внесём ошибку в блок 2 схемы алгоритма (см рис. 9.4):

(AA, BB, CH) ← (A, B, 1).

Тогда

α01: [(A, B: натуральные числа) ^ истина] → [AA = A – CH*BB];

A = A – 1*B;

A ≠ A – B (ошибка).

Таким образом, мы доказали, что схема алгоритма правильна по отношению к входному и выходному утверждению Р0 и Р2 , но то что программа не будет находиться в бесконечном цикле еще не доказано. Нет общего метода доказательства завершаемости программ, но обычно бывает достаточно неформальных рассуждений. В нашем случае алгоритм заканчивается только тогда, когда AA < BB. Согласно входному утверждению Р0, АА первоначально положительно и уменьшается при каждом повторении цикла на положительное число равное ВВ. Т.о. неформально установлено, что выполнение программы закончится.

Из анализа данного примера видно, что доказательство правильности весьма трудоемкий процесс и доказательство всегда длиннее самой программы.