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 HashMap<Integer, Set<Integer>> createVesselDepartureChromosome( HashMap<Integer, Set<Integer>> installationDepartureChromosome) { HashMap<Integer, Set<Integer>> individualVesselDeparturePatterns = new HashMap<Integer, Set<Integer>>(); Set<Integer> daysWithDeparture = getDaysWithDeparture( installationDepartureChromosome); // get all days that installations require a departure for (Vessel vessel : problemData .getVessels()) { // for each vessel, choose a random vessel pattern that fits with the // installationDepartureChromosome Set<Integer> randomVesselDeparturePattern = pickRandomVesselDeparturePattern(daysWithDeparture, individualVesselDeparturePatterns); if (randomVesselDeparturePattern == null) { // workaround until a smarter heuristic is created numberOfPatternRestarts++; return createVesselDepartureChromosome(installationDepartureChromosome); } individualVesselDeparturePatterns.put(vessel.getNumber(), randomVesselDeparturePattern); } if (isDepotConstraintViolated(individualVesselDeparturePatterns)) { numberOfDepotRestarts++; return createVesselDepartureChromosome(installationDepartureChromosome); } return individualVesselDeparturePatterns; }
private HashMap<Integer, Set<Integer>> createInstallationDepartureChromosome() { HashMap<Integer, Set<Integer>> individualInstallationDeparturePatterns = new HashMap<Integer, Set<Integer>>(); for (Installation installation : problemData .getCustomerInstallations()) { // for each installation, choose a random installation // pattern based on the frequency Set<Set<Integer>> possibleInstallationDeparturePatterns = problemData.getInstallationDeparturePatterns().get(installation.getFrequency()); Set<Integer> randomInstallationDeparturePattern = Utilities.pickRandomElementFromSet(possibleInstallationDeparturePatterns); individualInstallationDeparturePatterns.put( installation.getNumber(), randomInstallationDeparturePattern); } return individualInstallationDeparturePatterns; }
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; }
private HashMap<Integer, HashMap<Integer, ArrayList<Integer>>> createGiantTourChromosome( HashMap<Integer, Set<Integer>> installationDepartureChromosome, HashMap<Integer, Set<Integer>> vesselDepartureChromosome) { HashMap<Integer, Set<Integer>> reversedInstallationChromosome = Utilities.getReversedHashMap( installationDepartureChromosome); // the key is a period/day and the Set<Integer> is a // set of installation numbers HashMap<Integer, Set<Integer>> reversedVesselChromosome = Utilities.getReversedHashMap( vesselDepartureChromosome); // the key is a period/day, and the Set<Integer> is a set of // vessel numbers int nDays = problemData.getLengthOfPlanningPeriod(); int nVessels = problemData.getVessels().size(); // initializing HashMap<Integer, HashMap<Integer, ArrayList<Integer>>> giantTourChromosome = GenotypeHGS.generateEmptyGiantTourChromosome(nDays, nVessels); // allocating for (Integer day : reversedInstallationChromosome.keySet()) { Set<Integer> installationsToAllocate = reversedInstallationChromosome.get(day); Set<Integer> availableVessels = reversedVesselChromosome.get(day); HashMap<Integer, ArrayList<Integer>> vesselAllocations = giantTourChromosome.get(day); for (Integer installation : installationsToAllocate) { Integer randomVessel = Utilities.pickRandomElementFromSet(availableVessels); ArrayList<Integer> existingInstallations = vesselAllocations.get(randomVessel); existingInstallations.add(installation); vesselAllocations.put(randomVessel, existingInstallations); } giantTourChromosome.put(day, vesselAllocations); } // shuffle sequence of visits for (Integer day : giantTourChromosome.keySet()) { for (Integer vessel : giantTourChromosome.get(day).keySet()) { ArrayList<Integer> installationsToVisit = giantTourChromosome.get(day).get(vessel); Collections.shuffle(installationsToVisit); } } return giantTourChromosome; }
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 boolean isDepotConstraintViolated( HashMap<Integer, Set<Integer>> individualVesselDeparturePatterns) { HashMap<Integer, Integer> departureCount = new HashMap<Integer, Integer>(); for (int vesselNumber : individualVesselDeparturePatterns.keySet()) { Set<Integer> selectedPattern = individualVesselDeparturePatterns.get(vesselNumber); for (Integer day : selectedPattern) { Integer dayCount = departureCount.get(day); if (dayCount == null) { departureCount.put(day, 1); } else { departureCount.put(day, dayCount + 1); } } } HashMap<Integer, Integer> depotCapacity = problemData.getDepotCapacity(); for (Integer day : departureCount.keySet()) { if (departureCount.get(day) > depotCapacity.get(day)) { return true; } } return false; }