Comment puis-je tester un algorithme heuristique à l'unité?

10

Disons que nous avons notre algorithme de recherche d'itinéraire:

def myHeuristicTSP(graph):
    /*implementation*/
    return route

Maintenant, nous voulons tester ceci de manière unitaire:

class TestMyHeuristicTSP:
    def testNullGraphRaiseValueError(self):
        self.assertRaises(ValueError, myHueristicTSP(None))

    def testSimpleTwoNodeGraphReturnsRoute:
        self.assertEquals(expectedResult, myHeuristicTSP(input))

La question est, pour un algorithme TSP non heuristique, nous pouvons donner une variété de graphiques et vérifier qu'ils retournent toujours absolument la route la plus courte.

Mais parce qu'un algorithme heurtistique, bien qu'il soit encore déterministe, est moins prévisible, sont-ils simplement destinés à comprendre comment l'algorithme est censé fonctionner et à trouver ces cas limites?

dwjohnston
la source

Réponses:

11

Pour un algorithme heuristique censé ne pas renvoyer l'idéal mais une solution "assez bonne", vous auriez différents cas de test et vérifieriez

  1. la solution est-elle réellement valable? Vous voulez certainement vous assurer que votre algorithme de recherche d'itinéraire ne renvoie pas de chemins qui sont impossibles ou qui ne mènent pas réellement du début à la fin. Vous ne pourrez peut-être pas prouver que la solution est idéale, mais vous devriez au moins être en mesure de vérifier que la valeur de retour est bien une solution.
  2. la solution est-elle "assez bonne"? Vous devriez avoir des exigences qui définissent à quel point l'algorithme peut être pire que la solution idéale. Vous devriez avoir des cas de test où la solution idéale est connue (ou au moins une solution qui est considérée comme suffisamment bonne pour être utilisée comme standard de comparaison) et confirmer que la solution fournie par l'algorithme n'est pas pire que x%.
  3. L'algorithme est-il assez rapide? Vous utilisez souvent une approche heuristique lorsque vous présumez qu'ils compensent leur manque de précision en étant beaucoup plus rapides. Pour vérifier cela, vous devez mesurer leur temps d'exécution et vous assurer qu'ils sont en effet plus rapides qu'un algorithme qui obtient la solution exacte. Les mesures du temps d'exécution sont toujours un peu floues, donc le dépassement du temps d'exécution attendu devrait être un avertissement, pas une erreur (lorsque votre infrastructure de tests unitaires permet de faire la différence entre les avertissements et les erreurs).
Philipp
la source
Pouvez-vous peut-être fournir une suggestion pour tester comment vous détermineriez qu'un itinéraire est valide?
dwjohnston
@dwjohnston Prenez simplement votre graphique, prenez votre chemin et essayez de parcourir le chemin sur votre graphique. Vérifiez que chaque bord du chemin part du nœud actuel et que le chemin commence et se termine aux bons nœuds. Vous pouvez également vérifier que le nœud final n'est pas atteint avant la fin.
Philipp
Vous pouvez également vérifier qu'aucun nœud de votre chemin n'est utilisé deux fois, car cela indique une boucle inutile. À moins, bien sûr, que vous ayez des règles spéciales qui rendent les boucles utiles, comme le système de recherche d'itinéraire UPS qui préfère trois virages à droite à un virage à gauche .
Philipp
3

La plupart des algorithmes d'optimisation (y compris l'heuristique) fonctionnent sur certaines configurations (dans votre exemple, un itinéraire) en leur appliquant des opérations. Les opérations pour elles-mêmes devraient garantir qu'elles ne fournissent que des configurations valides, donc il devrait d'abord y avoir des tests unitaires pour chacune d'entre elles. Lorsque vous savez avec certitude que l'algorithme d'optimisation utilise uniquement ces opérations, il ne devrait généralement pas être nécessaire de tester la validité du résultat de l'algorithme.

Pour créer de bons tests unitaires pour tout type d'algorithme plus complexe, il faut en fait connaître l'algorithme lui-même en détail . Pour les heuristiques simples comme «l'escalade», vous pouvez généralement prédire le résultat pour de petites entrées. Par exemple, pour les itinéraires initiaux de 3 à 5 points, lorsqu'ils sont donnés dans un certain ordre, vous pouvez prédire ce qui se passera. Cela restera vrai pour la plupart des algorithmes heuristiques déterministes que je connais, c'est donc probablement un bon point de départ.

Pour des algorithmes plus complexes et une taille d'entrée plus grande, lorsque vous introduisez simplement l'entrée dans l'algorithme et essayez de vérifier la sortie, vous ne faites plus de test unitaire, vous faites un test d'acceptation ou d'intégration. La raison pour laquelle vous rencontrez des problèmes pour "tester à l'unité" un tel algo est qu'il se compose généralement d'une poignée de petites pièces (unités individuelles). Donc, pour vraiment tester un tel algorithme, vous devrez identifier ces parties et les tester individuellement. De plus, vous pouvez utiliser des techniques de couverture de code ou de couverture de branche pour vous assurer que vous disposez de suffisamment de cas de test.

Si vous ne recherchez pas des tests unitaires, mais des tests d'acceptation ou d'intégration automatisés, vous pouvez essayer ce que @Phillip a suggéré sous (2) ou (3) .

Doc Brown
la source