private Set<Integer> getPossibleNumberOfDepartures( Set<Integer> unvisitedDays, HashMap<Integer, Set<Integer>> individualVesselDeparturePatterns, int alreadyVisitedDaysAvailable) { int maxDeparturesInPattern = Collections.max( problemData .getVesselDeparturePatterns() .keySet()); // the maximum number of departures found in any vessel pattern int minimumNumberOfDepartures = Math.max( 0, maxDeparturesInPattern - alreadyVisitedDaysAvailable); // e.g. if the patterns have max 3 visits and only 1 // day that is already visited can be a part of the // pattern, the minimum pattern size is 2 (since // there are 2 unvisited days) Set<Integer> allNumberOfDepartures = problemData.getVesselDeparturePatterns().keySet(); Set<Integer> possibleNumberOfDepartures = new HashSet<Integer>(); for (Integer numberOfDepartures : allNumberOfDepartures) { if (numberOfDepartures >= minimumNumberOfDepartures) { possibleNumberOfDepartures.add(numberOfDepartures); } } return possibleNumberOfDepartures; }
private Set<Integer> pickRandomVesselDeparturePattern( Set<Integer> daysWithDeparture, HashMap<Integer, Set<Integer>> individualVesselDeparturePatterns) { Set<Integer> unvisitedDays = getUnvisitedDays( daysWithDeparture, individualVesselDeparturePatterns); // the set of days that installations require a // departure and no vessel depart on int alreadyVisitedDaysAvailable = getAlreadyVisitedDaysAvailable( individualVesselDeparturePatterns, unvisitedDays); // the number of days that already have visits that the vessel pattern // can contain Set<Integer> possibleNumberOfDepartures = getPossibleNumberOfDepartures( unvisitedDays, individualVesselDeparturePatterns, alreadyVisitedDaysAvailable); // the set of number of departures that a valid vessel // pattern can have, e.g. if it's the last vessel and // there are still 3 unvisited days, the vessel pattern // must have 3 depatures int unvisitedDaysThatNeedsVisit = Collections.min(possibleNumberOfDepartures); int numberOfVesselDepartures = Utilities.pickRandomElementFromSet( possibleNumberOfDepartures); // select a random number from the set of possible number // of departures Set<Set<Integer>> allPatternsForNumberOfDepartures = problemData.getVesselDeparturePatterns().get(numberOfVesselDepartures); Set<Set<Integer>> possibleVesselDeparturePatterns = getPossibleVesselPatterns( allPatternsForNumberOfDepartures, individualVesselDeparturePatterns, unvisitedDays, unvisitedDaysThatNeedsVisit); // get all vessel patterns with the selected number of // departures that visit enough of the unvisited // installations, e.g. if it's the last vessel the pattern // has to visit all unvisited installations if (possibleVesselDeparturePatterns.size() == 0) { // workaround until a smarter heuristic is fixed System.out.println("No possible patterns, start over!"); return null; } return Utilities.pickRandomElementFromSet(possibleVesselDeparturePatterns); }
private int getAlreadyVisitedDaysAvailable( HashMap<Integer, Set<Integer>> individualVesselDeparturePatterns, Set<Integer> unvisitedDays) { int vesselsLeft = problemData.getVessels().size() - individualVesselDeparturePatterns.keySet().size(); // number of unchartered vessels int maxDeparturesInPattern = Collections.max( problemData .getVesselDeparturePatterns() .keySet()); // the maximum number of departures found in any vessel pattern int alreadyVisitedDaysAvailable = (vesselsLeft * maxDeparturesInPattern - unvisitedDays .size()); // if there is 1 unchartered vessel and the patterns have maximum 3 // departures and there are 2 days without departures, at most 1*3 - 2 = 1 // day that already has a departure can be part of the new pattern return alreadyVisitedDaysAvailable; }