From 38f2974bd996564326eee263aa6894af7204c3c2 Mon Sep 17 00:00:00 2001 From: AngeHerman Date: Fri, 12 Apr 2024 11:49:51 +0200 Subject: [PATCH 1/5] Build csv added --- .../project/idfm/IDFMNetworkExtractor.java | 81 +++++++++++++++++++ .../itinerary/ItineraryCalculator.java | 4 +- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/u_paris/gla/project/idfm/IDFMNetworkExtractor.java b/src/main/java/fr/u_paris/gla/project/idfm/IDFMNetworkExtractor.java index 55e0bc2..7791003 100644 --- a/src/main/java/fr/u_paris/gla/project/idfm/IDFMNetworkExtractor.java +++ b/src/main/java/fr/u_paris/gla/project/idfm/IDFMNetworkExtractor.java @@ -10,6 +10,7 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; +import java.io.File; import java.text.MessageFormat; import java.util.*; import java.util.Map.Entry; @@ -46,6 +47,10 @@ public class IDFMNetworkExtractor { private static final int IDFM_STOPS_LON_INDEX = 6; private static final int IDFM_STOPS_LAT_INDEX = 7; + private static final String TRACE_FILE_NAME = "trace.csv"; + + private static final String HOURS_FILE_NAME = "hours.csv"; + // Magically chosen values /** * A number of stops on each line @@ -181,6 +186,82 @@ public class IDFMNetworkExtractor { } } + public static boolean checkFileExistence(String filePath) { + File file = new File(filePath); + if (file.exists()) { + LOGGER.severe(filePath+ " already exists."); + return true; + } else { + LOGGER.severe(filePath + " does not exist."); + return false; + } + } + + public static void builFiles() { + + if (checkFileExistence("./"+HOURS_FILE_NAME) && checkFileExistence("./"+TRACE_FILE_NAME)) { + LOGGER.severe("Files already exists."); + return; + } + + Map traces = new HashMap<>(); + try { + CSVTools.readCSVFromURL(TRACE_FILE_URL, + (String[] line) -> addLine(line, traces)); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Error while reading the line paths", e); + } + + List stops = new ArrayList<>(traces.size() * GUESS_STOPS_BY_LINE); + try { + CSVTools.readCSVFromURL(STOPS_FILE_URL, + (String[] line) -> addStop(line, traces, stops)); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, "Error while reading the stops", e); + } + + cleanTraces(traces); + + Map transports = new HashMap<>(); + CSVStreamProvider provider = new CSVStreamProvider(traces.values().iterator(), transports); + + // Write into args[0] + try { + CSVTools.writeCSVToFile(TRACE_FILE_NAME, Stream.iterate(provider.next(), + t -> provider.hasNext(), t -> provider.next())); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, e, + () -> MessageFormat.format("Could not write in file {0}", TRACE_FILE_NAME)); + } + + System.out.println("******************Building bifurcations ************************"); + long startTime = System.currentTimeMillis(); + + for (Transport entry : transports.values()) { + entry.buildBifurcationOptimzed(); + } + + long endTime = System.currentTimeMillis(); + long tempsPasse = endTime - startTime; + + long minutes = (tempsPasse / 1000) / 60; + long seconds = (tempsPasse / 1000) % 60; + long milliseconds = tempsPasse % 1000; + + System.out.println("Temps écoulé : " + minutes + " minutess, " + seconds + " secndes et " + milliseconds + " millis"); + + System.out.println("******************Fin Building bifurcations ************************"); + + CSVSchedulesProvider providerschedules = new CSVSchedulesProvider(transports.values().iterator()); + try { + CSVTools.writeCSVToFile(HOURS_FILE_NAME, Stream.iterate(providerschedules.next(), + t -> providerschedules.hasNext(), t -> providerschedules.next())); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, e, + () -> MessageFormat.format("Could not write in file {0}", HOURS_FILE_NAME)); + } + } + private static void cleanTraces(Map traces) { Set toRemove = new HashSet<>(); for (Entry traceEntry : traces.entrySet()) { diff --git a/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java b/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java index 5391c19..fcce253 100644 --- a/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java +++ b/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java @@ -94,7 +94,8 @@ public class ItineraryCalculator { Stop toStop = getOrCreateStop(nodes, tmp, line[IDFM_TRACE_TO_INDEX], line[IDFM_TRACE_TO_GPS_INDEX], line[IDFM_TRACE_ID_INDEX]); String[] timeString = line[IDFM_TRACE_TIME_INDEX].split(":"); - int time = Integer.parseInt(timeString[0]) * 60 + Integer.parseInt(timeString[1]); + String time0WithoutComma = timeString[0].replace(",", ""); + int time = Integer.parseInt(time0WithoutComma) * 60 + Integer.parseInt(timeString[1]); Connection connection = new Connection(toStop, line[IDFM_TRACE_ID_INDEX], Double.parseDouble(line[IDFM_TRACE_DISTANCE_INDEX]), time); @@ -106,6 +107,7 @@ public class ItineraryCalculator { LOGGER.severe("Invalid command line. Target file names are in the main file for now."); return; } + IDFMNetworkExtractor.builFiles(); try { HashSet nodes = new HashSet<>(); From 318a915b84423fa2d41930a26c8e2a87e449e10f Mon Sep 17 00:00:00 2001 From: HU helene Date: Mon, 15 Apr 2024 13:47:53 +0200 Subject: [PATCH 2/5] #16 Update priority queue --- .../java/fr/u_paris/gla/project/itinerary/Finder.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java b/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java index f91047d..5f837f2 100644 --- a/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java +++ b/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java @@ -52,6 +52,8 @@ public class Finder { if (!openSet.contains(neighbor)) { openSet.add(neighbor); + updatePriority(openSet, neighbor, fScore.get(neighbor)); + } else if (tentativeGScore >= gScore.get(neighbor)) { continue; // This is not a better path. } @@ -80,12 +82,16 @@ public class Finder { return totalPath; } + public void updatePriority(PriorityQueue openSet, Stop node, double newF) { + openSet.remove(node); + node.setF(newF); + openSet.add(node); + } + //TODO: public List findPath(double longitude, double latitude){ return null; } - } - From 37ced08d103f4b25642148cce39411e9191b8096 Mon Sep 17 00:00:00 2001 From: Francois Date: Mon, 15 Apr 2024 17:11:35 +0200 Subject: [PATCH 3/5] Schedule parser --- .../gla/project/itinerary/Connection.java | 26 ++++- .../itinerary/ItineraryCalculator.java | 98 ++++++++++++++++++- .../u_paris/gla/project/itinerary/Stop.java | 2 + 3 files changed, 121 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/u_paris/gla/project/itinerary/Connection.java b/src/main/java/fr/u_paris/gla/project/itinerary/Connection.java index 1cafbec..8bb0107 100644 --- a/src/main/java/fr/u_paris/gla/project/itinerary/Connection.java +++ b/src/main/java/fr/u_paris/gla/project/itinerary/Connection.java @@ -1,5 +1,7 @@ package fr.u_paris.gla.project.itinerary; +import java.util.ArrayList; + public class Connection{ // Destination of the connection between the two stops private final Stop stop; @@ -11,11 +13,21 @@ public class Connection{ private final int time; - public Connection(Stop stop, String lineName, double distance, int time){ + private final ArrayList schedules; + + private final int bifurcation; + + public Connection(Stop stop, String lineName, double distance, int time, int bifurcation){ this.stop = stop; this.lineName=lineName; this.distance = distance; this.time = time; + this.schedules = new ArrayList<>(); + this.bifurcation = bifurcation; + } + + public Connection(Stop stop, String lineName, double distance, int time){ + this(stop, lineName, distance, time, 0); } @@ -34,4 +46,16 @@ public class Connection{ public Stop getStop() { return stop; } + + public void addSchedule(int hours) { + this.schedules.add(hours); + } + + public ArrayList getSchedules() { + return this.schedules; + } + + public int getBifurcation() { + return this.bifurcation; + } } diff --git a/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java b/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java index fcce253..ca72f53 100644 --- a/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java +++ b/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java @@ -61,19 +61,23 @@ public class ItineraryCalculator { */ private static Stop getOrCreateStop(HashSet nodes, HashMap> tmp, String name, String gps, String lineId) { ArrayList stopList = tmp.get(name); + double[] coords = getCoords(gps); + // First we search by name, and then compare the coordinates since multiple stations can have the same name. A margin of error is necessary since stops can have multiple GPS coordinates if (stopList != null) { for(Stop stop : stopList) { - double[] coords = getCoords(gps); + double dist = GPS.distance(coords[0], coords[1], stop.getLatitude(), stop.getLongitude()); - if(dist < ERROR_MARGIN) { + if(dist == 0) { stop.addLine(lineId); return stop; } + if(dist < ERROR_MARGIN) { + + } } } - double[] coords = getCoords(gps); Stop newStop = new Stop(lineId, name, coords[0], coords[1]); nodes.add(newStop); stopList = stopList == null ? new ArrayList<>() : stopList; @@ -97,11 +101,94 @@ public class ItineraryCalculator { String time0WithoutComma = timeString[0].replace(",", ""); int time = Integer.parseInt(time0WithoutComma) * 60 + Integer.parseInt(timeString[1]); - Connection connection = new Connection(toStop, line[IDFM_TRACE_ID_INDEX], Double.parseDouble(line[IDFM_TRACE_DISTANCE_INDEX]), time); + Connection connection = new Connection(toStop, line[IDFM_TRACE_ID_INDEX], Double.parseDouble(line[IDFM_TRACE_DISTANCE_INDEX]), time, Integer.parseInt(line[IDFM_TRACE_DERIV_INDEX])); connections.computeIfAbsent(fromStop, k -> new HashSet<>()).add(connection); } + private static void addScheduleRec(Stop current, Stop previous, String line, ArrayList bifurcations, int time, HashMap> stopsHashSet, HashMap> connections, HashSet processed){ + time = time%86400; + //If the stop has already been processed, it is not reprocessed. + if(processed.contains(current)) {return;} + processed.add(current); + + Set neighborhood = connections.get(current); + if(neighborhood == null) {return;} + + + ArrayList directions = new ArrayList<>(); + for(Connection n : neighborhood) { + if(n.getLineName().equals(line) + && (previous == null || !n.getStop().getName().equals(previous.getName())) + ) { + directions.add(n); + } + } + + if(directions.size() == 0) {return;} + + Stop next_stop = null; + if(directions.size() > 1) { + int bifurcation = bifurcations.size() == 0 ? 0 : bifurcations.get(0); + if(bifurcations.size() > 0) {bifurcations.remove(0);} + for(Connection d : directions) { + if(d.getBifurcation() == bifurcation) { + next_stop = d.getStop(); + break; + } + } + if(next_stop == null) { + return; + } + } + else { + next_stop = directions.get(0).getStop(); + if(directions.get(0).getBifurcation() != 0) { + if(bifurcations.size() > 0 && directions.get(0).getBifurcation() == bifurcations.get(0)){ + bifurcations.remove(0); + } + } + } + + for(Connection n : neighborhood) { + if(n.getStop() == next_stop) { + n.addSchedule(time); + time += n.getTime(); + addScheduleRec(next_stop, current, line, bifurcations, time, stopsHashSet, connections, processed); + return; + } + } + } + + private static void addSchedule(String[] input, HashMap> stopsHashSet, HashMap> connections) { + + String line = input[0]; + + ArrayList bifurcations = new ArrayList<>(); + if(!input[1].equals("[]")) { + String[] b = input[1].substring(1, input[1].length()-1).split(","); + bifurcations = new ArrayList<>(); + for(String n : b){ + bifurcations.add(Integer.parseInt(n.trim())); + } + } + + String name = input[2]; + + String[] timeString = input[3].split(":"); + int time = Integer.parseInt(timeString[0]) * 3600 + Integer.parseInt(timeString[1])*60; + + + ArrayList stops = stopsHashSet.get(name); + if(stops == null) {return;} + + for(Stop stop : stops) { + if(stop.getLines().contains(line)) { + addScheduleRec(stop, null, line, bifurcations, time, stopsHashSet, connections, new HashSet<>()); + } + } + } + public static void main(String[] args){ if (args.length != 0) { LOGGER.severe("Invalid command line. Target file names are in the main file for now."); @@ -116,6 +203,9 @@ public class ItineraryCalculator { CSVTools.readCSVFromFile(TRACE_FILE_NAME, (String[] line) -> addLine(line, nodes, tmp, connections)); + CSVTools.readCSVFromFile(HOURS_FILE_NAME, + (String[] line) -> addSchedule(line, tmp, connections)); + Stop porteivry = tmp.get("Porte d'Ivry").get(0); Stop repu = tmp.get("République").get(0); diff --git a/src/main/java/fr/u_paris/gla/project/itinerary/Stop.java b/src/main/java/fr/u_paris/gla/project/itinerary/Stop.java index 98a2306..6d9169c 100644 --- a/src/main/java/fr/u_paris/gla/project/itinerary/Stop.java +++ b/src/main/java/fr/u_paris/gla/project/itinerary/Stop.java @@ -85,4 +85,6 @@ public class Stop implements GraphNode { public void addLine(String s){ lines.add(s); } + + public Set getLines() { return this.lines; } } From 48598bb896811fa150552ff4625cc14aeab7725b Mon Sep 17 00:00:00 2001 From: Abdoulbasti Date: Wed, 17 Apr 2024 11:23:48 +0200 Subject: [PATCH 4/5] Unit test bug fixed and add some units tests --- pom.xml | 14 +++- .../java/fr/u_paris/gla/project/AppTest.java | 2 +- .../fr/u_paris/gla/project/idfm/StopTest.java | 68 +++++++++++++++++++ .../gla/project/idfm/TransportTest.java | 64 +++++++++++++++++ .../gla/project/io/NetworkFormatTest.java | 16 ++--- .../gla/project/io/ScheduleFormatTest.java | 2 +- .../gla/project/utils/CSVToolsTest.java | 4 +- .../fr/u_paris/gla/project/utils/GPSTest.java | 8 +-- 8 files changed, 161 insertions(+), 17 deletions(-) create mode 100644 src/test/java/fr/u_paris/gla/project/idfm/StopTest.java create mode 100644 src/test/java/fr/u_paris/gla/project/idfm/TransportTest.java diff --git a/pom.xml b/pom.xml index 61d26c4..5c9b0da 100644 --- a/pom.xml +++ b/pom.xml @@ -31,7 +31,7 @@ org.json json - 20230618 + 20231013 @@ -67,6 +67,18 @@ + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + **/*Test.java + + true + + diff --git a/src/test/java/fr/u_paris/gla/project/AppTest.java b/src/test/java/fr/u_paris/gla/project/AppTest.java index 2351945..cdb42b4 100644 --- a/src/test/java/fr/u_paris/gla/project/AppTest.java +++ b/src/test/java/fr/u_paris/gla/project/AppTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test; class AppTest { /** Rigorous Test :-) */ @Test - void testPlaceholder() { + public void testPlaceholder() { assertTrue(true, "It should be true that true is true..."); } } diff --git a/src/test/java/fr/u_paris/gla/project/idfm/StopTest.java b/src/test/java/fr/u_paris/gla/project/idfm/StopTest.java new file mode 100644 index 0000000..6139466 --- /dev/null +++ b/src/test/java/fr/u_paris/gla/project/idfm/StopTest.java @@ -0,0 +1,68 @@ +package fr.u_paris.gla.project.idfm; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +public class StopTest { + + + @Test + public void testIsStopConnected() { + + Stop stop = new Stop("Stop1"); + BifStop bifStop1 = new BifStop(1, new Stop("Stop2")); + // Initially, no stops are connected + assertFalse(stop.isStopConnected("Stop2")); + + // Add a connected stop + stop.addConnectedStop(bifStop1); + + // Now, Stop2 should be connected + assertTrue(stop.isStopConnected("Stop2")); + } + + + @Test + public void testGetConnectedStop() { + + Stop stop = new Stop("Stop1"); + BifStop bifStop1 = new BifStop(1, new Stop("Stop2")); + BifStop bifStop2 = new BifStop(2, new Stop("Stop3")); + + // Add two connected stops + stop.addConnectedStop(bifStop1); + stop.addConnectedStop(bifStop2); + + // Retrieve the connected stops + BifStop retrievedStop1 = stop.getConnectedStop("Stop2"); + BifStop retrievedStop2 = stop.getConnectedStop("Stop3"); + + // Check if the correct stops were retrieved + assertEquals(bifStop1, retrievedStop1); + assertEquals(bifStop2, retrievedStop2); + } + + @Test + public void testAddConnectedStop() { + Stop stop = new Stop("Stop1"); + BifStop bifStop1 = new BifStop(1, new Stop("Stop2")); + + // Add a connected stop + stop.addConnectedStop(bifStop1); + + // Check if the stop was added + assertTrue(stop.isStopConnected("Stop2")); + } + + + @Test + public void testSHJH(){ + Stop stop = new Stop("Stop2323"); + BifStop bifStop1 = new BifStop(1, new Stop("Stop2323")); + + // Add a connected stop + stop.addConnectedStop(bifStop1); + + // Check if the stop was added + assertTrue(stop.isStopConnected("Stop2323")); + } +} \ No newline at end of file diff --git a/src/test/java/fr/u_paris/gla/project/idfm/TransportTest.java b/src/test/java/fr/u_paris/gla/project/idfm/TransportTest.java new file mode 100644 index 0000000..dec50d6 --- /dev/null +++ b/src/test/java/fr/u_paris/gla/project/idfm/TransportTest.java @@ -0,0 +1,64 @@ +package fr.u_paris.gla.project.idfm; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import java.util.AbstractMap.SimpleEntry; +import java.util.List; +import java.util.ArrayList; +import static org.junit.jupiter.api.Assertions.*; + +public class TransportTest { + + /*@Test + public void testRoadToLast() { + Transport transport = new Transport("Test Line", "Bus"); + transport.addStop("A", "B", 1); + transport.addStop("B", "C", 2); + transport.addStop("C", "D", 3); + TraceDescription td = new TraceDescription("A", "D", "A", "D"); + transport.descriptions.add(td); + + List visited = new ArrayList<>(); + List bifurcations = new ArrayList<>(); + SimpleEntry> result = transport.roadToLast("A", "D", visited, bifurcations); + assertFalse(result.getKey()); + assertEquals(List.of(1, 2, 3), result.getValue()); + }*/ + + /*@Test + public void testRoadToLastOptimized() { + SimpleEntry> result = transport.roadToLastOptimized("A", "D", new HashSet<>(), new ArrayList<>()); + assertTrue(result.getKey()); + assertEquals(List.of(1, 2, 3), result.getValue()); + }*/ + + @Test + public void testIsTerminus() { + Transport transport = new Transport("Test Line", "Bus"); + transport.addStop("A", "B", 1); + transport.addStop("B", "C", 2); + transport.addStop("C", "D", 3); + TraceDescription td = new TraceDescription("A", "D", "A", "D"); + transport.descriptions.add(td); + + assertTrue(transport.isTerminus("A")); + assertTrue(transport.isTerminus("D")); + assertFalse(transport.isTerminus("B")); + } + + @Test + public void testAddStop() { + Transport transport = new Transport("Test Line", "Bus"); + transport.addStop("A", "B", 1); + transport.addStop("B", "C", 2); + transport.addStop("C", "D", 3); + TraceDescription td = new TraceDescription("A", "D", "A", "D"); + transport.descriptions.add(td); + + transport.addStop("D", "E", 4); + assertTrue(transport.stopsMap.containsKey("E")); + assertEquals("E", transport.stopsMap.get("E").name); + assertTrue(transport.stopsMap.get("D").isStopConnected("E")); + } +} \ No newline at end of file diff --git a/src/test/java/fr/u_paris/gla/project/io/NetworkFormatTest.java b/src/test/java/fr/u_paris/gla/project/io/NetworkFormatTest.java index a46f12d..4422575 100644 --- a/src/test/java/fr/u_paris/gla/project/io/NetworkFormatTest.java +++ b/src/test/java/fr/u_paris/gla/project/io/NetworkFormatTest.java @@ -17,30 +17,30 @@ class NetworkFormatTest { NumberFormat GPS_test = NetworkFormat.getGPSFormatter(); @Test - void parseDurationEqual() { + public void testParseDurationEqual() { assertEquals(Duration.ZERO, NetworkFormat.parseDuration(t)); } @Test - void parseDurationTooBig() { + public void testParseDurationTooBig() { String y = "119:00"; assertThrows(DateTimeParseException.class, () -> NetworkFormat.parseDuration(y)); } @Test - void formatDuration() { + public void formatDuration() { assertEquals(t, NetworkFormat.formatDuration(Duration.ZERO)); } @Test - void parseThenFormatDuration(){ + public void parseThenFormatDuration(){ String t = "00:00"; assertEquals(t, NetworkFormat.formatDuration(NetworkFormat.parseDuration(t))); } @Test - void getGPSFormatterPos() { + public void getGPSFormatterPos() { double GPS_pos = 1.456489615649813; assertEquals(String.valueOf(GPS_pos), GPS_test.format(GPS_pos)); @@ -48,14 +48,14 @@ class NetworkFormatTest { } @Test - void getGPSFormatterNeg() { + public void getGPSFormatterNeg() { double GPS_neg = -1.456489615649813; assertEquals(String.valueOf(GPS_neg), GPS_test.format(GPS_neg)); } @Test - void getGPSFormatterNul() { + public void getGPSFormatterNul() { int GPS_nul = 0; assertEquals(String.valueOf(GPS_nul), GPS_test.format(GPS_nul)); @@ -63,7 +63,7 @@ class NetworkFormatTest { } @Test - void getGPSFormatterBig() { + public void getGPSFormatterBig() { String string_int = "4565156498156489"; String string_float = "5675747274674276474267479751262167"; BigDecimal GPS_big = new BigDecimal(string_int + "." + string_float); diff --git a/src/test/java/fr/u_paris/gla/project/io/ScheduleFormatTest.java b/src/test/java/fr/u_paris/gla/project/io/ScheduleFormatTest.java index f9eae35..152ffd9 100644 --- a/src/test/java/fr/u_paris/gla/project/io/ScheduleFormatTest.java +++ b/src/test/java/fr/u_paris/gla/project/io/ScheduleFormatTest.java @@ -21,7 +21,7 @@ class ScheduleFormatTest { } @Test - void getTimeFormatter() { + public void getTimeFormatter() { DateTimeFormatter formatter = ScheduleFormat.getTimeFormatter(); LocalDateTime date = LocalDateTime.now(); String test = date.format(formatter); diff --git a/src/test/java/fr/u_paris/gla/project/utils/CSVToolsTest.java b/src/test/java/fr/u_paris/gla/project/utils/CSVToolsTest.java index 949a97f..e40bca4 100644 --- a/src/test/java/fr/u_paris/gla/project/utils/CSVToolsTest.java +++ b/src/test/java/fr/u_paris/gla/project/utils/CSVToolsTest.java @@ -17,7 +17,7 @@ class CSVToolsTest { @Test - void readCSVFromURL_invalid() { + public void readCSVFromURL_invalid() { // TODO Fix the exception thrown /** assertThrows(IOException.class,() -> { @@ -31,7 +31,7 @@ class CSVToolsTest { } @Test - void readCSVFromURL_valid() { + public void testreadCSVFromURL_valid() { assertDoesNotThrow(() -> { Consumer test = s -> System.out.println(Arrays.toString(s)); CSVTools.readCSVFromURL("https://people.sc.fsu.edu/~jburkardt/data/csv/addresses.csv", diff --git a/src/test/java/fr/u_paris/gla/project/utils/GPSTest.java b/src/test/java/fr/u_paris/gla/project/utils/GPSTest.java index de63357..ed1dc45 100644 --- a/src/test/java/fr/u_paris/gla/project/utils/GPSTest.java +++ b/src/test/java/fr/u_paris/gla/project/utils/GPSTest.java @@ -8,7 +8,7 @@ class GPSTest { @Test - void distance_SameLat(){ + public void testDistance_SameLat(){ assertDoesNotThrow( () -> { GPS.distance(5, 3, 5, 11); @@ -17,7 +17,7 @@ class GPSTest { } @Test - void distance_SameLon(){ + public void distance_SameLon(){ assertDoesNotThrow( () -> { GPS.distance(5, 3, 7, 3); @@ -26,12 +26,12 @@ class GPSTest { } @Test - void distance_SamePoint() { + public void distance_SamePoint() { assertEquals(0.0, GPS.distance(5, 3, 5, 3) ); } @Test - void distance_NegativePoint(){ + public void distance_NegativePoint(){ assertNotEquals(0.0, GPS.distance(-5, 7, -13, 4)); } From 39c879bca1718e0675943e92b292728ecea952b2 Mon Sep 17 00:00:00 2001 From: Francois Date: Wed, 17 Apr 2024 14:52:03 +0200 Subject: [PATCH 5/5] Gestion des horaires dans l'algorithme A* --- .../gla/project/itinerary/Connection.java | 38 +++++++++++++++++++ .../u_paris/gla/project/itinerary/Finder.java | 28 ++++++++------ .../itinerary/ItineraryCalculator.java | 32 +++++++++++++--- 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/src/main/java/fr/u_paris/gla/project/itinerary/Connection.java b/src/main/java/fr/u_paris/gla/project/itinerary/Connection.java index 8bb0107..ed9dde6 100644 --- a/src/main/java/fr/u_paris/gla/project/itinerary/Connection.java +++ b/src/main/java/fr/u_paris/gla/project/itinerary/Connection.java @@ -1,6 +1,7 @@ package fr.u_paris.gla.project.itinerary; import java.util.ArrayList; +import java.util.Collections; public class Connection{ // Destination of the connection between the two stops @@ -9,8 +10,10 @@ public class Connection{ // The line used for this connection private final String lineName; + //Distance between the two stops private final double distance; + //Travel time between the two stops private final int time; private final ArrayList schedules; @@ -51,6 +54,10 @@ public class Connection{ this.schedules.add(hours); } + public void sortSchedule() { + Collections.sort(this.schedules); + } + public ArrayList getSchedules() { return this.schedules; } @@ -58,4 +65,35 @@ public class Connection{ public int getBifurcation() { return this.bifurcation; } + + public double getCost() { + return this.time; + } + + public double getNextTime(double currentTime) { + if(this.schedules.size() == 0) { + return currentTime; + } + + int i = 0; + while(i < this.schedules.size() && this.schedules.get(i) < currentTime) { + i++; + } + if(i < this.schedules.size()) { + return this.schedules.get(i); + } + return this.schedules.get(0); + } + + public double getCost(double currentTime) { + if(this.schedules.size() == 0) { + if(this.lineName.equals("WALK")) { + return this.time; + } + return this.time + 900; + } + double nextTime = this.getNextTime(currentTime); + if(nextTime < currentTime) { nextTime += 86400;} + return nextTime - currentTime + this.time; + } } diff --git a/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java b/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java index 5f837f2..1e557b3 100644 --- a/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java +++ b/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java @@ -9,6 +9,8 @@ public class Finder { } public List findPath(Stop startNode, Stop goalNode) { + double startTime = 43200; //12h + PriorityQueue openSet = new PriorityQueue<>(Comparator.comparingDouble(GraphNode::getF)); HashSet closedSet = new HashSet<>(); HashMap cameFrom = new HashMap<>(); @@ -21,16 +23,15 @@ public class Finder { fScore.put(node, Double.POSITIVE_INFINITY); } - // The cost of going from start to start is zero - gScore.put(startNode, 0.0); + // The cost of going from start to start is the start time + gScore.put(startNode, startTime); // For the first node, fScore = gScore + heuristic fScore.put(startNode, startNode.getHeuristicCost(goalNode)); openSet.add(startNode); while (!openSet.isEmpty()) { Stop current = openSet.poll(); - //System.out.println(current); - //System.out.println(graph.getConnections(current)); + double currentTime = gScore.get(current); if (current.equals(goalNode)) { return reconstructPath(cameFrom, current); @@ -42,19 +43,15 @@ public class Finder { continue; } - for (Connection connection : graph.getConnections(current) ) { + for (Connection connection : graph.getConnections(current)) { Stop neighbor = connection.getStop(); if (closedSet.contains(neighbor)) { continue; // Ignore the neighbor which is already evaluated. } - double tentativeGScore = gScore.get(current) + connection.getDistance(); + double tentativeGScore = currentTime + connection.getCost(currentTime); - if (!openSet.contains(neighbor)) { - openSet.add(neighbor); - updatePriority(openSet, neighbor, fScore.get(neighbor)); - - } else if (tentativeGScore >= gScore.get(neighbor)) { + if (tentativeGScore >= gScore.get(neighbor)) { continue; // This is not a better path. } @@ -62,7 +59,14 @@ public class Finder { cameFrom.put(neighbor, current); gScore.put(neighbor, tentativeGScore); fScore.put(neighbor, tentativeGScore + neighbor.getHeuristicCost(goalNode)); - neighbor.setF(fScore.get(neighbor)); + + if (!openSet.contains(neighbor)) { + neighbor.setF(fScore.get(neighbor)); + openSet.add(neighbor); + } + else { + updatePriority(openSet, neighbor, fScore.get(neighbor)); + } } } diff --git a/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java b/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java index ca72f53..f2ebe85 100644 --- a/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java +++ b/src/main/java/fr/u_paris/gla/project/itinerary/ItineraryCalculator.java @@ -38,6 +38,11 @@ public class ItineraryCalculator { private static final double ERROR_MARGIN = 1.; + //The time public vehicles spend at each stop in seconds. + private static final int STOP_TIME = 30; + + //Walking speed in m/s + private static final double WALK_SPEED = 1.; /** * Returns the coordinates from a String to a double array: @@ -59,11 +64,12 @@ public class ItineraryCalculator { * @param lineId the line the stop is on * @return the Stop object */ - private static Stop getOrCreateStop(HashSet nodes, HashMap> tmp, String name, String gps, String lineId) { + private static Stop getOrCreateStop(HashSet nodes, HashMap> tmp, String name, String gps, String lineId, HashMap> connections) { ArrayList stopList = tmp.get(name); double[] coords = getCoords(gps); // First we search by name, and then compare the coordinates since multiple stations can have the same name. A margin of error is necessary since stops can have multiple GPS coordinates + ArrayList lineChanges = new ArrayList<>(); if (stopList != null) { for(Stop stop : stopList) { @@ -73,7 +79,7 @@ public class ItineraryCalculator { return stop; } if(dist < ERROR_MARGIN) { - + lineChanges.add(stop); } } } @@ -83,6 +89,15 @@ public class ItineraryCalculator { stopList = stopList == null ? new ArrayList<>() : stopList; stopList.add(newStop); tmp.put(name, stopList); + for(Stop s : lineChanges) { + double dist = GPS.distance(coords[0], coords[1], s.getLatitude(), s.getLongitude()); + int time = (int) (dist*1000/WALK_SPEED); + Connection c1 = new Connection(s, "WALK", dist, time); + connections.computeIfAbsent(newStop, k -> new HashSet<>()).add(c1); + + Connection c2 = new Connection(newStop, "WALK", dist, time); + connections.computeIfAbsent(s, k -> new HashSet<>()).add(c2); + } return newStop; } @@ -94,8 +109,8 @@ public class ItineraryCalculator { * @param connections */ private static void addLine(String[] line, HashSet nodes, HashMap> tmp, HashMap> connections) { - Stop fromStop = getOrCreateStop(nodes, tmp, line[IDFM_TRACE_FROM_INDEX], line[IDFM_TRACE_FROM_GPS_INDEX], line[IDFM_TRACE_ID_INDEX]); - Stop toStop = getOrCreateStop(nodes, tmp, line[IDFM_TRACE_TO_INDEX], line[IDFM_TRACE_TO_GPS_INDEX], line[IDFM_TRACE_ID_INDEX]); + Stop fromStop = getOrCreateStop(nodes, tmp, line[IDFM_TRACE_FROM_INDEX], line[IDFM_TRACE_FROM_GPS_INDEX], line[IDFM_TRACE_ID_INDEX], connections); + Stop toStop = getOrCreateStop(nodes, tmp, line[IDFM_TRACE_TO_INDEX], line[IDFM_TRACE_TO_GPS_INDEX], line[IDFM_TRACE_ID_INDEX], connections); String[] timeString = line[IDFM_TRACE_TIME_INDEX].split(":"); String time0WithoutComma = timeString[0].replace(",", ""); @@ -176,7 +191,7 @@ public class ItineraryCalculator { String name = input[2]; String[] timeString = input[3].split(":"); - int time = Integer.parseInt(timeString[0]) * 3600 + Integer.parseInt(timeString[1])*60; + int time = Integer.parseInt(timeString[0]) * 3600 + Integer.parseInt(timeString[1])*60 + STOP_TIME; ArrayList stops = stopsHashSet.get(name); @@ -206,6 +221,12 @@ public class ItineraryCalculator { CSVTools.readCSVFromFile(HOURS_FILE_NAME, (String[] line) -> addSchedule(line, tmp, connections)); + for(Set set : connections.values()) { + for(Connection c : set) { + c.sortSchedule(); + } + } + Stop porteivry = tmp.get("Porte d'Ivry").get(0); Stop repu = tmp.get("République").get(0); @@ -224,7 +245,6 @@ public class ItineraryCalculator { Finder finder = new Finder(graph); List res = finder.findPath(porteivry, chatelet); - for (Stop element : res) { System.out.println(element); }