Em poucas palavras:
A correção parcial é uma questão de rescisão, não a correção do que é calculado. Uma função está parcialmente correta com relação a uma especificação, se o que ela calcula estiver correto, quando terminar. Essa idéia pode ser estendida ao cálculo de respostas incompletas (parciais). O que quer que seja calculado da resposta está correto, mas o programa pode, em algum momento, entrar em um loop sem fim, possivelmente sem ter computado toda a resposta. Respostas parciais são aproximações de respostas completas.
Essa estrutura de aproximação é uma ordem parcial, que é o conceito básico dos domínios semânticos de Scott, e pode realmente ser usada para responder a outra interpretação da questão. Podemos medir a distância entre uma resposta correta e uma não muito correta, como ter um elemento de uma matriz que está errado (em vez de desconhecido). Uma maneira de definir essa distância é considerar a ordem das aproximações e relacionar as duas respostas incompatíveis (a correta e a incorreta) com a melhor resposta parcial que é uma aproximação de ambas. Esse problema é analisado rapidamente do ponto de vista da análise numérica, onde a análise de precisão é essencial e de algumas outras áreas.
Este segundo ponto é realmente explorado em uma segunda resposta à pergunta, pois não percebi a princípio que as duas respostas poderiam ter uma conexão. Mas as duas respostas são bastante longas e não me senti sábio em mesclá-las quando percebi a conexão.
Uma primeira visão simples da correção parcial
Não existe algo (parcialmente) correto em um sentido absoluto . Um programa está correto se atender a uma especificação, de qualquer forma. A especificação pode ser outro programa, uma declaração lógica ou qualquer outra coisa que possa ser formalizada. A especificação deve de alguma forma incluir informações sobre quando o programa termina, possivelmente sempre (o que é realmente assumido na maioria das definições, para que nada mais complexo precise ser dito). Na verdade, o domínio pode estar restrito na especificação à parte em que a rescisão é esperada, de modo que a rescisão seja sempre esperada , o que pode justificar a suposição de rescisão em todo o domínio na definição usual ( wikipedia e wikipedia) Por sua vez, isso impõe uma suposição implícita a qualquer especificação, que pode ser ou não ser tão conveniente.
Um programa P está correto com relação a uma especificação S
iff termina sempre que a especificação diz que deve, e com um resultado que atenda à especificação. Está parcialmente correto se, às vezes, não terminar onde a especificação diz que deveria, mas sempre fornecer um resultado correto ao finalizar.
Como conseqüência, um programa que nunca termina é parcialmente correto com relação a qualquer especificação .
Escolhi uma definição um pouco extensa também porque corresponde precisamente à noção de aproximação nos domínios semânticos de Scott , como a usada na semântica denotacional. Um domínio Scott inclui uma ordem parcial correspondente precisamente à idéia de correção parcial (os dois usos da palavra "parcial" não são relacionados). Uma funçãoF é e aproximação de uma função G é G termina sempre que F
termina e ambos dão o mesmo resultado. assimG pode dar um resultado quando Fnão. E podemos dizer queF está parcialmente correto com relação a G, ou aquilo F aproximado Gou F⊑ G.
Essas idéias são essenciais para definir a semântica de funções com loop (ou recursão) como o limite de um conjunto infinito de funções sem loop ou recursão. Veja, por exemplo , a Wikipedia , ou uma apresentação muito informal sobre SE .
A lógica padrão do Hoare funcionará apenas para provar a correção parcial e precisa ser estendida para tratar das propriedades de terminação, portanto, para corrigir a correção total (consulte a Wikipedia ). Existem exemplos implementados dessas extensões específicas.
Provar correção total equivale a comprovação de correção parcial e rescisão. A lógica de Hoare é bastante apropriada para correção parcial. Provar a terminação requer geralmente uma prova por indução (recorrência), que é a abordagem natural para provar as coisas na semântica de Scott (como a própria semântica é definida dessa maneira, indutivamente). A resposta de danielp mostra como tal indução pode complementar uma prova na lógica de Hoare.
Quanto à quantificação da correção parcial, supondo que você ainda queira fazê-lo, pode ser de alguma forma identificando as partes do domínio em que o programa termina ou não termina ou algumas propriedades dessas partes.
Extensão para resultados complexos, aplicada ao exemplo de classificação.
Na verdade, o problema pode ser um pouco mais complexo quando você considera respostas complexas, como estruturas de dados (que é o caso ao classificar matrizes). A especificação pode exigir o cálculo de duas respostas (ou seja, um par) e, para algumas partes do domínio de entrada, um programa real pode encontrar um elemento do par, mas não terminar enquanto calcula o outro, em outros casos, encontrar apenas o outro elemento, ou encontre ambos, ou não encontre nenhum. Ainda é uma aproximação no sentido de Scott, e esse programa está parcialmente correto.
De maneira mais geral, a idéia de aproximação no sentido de Scott se aplica aos dados e também ao programa. Para isso, informalmente, você precisa do conceito de uma resposta desconhecida (ainda não calculada, possivelmente nunca conhecida se o seu cálculo não terminar). Geralmente é representado pelo símbolo⊥. O par( ⊥ , 36 ) aproxima ( 25 , 36 ). O que você obtém de um programa que entrega a parte 36 e depois não termina pode ser representado por( ⊥ , 36 ).
Como isso pode ser aplicado a um programa que classifica matrizes de cinco números inteiros? Suponha que você escreva um programa SORT5 que seja executado paralelamente ao seu aplicativo principal (estou tentando tornar as coisas realistas) e que deve classificar essa matriz para o aplicativo. O programa SORT5 deve armazenar seu resultado em alguma matriz fornecida pelo aplicativo e pode ser feito separadamente para cada elemento, assim que souber onde colocá-lo. Primeiro, ele procura o maior e o menor, e os armazena nas duas extremidades; depois, tenta fazer uma recursão (ou qualquer outra coisa), mas tem um bug que o envia a um loop infinito sem mais resultados. O aplicativo principal ainda recebe uma resposta parcial. Se a matriz a ser classificada fosse[ 25 , 36 , 3 , 9 , 12 ], a resposta fornecida é [3,⊥,⊥,⊥,36] ao invés de
[3,9,12,25,36]. Tudo o que é fornecido está correto, e o restante não é calculado, de modo que você tem apenas parte da resposta . Assim, você tem uma aproximação do resultado desejado. Se você puder provar que esse é sempre o caso, seu programa de buggy SORT5 que não termina ainda estará parcialmente correto com relação à especificação de um programa de classificação.
Um programa parcialmente correto pode ser útil. Pode ser que você realmente não precise de classificação, mas apenas o maior e menor elemento. Nesse caso, o fato de o seu programa de classificação SORT5 não terminar e estar apenas parcialmente correto não importa, e seu aplicativo funcionará e, com sorte, será finalizado com uma resposta correta.
Mas quem interromperá o seu algoritmo de classificação não autorizado que continuará desperdiçando o poder da computação? Existem estratégias de computação (avaliação lenta), que não executam um subprograma quando mais informações sobre seu resultado não são necessárias no momento. Então, depois que você obtiver o maior e o menor elemento, o programa SORT5 ficará em espera até que outros elementos sejam solicitados.
Nesse caso, é claro, poderia haver uma maneira de quantificar a correção parcial. No entanto, não tenho certeza de que seria muito útil.
Nesse contexto, é necessário revisar um pouco a definição, que estou fazendo de maneira informal:
Um programa P está parcialmente correto em relação a uma especificação S, se der uma resposta completa que atenda à especificação antes de terminar ou forneça parte de uma resposta que atenda à especificação antes de entrar em um cálculo não final que não forneça mais parte da resposta .
Então, um programa que nunca termina e não produz parte do resultado está parcialmente correto com relação a qualquer especificação.
Observe que essa definição deixa de fora um programa que mantém a computação, sempre produzindo novas partes da resposta. Mas, como não produz números infinitesimais (não sei se isso poderia fazer sentido computacional), na verdade, ele está computando uma resposta infinita.
Essas técnicas podem realmente ser muito proveitosas para formalizar a semântica da computação de objetos infinitos (apenas para usuários muito pacientes), como a representação decimal exata (ou binária) do valor de πou listas infinitas. Existem outras aplicações interessantes. Mas isso está longe de ser a pergunta inicial, e é por isso que estou deixando de fora.