1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

add regret insertion and build infrastructure to simplify the creation of new insertion strategy

This commit is contained in:
oblonski 2014-11-22 12:34:54 +01:00
parent 54f1d8819e
commit 369877e9fc
5 changed files with 394 additions and 206 deletions

View file

@ -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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
import jsprit.core.algorithm.recreate.InsertionData.NoInsertionFound; 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.VehicleRoutingProblem;
import jsprit.core.problem.driver.Driver;
import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute; 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.LogManager;
import org.apache.logging.log4j.Logger; 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 * @author stefan schroeder
* *
*/ */
final class BestInsertion implements InsertionStrategy{ public final class BestInsertion extends AbstractInsertionStrategy{
class Insertion {
private final VehicleRoute route;
private final InsertionData insertionData;
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 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; private JobInsertionCostsCalculator bestInsertionCostCalculator;
public void setRandom(Random random) {
this.random = random;
}
public BestInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) { public BestInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) {
super(); super(vehicleRoutingProblem);
this.insertionsListeners = new InsertionListeners();
inserter = new Inserter(insertionsListeners, vehicleRoutingProblem);
bestInsertionCostCalculator = jobInsertionCalculator; bestInsertionCostCalculator = jobInsertionCalculator;
logger.info("initialise " + this); logger.info("initialise " + this);
} }
@ -97,8 +55,7 @@ final class BestInsertion implements InsertionStrategy{
} }
@Override @Override
public Collection<Job> insertJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) { public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
insertionsListeners.informInsertionStarts(vehicleRoutes,unassignedJobs);
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size()); List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs); List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
Collections.shuffle(unassignedJobList, random); Collections.shuffle(unassignedJobList, random);
@ -124,26 +81,9 @@ final class BestInsertion implements InsertionStrategy{
} }
} }
if(bestInsertion == null) badJobs.add(unassignedJob); 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; return badJobs;
} }
@Override
public void removeListener(InsertionListener insertionListener) {
insertionsListeners.removeListener(insertionListener);
}
@Override
public Collection<InsertionListener> getListeners() {
return Collections.unmodifiableCollection(insertionsListeners.getListeners());
}
@Override
public void addListener(InsertionListener insertionListener) {
insertionsListeners.addListener(insertionListener);
}
} }

View file

@ -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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * 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. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * 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. * 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 *
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -154,8 +152,7 @@ public class BestInsertionBuilder {
} }
else{ else{
bestInsertion = new BestInsertionConcurrent(jobInsertions,executor,nuOfThreads,vrp); bestInsertion = new BestInsertionConcurrent(jobInsertions,executor,nuOfThreads,vrp);
}
}
for(InsertionListener l : iListeners) bestInsertion.addListener(l); for(InsertionListener l : iListeners) bestInsertion.addListener(l);
return bestInsertion; return bestInsertion;
} }

View file

@ -153,6 +153,7 @@ class Inserter {
vehicleRoute.setVehicleAndDepartureTime(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime()); vehicleRoute.setVehicleAndDepartureTime(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
} }
jobInsertionHandler.handleJobInsertion(job, insertionData, vehicleRoute); jobInsertionHandler.handleJobInsertion(job, insertionData, vehicleRoute);
insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime()); insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime());
} }
} }

View file

@ -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 <http://www.gnu.org/licenses/>.
******************************************************************************/
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<InsertionListener> iListeners = new ArrayList<InsertionListener>();
List<PrioritizedVRAListener> algorithmListeners = new ArrayList<PrioritizedVRAListener>();
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;
}
}

View file

@ -17,8 +17,17 @@
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service; 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. * Insertion based on regret approach.
@ -31,8 +40,48 @@ import jsprit.core.problem.job.Service;
* @author stefan schroeder * @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. * 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 { 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 * @author schroeder
* *
*/ */
static class TimeWindowScorer implements ScoringFunction { public static class DefaultScorer implements ScoringFunction {
private double tw_scoringParam = - 0.1; private VehicleRoutingProblem vrp;
@Override private double tw_param = - 0.5;
public double score(Job job) {
double twStart = 0.0; private double depotDistance_param = + 0.1;
double twEnd = 0.0;
// if(job instanceof Shipment){ public DefaultScorer(VehicleRoutingProblem vrp) {
// twStart = ((Shipment) job).getDeliveryTW().getStart(); this.vrp = vrp;
// twEnd = ((Shipment) job).getDeliveryTW().getEnd(); }
// }
// else public void setTimeWindowParam(double tw_param){ this.tw_param = tw_param; }
if(job instanceof Service){
twStart = ((Service) job).getTimeWindow().getStart(); public void setDepotDistanceParam(double depotDistance_param){ this.depotDistance_param = depotDistance_param; }
twEnd = ((Service) job).getTimeWindow().getEnd();
} @Override
return (twEnd-twStart)*tw_scoringParam; 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 @Override
public String toString() { public String toString() {
return "[name=timeWindowScorer][scoringParam="+tw_scoringParam+"]"; return "[name=timeWindowScorer][scoringParam="+tw_param+"]";
} }
} }
public static RegretInsertion newInstance(RouteAlgorithm routeAlgorithm) { private static Logger logger = LogManager.getLogger(RegretInsertion.class);
return new RegretInsertion(routeAlgorithm);
}
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. * Sets the scoring function.
* *
* <p>By default, the this.TimeWindowScorer is used. * <p>By default, the this.TimeWindowScorer is used.
* *
* @param scoringFunction * @param scoringFunction to score
*/ */
public void setScoringFunction(ScoringFunction scoringFunction) { public void setScoringFunction(ScoringFunction scoringFunction) {
this.scoringFunction = scoringFunction; this.scoringFunction = scoringFunction;
} }
public RegretInsertion(RouteAlgorithm routeAlgorithm) { public RegretInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) {
super(); super(vehicleRoutingProblem);
this.routeAlgorithm = routeAlgorithm; this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
this.insertionCostsCalculator = jobInsertionCalculator;
this.vrp = vehicleRoutingProblem;
logger.info("initialise " + this); logger.info("initialise " + this);
} }
@ -113,9 +174,6 @@ public class RegretInsertion implements InsertionStrategy{
return "[name=regretInsertion][additionalScorer="+scoringFunction+"]"; return "[name=regretInsertion][additionalScorer="+scoringFunction+"]";
} }
public RouteAlgorithm getRouteAlgorithm(){
return routeAlgorithm;
}
/** /**
* Runs insertion. * Runs insertion.
@ -124,104 +182,100 @@ public class RegretInsertion implements InsertionStrategy{
* *
*/ */
@Override @Override
public void insertJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) { public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
List<Job> jobs = new ArrayList<Job>(unassignedJobs); List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
// informInsertionStarts(routes,unassignedJobs); List<Job> jobs = new ArrayList<Job>(unassignedJobs);
int inserted = 0;
while(!jobs.isEmpty()){
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
ScoredJob bestScoredJob = null;
double bestScore = -1*Double.MAX_VALUE;
VehicleRoute insertIn = null;
for(Job unassignedJob : unassignedJobList){ while (!jobs.isEmpty()) {
InsertionData best = null; List<Job> unassignedJobList = new ArrayList<Job>(jobs);
InsertionData secondBest = null; ScoredJob bestScoredJob = nextJob(routes, unassignedJobList);
VehicleRoute bestRoute = null; 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; private ScoredJob nextJob(Collection<VehicleRoute> routes, List<Job> unassignedJobList) {
for(VehicleRoute route : routes){ ScoredJob bestScoredJob = null;
if(secondBest != null){ double bestScore = -1 * Double.MAX_VALUE;
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);
} for (Job unassignedJob : unassignedJobList) {
else{ InsertionData best = null;
routeAlgorithm.insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(), bestScoredJob.getRoute()); InsertionData secondBest = null;
insertIn=bestScoredJob.getRoute(); VehicleRoute bestRoute = null;
assignedJob=bestScoredJob.getJob();
jobs.remove(bestScoredJob.getJob());
}
inserted++;
// informJobInserted(assignedJob, insertIn);
} 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){ if(best == null){
throw new IllegalStateException("cannot insert job " + unassignedJob.getId()); throw new IllegalStateException("cannot insert job " + unassignedJob.getId());
} }
double score;
if(secondBest == null){ 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<InsertionListener> getListeners() {
// TODO Auto-generated method stub
return null;
}
@Override
public void addListener(InsertionListener insertionListener) {
// TODO Auto-generated method stub
}
}
} }