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:
parent
54f1d8819e
commit
369877e9fc
5 changed files with 394 additions and 206 deletions
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
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<Job> insertJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||
insertionsListeners.informInsertionStarts(vehicleRoutes,unassignedJobs);
|
||||
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
|
||||
List<Job> unassignedJobList = new ArrayList<Job>(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<InsertionListener> getListeners() {
|
||||
return Collections.unmodifiableCollection(insertionsListeners.getListeners());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(InsertionListener insertionListener) {
|
||||
insertionsListeners.addListener(insertionListener);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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.
|
||||
*
|
||||
* <p>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<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
||||
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||
// informInsertionStarts(routes,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;
|
||||
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
||||
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
|
||||
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||
|
||||
for(Job unassignedJob : unassignedJobList){
|
||||
InsertionData best = null;
|
||||
InsertionData secondBest = null;
|
||||
VehicleRoute bestRoute = null;
|
||||
while (!jobs.isEmpty()) {
|
||||
List<Job> unassignedJobList = new ArrayList<Job>(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<VehicleRoute> routes, List<Job> 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<InsertionListener> getListeners() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(InsertionListener insertionListener) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue