Предикатное программирование Лекция 2 01.10.09

advertisement
01.10.09
Лекция 2
Предикатное программирование
2. Постановка задачи дедуктивной верификации
Программа в виде тройки Хоара, однозначность программы, тотальность и
однозначность спецификации
Тотальная корректность программы
Теорема тождества спецификации и программы
3.Язык исчисления вычислимых предикатов
Структура программы на языке CCP
Система типов данных
Основные свойства программы:
• автоматическая вычислимость
• наличие спецификации программы
• логика программы
Свойство 2. Программа должна
соответствовать спецификации.
Спецификация
свойства
алгоритм
Свойства
Алгоритм
программа
Программа
Рис1. Схема построения программы с предикатной спецификацией
Предикатная спецификация ― может быть записана в виде
формулы на языке исчисления предикатов. Спецификация
определяет функцию, отображающую значения входных данных
в значения результатов.
Предикатная спецификация ― условие математической задачи,
исходными данными которой являются входные данные
программы, а неизвестными  результаты программы.
Алгоритм строится с использованием свойств (утверждений, лемм,
теорем), доказуемых из условия задачи. Эти свойства
определяют логику решения задачи.
Программа ― реализация алгоритма решения математической
задачи. В процессе реализации программа оптимизируется
привычным образом: используются циклы вместо рекурсии,
используются указатели и т.д.
Логика программы
Логика программы ― набор предикатов {Lp} на
значениях переменных для разных точек p
программы
1. Предикат Lp(z) истинен, когда исполнение
программы находится в точке p.
2. Если предикат Lp(z) истинен на некотором наборе
значений z=z0, то существует исполнение с
такими значениями переменных в точке p.
Язык программирования называется
предикатным, если логика любой
конструкции Z этого языка может быть
определена единственным предикатом
LS(Z), истинным после исполнения Z.
Функция LS называется логической
семантикой языка. Языки предикатного
программирования находятся на границе
между функциональными и логическими
языками.
2. Постановка задачи
дедуктивной
верификации для класса
программ с предикатной
спецификацией
Программа – оператор S(x, y)
x  аргументы  набор входных данных,
y  результаты  набор выходных данных.
Предикатная спецификация программы  формула
P(x) & Q(x, y)
P(x)  предусловие, истинное перед исполнением
программы,
Q(x, y)  постусловие, истинное после исполнения
программы.
Спецификация изображается в виде:
[ P (x), Q(x, y) ]
Программа со спецификацией представляется
тройкой Хоара {P(x)} S(x, y) {Q(x, y)}.
P(x) { S (x, y) ♦k } Q(x, y)
♦k
(2.1)
– маркер, обозначающий точку k в конце программы
Lk(x, y) – логика программы в конце программы.
Однозначность программы S(x, y) :
P(x) & Lk(x, y1) & Lk(x, y2)  y1 = y2
Однозначность спецификации [P(x), Q(x, y)] :
P(x) & Q(x, y1) & Q(x, y2)  y1 = y2
Тотальность спецификации [P(x), Q(x, y)] :
P(x)  y. Q(x, y)
Свойство 2. Программа должна соответствовать
спецификации.
Конкретизация закона соответствия программы и
спецификации:
- аргументы x должны соответствовать предусловию P(x)
перед исполнением программы;
- аргументы x и результаты y должны удовлетворять
постусловию Q(x, y) после завершения исполнения
программы.
P(x) { S (x, y) ♦k } Q(x, y)
(2.1)
P(x) & (Lk(x, y)  Q(x, y) )
(2.2)
P(x) & Lk(x, y)  Q(x, y)
(2.3)
Непосредственная экспликация закона соответствия
спецификации и программы:
Предусловие P(x) не следует из Lk(x, y). Оно должно быть
доказано ранее – перед вызовом S(x, y). Здесь же оно
должно быть истинно априори, и поэтому должно быть
посылкой, т.е.:
Данное условие определяет частичную корректность
программы S (x, y).
Условие завершения программы:
P(x)  y. Lk(x, y)
(2.4)
Тотальная корректность программы S(x, y) относительно
спецификации [P(x), Q(x, y)] складывается из частичной
корректности и условия завершения программы:
P(x)  [Lk(x, y)  Q(x, y)] & y. Lk(x, y)
Частичная корректность
Условие завершения
программы
(2.5)
P(x) & Lk(x, y)  Q(x, y)
(2.3)
P(x)  y. Lk(x, y)
(2.4)
Термин «корректность» далее используется в
смысле тотальной корректности.
Лемма 2.1. Если программа корректна
относительно спецификации, то
спецификация тотальна.
Доказательство. Пусть истинно P(x).
Необходимо доказать истинность y. Q(x, y).
Из условия (2.4) следует истинность
y. Lk(x, y). Допустим, истинность этой
формулы реализуется для некоторого y0. Из
условия (2.3) получаем истинность Q(x, y0), а
значит и y. Q(x, y). □
Предикат A(x, y) является однозначным в области X, если:
xX. A(x, y1) & A(x, y2)  y1 = y2
Лемма 2.2. Допустим, предикат D(x, y) является
однозначным в области X, а предикат Z(x, y) 
тотальный в области X. Пусть истинна формула
xX. Z(x, y)  D(x, y). Тогда истинна следующая
формула: xX. D(x, y)  Z(x, y). Как следствие,
предикаты D и Z оказываются тождественными в
области X.
Доказательство. Пусть истинно D(x, y) для
некоторого xX. Докажем истинность Z(x, y).
Поскольку предикат Z  тотальный, то существует
некоторый y’, для которого истинно Z(x, y’). Из
Z(x, y)  D(x, y) получаем истинность D(x, y’).
Поскольку истинны D(x, y) и D(x, y’), то из
однозначности D следует y = y’. Тогда истинно
Z(x, y). □
Теорема 2.1 тождества спецификации и программы
P(x) { S (x, y) ♦k } Q(x, y)
(2.1)
Оператор S(x, y) является однозначным, а
спецификация [P(x), Q(x, y)]  тотальной. Пусть
истина формула:
P(x) & Q(x, y)  Lk(x, y)
(2.6)
Тогда программа (2.1) является корректной.
Доказательство. Достаточно доказать (2.5), т.е.:
P(x)  [Lk(x, y)  Q(x, y)] & y. Lk(x, y)
(2.5)
Пусть предусловие P(x) истинно. Докажем
истинность y. Lk(x, y). Из тотальности
спецификации следует y. Q(x, y). Пусть эта
формула истинна для некоторого y’. Тогда из (2.6)
истинна Lk(x, y’) и, следовательно, y. Lk(x, y).
Докажем истинность формулы Lk(x, y)  Q(x, y).
Поскольку истинны P(x) и формула (2.6), то
истинна формула Q(x, y)  Lk(x, y).
В соответствии с леммой 2.2 истинна формула
Lk(x, y)  Q(x, y), поскольку постусловие Q(x, y)
тотально, а Lk(x, y)  однозначно. □
Лемма 2.8. В условиях теоремы 2.1 истинна ф-ла:
P(x)  (Lk(x, y)  Q(x, y))
Доказательство. Допустим, предусловие P(x)
истинно. Истинность формулы Lk(x, y)  Q(x, y)
установлена при доказательстве теоремы 2.1.
Обратная импликация следует из (2.16). □
Следствие леммы 2.8: спецификация [P(x), Q(x, y)]
является однозначной.
Лемма 2.9. Допустим, программа (2.1) является
корректной, а ее спецификация  однозначной.
Тогда истинна формула (2.6), т.е. Lk(x, y) выводима
из спецификации.
Доказательство. Допустим, истинны P(x) и Q(x, y).
Докажем истинность Lk(x, y). Из корректности
программы (2.1) по формуле (2.5) следует
истинность формулы Lk(x, y)  Q(x, y), а также
тотальность Lk(x, y). Пусть для некоторого y’
истинно Lk(x, y’). Тогда истинно Q(x, y’), а из
однозначности Q следует y = y’. Следовательно,
истинно Lk(x, y). □
3. Язык
исчисления
вычислимых
предикатов
Исчисление вычислимых предикатов ― множество
вычислимых формул языка исчисления предикатов
― язык CCP (Calculus of Computable Predicates)
― ядро для построения языка предикатного
программирования
Структура программы на языке CCP
Программа ─ набор определений предикатов
Определение A  K  предикат A , оператор K
параллельный оператор, оператор суперпозиции, условный оператор
Вызов предиката
(d1, d2, …, dn : e1, e2, …, em)
(3.1)
φ ─ имя предиката или переменной предикатного типа, n  0, m > 0,
d1, d2, …, dn ─ имена переменных ─ аргументы вызова,
e1, e2, …, em ─ результаты вызова
Вычисление предиката
Вызов φ(d: e), где d = d1, d2, …, dn, e = e1, e2, …, em – наборы
переменных
n = 0 – вызов предикта соответствует константе
Значение φ(d)  φ(d: b) , где b ─ переменная логического типа
Определение предиката
A(x: y)  K(x: y)
(3.2)
A  имя предиката; набор x  аргументы предиката, набор y 
результаты предиката, K(x: y) – оператор.
Предикат – определяемый, базисный, значение переменной.
Тип данных определяет набор базисных предикатов со значениями типа
Система типов определяет совокупность всех базисных предикатов
Система типов данных
Тип ― множество значений, имя типа
Система типов: примитивные типы,
подмножество типа и структурные типы
Примитивные типы: логический BOOL,
целый INT, вещественный REAL и литерный
CHAR.
Базисные предикаты: +(x, y: z)  z = x + y,
(x, y: z)  z = x - y, -(x: y)  y = -x,
<(x, y: b)  b = x < y и др.
Предикаты равенства =(x: y)  y = x и
=(x, y: b)  b = (x = y) для всех примитивных типов
Предикаты
ConsIntZero( : x)  x = 0
ConsIntOne( : x)  x = 1
x  переменная типа T, d  возможно пустой набор
переменных – параметров типа
Подмножество типа T на базе предиката P(x, d) 
S = Subset(T, x, P, d) = {xT | P(x, d)}
(3.3)
Subset  стандартное имя, P  вычислимый,
d  параметры типа
NAT = Subset(INT, x, GE0) = {xINT | x  0}.
DIAP(n) = Subset(INT, x, IN1_n, n) = {xINT | x  1  x  n}
Структурный тип ― композиция
компонентных типов
Структурные типы: произведение типов
(кортеж), объединение типов, множество
подмножеств типа, предикатный тип (в т.ч.
массив).
Базисные предикаты  конструкторы,
деструкторы и другие операции
Конструктор по значениям компонентных
типов строит значение структурного типа.
Деструктор для значения структурного типа
определяет соответствующие значения
компонент.
Нет типов указателей !
Произведение типов
Z = X  Y = {(x, y) | x  X, y  Y}
x  X, y  Y, z  Z
Конструктор ConsStruct(x, y: z)  z = (x, y)
Деструктор CompStruct(z: x, y)  z = (x, y)
(3.4)
Объединение типов
Z = X + Y = {(1, x) | x  X}  {(2, y) | y  Y}
(3.5)
Первая компонента (1 или 2) ― тег значения
Конструктор ConsUnion1(x: z)  z = (1, x).
Конструктор ConsUnion2(y: z)  z = (2, y)
Деструктор CompUnion(z: i, x, y)  либо z = (1, x) и
i = 1, либо z = (2, y) и i = 2. Если i = 1, то y не
определено. Если i = 2, то x не определено
Множество подмножеств конечного типа X:
Z = Set(X) = {z | z  X}
(3.6)
Конструктор ConsSetEmpty( : z)  z = 
Конструктор ConsSetElem(x : z)  z = {x}
Предикат
CompSet(z, x: b)  b = x  z
Предикатный тип
Z = Pred(D: E) = {(d: e) | d  D, e  E,  - вычислимый} (3.7)
― множество вычислимых предикатов вида (d: e)
для непересекающихся списков переменных d и e
Z = {(d: e) | d  D, e  E,   CCP}
Конструктор предиката ConsPred будет определен позже
Z ― тип массива  D не пуст & типы D конечны &
  Z d  D e (d: e)
(d: e) ― массив с индексом d и элементом массива e
Конструктор предиката ConsArray будет определен позже
Деструктор CompArray(a, i: x)  x = a(i)  a(i: x)
Произвольный тип либо примитивный, либо
вводится следующим определением:
<имя типа> = <типовый терм>
Z = Subset(T, x, P, d)
(3.3)
Z=XY
(3.4)
Z=X+Y
(3.5)
Z = Set(X)
(3.6)
Z = Pred(D: E)
(3.7)
Z, T, X, Y, D, E ― имена типов, примитивных
или определяемых.
Тип “подмножество типа” может быть
параметризован набором переменных d
Структурный тип параметризован, если
параметризован один из его компонентных типов.
В качестве параметра может выступать также имя
типа.
Если <имя типа>, встречающееся в правой части
определения типа, не есть имя примитивного типа
и этот тип не объявлен как параметр, то должно
существовать определение для этого типа
Замкнутая совокупность определений типов ―
любой встречающийся тип либо является
примитивным, либо имеет определение, либо
считается параметром для некоторых типов из
совокупности определений
Рекурсивный тип ― определение типа прямо или
косвенно, через совокупность определений,
использует этот тип
Примеры рекурсивных типов
Специальный тип NIL = { nil }; nil обозначает
пустую последовательность
Тип последовательности, составленной из
элементов типа T:
Seq(T) = NIL + (T  Seq)
Тип списка LIST для языка Лисп:
LIST = Seq(ATOM)
ATOM = NIL + NUM + SYMBOL + LIST
NUM = INT + REAL
SYMBOL = STRING
STRING = Seq(CHAR)
Download