Regras da Verificação de Programas

As regras da verificação de programas estão organizadas (essencialmente) pelos tipos de instruções.

Ciclos e Programas Parciais

Num triplo de Hoare, , a verificação da pós-condição pressupõe que termina quando .

Entre os tipos de instruções, apenas os ciclos podem contribuir para programas que não terminam; Um programa apenas com instruções "cópia" ou "condição" sem ciclos termina sempre.

Como o problema da paragem é indecidível, isto é, não há um algoritmo para classificar um programa como total ou parcial, as regras de verificação que envolvem ciclos (onde está o "problema" da paragem) devem contemplar ambos os casos.

De facto, existe uma regra para ciclos totais e outra regra para ciclos parciais.

O tratamento dos ciclos totais está fora do âmbito desta disciplina e vai-se usar apenas a regra do caso parcial nos ciclos.

A razão desta escolha está na complexidade adicional de tratar o caso total. Os ciclos, como estão apresentados, permitem programas parciais e, claro, também programas totais.

Uma forma de garantir que um ciclo termina consiste em usar ciclos limitados. Por exemplo, a sintaxe do C permite

for (int i = 0; i < 10; i++) {
    // instruções que não afetam i
}

Claro, isto é um caso particular de ciclos ilimitados:

#![allow(unused)]
fn main() {
i = 0;
while i < 10 {
    // instruções que não afetam i
    i = i + 1;
}
}

Regras para a Verificação de Programas Parciais

Implicação


Definição ()

Nesta regra:

  • são fórmulas FOL+Aritmética.
  • significa que existe uma prova de com hipóteses na lógica FOL+Aritmética.
  • P é um programa.

Esta é uma regra de "conveniência", que permite generalizar a pré-condição e restringir a pós-condição.

Sequência


Sequência ()

Nesta regra:

  • são fórmulas FOL+Aritmética.
  • P e Q são programas.

Intuitivamente:

  1. Se antes de e depois,
  2. e se antes de e depois;
  3. Estão, quando antes de também depois:

Cópia


Cópia ()

Nesta regra:

  • é uma fórmula FOL+Aritmética.
  • é um termo aritmético.
  • resulta de substituir, em , algumas ocorrências da variável por .

Exemplo. Provas em Tabela

Mostrar que

Temos de usar a regra

Para esta regra ser corretamente aplicada é necessário identificar o termo e a fórmula .

Uma prova em tabela é:

LinhaInstruçãoFórmulaRegraHipótesesObservação
1precpré-condição
2aritm1aritmética na linha anterior
3x = y + 1
4copy2, 3 é a fórmula ""
  1. Na primeira linha está a pré-condição do triplo (prec) e na última linha está a pós-condição do triplo.
  2. A segunda linha resulta da primeira por aplicação das regras da aritmética (aritm).
  3. Na terceira linha está (apenas) a instrução do triplo.
  4. Finalmente, a última linha resulta de aplicar a regra .

Mas ficam algumas dúvidas:

  • Qual a justificação para a linha 2? É necessária?
  • Donde vêm a fórmula e o termo ? O que se passa com a substituição ?

Como identificar a fórmula e o termo usados na regra .

  1. De acordo com a regra, deve ser a pós-condição de uma instrução da forma x = E.
  2. O que pretendemos com esta regra é obter a fórmula . Portanto, deve ser .
  3. Falta o . A instrução "real" é x = y + 1. Portanto, deve ser .
  4. Isso significa que na prova deve estar a fórmula , que resulta de .
  5. Por isso é usado o teorema da aritmética e a regra .
    • Em casos diretos, como este, pode usar-se a "pseudo-regra" para simplificar a prova.

Mais rigorosamente, o que aquela tabela apresenta é a seguinte prova formal:

Este exemplo ilustra a seguinte eurística para as provas de verificação:

As linhas de uma prova lêem-se "de cima para baixo" mas escrevem-se "de fora para dentro"

O que isto significa é que as seguintes regras ajudam a fazer uma prova:

  1. Começar por escrever as hipóteses ou pré-condições dadas e a conclusão ou pós-condição pretendida.
  2. "Descer" a partir das linhas superiores enquanto as conclusões são diretas.
  3. "Subir" das linhas inferiores enquanto a hipóteses necessárias são diretas.

Exemplos da regra .

Condicional

Condicional ()

Nesta regra:

  • e são fórmulas FOL + Aritmética.
  • P e Q são programas, respetivamente os ramos positivo e negativo da instrução condicional.

Exemplo.

Seja Max o programa

#![allow(unused)]
fn main() {
if x > y {
    z = x
} else {
    z = y
}
}

Recapitulando a definição de da aritmética:

L.InstruçãoFórmulaRegraHipótesesObservação
1prec
2if x > y {
?
?z = x
?
?} else {
?
?z = y
?
?}
?cond2, ? - ?, ? - ?
L.InstruçãoFórmulaRegraHipótesesObservação
1prec
2if x > y {
?
?z = x
?copytêm de ser iguais
?} else {
?
?z = y
?copytêm de ser iguais
?}
?cond2, ? - ?, ? - ?têm de ser iguais
L.InstruçãoFórmulaRegraHipótesesObservação
1prec
2if x > y {
3posbguarda
?z = x
?copy
?} else {
8negbnegação da guarda
?z = y
?copy
?}
?cond2, ? - ?, ? - ?
L.InstruçãoFórmulaRegraHipótesesObservação
1prec
2if x > y {
3posb
4?
5z = x
6copy
7} else {
8negbnegação da guarda
?z = y
?copy
?}
?cond2, ? - ?, ? - ?
L.InstruçãoFórmulaRegraHipótesesObservação
1prec
2if x > y {
3posb
4impl
5z = x
6copy
7} else {
8negb
9impl
10z = y
11copy
12}
13cond2, ? - ?, ? - ?
L.InstruçãoFórmulaRegraHipótesesObservação
1prec
2if x > y {
3posb
4z = x
5copy
6impl
7} else {
8negb
9z = y
10copy
11impl
12}
13cond2, 3 - 6, 8 - 11

Ciclo Parcial e Invariante


Definição (, Invariante)

Uma invariante do ciclo é qualquer fórmula tal que


Isto é,

A fórmula é um invariante do ciclo se para qualquer estado tal que , quando é executado no estado e termina, no estado final, , ainda .

Por outras palavras, um invariante de um ciclo é uma condição que é válida antes e depois da computação do corpo do ciclo. Pode acontecer que durante essa computação a condição deixe de ser válida desde que, no fim, volte a sê-lo.

Exemplo. Verificação de um programa para calcular .

Mostre que em que Fac1 é o programa

#![allow(unused)]
fn main() {
y = 1;
z = 0;
while z != x {
    z = z + 1;
    y = y * z;
}
}

Para este exemplo é preciso recapitular a seguinte propriedade da aritmética:

L.InstruçãoFórmulaRegraHipótesesObservação
1prec
2if x > y {
3posb
4z = x
5copy
6impl
7} else {
8negb
9z = y
10copy
11impl
12}
13cond2, 3 - 6, 8 - 11