mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
renaming of regret
This commit is contained in:
parent
bce6f1a9f5
commit
8af268b1dc
10 changed files with 447 additions and 474 deletions
|
|
@ -407,7 +407,7 @@ public class Jsprit {
|
||||||
final DefaultScorer scorer;
|
final DefaultScorer scorer;
|
||||||
|
|
||||||
if (es != null) {
|
if (es != null) {
|
||||||
RegretInsertionConcurrentSlow regretInsertion = (RegretInsertionConcurrentSlow) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
||||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||||
.setConcurrentMode(es, noThreads)
|
.setConcurrentMode(es, noThreads)
|
||||||
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
||||||
|
|
@ -418,7 +418,7 @@ public class Jsprit {
|
||||||
regretInsertion.setScoringFunction(scorer);
|
regretInsertion.setScoringFunction(scorer);
|
||||||
regret = regretInsertion;
|
regret = regretInsertion;
|
||||||
} else {
|
} else {
|
||||||
RegretInsertionSlow regretInsertion = (RegretInsertionSlow) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
||||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||||
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
|
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
|
||||||
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
||||||
|
|
|
||||||
|
|
@ -166,12 +166,12 @@ public class InsertionBuilder {
|
||||||
}
|
}
|
||||||
} else if (strategy.equals(Strategy.REGRET)) {
|
} else if (strategy.equals(Strategy.REGRET)) {
|
||||||
if (executor == null) {
|
if (executor == null) {
|
||||||
RegretInsertionSlow regret = new RegretInsertionSlow(costCalculator, vrp);
|
RegretInsertion regret = new RegretInsertion(costCalculator, vrp);
|
||||||
// regret.setSwitchAllowed(allowVehicleSwitch);
|
// regret.setSwitchAllowed(allowVehicleSwitch);
|
||||||
insertion = regret;
|
insertion = regret;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
RegretInsertionConcurrentSlow regret = new RegretInsertionConcurrentSlow(costCalculator, vrp, executor);
|
RegretInsertionConcurrent regret = new RegretInsertionConcurrent(costCalculator, vrp, executor);
|
||||||
// regret.setSwitchAllowed(allowVehicleSwitch);
|
// regret.setSwitchAllowed(allowVehicleSwitch);
|
||||||
insertion = regret;
|
insertion = regret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,13 @@ import jsprit.core.problem.VehicleRoutingProblem;
|
||||||
import jsprit.core.problem.job.Break;
|
import jsprit.core.problem.job.Break;
|
||||||
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.VehicleFleetManager;
|
|
||||||
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.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insertion based on regret approach.
|
* Insertion based on regret approach.
|
||||||
|
|
@ -39,29 +41,14 @@ import java.util.*;
|
||||||
*/
|
*/
|
||||||
public class RegretInsertion extends AbstractInsertionStrategy {
|
public class RegretInsertion extends AbstractInsertionStrategy {
|
||||||
|
|
||||||
private static Logger logger = LogManager.getLogger(RegretInsertion.class);
|
|
||||||
|
|
||||||
|
private static Logger logger = LogManager.getLogger(RegretInsertionFast.class);
|
||||||
|
|
||||||
private ScoringFunction scoringFunction;
|
private ScoringFunction scoringFunction;
|
||||||
|
|
||||||
private JobInsertionCostsCalculator insertionCostsCalculator;
|
private JobInsertionCostsCalculator insertionCostsCalculator;
|
||||||
|
|
||||||
private VehicleFleetManager fleetManager;
|
|
||||||
|
|
||||||
private Set<String> initialVehicleIds;
|
|
||||||
|
|
||||||
private boolean switchAllowed = true;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public RegretInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, VehicleFleetManager fleetManager) {
|
|
||||||
super(vehicleRoutingProblem);
|
|
||||||
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
|
|
||||||
this.insertionCostsCalculator = jobInsertionCalculator;
|
|
||||||
this.fleetManager = fleetManager;
|
|
||||||
this.vrp = vehicleRoutingProblem;
|
|
||||||
this.initialVehicleIds = getInitialVehicleIds(vehicleRoutingProblem);
|
|
||||||
logger.debug("initialise {}", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the scoring function.
|
* Sets the scoring function.
|
||||||
|
|
@ -74,16 +61,12 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
||||||
this.scoringFunction = scoringFunction;
|
this.scoringFunction = scoringFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSwitchAllowed(boolean switchAllowed) {
|
public RegretInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) {
|
||||||
this.switchAllowed = switchAllowed;
|
super(vehicleRoutingProblem);
|
||||||
}
|
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
|
||||||
|
this.insertionCostsCalculator = jobInsertionCalculator;
|
||||||
private Set<String> getInitialVehicleIds(VehicleRoutingProblem vehicleRoutingProblem) {
|
this.vrp = vehicleRoutingProblem;
|
||||||
Set<String> ids = new HashSet<String>();
|
logger.debug("initialise {}", this);
|
||||||
for(VehicleRoute r : vehicleRoutingProblem.getInitialVehicleRoutes()){
|
|
||||||
ids.add(r.getVehicle().getId());
|
|
||||||
}
|
|
||||||
return ids;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -105,7 +88,7 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
||||||
while (jobIterator.hasNext()){
|
while (jobIterator.hasNext()){
|
||||||
Job job = jobIterator.next();
|
Job job = jobIterator.next();
|
||||||
if(job instanceof Break){
|
if(job instanceof Break){
|
||||||
VehicleRoute route = InsertionDataUpdater.findRoute(routes, job);
|
VehicleRoute route = findRoute(routes,job);
|
||||||
if(route == null){
|
if(route == null){
|
||||||
badJobs.add(job);
|
badJobs.add(job);
|
||||||
}
|
}
|
||||||
|
|
@ -122,35 +105,17 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||||
TreeSet<VersionedInsertionData>[] priorityQueues = new TreeSet[vrp.getJobs().values().size() + 2];
|
|
||||||
VehicleRoute lastModified = null;
|
|
||||||
boolean firstRun = true;
|
|
||||||
int updateRound = 0;
|
|
||||||
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
|
|
||||||
while (!jobs.isEmpty()) {
|
while (!jobs.isEmpty()) {
|
||||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||||
List<Job> badJobList = new ArrayList<Job>();
|
List<Job> badJobList = new ArrayList<Job>();
|
||||||
if(!firstRun && lastModified == null) throw new IllegalStateException("fooo");
|
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||||
if(firstRun){
|
|
||||||
firstRun = false;
|
|
||||||
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound);
|
|
||||||
for(VehicleRoute r : routes) updates.put(r,updateRound);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, updateRound);
|
|
||||||
updates.put(lastModified,updateRound);
|
|
||||||
}
|
|
||||||
updateRound++;
|
|
||||||
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager,insertionCostsCalculator,scoringFunction,priorityQueues,updates,unassignedJobList,badJobList);
|
|
||||||
if (bestScoredJob != null) {
|
if (bestScoredJob != null) {
|
||||||
if (bestScoredJob.isNewRoute()) {
|
if (bestScoredJob.isNewRoute()) {
|
||||||
routes.add(bestScoredJob.getRoute());
|
routes.add(bestScoredJob.getRoute());
|
||||||
}
|
}
|
||||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||||
jobs.remove(bestScoredJob.getJob());
|
jobs.remove(bestScoredJob.getJob());
|
||||||
lastModified = bestScoredJob.getRoute();
|
|
||||||
}
|
}
|
||||||
else lastModified = null;
|
|
||||||
for (Job bad : badJobList) {
|
for (Job bad : badJobList) {
|
||||||
jobs.remove(bad);
|
jobs.remove(bad);
|
||||||
badJobs.add(bad);
|
badJobs.add(bad);
|
||||||
|
|
@ -159,15 +124,99 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
||||||
return badJobs;
|
return badJobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateInsertionData(TreeSet<VersionedInsertionData>[] priorityQueues, Collection<VehicleRoute> routes, List<Job> unassignedJobList, int updateRound) {
|
private VehicleRoute findRoute(Collection<VehicleRoute> routes, Job job) {
|
||||||
for (Job unassignedJob : unassignedJobList) {
|
for(VehicleRoute r : routes){
|
||||||
if(priorityQueues[unassignedJob.getIndex()] == null){
|
if(r.getVehicle().getBreak() == job) return r;
|
||||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
|
|
||||||
}
|
}
|
||||||
InsertionDataUpdater.update(switchAllowed, initialVehicleIds,fleetManager,insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes);
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<Job> badJobs) {
|
||||||
|
ScoredJob bestScoredJob = null;
|
||||||
|
for (Job unassignedJob : unassignedJobList) {
|
||||||
|
ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
|
||||||
|
if (scoredJob instanceof ScoredJob.BadJob) {
|
||||||
|
badJobs.add(unassignedJob);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (bestScoredJob == null) bestScoredJob = scoredJob;
|
||||||
|
else {
|
||||||
|
if (scoredJob.getScore() > bestScoredJob.getScore()) {
|
||||||
|
bestScoredJob = scoredJob;
|
||||||
|
} else if (scoredJob.getScore() == bestScoredJob.getScore()) {
|
||||||
|
if (scoredJob.getJob().getId().compareTo(bestScoredJob.getJob().getId()) <= 0) {
|
||||||
|
bestScoredJob = scoredJob;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestScoredJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ScoredJob getScoredJob(Collection<VehicleRoute> routes, Job unassignedJob, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction) {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best == null) {
|
||||||
|
return new ScoredJob.BadJob(unassignedJob);
|
||||||
|
}
|
||||||
|
double score = score(unassignedJob, best, secondBest, scoringFunction);
|
||||||
|
ScoredJob scoredJob;
|
||||||
|
if (bestRoute == emptyRoute) {
|
||||||
|
scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, true);
|
||||||
|
} else scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, false);
|
||||||
|
return scoredJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) {
|
||||||
|
if (best == null) {
|
||||||
|
throw new IllegalStateException("cannot insert job " + unassignedJob.getId());
|
||||||
|
}
|
||||||
|
double score;
|
||||||
|
if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob
|
||||||
|
//if only one vehicle, I want the job to be inserted with min iCosts
|
||||||
|
//if there are more vehicles, I want this job to be prioritized since there are no alternatives
|
||||||
|
score = Integer.MAX_VALUE - best.getInsertionCost() + scoringFunction.score(best, unassignedJob);
|
||||||
|
} else {
|
||||||
|
score = (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,14 @@ import jsprit.core.problem.VehicleRoutingProblem;
|
||||||
import jsprit.core.problem.job.Break;
|
import jsprit.core.problem.job.Break;
|
||||||
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.VehicleFleetManager;
|
|
||||||
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.concurrent.Callable;
|
import java.util.Collection;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.Iterator;
|
||||||
import java.util.concurrent.Future;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insertion based on regret approach.
|
* Insertion based on regret approach.
|
||||||
|
|
@ -43,20 +43,13 @@ import java.util.concurrent.Future;
|
||||||
public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
|
|
||||||
|
|
||||||
private static Logger logger = LogManager.getLogger(RegretInsertionConcurrent.class);
|
private static Logger logger = LogManager.getLogger(RegretInsertionConcurrentFast.class);
|
||||||
|
|
||||||
private ScoringFunction scoringFunction;
|
private ScoringFunction scoringFunction;
|
||||||
|
|
||||||
private final JobInsertionCostsCalculator insertionCostsCalculator;
|
private final JobInsertionCostsCalculator insertionCostsCalculator;
|
||||||
|
|
||||||
private final ExecutorService executor;
|
private final ExecutorCompletionService<ScoredJob> completionService;
|
||||||
|
|
||||||
private VehicleFleetManager fleetManager;
|
|
||||||
|
|
||||||
private Set<String> initialVehicleIds;
|
|
||||||
|
|
||||||
private boolean switchAllowed = true;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the scoring function.
|
* Sets the scoring function.
|
||||||
|
|
@ -69,14 +62,12 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
this.scoringFunction = scoringFunction;
|
this.scoringFunction = scoringFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RegretInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, ExecutorService executorService, VehicleFleetManager fleetManager) {
|
public RegretInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, ExecutorService executorService) {
|
||||||
super(vehicleRoutingProblem);
|
super(vehicleRoutingProblem);
|
||||||
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
|
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
|
||||||
this.insertionCostsCalculator = jobInsertionCalculator;
|
this.insertionCostsCalculator = jobInsertionCalculator;
|
||||||
this.vrp = vehicleRoutingProblem;
|
this.vrp = vehicleRoutingProblem;
|
||||||
this.executor = executorService;
|
completionService = new ExecutorCompletionService<ScoredJob>(executorService);
|
||||||
this.fleetManager = fleetManager;
|
|
||||||
this.initialVehicleIds = getInitialVehicleIds(vehicleRoutingProblem);
|
|
||||||
logger.debug("initialise " + this);
|
logger.debug("initialise " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,18 +76,6 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
|
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSwitchAllowed(boolean switchAllowed) {
|
|
||||||
this.switchAllowed = switchAllowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> getInitialVehicleIds(VehicleRoutingProblem vehicleRoutingProblem) {
|
|
||||||
Set<String> ids = new HashSet<String>();
|
|
||||||
for(VehicleRoute r : vehicleRoutingProblem.getInitialVehicleRoutes()){
|
|
||||||
ids.add(r.getVehicle().getId());
|
|
||||||
}
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs insertion.
|
* Runs insertion.
|
||||||
|
|
@ -113,7 +92,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
while (jobIterator.hasNext()){
|
while (jobIterator.hasNext()){
|
||||||
Job job = jobIterator.next();
|
Job job = jobIterator.next();
|
||||||
if(job instanceof Break){
|
if(job instanceof Break){
|
||||||
VehicleRoute route = InsertionDataUpdater.findRoute(routes, job);
|
VehicleRoute route = findRoute(routes,job);
|
||||||
if(route == null){
|
if(route == null){
|
||||||
badJobs.add(job);
|
badJobs.add(job);
|
||||||
}
|
}
|
||||||
|
|
@ -130,67 +109,72 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||||
TreeSet<VersionedInsertionData>[] priorityQueues = new TreeSet[vrp.getJobs().values().size() + 2];
|
|
||||||
VehicleRoute lastModified = null;
|
|
||||||
boolean firstRun = true;
|
|
||||||
int updateRound = 0;
|
|
||||||
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
|
|
||||||
while (!jobs.isEmpty()) {
|
while (!jobs.isEmpty()) {
|
||||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||||
List<Job> badJobList = new ArrayList<Job>();
|
List<Job> badJobList = new ArrayList<Job>();
|
||||||
if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
|
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||||
if(firstRun){
|
|
||||||
firstRun = false;
|
|
||||||
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound);
|
|
||||||
for(VehicleRoute r : routes) updates.put(r,updateRound);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, updateRound);
|
|
||||||
updates.put(lastModified,updateRound);
|
|
||||||
}
|
|
||||||
updateRound++;
|
|
||||||
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, scoringFunction, priorityQueues, updates, unassignedJobList, badJobList);
|
|
||||||
if (bestScoredJob != null) {
|
if (bestScoredJob != null) {
|
||||||
if (bestScoredJob.isNewRoute()) {
|
if (bestScoredJob.isNewRoute()) {
|
||||||
routes.add(bestScoredJob.getRoute());
|
routes.add(bestScoredJob.getRoute());
|
||||||
}
|
}
|
||||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||||
jobs.remove(bestScoredJob.getJob());
|
jobs.remove(bestScoredJob.getJob());
|
||||||
lastModified = bestScoredJob.getRoute();
|
|
||||||
}
|
}
|
||||||
else lastModified = null;
|
for (Job j : badJobList) {
|
||||||
for (Job bad : badJobList) {
|
jobs.remove(j);
|
||||||
jobs.remove(bad);
|
badJobs.add(j);
|
||||||
badJobs.add(bad);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return badJobs;
|
return badJobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateInsertionData(final TreeSet<VersionedInsertionData>[] priorityQueues, final Collection<VehicleRoute> routes, List<Job> unassignedJobList, final int updateRound) {
|
private ScoredJob nextJob(final Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<Job> badJobList) {
|
||||||
List<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>();
|
ScoredJob bestScoredJob = null;
|
||||||
|
|
||||||
for (final Job unassignedJob : unassignedJobList) {
|
for (final Job unassignedJob : unassignedJobList) {
|
||||||
if(priorityQueues[unassignedJob.getIndex()] == null){
|
completionService.submit(new Callable<ScoredJob>() {
|
||||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
|
|
||||||
}
|
|
||||||
final TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[unassignedJob.getIndex()];
|
|
||||||
tasks.add(new Callable<Boolean>() {
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean call() throws Exception {
|
public ScoredJob call() throws Exception {
|
||||||
return InsertionDataUpdater.update(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, priorityQueue, updateRound, unassignedJob, routes);
|
return RegretInsertion.getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<Future<Boolean>> futures = executor.invokeAll(tasks);
|
for (int i = 0; i < unassignedJobList.size(); i++) {
|
||||||
|
Future<ScoredJob> fsj = completionService.take();
|
||||||
|
ScoredJob sJob = fsj.get();
|
||||||
|
if (sJob instanceof ScoredJob.BadJob) {
|
||||||
|
badJobList.add(sJob.getJob());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (bestScoredJob == null) {
|
||||||
|
bestScoredJob = sJob;
|
||||||
|
} else if (sJob.getScore() > bestScoredJob.getScore()) {
|
||||||
|
bestScoredJob = sJob;
|
||||||
|
} else if (sJob.getScore() == bestScoredJob.getScore()) {
|
||||||
|
if (sJob.getJob().getId().compareTo(bestScoredJob.getJob().getId()) <= 0) {
|
||||||
|
bestScoredJob = sJob;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
|
} catch (ExecutionException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bestScoredJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private VehicleRoute findRoute(Collection<VehicleRoute> routes, Job job) {
|
||||||
|
for(VehicleRoute r : routes){
|
||||||
|
if(r.getVehicle().getBreak() == job) return r;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.problem.VehicleRoutingProblem;
|
||||||
|
import jsprit.core.problem.job.Break;
|
||||||
|
import jsprit.core.problem.job.Job;
|
||||||
|
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
|
import jsprit.core.problem.vehicle.VehicleFleetManager;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insertion based on regret approach.
|
||||||
|
* <p/>
|
||||||
|
* <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference
|
||||||
|
* between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction.
|
||||||
|
* The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this
|
||||||
|
* customer immediatedly. If difference is not that high, it might not impact solution if this customer is inserted later.
|
||||||
|
*
|
||||||
|
* @author stefan schroeder
|
||||||
|
*/
|
||||||
|
public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
||||||
|
|
||||||
|
|
||||||
|
private static Logger logger = LogManager.getLogger(RegretInsertionConcurrentFast.class);
|
||||||
|
|
||||||
|
private ScoringFunction scoringFunction;
|
||||||
|
|
||||||
|
private final JobInsertionCostsCalculator insertionCostsCalculator;
|
||||||
|
|
||||||
|
private final ExecutorService executor;
|
||||||
|
|
||||||
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
|
private Set<String> initialVehicleIds;
|
||||||
|
|
||||||
|
private boolean switchAllowed = true;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scoring function.
|
||||||
|
* <p/>
|
||||||
|
* <p>By default, the this.TimeWindowScorer is used.
|
||||||
|
*
|
||||||
|
* @param scoringFunction to score
|
||||||
|
*/
|
||||||
|
public void setScoringFunction(ScoringFunction scoringFunction) {
|
||||||
|
this.scoringFunction = scoringFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegretInsertionConcurrentFast(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, ExecutorService executorService, VehicleFleetManager fleetManager) {
|
||||||
|
super(vehicleRoutingProblem);
|
||||||
|
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
|
||||||
|
this.insertionCostsCalculator = jobInsertionCalculator;
|
||||||
|
this.vrp = vehicleRoutingProblem;
|
||||||
|
this.executor = executorService;
|
||||||
|
this.fleetManager = fleetManager;
|
||||||
|
this.initialVehicleIds = getInitialVehicleIds(vehicleRoutingProblem);
|
||||||
|
logger.debug("initialise " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSwitchAllowed(boolean switchAllowed) {
|
||||||
|
this.switchAllowed = switchAllowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getInitialVehicleIds(VehicleRoutingProblem vehicleRoutingProblem) {
|
||||||
|
Set<String> ids = new HashSet<String>();
|
||||||
|
for(VehicleRoute r : vehicleRoutingProblem.getInitialVehicleRoutes()){
|
||||||
|
ids.add(r.getVehicle().getId());
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs insertion.
|
||||||
|
* <p/>
|
||||||
|
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
|
||||||
|
*
|
||||||
|
* @throws java.lang.RuntimeException if smth went wrong with thread execution
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
||||||
|
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
|
||||||
|
|
||||||
|
Iterator<Job> jobIterator = unassignedJobs.iterator();
|
||||||
|
while (jobIterator.hasNext()){
|
||||||
|
Job job = jobIterator.next();
|
||||||
|
if(job instanceof Break){
|
||||||
|
VehicleRoute route = InsertionDataUpdater.findRoute(routes, job);
|
||||||
|
if(route == null){
|
||||||
|
badJobs.add(job);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
|
||||||
|
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||||
|
badJobs.add(job);
|
||||||
|
} else {
|
||||||
|
insertJob(job, iData, route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jobIterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||||
|
TreeSet<VersionedInsertionData>[] priorityQueues = new TreeSet[vrp.getJobs().values().size() + 2];
|
||||||
|
VehicleRoute lastModified = null;
|
||||||
|
boolean firstRun = true;
|
||||||
|
int updateRound = 0;
|
||||||
|
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
|
||||||
|
while (!jobs.isEmpty()) {
|
||||||
|
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||||
|
List<Job> badJobList = new ArrayList<Job>();
|
||||||
|
if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
|
||||||
|
if(firstRun){
|
||||||
|
firstRun = false;
|
||||||
|
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound);
|
||||||
|
for(VehicleRoute r : routes) updates.put(r,updateRound);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, updateRound);
|
||||||
|
updates.put(lastModified,updateRound);
|
||||||
|
}
|
||||||
|
updateRound++;
|
||||||
|
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, scoringFunction, priorityQueues, updates, unassignedJobList, badJobList);
|
||||||
|
if (bestScoredJob != null) {
|
||||||
|
if (bestScoredJob.isNewRoute()) {
|
||||||
|
routes.add(bestScoredJob.getRoute());
|
||||||
|
}
|
||||||
|
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||||
|
jobs.remove(bestScoredJob.getJob());
|
||||||
|
lastModified = bestScoredJob.getRoute();
|
||||||
|
}
|
||||||
|
else lastModified = null;
|
||||||
|
for (Job bad : badJobList) {
|
||||||
|
jobs.remove(bad);
|
||||||
|
badJobs.add(bad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return badJobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateInsertionData(final TreeSet<VersionedInsertionData>[] priorityQueues, final Collection<VehicleRoute> routes, List<Job> unassignedJobList, final int updateRound) {
|
||||||
|
List<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>();
|
||||||
|
for (final Job unassignedJob : unassignedJobList) {
|
||||||
|
if(priorityQueues[unassignedJob.getIndex()] == null){
|
||||||
|
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
|
||||||
|
}
|
||||||
|
final TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[unassignedJob.getIndex()];
|
||||||
|
tasks.add(new Callable<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public Boolean call() throws Exception {
|
||||||
|
return InsertionDataUpdater.update(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, priorityQueue, updateRound, unassignedJob, routes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<Future<Boolean>> futures = executor.invokeAll(tasks);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -21,14 +21,11 @@ import jsprit.core.problem.VehicleRoutingProblem;
|
||||||
import jsprit.core.problem.job.Break;
|
import jsprit.core.problem.job.Break;
|
||||||
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.VehicleFleetManager;
|
||||||
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.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insertion based on regret approach.
|
* Insertion based on regret approach.
|
||||||
|
|
@ -40,16 +37,31 @@ import java.util.concurrent.*;
|
||||||
*
|
*
|
||||||
* @author stefan schroeder
|
* @author stefan schroeder
|
||||||
*/
|
*/
|
||||||
public class RegretInsertionConcurrentSlow extends AbstractInsertionStrategy {
|
public class RegretInsertionFast extends AbstractInsertionStrategy {
|
||||||
|
|
||||||
|
private static Logger logger = LogManager.getLogger(RegretInsertionFast.class);
|
||||||
private static Logger logger = LogManager.getLogger(RegretInsertionConcurrent.class);
|
|
||||||
|
|
||||||
private ScoringFunction scoringFunction;
|
private ScoringFunction scoringFunction;
|
||||||
|
|
||||||
private final JobInsertionCostsCalculator insertionCostsCalculator;
|
private JobInsertionCostsCalculator insertionCostsCalculator;
|
||||||
|
|
||||||
private final ExecutorCompletionService<ScoredJob> completionService;
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
|
private Set<String> initialVehicleIds;
|
||||||
|
|
||||||
|
private boolean switchAllowed = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public RegretInsertionFast(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, VehicleFleetManager fleetManager) {
|
||||||
|
super(vehicleRoutingProblem);
|
||||||
|
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
|
||||||
|
this.insertionCostsCalculator = jobInsertionCalculator;
|
||||||
|
this.fleetManager = fleetManager;
|
||||||
|
this.vrp = vehicleRoutingProblem;
|
||||||
|
this.initialVehicleIds = getInitialVehicleIds(vehicleRoutingProblem);
|
||||||
|
logger.debug("initialise {}", this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the scoring function.
|
* Sets the scoring function.
|
||||||
|
|
@ -62,13 +74,16 @@ public class RegretInsertionConcurrentSlow extends AbstractInsertionStrategy {
|
||||||
this.scoringFunction = scoringFunction;
|
this.scoringFunction = scoringFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RegretInsertionConcurrentSlow(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, ExecutorService executorService) {
|
public void setSwitchAllowed(boolean switchAllowed) {
|
||||||
super(vehicleRoutingProblem);
|
this.switchAllowed = switchAllowed;
|
||||||
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
|
}
|
||||||
this.insertionCostsCalculator = jobInsertionCalculator;
|
|
||||||
this.vrp = vehicleRoutingProblem;
|
private Set<String> getInitialVehicleIds(VehicleRoutingProblem vehicleRoutingProblem) {
|
||||||
completionService = new ExecutorCompletionService<ScoredJob>(executorService);
|
Set<String> ids = new HashSet<String>();
|
||||||
logger.debug("initialise " + this);
|
for(VehicleRoute r : vehicleRoutingProblem.getInitialVehicleRoutes()){
|
||||||
|
ids.add(r.getVehicle().getId());
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -81,8 +96,6 @@ public class RegretInsertionConcurrentSlow extends AbstractInsertionStrategy {
|
||||||
* Runs insertion.
|
* Runs insertion.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
|
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
|
||||||
*
|
|
||||||
* @throws java.lang.RuntimeException if smth went wrong with thread execution
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
||||||
|
|
@ -92,7 +105,7 @@ public class RegretInsertionConcurrentSlow extends AbstractInsertionStrategy {
|
||||||
while (jobIterator.hasNext()){
|
while (jobIterator.hasNext()){
|
||||||
Job job = jobIterator.next();
|
Job job = jobIterator.next();
|
||||||
if(job instanceof Break){
|
if(job instanceof Break){
|
||||||
VehicleRoute route = findRoute(routes,job);
|
VehicleRoute route = InsertionDataUpdater.findRoute(routes, job);
|
||||||
if(route == null){
|
if(route == null){
|
||||||
badJobs.add(job);
|
badJobs.add(job);
|
||||||
}
|
}
|
||||||
|
|
@ -109,72 +122,52 @@ public class RegretInsertionConcurrentSlow extends AbstractInsertionStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||||
|
TreeSet<VersionedInsertionData>[] priorityQueues = new TreeSet[vrp.getJobs().values().size() + 2];
|
||||||
|
VehicleRoute lastModified = null;
|
||||||
|
boolean firstRun = true;
|
||||||
|
int updateRound = 0;
|
||||||
|
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
|
||||||
while (!jobs.isEmpty()) {
|
while (!jobs.isEmpty()) {
|
||||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||||
List<Job> badJobList = new ArrayList<Job>();
|
List<Job> badJobList = new ArrayList<Job>();
|
||||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
if(!firstRun && lastModified == null) throw new IllegalStateException("fooo");
|
||||||
|
if(firstRun){
|
||||||
|
firstRun = false;
|
||||||
|
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound);
|
||||||
|
for(VehicleRoute r : routes) updates.put(r,updateRound);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, updateRound);
|
||||||
|
updates.put(lastModified,updateRound);
|
||||||
|
}
|
||||||
|
updateRound++;
|
||||||
|
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager,insertionCostsCalculator,scoringFunction,priorityQueues,updates,unassignedJobList,badJobList);
|
||||||
if (bestScoredJob != null) {
|
if (bestScoredJob != null) {
|
||||||
if (bestScoredJob.isNewRoute()) {
|
if (bestScoredJob.isNewRoute()) {
|
||||||
routes.add(bestScoredJob.getRoute());
|
routes.add(bestScoredJob.getRoute());
|
||||||
}
|
}
|
||||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||||
jobs.remove(bestScoredJob.getJob());
|
jobs.remove(bestScoredJob.getJob());
|
||||||
|
lastModified = bestScoredJob.getRoute();
|
||||||
}
|
}
|
||||||
for (Job j : badJobList) {
|
else lastModified = null;
|
||||||
jobs.remove(j);
|
for (Job bad : badJobList) {
|
||||||
badJobs.add(j);
|
jobs.remove(bad);
|
||||||
|
badJobs.add(bad);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return badJobs;
|
return badJobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScoredJob nextJob(final Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<Job> badJobList) {
|
private void updateInsertionData(TreeSet<VersionedInsertionData>[] priorityQueues, Collection<VehicleRoute> routes, List<Job> unassignedJobList, int updateRound) {
|
||||||
ScoredJob bestScoredJob = null;
|
for (Job unassignedJob : unassignedJobList) {
|
||||||
|
if(priorityQueues[unassignedJob.getIndex()] == null){
|
||||||
for (final Job unassignedJob : unassignedJobList) {
|
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
|
||||||
completionService.submit(new Callable<ScoredJob>() {
|
}
|
||||||
|
InsertionDataUpdater.update(switchAllowed, initialVehicleIds,fleetManager,insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes);
|
||||||
@Override
|
}
|
||||||
public ScoredJob call() throws Exception {
|
|
||||||
return RegretInsertionSlow.getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (int i = 0; i < unassignedJobList.size(); i++) {
|
|
||||||
Future<ScoredJob> fsj = completionService.take();
|
|
||||||
ScoredJob sJob = fsj.get();
|
|
||||||
if (sJob instanceof ScoredJob.BadJob) {
|
|
||||||
badJobList.add(sJob.getJob());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (bestScoredJob == null) {
|
|
||||||
bestScoredJob = sJob;
|
|
||||||
} else if (sJob.getScore() > bestScoredJob.getScore()) {
|
|
||||||
bestScoredJob = sJob;
|
|
||||||
} else if (sJob.getScore() == bestScoredJob.getScore()) {
|
|
||||||
if (sJob.getJob().getId().compareTo(bestScoredJob.getJob().getId()) <= 0) {
|
|
||||||
bestScoredJob = sJob;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bestScoredJob;
|
|
||||||
}
|
|
||||||
|
|
||||||
private VehicleRoute findRoute(Collection<VehicleRoute> routes, Job job) {
|
|
||||||
for(VehicleRoute r : routes){
|
|
||||||
if(r.getVehicle().getBreak() == job) return r;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,222 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* 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.problem.VehicleRoutingProblem;
|
|
||||||
import jsprit.core.problem.job.Break;
|
|
||||||
import jsprit.core.problem.job.Job;
|
|
||||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insertion based on regret approach.
|
|
||||||
* <p/>
|
|
||||||
* <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference
|
|
||||||
* between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction.
|
|
||||||
* The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this
|
|
||||||
* customer immediatedly. If difference is not that high, it might not impact solution if this customer is inserted later.
|
|
||||||
*
|
|
||||||
* @author stefan schroeder
|
|
||||||
*/
|
|
||||||
public class RegretInsertionSlow extends AbstractInsertionStrategy {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static Logger logger = LogManager.getLogger(RegretInsertion.class);
|
|
||||||
|
|
||||||
private ScoringFunction scoringFunction;
|
|
||||||
|
|
||||||
private JobInsertionCostsCalculator insertionCostsCalculator;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the scoring function.
|
|
||||||
* <p/>
|
|
||||||
* <p>By default, the this.TimeWindowScorer is used.
|
|
||||||
*
|
|
||||||
* @param scoringFunction to score
|
|
||||||
*/
|
|
||||||
public void setScoringFunction(ScoringFunction scoringFunction) {
|
|
||||||
this.scoringFunction = scoringFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RegretInsertionSlow(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) {
|
|
||||||
super(vehicleRoutingProblem);
|
|
||||||
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
|
|
||||||
this.insertionCostsCalculator = jobInsertionCalculator;
|
|
||||||
this.vrp = vehicleRoutingProblem;
|
|
||||||
logger.debug("initialise {}", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs insertion.
|
|
||||||
* <p/>
|
|
||||||
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
|
||||||
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
|
|
||||||
|
|
||||||
Iterator<Job> jobIterator = unassignedJobs.iterator();
|
|
||||||
while (jobIterator.hasNext()){
|
|
||||||
Job job = jobIterator.next();
|
|
||||||
if(job instanceof Break){
|
|
||||||
VehicleRoute route = findRoute(routes,job);
|
|
||||||
if(route == null){
|
|
||||||
badJobs.add(job);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
|
|
||||||
if (iData instanceof InsertionData.NoInsertionFound) {
|
|
||||||
badJobs.add(job);
|
|
||||||
} else {
|
|
||||||
insertJob(job, iData, route);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jobIterator.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
|
||||||
while (!jobs.isEmpty()) {
|
|
||||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
|
||||||
List<Job> badJobList = new ArrayList<Job>();
|
|
||||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
|
||||||
if (bestScoredJob != null) {
|
|
||||||
if (bestScoredJob.isNewRoute()) {
|
|
||||||
routes.add(bestScoredJob.getRoute());
|
|
||||||
}
|
|
||||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
|
||||||
jobs.remove(bestScoredJob.getJob());
|
|
||||||
}
|
|
||||||
for (Job bad : badJobList) {
|
|
||||||
jobs.remove(bad);
|
|
||||||
badJobs.add(bad);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return badJobs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private VehicleRoute findRoute(Collection<VehicleRoute> routes, Job job) {
|
|
||||||
for(VehicleRoute r : routes){
|
|
||||||
if(r.getVehicle().getBreak() == job) return r;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<Job> badJobs) {
|
|
||||||
ScoredJob bestScoredJob = null;
|
|
||||||
for (Job unassignedJob : unassignedJobList) {
|
|
||||||
ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
|
|
||||||
if (scoredJob instanceof ScoredJob.BadJob) {
|
|
||||||
badJobs.add(unassignedJob);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (bestScoredJob == null) bestScoredJob = scoredJob;
|
|
||||||
else {
|
|
||||||
if (scoredJob.getScore() > bestScoredJob.getScore()) {
|
|
||||||
bestScoredJob = scoredJob;
|
|
||||||
} else if (scoredJob.getScore() == bestScoredJob.getScore()) {
|
|
||||||
if (scoredJob.getJob().getId().compareTo(bestScoredJob.getJob().getId()) <= 0) {
|
|
||||||
bestScoredJob = scoredJob;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bestScoredJob;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ScoredJob getScoredJob(Collection<VehicleRoute> routes, Job unassignedJob, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (best == null) {
|
|
||||||
return new ScoredJob.BadJob(unassignedJob);
|
|
||||||
}
|
|
||||||
double score = score(unassignedJob, best, secondBest, scoringFunction);
|
|
||||||
ScoredJob scoredJob;
|
|
||||||
if (bestRoute == emptyRoute) {
|
|
||||||
scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, true);
|
|
||||||
} else scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, false);
|
|
||||||
return scoredJob;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) {
|
|
||||||
if (best == null) {
|
|
||||||
throw new IllegalStateException("cannot insert job " + unassignedJob.getId());
|
|
||||||
}
|
|
||||||
double score;
|
|
||||||
if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob
|
|
||||||
//if only one vehicle, I want the job to be inserted with min iCosts
|
|
||||||
//if there are more vehicles, I want this job to be prioritized since there are no alternatives
|
|
||||||
score = Integer.MAX_VALUE - best.getInsertionCost() + scoringFunction.score(best, unassignedJob);
|
|
||||||
} else {
|
|
||||||
score = (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
|
|
||||||
}
|
|
||||||
return score;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -49,7 +49,7 @@ public class RegretInsertionTest {
|
||||||
|
|
||||||
VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
||||||
JobInsertionCostsCalculator calculator = getCalculator(vrp);
|
JobInsertionCostsCalculator calculator = getCalculator(vrp);
|
||||||
RegretInsertion regretInsertion = new RegretInsertion(calculator, vrp, fm);
|
RegretInsertionFast regretInsertion = new RegretInsertionFast(calculator, vrp, fm);
|
||||||
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
||||||
|
|
||||||
regretInsertion.insertJobs(routes, vrp.getJobs().values());
|
regretInsertion.insertJobs(routes, vrp.getJobs().values());
|
||||||
|
|
@ -66,7 +66,7 @@ public class RegretInsertionTest {
|
||||||
|
|
||||||
VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
||||||
JobInsertionCostsCalculator calculator = getCalculator(vrp);
|
JobInsertionCostsCalculator calculator = getCalculator(vrp);
|
||||||
RegretInsertion regretInsertion = new RegretInsertion(calculator, vrp, fm);
|
RegretInsertionFast regretInsertion = new RegretInsertionFast(calculator, vrp, fm);
|
||||||
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
||||||
|
|
||||||
regretInsertion.insertJobs(routes, vrp.getJobs().values());
|
regretInsertion.insertJobs(routes, vrp.getJobs().values());
|
||||||
|
|
@ -83,7 +83,7 @@ public class RegretInsertionTest {
|
||||||
|
|
||||||
VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
||||||
JobInsertionCostsCalculator calculator = getCalculator(vrp);
|
JobInsertionCostsCalculator calculator = getCalculator(vrp);
|
||||||
RegretInsertion regretInsertion = new RegretInsertion(calculator, vrp, fm);
|
RegretInsertionFast regretInsertion = new RegretInsertionFast(calculator, vrp, fm);
|
||||||
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
||||||
|
|
||||||
CkeckJobSequence position = new CkeckJobSequence(2, s1);
|
CkeckJobSequence position = new CkeckJobSequence(2, s1);
|
||||||
|
|
@ -109,7 +109,7 @@ public class RegretInsertionTest {
|
||||||
|
|
||||||
VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
VehicleFleetManager fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
||||||
JobInsertionCostsCalculator calculator = getShipmentCalculator(vrp);
|
JobInsertionCostsCalculator calculator = getShipmentCalculator(vrp);
|
||||||
RegretInsertion regretInsertion = new RegretInsertion(calculator, vrp, fm);
|
RegretInsertionFast regretInsertion = new RegretInsertionFast(calculator, vrp, fm);
|
||||||
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
||||||
|
|
||||||
CkeckJobSequence position = new CkeckJobSequence(2, s2);
|
CkeckJobSequence position = new CkeckJobSequence(2, s2);
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,24 @@
|
||||||
<problem xmlns="http://www.w3schools.com"
|
<problem xmlns="http://www.w3schools.com"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3schools.com vrp_xml_schema.xsd">
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3schools.com vrp_xml_schema.xsd">
|
||||||
<problemType>
|
<problemType>
|
||||||
<fleetSize>INFINITE</fleetSize>
|
<fleetSize>FINITE</fleetSize>
|
||||||
</problemType>
|
</problemType>
|
||||||
<vehicles>
|
<vehicles>
|
||||||
|
<vehicle>
|
||||||
|
<id>v2</id>
|
||||||
|
<typeId>vehType2</typeId>
|
||||||
|
<startLocation>
|
||||||
|
<id>loc</id>
|
||||||
|
</startLocation>
|
||||||
|
<endLocation>
|
||||||
|
<id>loc</id>
|
||||||
|
</endLocation>
|
||||||
|
<timeSchedule>
|
||||||
|
<start>0.0</start>
|
||||||
|
<end>1.7976931348623157E308</end>
|
||||||
|
</timeSchedule>
|
||||||
|
<returnToDepot>true</returnToDepot>
|
||||||
|
</vehicle>
|
||||||
<vehicle>
|
<vehicle>
|
||||||
<id>v1</id>
|
<id>v1</id>
|
||||||
<typeId>vehType</typeId>
|
<typeId>vehType</typeId>
|
||||||
|
|
@ -33,58 +48,16 @@
|
||||||
<time>0.0</time>
|
<time>0.0</time>
|
||||||
</costs>
|
</costs>
|
||||||
</type>
|
</type>
|
||||||
|
<type>
|
||||||
|
<id>vehType2</id>
|
||||||
|
<capacity-dimensions>
|
||||||
|
<dimension index="0">200</dimension>
|
||||||
|
</capacity-dimensions>
|
||||||
|
<costs>
|
||||||
|
<fixed>0.0</fixed>
|
||||||
|
<distance>1.0</distance>
|
||||||
|
<time>0.0</time>
|
||||||
|
</costs>
|
||||||
|
</type>
|
||||||
</vehicleTypes>
|
</vehicleTypes>
|
||||||
<services>
|
|
||||||
<service id="1" type="service">
|
|
||||||
<location>
|
|
||||||
<id>loc</id>
|
|
||||||
</location>
|
|
||||||
<capacity-dimensions>
|
|
||||||
<dimension index="0">1</dimension>
|
|
||||||
</capacity-dimensions>
|
|
||||||
<duration>2.0</duration>
|
|
||||||
<timeWindows>
|
|
||||||
<timeWindow>
|
|
||||||
<start>0.0</start>
|
|
||||||
<end>1.7976931348623157E308</end>
|
|
||||||
</timeWindow>
|
|
||||||
</timeWindows>
|
|
||||||
</service>
|
|
||||||
<service id="2" type="service">
|
|
||||||
<location>
|
|
||||||
<id>loc2</id>
|
|
||||||
</location>
|
|
||||||
<capacity-dimensions>
|
|
||||||
<dimension index="0">1</dimension>
|
|
||||||
</capacity-dimensions>
|
|
||||||
<duration>4.0</duration>
|
|
||||||
<timeWindows>
|
|
||||||
<timeWindow>
|
|
||||||
<start>0.0</start>
|
|
||||||
<end>1.7976931348623157E308</end>
|
|
||||||
</timeWindow>
|
|
||||||
</timeWindows>
|
|
||||||
</service>
|
|
||||||
</services>
|
|
||||||
<solutions>
|
|
||||||
<solution>
|
|
||||||
<cost>10.0</cost>
|
|
||||||
<routes>
|
|
||||||
<route>
|
|
||||||
<driverId>noDriver</driverId>
|
|
||||||
<vehicleId>v1</vehicleId>
|
|
||||||
<start>0.0</start>
|
|
||||||
<act type="service">
|
|
||||||
<serviceId>1</serviceId>
|
|
||||||
<arrTime>0.0</arrTime>
|
|
||||||
<endTime>0.0</endTime>
|
|
||||||
</act>
|
|
||||||
<end>0.0</end>
|
|
||||||
</route>
|
|
||||||
</routes>
|
|
||||||
<unassignedJobs>
|
|
||||||
<job id="2"/>
|
|
||||||
</unassignedJobs>
|
|
||||||
</solution>
|
|
||||||
</solutions>
|
|
||||||
</problem>
|
</problem>
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ public class BuildAlgorithmFromScratch {
|
||||||
//regret insertion
|
//regret insertion
|
||||||
InsertionBuilder iBuilder = new InsertionBuilder(vrp, fleetManager, stateManager, constraintManager);
|
InsertionBuilder iBuilder = new InsertionBuilder(vrp, fleetManager, stateManager, constraintManager);
|
||||||
iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET);
|
iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET);
|
||||||
RegretInsertion regret = (RegretInsertion) iBuilder.build();
|
RegretInsertionFast regret = (RegretInsertionFast) iBuilder.build();
|
||||||
DefaultScorer scoringFunction = new DefaultScorer(vrp);
|
DefaultScorer scoringFunction = new DefaultScorer(vrp);
|
||||||
scoringFunction.setDepotDistanceParam(0.2);
|
scoringFunction.setDepotDistanceParam(0.2);
|
||||||
scoringFunction.setTimeWindowParam(-.2);
|
scoringFunction.setTimeWindowParam(-.2);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue