- •31.10.12 Лекция 7
- •7. Технология предикатного программирования
- •Предикатная программа транслируется на императивное расширение языка P с применением оптимизирующих трансформаций.
- •Подстановка определения предиката на место вызова
- •Замена хвостовой рекурсии циклом
- •Определение предиката A(x: y) { S }
- •Склеивание переменных
- •Метод обобщения исходной задачи
- •Трансформация кодирования рекурсивных структур
- •sumG(seqR s, real d: real c)
- •Кодирование списка вырезкой массива
- •Кодирование списка через указатели
- •Пример. Обращение списка
- •reverseIn(LT s: LT s’) pre s nil
- •Оформление цикла и подстановка на место вызова: reverseIn(LT s: LT s){
- •method ReverseInPlace ( ) returns ( reverse : Node)
- •Пример. Сортировка простыми вставками
- •sort1(Arn a, natn m: Arn a’) pre sorted(a, m)
- •sort1(Arn a, natn m: Arn a’) pre sorted(a, m)
- •Улучшенная версия pop_into
- •Замена хвостовой рекурсии циклом. Раскрытие групповых операторов и модификаторов.
- •Оформление циклов. Упрощения.
- •Подстановка pop_into на место вызова в sort1 и sort1 в sort. Упрощения.
- •Подстановка sort1 на место вызова в sort. Упрощения.
Трансформация кодирования рекурсивных структур
Пример. Программа суммирования sum(s: c) эл-тов посл-ти s.
type seqR = list (real); formula SUM(seqR s, real c) =
s = nil ? c = 0 : exists real a. SUM(s.cdr, a) & c = s.car + a;
sum(seqR s: real c) |
|
{ switch (s){ case nil: |
c = 0 |
case cons(h, t): c = h + sum(t) } |
|
} post SUM(s, c); |
|
sum(seqR s: real c) |
nil?(s) or cons?(s) = true |
{ if (nil?(s)) c = 0 |
|
else {{h = s.car || t = s.cdr}; c = h + sum(t)} } post SUM(s, c);
sum(seqR s: real c) { if (s = nil) c = 0
else c = s.car + sum(s.cdr) } post SUM(s, c);
type seqR = list (real); formula SUM(seqR s, real c) =
s = nil ? c = 0 : exists real a. SUM(s.cdr, a) & c = s.car + a; sum(seqR s: real c)
{ if (s = nil) c = 0 else c = s.car + sum(s.cdr) } post SUM(s, c);
Обобщение задачи SUM
formula SUMG(seqR s, real d, c) = e. SUM(s, e) & c = e + d; sumG(seqR s, real d: real c) post SUMG(s, d, c);
sum(seqR s: real c)
{ sumG(s, 0: c) } post SUM(s, c);
sumG(seqR s, real d: real c)
{ if (s = nil ) c = d else sumG(s.cdr, d + s.car : c) } post SUMG(s, d, c) measure len(s);
sumG(seqR s, real d: real c)
{ if (s = nil ) c = d else sumG(s.cdr, d + s.car : c) } post measure
Склеивание c d. sumG(seqR s, real с: c)
{ if (s = nil ) c = c else sumG(s.cdr, c + s.car : c) }
Замена хвостовой рекурсии циклом. При раскрытии
группового оператора меняется порядок присваивания параметрам s и с.
sumG(seqR s, real с: real c)
{ for (; s != nil; ) { с = с + s.car; s = s.cdr }
Подстановка определения на место вызова
real c = 0; for (; s != nil; ) { с = с + s.car; s = s.cdr }
Кодирование списка вырезкой массива
Кодирование начального и текущего состояния списка S
type SEQR = array (real, M..N); Начальное S[m..n], текущее S[j..n]. SEQR S;
int j = m;
Значения границ M и N должны быть достаточными, т.е. M ≤ m, n, j ≤ N.
Кодирование операций:
s = nil |
→ |
j > n |
s != nil |
→ |
j <= n |
s.car |
→ |
S[j] |
s = s.cdr |
→ |
j = j + 1 |
Итоговая программа
real c = 0; for (int j = m; j <= n; ) { c = с + S[j]; j = j + 1 }
real c = 0; for (; s != nil; ) { c = с + s.car; s = s.cdr }
Кодирование списка через указатели
type LISTP = struct (real car, LISTP *cdr);
LISTP *S; |
|
|
s |
→ |
S |
Кодирование операций: |
||
s = nil |
→ |
S = null |
s != nil |
→ |
S != null |
s.car |
→ |
S->car |
s = s.cdr |
→ |
S = S->cdr |
Итоговая программа
real c = 0; for ( ; S != null; ) { c = с + S->car; S = S->cdr }
real c = 0; for (; s != nil; ) { c = с + s.car; s = s.cdr }
Пример. Обращение списка
a1 |
a2 |
a3 |
an |
Результат обращения списка:
a1 a2 a3 an
type T; type LT = list(T);
formula reverse(LT s: LT) = (s = nil)? s : reverse(s.cdr) + s.car; reverseIn(LT s: LT s’) pre s nil
{ reverseG([s.car], s.cdr: s’) } post s’ = reverse(s);
reverseG(LT s, u: LT s’) post s’ = reverse(reverse(s) + u);
reverseIn(LT s: LT s’) pre s nil
{ reverseG([s.car], s.cdr: s’) } post s’ = reverse(s);
reverseG(LT s, u: LT s’){ if (u = nil) s’ = s
else reverseG(u.car + s, u.cdr: s’) } post s’ = reverse(reverse(s) + u);
Склеивание и замена хвостовой рекурсии циклом: reverseIn(LT s: LT s){ reverseG([s.car], s.cdr: s) };
reverseG(LT s, u: LT s){ М: if (u = nil) s = s
else |s, u| = |u.car + s, u.cdr|; goto M
};
Оформление цикла и подстановка на место вызова: reverseIn(LT s: LT s){
LT u; |s, u| = |[s.car], s.cdr|;
while (u != nil) { s = u.car + s; u = u.cdr }
}; Раскрытие мультиприсваивания:
reverseIn(LT s: LT s){
LT u = s.cdr; s = [s.car];
while (u != nil) { s = u.car + s; u = u.cdr }
};
type LTP = struct (T car, LTP *cdr);
LTP *S; |
s |
→ S; u → U |
Кодирование операций: |
||
u != nil |
→ |
U != null |
s = [s.car] |
→ |
S->cdr := null |
u = s.cdr |
→ |
U = S->cdr |
reverseIn(LT s: LT s){ LT u = s.cdr; s = [s.car];
|
|
while (u != nil) { s = u.car + s; u = u.cdr }}; |
type LTP = struct (T car, LTP *cdr); |
||
LTP *S; s |
→ |
S; u → U |
Кодирование операций: |
||
u != nil |
→ |
U != null |
s = [s.car] |
→ |
S->cdr := null; u = s.cdr → U = S->cdr |
u = u.cdr |
→ |
U = U->cdr; |
s = u.car + s → U.cdr = s; S = U // портится U
s = u.car + s; u = u.cdr → LTP* a = U; U = U->cdr; a->cdr = S; S = a
reverseIn(LTP* S) {
LTP* U = S->cdr; S->cdr = null;
while (U != null) {LTP* a = U; U = U->cdr; a->cdr = S; S = a }
};
method ReverseInPlace ( ) returns ( reverse : Node)
requires Val id ( ) ; modifies f o o t p r i n t ; ensures reverse 6= nul l ^ reverse . Val id ( ) ;
ensures fresh ( reverse . f o o t p r i n t .. old ( f o o t p r i n t ) ) ; ensures | reverse . l i s t | = | old ( l i s t ) | ; ensures (8 i : int ¤ 0 i ^ i < | old ( l i s t ) | =) old ( l i s t ) [ i ] = reverse . l i s t [ | old ( l i s t )|..1.. i ] ) ;
{
var current : Node ; current := next ; reverse := this ; reverse . next := null ; reverse . f o o t p r i n t := { reverse } ; reverse . l i s t := [ data ] ;
while ( cur rent 6= nul l )
invar iant reverse 6= nul l ^ reverse . Val id ( ) ; invar iant reverse . f o o t p r i n t old ( f o o t p r i n t ) ; invar iant cur rent = nul l =) | old ( l i s t ) | = | reverse . l i s t | ; invar iant cur rent 6= nul l =)
cur rent . Val id ( ) ^ cur rent 2 old ( f o o t p r i n t ) ^ cur rent . f o o t p r i n t old ( f o o t p r i n t ) ^
cur rent . f o o t p r i n t , reverse . f o o t p r i n t ^ | old ( l i s t ) | = | reverse . l i s t | + | cur rent . l i s t | ^ (8 i : int ¤ 0 i ^ i < | cur rent . l i s t | =) cur rent . l i s t [ i ] = old ( l i s t ) [ | reverse . l i s t |+ i ] ) ;
invar iant (8 i : int ¤ 0 i ^ i < | reverse . l i s t | =) old ( l i s t ) [ i ] = reverse . l i s t [ | reverse . l i s t |..1.. i ] ) ;
{
var nx : Node ;
nx := current . next ;
assert nx 6= nul l =) (8 i : int ¤ 0 i ^ i < | nx . l i s t | =) cur rent . l i s t [1+ i ] = nx . l i s t [ i ] ) ;
/ / The s ta t e looks l i k e : . . . , reverse , cur rent , nx , . . .
assert cur rent . data = cur rent . l i s t [ 0 ] ; current . next := reverse ;
cur rent . f o o t p r i n t := { cur rent } [ reverse . f o o t p r i n t ; cur rent . l i s t := [ cur rent . data ] + reverse . l i s t ;
reverse := current ; current := nx ;
}
}