ajout: Tests unitaires de Dijkstra
This commit is contained in:
parent
0b08b70cb9
commit
5fc064e863
4 changed files with 242 additions and 7 deletions
|
|
@ -12,7 +12,7 @@ import org.insa.graphs.model.AccessRestrictions.AccessRestriction;
|
|||
|
||||
public class ArcInspectorFactory {
|
||||
|
||||
private static class NoFilterByLengthArcInspector implements ArcInspector {
|
||||
public static class NoFilterByLengthArcInspector implements ArcInspector {
|
||||
|
||||
@Override
|
||||
public boolean isAllowed(Arc arc) {
|
||||
|
|
@ -40,7 +40,7 @@ public class ArcInspectorFactory {
|
|||
}
|
||||
};
|
||||
|
||||
private static class OnlyCarsByLengthArcInspector
|
||||
public static class OnlyCarsByLengthArcInspector
|
||||
extends NoFilterByLengthArcInspector {
|
||||
|
||||
@Override
|
||||
|
|
@ -57,7 +57,7 @@ public class ArcInspectorFactory {
|
|||
}
|
||||
};
|
||||
|
||||
private static class OnlyCarsByTimeArcInspector
|
||||
public static class OnlyCarsByTimeArcInspector
|
||||
extends NoFilterByLengthArcInspector {
|
||||
|
||||
@Override
|
||||
|
|
@ -76,7 +76,7 @@ public class ArcInspectorFactory {
|
|||
}
|
||||
};
|
||||
|
||||
private static class OnlyPedestrianByTime implements ArcInspector {
|
||||
public static class OnlyPedestrianByTime implements ArcInspector {
|
||||
|
||||
static final int maxPedestrianSpeed = 5;
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ public class ArcInspectorFactory {
|
|||
}
|
||||
};
|
||||
|
||||
private static class BicyleByTime implements ArcInspector {
|
||||
public static class BicyleByTime implements ArcInspector {
|
||||
static int maxBicycleSpeed = 20;
|
||||
|
||||
@Override
|
||||
|
|
@ -142,7 +142,7 @@ public class ArcInspectorFactory {
|
|||
}
|
||||
}
|
||||
|
||||
private static class BicyleByLength implements ArcInspector {
|
||||
public static class BicyleByLength implements ArcInspector {
|
||||
static int maxBicycleSpeed = 20;
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ public class DijkstraAlgorithm extends ShortestPathAlgorithm {
|
|||
heap.insert(label);
|
||||
labels.put(data.getOrigin().getId(), label);
|
||||
System.out.println("==> Tas initialisté");
|
||||
//System.out.println(heap.toStringTree());
|
||||
|
||||
System.out.println("==> Dijkstra commence");
|
||||
notifyOriginProcessed(data.getOrigin());
|
||||
|
|
@ -41,6 +40,8 @@ public class DijkstraAlgorithm extends ShortestPathAlgorithm {
|
|||
break;
|
||||
|
||||
currentLabel.setMarque(true);
|
||||
// On constate que les coûts des sommets marqués est bel et bien croissant
|
||||
//System.out.println("-> Sommet marqué: " + currentLabel.getCoutRealise());
|
||||
notifyNodeMarked(currentLabel.getNode());
|
||||
|
||||
// Si on atteint notre destination, on arrête l'algo
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package org.insa.graphs.algorithm.shortestpath;
|
||||
|
||||
public class DijkstraTest extends ShortestPathAlgorithmTest {
|
||||
|
||||
@Override
|
||||
public ShortestPathSolution runAlgo(ShortestPathData algoData) {
|
||||
final DijkstraAlgorithm algo = new DijkstraAlgorithm(algoData);
|
||||
return algo.doRun();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,223 @@
|
|||
package org.insa.graphs.algorithm.shortestpath;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.insa.graphs.algorithm.ArcInspector;
|
||||
import org.insa.graphs.algorithm.ArcInspectorFactory;
|
||||
import org.insa.graphs.algorithm.AbstractInputData.Mode;
|
||||
import org.insa.graphs.model.Arc;
|
||||
import org.insa.graphs.model.Graph;
|
||||
import org.insa.graphs.model.Node;
|
||||
import org.insa.graphs.model.Path;
|
||||
import org.insa.graphs.model.io.BinaryGraphReader;
|
||||
import org.insa.graphs.model.io.GraphReader;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public abstract class ShortestPathAlgorithmTest {
|
||||
|
||||
public abstract ShortestPathSolution runAlgo(ShortestPathData algoData);
|
||||
|
||||
private static String MAP_CARRE = "/mnt/commetud/3eme Annee MIC/Graphes-et-Algorithmes/Maps/carre.mapgr";
|
||||
private static String MAP_INSA = "/mnt/commetud/3eme Annee MIC/Graphes-et-Algorithmes/Maps/insa.mapgr";
|
||||
private static String MAP_HAITI = "/mnt/commetud/3eme Annee MIC/Graphes-et-Algorithmes/Maps/haiti-and-domrep.mapgr";
|
||||
private static String MAP_TOULOUSE = "/mnt/commetud/3eme Annee MIC/Graphes-et-Algorithmes/Maps/toulouse.mapgr";
|
||||
private static String MAP_FRANCE = "/mnt/commetud/3eme Annee MIC/Graphes-et-Algorithmes/Maps/france.mapgr";
|
||||
|
||||
private static Graph carreGraph, insaGraph, haitiGraph, toulouseGraph, franceGraph;
|
||||
|
||||
protected static class TestScenario {
|
||||
public final Graph graph; // chemin du fichier mapgr
|
||||
public final Node origin, destination;
|
||||
public final ArcInspector arcInspector;
|
||||
public final boolean isFeasible;
|
||||
|
||||
public TestScenario(Graph graph, int originId, int destinationId, boolean isFeasible, ArcInspector arcInspector) {
|
||||
this.graph = graph;
|
||||
this.origin = graph.get(originId);
|
||||
this.destination = graph.get(destinationId);
|
||||
this.isFeasible = isFeasible;
|
||||
this.arcInspector = arcInspector;
|
||||
}
|
||||
|
||||
public TestScenario(Graph graph, int originId, int destinationId, boolean isFeasible) {
|
||||
this(graph, originId, destinationId, isFeasible, new ArcInspectorFactory.NoFilterByLengthArcInspector()); // par défaut, aucune restriction sur les arcs
|
||||
}
|
||||
};
|
||||
|
||||
private static Graph loadGraph(String pathname) {
|
||||
Graph graph = null;
|
||||
|
||||
try (final GraphReader reader = new BinaryGraphReader(new DataInputStream(new BufferedInputStream(new FileInputStream(pathname))))) {
|
||||
graph = reader.read();
|
||||
} catch (FileNotFoundException e) {
|
||||
System.err.println("> Impossible de trouver le fichier " + MAP_CARRE);
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
System.err.println("> Impossible d'ouvrir le fichier " + MAP_CARRE);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object> data() {
|
||||
carreGraph = loadGraph(MAP_CARRE);
|
||||
assertNotNull("Impossible de charger le graphe carré", carreGraph);
|
||||
insaGraph = loadGraph(MAP_INSA);
|
||||
assertNotNull("Impossible de charger le graphe INSA", insaGraph);
|
||||
haitiGraph = loadGraph(MAP_HAITI);
|
||||
assertNotNull("Impossible de charger le graphe Haïti", haitiGraph);
|
||||
toulouseGraph = loadGraph(MAP_TOULOUSE);
|
||||
assertNotNull("Impossible de charger le graphe Toulouse", toulouseGraph);
|
||||
franceGraph = loadGraph(MAP_FRANCE);
|
||||
assertNotNull("Impossible de charger le graphe France", franceGraph);
|
||||
|
||||
Collection<Object> objects = new ArrayList<>();
|
||||
|
||||
// Exemple trajet court, toutes routes
|
||||
objects.add(new TestScenario(carreGraph, 9, 11, true));
|
||||
// Exemple trajet moyen, toutes routes
|
||||
objects.add(new TestScenario(insaGraph, 286, 823, true));
|
||||
// Exemple trajet infaisable (composantes non connexes)
|
||||
objects.add(new TestScenario(haitiGraph, 265362, 92314, false));
|
||||
// Exemple trajet moyen, à pieds
|
||||
objects.add(new TestScenario(toulouseGraph, 16824, 4028, true, new ArcInspectorFactory.OnlyPedestrianByTime()));
|
||||
// Exemple trajet de longueur nulle
|
||||
objects.add(new TestScenario(insaGraph, 297, 297, true));
|
||||
// Exemple trajet très long
|
||||
//objects.add(new TestScenario(franceGraph, 981717, 5539046, true));
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
@Parameter
|
||||
public TestScenario scenario;
|
||||
|
||||
@Test
|
||||
public void testScenario() {
|
||||
assertNotNull(scenario.graph);
|
||||
assertNotNull(scenario.origin);
|
||||
assertNotNull(scenario.destination);
|
||||
assertNotNull(scenario.arcInspector);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFeasability() {
|
||||
final ShortestPathData algoData = new ShortestPathData(scenario.graph, scenario.origin, scenario.destination, scenario.arcInspector);
|
||||
final ShortestPathSolution solution = this.runAlgo(algoData);
|
||||
assertEquals(solution.isFeasible(), scenario.isFeasible);
|
||||
|
||||
if (solution.isFeasible()) assertTrue(solution.getPath().isValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareWithBellman() {
|
||||
// On ne compare avec Bellman qui si le scenario est faisable
|
||||
Assume.assumeTrue(scenario.isFeasible);
|
||||
// Si un chemin de longueur nulle (origin==destination) on ne compare pas avec Bellman, qui ne respecte pas les mêmes conventions que notre Dijkstra
|
||||
Assume.assumeFalse(scenario.origin.equals(scenario.destination));
|
||||
|
||||
final ShortestPathData algoData = new ShortestPathData(scenario.graph, scenario.origin, scenario.destination, scenario.arcInspector);
|
||||
|
||||
final ShortestPathSolution solutionDijkstra = this.runAlgo(algoData);
|
||||
final ShortestPathSolution solutionBellman = new BellmanFordAlgorithm(algoData).doRun();
|
||||
|
||||
final Path pathDijkstra = solutionDijkstra.getPath();
|
||||
final Path pathBellman = solutionBellman.getPath();
|
||||
|
||||
assertEquals(pathDijkstra.getArcs().size(), pathBellman.getArcs().size());
|
||||
|
||||
for (int i=0; i<pathDijkstra.getArcs().size(); i++) {
|
||||
final Arc arcDijkstra = pathDijkstra.getArcs().get(i);
|
||||
final Node from1 = arcDijkstra.getOrigin();
|
||||
final Node to1 = arcDijkstra.getDestination();
|
||||
|
||||
final Arc arcBellman = pathBellman.getArcs().get(i);
|
||||
final Node from2 = arcBellman.getOrigin();
|
||||
final Node to2 = arcBellman.getDestination();
|
||||
|
||||
assertEquals(arcDijkstra.getLength(), arcBellman.getLength(), 0.0);
|
||||
assertEquals(from1, from2);
|
||||
assertEquals(to1, to2);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareCost() {
|
||||
Assume.assumeTrue(scenario.isFeasible);
|
||||
|
||||
final ShortestPathData algoData = new ShortestPathData(scenario.graph, scenario.origin, scenario.destination, scenario.arcInspector);
|
||||
final ShortestPathSolution solution = this.runAlgo(algoData);
|
||||
|
||||
final Path dijkstraPath = solution.getPath();
|
||||
double coutDijkstra = 0;
|
||||
for (Arc arc : dijkstraPath.getArcs()) coutDijkstra += scenario.arcInspector.getCost(arc);
|
||||
|
||||
// On doit comparer le cout de dijkstra (calculé au dessus) au cout du shortest path passant par les mêmes nodes.
|
||||
final List<Node> nodes = dijkstraPath.getArcs().stream().map(arc -> arc.getOrigin()).collect(Collectors.toList());
|
||||
if (!nodes.isEmpty()) nodes.add(dijkstraPath.getArcs().getLast().getDestination());
|
||||
final Path computedPath = Path.createShortestPathFromNodes(scenario.graph, nodes);
|
||||
double coutComputed = 0;
|
||||
for (Arc arc : computedPath.getArcs()) coutComputed += scenario.arcInspector.getCost(arc);
|
||||
|
||||
assertEquals(coutDijkstra, coutComputed, 0.0);
|
||||
}
|
||||
|
||||
// Tout sous chemin d'un PCC est un PCC
|
||||
@Test
|
||||
public void testConherence() {
|
||||
Assume.assumeTrue(scenario.isFeasible);
|
||||
|
||||
final ShortestPathData algoData = new ShortestPathData(scenario.graph, scenario.origin, scenario.destination, scenario.arcInspector);
|
||||
final ShortestPathSolution solution = this.runAlgo(algoData);
|
||||
final Path dijkstraPath = solution.getPath();
|
||||
|
||||
System.out.println("testCoherence()");
|
||||
if (dijkstraPath.getArcs().size() > 0) {
|
||||
System.out.println("OUI");
|
||||
Random random = new Random();
|
||||
for (int i=0; i<10; i++) {
|
||||
final int k = random.nextInt(1, dijkstraPath.getArcs().size()-1);
|
||||
final Node randomNode = dijkstraPath.getArcs().get(k).getOrigin();
|
||||
|
||||
final ShortestPathData algoDataSousChemin = new ShortestPathData(scenario.graph, scenario.origin, randomNode, scenario.arcInspector);
|
||||
final ShortestPathSolution solutionSousChemin = this.runAlgo(algoDataSousChemin);
|
||||
final Path dijkstraPathSousChemin = solutionSousChemin.getPath();
|
||||
|
||||
double coutDijkstraSousChemin = 0;
|
||||
for (Arc arc : dijkstraPathSousChemin.getArcs()) coutDijkstraSousChemin += scenario.arcInspector.getCost(arc);
|
||||
|
||||
double coutDijkstraPortion = 0;
|
||||
for (Arc arc : dijkstraPath.getArcs()) {
|
||||
coutDijkstraPortion += scenario.arcInspector.getCost(arc);
|
||||
// Si on arrive au noeud random sur le dijkstra de référence, on s'arrête pour comparer les couts du sous chemin
|
||||
if (arc.getDestination().equals(randomNode)) break;
|
||||
}
|
||||
|
||||
assertEquals(coutDijkstraSousChemin, coutDijkstraPortion, 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue