/** * Check if a {@linkplain TRSPTwoOptMove 2-opt move} is feasible for the given <code>tour</code> * * @param tour the base tour * @param move the {@link TRSPTwoOptMove} to be tested * @return <code>true</code> if applying <code>move</code> to the given <code>tour</code> will * result in a feasible tour */ @Override public boolean isTwoOptFeasible(ITRSPTour itour, TRSPTwoOptMove move) { if (!TRSPTour.class.isAssignableFrom(itour.getClass())) { TRSPLogging.getOptimizationLogger() .warn( String.format( "ToolsConstraint.isTwoOptFeasible: unsupported tour class (%s)", itour.getClass())); return true; } TRSPTour tour = (TRSPTour) itour; if (!tour.isMainDepotVisited() // The main depot is not visited, the tour is already feasible || tour.isMainDepotVisited( tour.getSucc(move.getFirst())) // The visit to the main depot is done before // the first // affected node || !tour.isMainDepotVisited(move.getSecond())) // The visit to the main depot is done // after the last affected node return true; // The main depot is visited between j and m TRSPTourIterator it = tour.iterator(move.getSecond()); // Start with node m and iterate backward int node = it.previous(); while (node != tour.getMainDepotId() && it.hasNext()) { if (!tour.getInstance().hasRequiredTools(tour.getTechnician().getID(), node)) // The technician does not have the required tools for this request return false; } // No incompatible request was found, the move is feasible return true; }