Teste de algoritmos (determinísticos) com múltiplas ou difíceis de provar as respostas corretas corretas

11

Eu gostaria de prefácio que esta pergunta é semelhante, mas minha pergunta não envolve aleatoriedade, apenas determinismo exigente, portanto a resposta de "usar uma semente conhecida" não se aplica realmente. Da mesma forma, essa pergunta é semelhante, mas, novamente, não espero que o algoritmo falhe - apenas não sei de que maneira ele estará correto.

Essa pergunta surgiu ao testar algoritmos gráficos. mas não se limita a eles. Alguns algoritmos como A * podem ter várias respostas corretas. Dependendo da sua implementação exata, você pode obter qualquer uma das várias respostas, cada uma das quais está igualmente correta. No entanto, isso pode dificultar o teste, porque você não sabe qual deles cuspirá antes do tempo e é muito demorado calcular as respostas manualmente.

No meu caso específico, resolvi modificar o Floyd-Warshall para cuspir todos os caminhos mais curtos possíveis e passei o tempo testando isso. Teve o benefício de ser um bom recurso por si só. Depois, pude testar outras funções em termos dos caminhos corretos conhecidos do FW (se o caminho retornado for qualquer um dos caminhos retornados pelo FW para esse par de início / fim, está correto). Obviamente, isso só funciona para gráficos densos devido à forma como o FW funciona, mas ainda é bom.

No entanto, isso nem sempre é viável para todos os algoritmos com essa característica. Até agora, a melhor resposta que encontrei é testar as características de uma resposta correta, em vez da resposta correta em si. Para voltar aos algoritmos de caminho mais curto, você pode verificar o custo do caminho retornado em relação ao custo correto conhecido e garantir que o caminho seja válido.

Isso funciona, mas pode correr o risco de não verificar tudo corretamente, pois existem mais critérios de correção, especialmente se a verificação for complexa (por exemplo, enquanto existem algoritmos corretos , verificar uma árvore de abrangência mínima é um problema difícil conhecido; provavelmente mais difícil do que isso). construindo o próprio MST); nesse caso, agora você precisa testar extensivamente seu código de teste. Pior: presumivelmente, você precisa construir um MST para testar um algoritmo de verificação MST, para ter um ótimo cenário em que seu teste MST se baseia no funcionamento do seu algoritmo de verificação MST e seu teste no algoritmo de verificação MST se baseia no funcionamento do código de geração MST.

Por fim, existe a "maneira barata", que envolve observar a saída, verificá-la manualmente e depois codificar o teste para testar a saída que você acabou de verificar, mas isso não é uma boa idéia, pois você pode precisar revisar o teste toda vez que altere um pouco a implementação (que é o que o teste automatizado deve evitar).

Obviamente, a resposta depende do algoritmo exato que você está testando até certo ponto, mas eu queria saber se havia alguma "prática recomendada" para verificar algoritmos que tenham várias saídas "corretas" determinísticas e definidas, mas essas saídas corretas precisas são difíceis de saber com antecedência e, possivelmente, difícil de verificar após o fato.

LinearZoetrope
fonte
3
Se o idioma permitir, você poderá provar a correção em vez de testá-lo.
miniBill 24/04
Há muito texto, mas não há dúvida. Então, o que exatamente você está perguntando?
BЈовић
@ Bћовић "Como devo testar implementações de algoritmos com múltiplas e / ou difíceis de verificar saídas corretas?" Não sei bem como deixar isso muito claro, desculpe. Concordo que possa ser considerado um pouco amplo, dependendo da sua perspectiva, mas não acho que seja indefinido.
LinearZoetrope
Eu ainda não entendo. Seu algoritmo não depende de aleatoriedade e, no entanto, ainda pode produzir resultados diferentes. Isso não faz sentido. Todo algoritmo, para entradas definidas, deve ter as mesmas saídas. E é isso que é feito e testado em testes de unidade. Até o algoritmo no artigo que você vinculou.
BЈовић
@ Bћовић É claro que é determinístico, mas também é muito sensível, por exemplo, a ordem em que o gráfico retorna os sucessores de um nó. Pode causar um pouco de efeito borboleta. Se você pressionar o vértice A em uma pilha antes do vértice B, resultará em uma saída diferente se os dois levarem ao caminho mais curto. O uso de funções de biblioteca como classificações não estáveis ​​ou min-heaps apenas exacerba o problema.
precisa saber é o seguinte

Respostas:

5

Não tenho certeza se você está tentando testar a propriedade correta, e isso causa sua ambiguidade.

Os algoritmos de gráfico não têm como objetivo encontrar um caminho mais curto (esse é um efeito colateral), mas minimizar ou maximizar alguma função de custo definida no conjunto de arestas e vértices. Assim, você pode verificar a correção de uma solução testando o valor final dessa funcionalidade e afirmando que o primeiro e o último nó são os realmente necessários.

Se você pode pré-calcular o valor da função de custo final para cada caminho possível (geralmente irrealista), basta verificar se o custo da solução fornecida pela implementação em teste é igual ao custo mínimo entre este conjunto (comparação absoluta ) Se você "apenas" possui um algoritmo e / ou implementação padrão-ouro, deve comparar o custo de sua saída com o do algoritmo em teste (comparação relativa)

Por exemplo, uma configuração de teste ingênua seria:

  1. Calcule todos os caminhos possíveis entre Va e Vb no gráfico de teste com um algoritmo ganancioso.
  2. Calcule a função de custo (por exemplo, o comprimento se todos os seus pesos de borda forem iguais a 1) para cada um desses caminhos e encontre o valor mínimo.
  3. Aplique o algoritmo em teste.
  4. Faça uma afirmação em seu teste de unidade de que o valor do custo do algoritmo testado é igual ao mínimo das soluções gananciosas.

Se você quiser saber mais sobre a otimização baseada em gráficos, pode dar uma olhada nas publicações de Yuri Boykov aqui , embora em outro contexto (problemas de visão computacional).

sansuiso
fonte
Eu votei, mas vou esperar um pouco para aceitar. Este é o "teste para as características de uma resposta correta" que mencionei na pergunta. O problema sempre vem em garantir que você esteja verificando a coisa certa. Por exemplo, em um momento eu estava verificando o custo retornado e certificando-me de que o caminho era válido. Claro que o caminho era válido! Era apenas o nó inicial! Portanto, tive que alterar os testes para garantir que o caminho em si realmente tivesse o custo correto e retornado. Erro bobo, com certeza, mas quanto mais interações como essa sua produção tiver, maior a probabilidade delas serem.
precisa saber é o seguinte
@Jsor, no meu ponto de vista, é o benefício da melhoria contínua dos testes: você não pode descobrir todas as propriedades de correção da solução primeiro e depois passar um dia em alguma falha, melhorar seu teste e assim por diante.
Sansuiso
Esta resposta recomenda testar as características da resposta correta, mas o importante é escolher quais características fazem um bom teste. Neste exemplo, verificar se a resposta é um caminho de A a B e se a função de custo é igual ao valor mínimo fornece dois critérios que todas as respostas corretas atenderão, enquanto nenhuma resposta incorreta atenderá a ambos os critérios. Se essa resposta ainda não tivesse sido dada, eu recomendaria algo semelhante. É certo que muitas vezes não é fácil saber quais características testar.
David K
0

Acho que a resposta direta à sua pergunta é escolher melhores casos de teste. Eu me pergunto sobre os casos de teste que você está usando. Os gráficos que você usa podem ser CANNED, onde é relativamente fácil para um ser humano determinar a resposta esperada. Tente descobrir os casos de "borda" com os quais você deseja garantir que seu algoritmo lide e crie um gráfico fixo para cada um dos casos de borda específicos que é fácil para o ser humano calcular. Por exemplo, no caso do algoritmo Djikstra, você provavelmente pode criar alguns gráficos 5x5 ou 7x7 que cobrem todos os seus casos extremos, mesmo que o seu sistema real possa ser 500x500.

Então, como uma verificação final de sanidade, você pode criar um caso de teste gráfico mais realista ou dois. Mas, de qualquer forma, acho que o sansuiso indica onde é indicado que você precisa ter certeza de que está testando a propriedade correta.

Dunk
fonte