From 369877e9fc20d8b028461cbd4bbf7d2a74503e75 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Sat, 22 Nov 2014 12:34:54 +0100 Subject: [PATCH] add regret insertion and build infrastructure to simplify the creation of new insertion strategy --- .../algorithm/recreate/BestInsertion.java | 86 +---- .../recreate/BestInsertionBuilder.java | 21 +- .../core/algorithm/recreate/Inserter.java | 1 + .../algorithm/recreate/InsertionBuilder.java | 196 ++++++++++++ .../algorithm/recreate/RegretInsertion.java | 296 +++++++++++------- 5 files changed, 394 insertions(+), 206 deletions(-) create mode 100644 jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/BestInsertion.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/BestInsertion.java index 12dbb17d..b5915f5c 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/BestInsertion.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/BestInsertion.java @@ -1,34 +1,32 @@ /******************************************************************************* - * Copyright (C) 2013 Stefan Schroeder - * + * Copyright (C) 2014 Stefan Schroeder + * * This library 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 + * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . ******************************************************************************/ package jsprit.core.algorithm.recreate; import jsprit.core.algorithm.recreate.InsertionData.NoInsertionFound; -import jsprit.core.algorithm.recreate.listener.InsertionListener; -import jsprit.core.algorithm.recreate.listener.InsertionListeners; import jsprit.core.problem.VehicleRoutingProblem; -import jsprit.core.problem.driver.Driver; import jsprit.core.problem.job.Job; import jsprit.core.problem.solution.route.VehicleRoute; -import jsprit.core.problem.vehicle.Vehicle; -import jsprit.core.util.RandomNumberGeneration; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; @@ -39,54 +37,14 @@ import java.util.*; * @author stefan schroeder * */ -final class BestInsertion implements InsertionStrategy{ - - class Insertion { - - private final VehicleRoute route; - - private final InsertionData insertionData; +public final class BestInsertion extends AbstractInsertionStrategy{ - public Insertion(VehicleRoute vehicleRoute, InsertionData insertionData) { - super(); - this.route = vehicleRoute; - this.insertionData = insertionData; - } - - public VehicleRoute getRoute() { - return route; - } - - public InsertionData getInsertionData() { - return insertionData; - } - - } - private static Logger logger = LogManager.getLogger(BestInsertion.class); - private Random random = RandomNumberGeneration.getRandom(); - - private final static double NO_NEW_DEPARTURE_TIME_YET = -12345.12345; - - private final static Vehicle NO_NEW_VEHICLE_YET = null; - - private final static Driver NO_NEW_DRIVER_YET = null; - - private InsertionListeners insertionsListeners; - - private Inserter inserter; - private JobInsertionCostsCalculator bestInsertionCostCalculator; - public void setRandom(Random random) { - this.random = random; - } - public BestInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) { - super(); - this.insertionsListeners = new InsertionListeners(); - inserter = new Inserter(insertionsListeners, vehicleRoutingProblem); + super(vehicleRoutingProblem); bestInsertionCostCalculator = jobInsertionCalculator; logger.info("initialise " + this); } @@ -97,8 +55,7 @@ final class BestInsertion implements InsertionStrategy{ } @Override - public Collection insertJobs(Collection vehicleRoutes, Collection unassignedJobs) { - insertionsListeners.informInsertionStarts(vehicleRoutes,unassignedJobs); + public Collection insertUnassignedJobs(Collection vehicleRoutes, Collection unassignedJobs) { List badJobs = new ArrayList(unassignedJobs.size()); List unassignedJobList = new ArrayList(unassignedJobs); Collections.shuffle(unassignedJobList, random); @@ -124,26 +81,9 @@ final class BestInsertion implements InsertionStrategy{ } } if(bestInsertion == null) badJobs.add(unassignedJob); - else inserter.insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute()); + else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute()); } - insertionsListeners.informInsertionEndsListeners(vehicleRoutes); return badJobs; } - @Override - public void removeListener(InsertionListener insertionListener) { - insertionsListeners.removeListener(insertionListener); - } - - @Override - public Collection getListeners() { - return Collections.unmodifiableCollection(insertionsListeners.getListeners()); - } - - @Override - public void addListener(InsertionListener insertionListener) { - insertionsListeners.addListener(insertionListener); - - } - } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/BestInsertionBuilder.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/BestInsertionBuilder.java index f3cb95ca..c7c7d3b1 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/BestInsertionBuilder.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/BestInsertionBuilder.java @@ -1,20 +1,18 @@ /******************************************************************************* - * Copyright (c) 2014 Stefan Schroeder. - * + * Copyright (C) 2014 Stefan Schroeder + * * This library 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 + * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . - * - * Contributors: - * Stefan Schroeder - initial API and implementation ******************************************************************************/ package jsprit.core.algorithm.recreate; @@ -154,8 +152,7 @@ public class BestInsertionBuilder { } else{ bestInsertion = new BestInsertionConcurrent(jobInsertions,executor,nuOfThreads,vrp); - - } + } for(InsertionListener l : iListeners) bestInsertion.addListener(l); return bestInsertion; } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/Inserter.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/Inserter.java index 6b7b597b..cd052dc5 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/Inserter.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/Inserter.java @@ -153,6 +153,7 @@ class Inserter { vehicleRoute.setVehicleAndDepartureTime(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime()); } jobInsertionHandler.handleJobInsertion(job, insertionData, vehicleRoute); + insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime()); } } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java new file mode 100644 index 00000000..c9117119 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * Copyright (C) 2014 Stefan Schroeder + * + * This library 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.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + ******************************************************************************/ +package jsprit.core.algorithm.recreate; + +import jsprit.core.algorithm.listener.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener; +import jsprit.core.algorithm.recreate.listener.InsertionListener; +import jsprit.core.algorithm.state.StateManager; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.constraint.ConstraintManager; +import jsprit.core.problem.vehicle.VehicleFleetManager; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; + + +public class InsertionBuilder { + + public enum Strategy { + REGRET, BEST + } + + private VehicleRoutingProblem vrp; + + private StateManager stateManager; + + private boolean local = true; + + private ConstraintManager constraintManager; + + private VehicleFleetManager fleetManager; + + private double weightOfFixedCosts; + + private boolean considerFixedCosts = false; + + private ActivityInsertionCostsCalculator actInsertionCostsCalculator = null; + + private int forwaredLooking; + + private int memory; + + private ExecutorService executor; + + private int nuOfThreads; + + private double timeSlice; + + private int nNeighbors; + + private boolean timeScheduling=false; + + private boolean allowVehicleSwitch=true; + + private boolean addDefaultCostCalc=true; + + private Strategy strategy = Strategy.BEST; + + public InsertionBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager, ConstraintManager constraintManager) { + super(); + this.vrp = vrp; + this.stateManager = stateManager; + this.constraintManager = constraintManager; + this.fleetManager = vehicleFleetManager; + } + + public InsertionBuilder setInsertionStrategy(Strategy strategy){ + this.strategy = strategy; + return this; + } + + public InsertionBuilder setRouteLevel(int forwardLooking, int memory){ + local = false; + this.forwaredLooking = forwardLooking; + this.memory = memory; + return this; + } + + public InsertionBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalculation){ + local = false; + this.forwaredLooking = forwardLooking; + this.memory = memory; + this.addDefaultCostCalc = addDefaultMarginalCostCalculation; + return this; + } + + public InsertionBuilder setLocalLevel(){ + local = true; + return this; + } + + /** + * If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation + * is controlled by your custom soft constraints. + * + * @param addDefaultMarginalCostCalculation + * @return + */ + public InsertionBuilder setLocalLevel(boolean addDefaultMarginalCostCalculation){ + local = true; + addDefaultCostCalc = addDefaultMarginalCostCalculation; + return this; + } + + public InsertionBuilder considerFixedCosts(double weightOfFixedCosts){ + this.weightOfFixedCosts = weightOfFixedCosts; + this.considerFixedCosts = true; + return this; + } + + public InsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){ + this.actInsertionCostsCalculator = activityInsertionCostsCalculator; + return this; + } + + public InsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads){ + this.executor = executor; + this.nuOfThreads = nuOfThreads; + return this; + } + + + public InsertionStrategy build() { + List iListeners = new ArrayList(); + List algorithmListeners = new ArrayList(); + CalculatorBuilder calcBuilder = new CalculatorBuilder(iListeners, algorithmListeners); + if(local){ + calcBuilder.setLocalLevel(addDefaultCostCalc); + } + else { + calcBuilder.setRouteLevel(forwaredLooking, memory, addDefaultCostCalc); + } + calcBuilder.setConstraintManager(constraintManager); + calcBuilder.setStates(stateManager); + calcBuilder.setVehicleRoutingProblem(vrp); + calcBuilder.setVehicleFleetManager(fleetManager); + calcBuilder.setActivityInsertionCostsCalculator(actInsertionCostsCalculator); + if(considerFixedCosts) { + calcBuilder.considerFixedCosts(weightOfFixedCosts); + } + if(timeScheduling){ + calcBuilder.experimentalTimeScheduler(timeSlice, nNeighbors); + } + calcBuilder.setAllowVehicleSwitch(allowVehicleSwitch); + JobInsertionCostsCalculator costCalculator = calcBuilder.build(); + + InsertionStrategy insertion; + if(strategy.equals(Strategy.BEST)) { + if (executor == null) { + insertion = new BestInsertion(costCalculator, vrp); + } else { + insertion = new BestInsertionConcurrent(costCalculator, executor, nuOfThreads, vrp); + } + } + else if(strategy.equals(Strategy.REGRET)){ + insertion = new RegretInsertion(costCalculator, vrp); + } + else throw new IllegalStateException("you should never get here"); + for(InsertionListener l : iListeners) insertion.addListener(l); + return insertion; + } + + /** + * @deprecated this is experimental and can disappear. + * @param timeSlice the time slice + * @param nNeighbors number of neighbors + */ + @Deprecated + public void experimentalTimeScheduler(double timeSlice, int nNeighbors) { + this.timeSlice=timeSlice; + this.nNeighbors=nNeighbors; + timeScheduling=true; + } + + public void setAllowVehicleSwitch(boolean allowVehicleSwitch) { + this.allowVehicleSwitch = allowVehicleSwitch; + } + + + + +} diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java index 008b8784..640f86d1 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java @@ -17,8 +17,17 @@ package jsprit.core.algorithm.recreate; +import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Service; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.vehicle.Vehicle; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; /** * Insertion based on regret approach. @@ -31,8 +40,48 @@ import jsprit.core.problem.job.Service; * @author stefan schroeder * */ -public class RegretInsertion implements InsertionStrategy{ +public class RegretInsertion extends AbstractInsertionStrategy { + static class ScoredJob { + + private Job job; + + private double score; + + private InsertionData insertionData; + + private VehicleRoute route; + + private boolean newRoute; + + ScoredJob(Job job, double score, InsertionData insertionData, VehicleRoute route, boolean isNewRoute) { + this.job = job; + this.score = score; + this.insertionData = insertionData; + this.route = route; + this.newRoute = isNewRoute; + } + + public boolean isNewRoute() { + return newRoute; + } + + public Job getJob() { + return job; + } + + public double getScore() { + return score; + } + + public InsertionData getInsertionData() { + return insertionData; + } + + public VehicleRoute getRoute() { + return route; + } + } /** * Scorer to include other impacts on score such as time-window length or distance to depot. @@ -42,7 +91,7 @@ public class RegretInsertion implements InsertionStrategy{ */ static interface ScoringFunction { - public double score(Job job); + public double score(InsertionData best, Job job); } @@ -54,57 +103,69 @@ public class RegretInsertion implements InsertionStrategy{ * @author schroeder * */ - static class TimeWindowScorer implements ScoringFunction { + public static class DefaultScorer implements ScoringFunction { - private double tw_scoringParam = - 0.1; + private VehicleRoutingProblem vrp; - @Override - public double score(Job job) { - double twStart = 0.0; - double twEnd = 0.0; -// if(job instanceof Shipment){ -// twStart = ((Shipment) job).getDeliveryTW().getStart(); -// twEnd = ((Shipment) job).getDeliveryTW().getEnd(); -// } -// else - if(job instanceof Service){ - twStart = ((Service) job).getTimeWindow().getStart(); - twEnd = ((Service) job).getTimeWindow().getEnd(); - } - return (twEnd-twStart)*tw_scoringParam; - } + private double tw_param = - 0.5; + + private double depotDistance_param = + 0.1; + + public DefaultScorer(VehicleRoutingProblem vrp) { + this.vrp = vrp; + } + + public void setTimeWindowParam(double tw_param){ this.tw_param = tw_param; } + + public void setDepotDistanceParam(double depotDistance_param){ this.depotDistance_param = depotDistance_param; } + + @Override + public double score(InsertionData best, Job job) { + + double avgDepotDistance = getAvgDistance(best.getSelectedVehicle(),job); + + return Math.max(tw_param * (((Service)job).getTimeWindow().getEnd() - ((Service)job).getTimeWindow().getStart()),-100000) + + depotDistance_param * avgDepotDistance; + } + + private double getAvgDistance(Vehicle vehicle, Job job) { + double distance = vrp.getTransportCosts().getTransportCost(vehicle.getStartLocationId(),((Service)job).getLocationId(),0.,null,vehicle); + if(vehicle.isReturnToDepot() && !vehicle.getStartLocationId().equals(vehicle.getEndLocationId())){ + distance = (distance + vrp.getTransportCosts().getTransportCost(vehicle.getEndLocationId(),((Service)job).getLocationId(),0.,null,vehicle))/2.; + } + return distance; + } @Override public String toString() { - return "[name=timeWindowScorer][scoringParam="+tw_scoringParam+"]"; + return "[name=timeWindowScorer][scoringParam="+tw_param+"]"; } } - public static RegretInsertion newInstance(RouteAlgorithm routeAlgorithm) { - return new RegretInsertion(routeAlgorithm); - } + private static Logger logger = LogManager.getLogger(RegretInsertion.class); - private Logger logger = Logger.getLogger(RegretInsertion.class); + private ScoringFunction scoringFunction; - private RouteAlgorithm routeAlgorithm; + private JobInsertionCostsCalculator insertionCostsCalculator; - private ScoringFunction scoringFunction = new TimeWindowScorer(); /** * Sets the scoring function. * *

By default, the this.TimeWindowScorer is used. * - * @param scoringFunction + * @param scoringFunction to score */ public void setScoringFunction(ScoringFunction scoringFunction) { this.scoringFunction = scoringFunction; } - public RegretInsertion(RouteAlgorithm routeAlgorithm) { - super(); - this.routeAlgorithm = routeAlgorithm; + public RegretInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) { + super(vehicleRoutingProblem); + this.scoringFunction = new DefaultScorer(vehicleRoutingProblem); + this.insertionCostsCalculator = jobInsertionCalculator; + this.vrp = vehicleRoutingProblem; logger.info("initialise " + this); } @@ -113,9 +174,6 @@ public class RegretInsertion implements InsertionStrategy{ return "[name=regretInsertion][additionalScorer="+scoringFunction+"]"; } - public RouteAlgorithm getRouteAlgorithm(){ - return routeAlgorithm; - } /** * Runs insertion. @@ -124,104 +182,100 @@ public class RegretInsertion implements InsertionStrategy{ * */ @Override - public void insertJobs(Collection routes, Collection unassignedJobs) { - List jobs = new ArrayList(unassignedJobs); -// informInsertionStarts(routes,unassignedJobs); - int inserted = 0; - while(!jobs.isEmpty()){ - List unassignedJobList = new ArrayList(jobs); - ScoredJob bestScoredJob = null; - double bestScore = -1*Double.MAX_VALUE; - VehicleRoute insertIn = null; + public Collection insertUnassignedJobs(Collection routes, Collection unassignedJobs) { + List badJobs = new ArrayList(unassignedJobs.size()); + List jobs = new ArrayList(unassignedJobs); - for(Job unassignedJob : unassignedJobList){ - InsertionData best = null; - InsertionData secondBest = null; - VehicleRoute bestRoute = null; + while (!jobs.isEmpty()) { + List unassignedJobList = new ArrayList(jobs); + ScoredJob bestScoredJob = nextJob(routes, unassignedJobList); + Job handledJob; + if(bestScoredJob == null){ + handledJob = unassignedJobList.get(0); + badJobs.add(handledJob); + } + else { + if(bestScoredJob.isNewRoute()){ + routes.add(bestScoredJob.getRoute()); + } + insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(),bestScoredJob.getRoute()); + handledJob = bestScoredJob.getJob(); + } + jobs.remove(handledJob); + } + return badJobs; + } - double benchmark = Double.MAX_VALUE; - for(VehicleRoute route : routes){ - if(secondBest != null){ - benchmark = secondBest.getInsertionCost(); - } - InsertionData iData = routeAlgorithm.calculateBestInsertion(route, unassignedJob, benchmark); - if(iData instanceof NoInsertionFound) continue; - if(best == null){ - best = iData; - bestRoute = route; - } - else if(iData.getInsertionCost() < best.getInsertionCost()){ - secondBest = best; - best = iData; - bestRoute = route; - } - else if(secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())){ - secondBest = iData; - } - } - if(best == null){ - break; - } - double score = score(unassignedJob,best,secondBest); - if(score > bestScore){ - bestScoredJob = new ScoredJob(unassignedJob,score,best,bestRoute); - bestScore = score; - } - } - Job assignedJob; - if(bestScoredJob == null){ - Job job = unassignedJobList.get(0); - VehicleRoute newRoute = VehicleRoute.emptyRoute(); - InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, job, Double.MAX_VALUE); - if(bestI instanceof InsertionData.NoInsertionFound) throw new IllegalStateException("given the vehicles, could not create a valid solution"); - insertIn=newRoute; - assignedJob=job; - routeAlgorithm.insertJob(job,bestI,newRoute); - routes.add(newRoute); - jobs.remove(job); + private ScoredJob nextJob(Collection routes, List unassignedJobList) { + ScoredJob bestScoredJob = null; + double bestScore = -1 * Double.MAX_VALUE; - } - else{ - routeAlgorithm.insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(), bestScoredJob.getRoute()); - insertIn=bestScoredJob.getRoute(); - assignedJob=bestScoredJob.getJob(); - jobs.remove(bestScoredJob.getJob()); - } - inserted++; -// informJobInserted(assignedJob, insertIn); + for (Job unassignedJob : unassignedJobList) { + InsertionData best = null; + InsertionData secondBest = null; + VehicleRoute bestRoute = null; - } - } + double benchmark = Double.MAX_VALUE; + for (VehicleRoute route : routes) { + if (secondBest != null) { + benchmark = secondBest.getInsertionCost(); + } + InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark); + if (iData instanceof InsertionData.NoInsertionFound) continue; + if (best == null) { + best = iData; + bestRoute = route; + } else if (iData.getInsertionCost() < best.getInsertionCost()) { + secondBest = best; + best = iData; + bestRoute = route; + } else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) { + secondBest = iData; + } + } - private double score(Job unassignedJob, InsertionData best, InsertionData secondBest) { + VehicleRoute emptyRoute = VehicleRoute.emptyRoute(); + InsertionData iData = insertionCostsCalculator.getInsertionData(emptyRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark); + if (!(iData instanceof InsertionData.NoInsertionFound)) { +// iData = new InsertionData(iData.getInsertionCost()*1000.,iData.getPickupInsertionIndex(),iData.getDeliveryInsertionIndex(),iData.getSelectedVehicle(),iData.getSelectedDriver()); + if (best == null) { + best = iData; + bestRoute = emptyRoute; + } else if (iData.getInsertionCost() < best.getInsertionCost()) { + secondBest = best; + best = iData; + bestRoute = emptyRoute; + } else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) { + secondBest = iData; + } + } + + double score = score(unassignedJob, best, secondBest); + if (score > bestScore) { + if(bestRoute == emptyRoute){ + bestScoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, true); + } + else bestScoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, false); + bestScore = score; + } + } + return bestScoredJob; + } + + + private double score(Job unassignedJob, InsertionData best, InsertionData secondBest) { if(best == null){ throw new IllegalStateException("cannot insert job " + unassignedJob.getId()); } + double score; if(secondBest == null){ - return Double.MAX_VALUE; + score = best.getInsertionCost() + scoringFunction.score(best,unassignedJob); } - return (secondBest.getInsertionCost()-best.getInsertionCost()) + scoringFunction.score(unassignedJob); + else{ + score = (secondBest.getInsertionCost()-best.getInsertionCost()) + scoringFunction.score(best,unassignedJob); + } + return score; + } - } - - @Override - public void removeListener(InsertionListener insertionListener) { - // TODO Auto-generated method stub - - } - - @Override - public Collection getListeners() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void addListener(InsertionListener insertionListener) { - // TODO Auto-generated method stub - - } - -} }