/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.opentripplanner.routing.algorithm; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import junit.framework.TestCase; import org.onebusaway.gtfs.model.AgencyAndId; import org.onebusaway.gtfs.model.Route; import org.opentripplanner.ConstantsForTests; import org.opentripplanner.common.model.T2; import org.opentripplanner.routing.core.RoutingRequest; import org.opentripplanner.routing.core.State; import org.opentripplanner.routing.edgetype.PatternHop; import org.opentripplanner.routing.edgetype.TransitBoardAlight; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graph.Vertex; import org.opentripplanner.routing.request.BannedStopSet; import org.opentripplanner.routing.spt.GraphPath; import org.opentripplanner.routing.spt.ShortestPathTree; import org.opentripplanner.util.TestUtils; public class TestBanning extends TestCase { GenericAStar aStar = new GenericAStar(); public void testBannedRoutes() { Graph graph = ConstantsForTests.getInstance().getPortlandGraph(); RoutingRequest options = new RoutingRequest(); Vertex start = graph.getVertex("TriMet_8371"); Vertex end = graph.getVertex("TriMet_8374"); options.dateTime = TestUtils.dateInSeconds("America/Los_Angeles", 2009, 11, 1, 12, 34, 25); // must set routing context _after_ options is fully configured (time) options.setRoutingContext(graph, start, end); ShortestPathTree spt = null; /* * The MAX Red, Blue, and Green lines all run along the same trackage between the stops 8374 and 8371. Together, they form the white line. No, * wait, that's light. They make a pretty good test case for banned routes, since if one is banned, you can always take another. */ String[][] maxLines = { { "MAX Red Line", null }, { "MAX Blue Line", null }, { "MAX Green Line", null }, { null, "90" }, { null, "100" }, { null, "200" } }; for (int i = 0; i < maxLines.length; ++i) { String lineName = maxLines[i][0]; String lineId = maxLines[i][1]; String routeSpecStr = "TriMet_" + (lineName != null ? lineName : "") + (lineId != null ? "_" + lineId : ""); options.setBannedRoutes(routeSpecStr); spt = aStar.getShortestPathTree(options); GraphPath path = spt.getPath(end, true); for (State s : path.states) { if (s.getBackEdge() instanceof PatternHop) { PatternHop e = (PatternHop) s.getBackEdge(); Route route = e.getPattern().getExemplar().getRoute(); assertFalse(options.bannedRoutes.matches(route)); boolean foundMaxLine = false; for (int j = 0; j < maxLines.length; ++j) { if (j != i) { if (e.getName().equals(maxLines[j][0])) { foundMaxLine = true; } } } assertTrue(foundMaxLine); } } } } public void testWholeBannedTrips() { doTestBannedTrips(false, 42); } public void testPartialBannedTrips() { doTestBannedTrips(true, 43); } /** * Test trip banning. We compute a set of shortest routes between two random stops in the Portland graph. We then ban, for each route, up to a * certain amount of trips used in this route, one by one, and recompute the path. The banned trips must not appear in the new computed route. * * This is using a seeded random generator to easily make a reproducible and arbitrary list * of start/end points and trip to ban. It allow for a (bit) more coverage than doing a * single hand-picked test only. * * @param partial True to test partial trip banning, false for complete trip * @param seed Value to use for random generator seed -- Keep the same value for consistency. */ public void doTestBannedTrips(boolean partial, int seed) { Graph graph = ConstantsForTests.getInstance().getPortlandGraph(); Random rand = new Random(seed); for (int i = 0; i < 20; i++) { RoutingRequest options = new RoutingRequest(); options.dateTime = TestUtils.dateInSeconds("America/Los_Angeles", 2009, 11, 1, 12, 34, 25); // Pick two random locations Vertex start = null; Vertex end = null; while (start == null) start = graph.getVertex("TriMet_" + rand.nextInt(10000)); while (end == null) end = graph.getVertex("TriMet_" + rand.nextInt(10000)); options.setRoutingContext(graph, start, end); ShortestPathTree spt = null; int n = rand.nextInt(5) + 3; for (int j = 0; j < n; j++) { spt = aStar.getShortestPathTree(options); GraphPath path = spt.getPath(end, true); if (path == null || spt == null) break; // No path found // List of used [trip,stop index] in the path Set<T2<AgencyAndId, BannedStopSet>> usedTripDefs = new HashSet<T2<AgencyAndId, BannedStopSet>>(); for (State s : path.states) { if (s.getBackEdge() instanceof TransitBoardAlight) { TransitBoardAlight tbae = (TransitBoardAlight) s.getBackEdge(); int boardingStopIndex = tbae.getStopIndex(); AgencyAndId tripId = s.getTripId(); BannedStopSet stopSet; if (partial) { stopSet = new BannedStopSet(); stopSet.add(boardingStopIndex); } else { stopSet = BannedStopSet.ALL; } if (tripId != null) usedTripDefs.add(new T2<AgencyAndId, BannedStopSet>(tripId, stopSet)); } } // Used trips should not contains a banned trip for (T2<AgencyAndId, BannedStopSet> usedTripDef : usedTripDefs) { BannedStopSet bannedStopSet = options.bannedTrips.get(usedTripDef.getFirst()); if (bannedStopSet != null) { for (Integer stopIndex : usedTripDef.getSecond()) { assertFalse(bannedStopSet.contains(stopIndex)); } } } if (usedTripDefs.size() == 0) break; // Not a transit trip, no sense to ban trip any longer // Pick a random used trip + stop set to ban List<T2<AgencyAndId, BannedStopSet>> usedTripDefsList = new ArrayList<T2<AgencyAndId, BannedStopSet>>( usedTripDefs); T2<AgencyAndId, BannedStopSet> tripDefToBan = usedTripDefsList.get(rand .nextInt(usedTripDefs.size())); options.bannedTrips.put(tripDefToBan.getFirst(), tripDefToBan.getSecond()); } options.bannedTrips.clear(); } } }