mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
memorize failed constraint names - related to #180
This commit is contained in:
parent
ba6dbfae45
commit
8da37cf4b3
14 changed files with 237 additions and 68 deletions
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Licensed to GraphHopper GmbH under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* GraphHopper GmbH licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.graphhopper.jsprit.core.algorithm.recreate;
|
||||
|
||||
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.HardRouteConstraint;
|
||||
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 06/02/17.
|
||||
*/
|
||||
abstract class AbstractInsertionCalculator implements JobInsertionCostsCalculator {
|
||||
|
||||
InsertionData checkRouteContraints(JobInsertionContext insertionContext, ConstraintManager constraintManager) {
|
||||
for (HardRouteConstraint hardRouteConstraint : constraintManager.getHardRouteConstraints()) {
|
||||
if (!hardRouteConstraint.fulfilled(insertionContext)) {
|
||||
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
|
||||
emptyInsertionData.addFailedConstrainName(hardRouteConstraint.getClass().getSimpleName());
|
||||
return emptyInsertionData;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime, Collection<String> failedActivityConstraints, ConstraintManager constraintManager) {
|
||||
ConstraintsStatus notFulfilled = null;
|
||||
List<String> failed = new ArrayList<>();
|
||||
for (HardActivityConstraint c : constraintManager.getCriticalHardActivityConstraints()) {
|
||||
ConstraintsStatus status = c.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
|
||||
if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
|
||||
failedActivityConstraints.add(c.getClass().getSimpleName());
|
||||
return status;
|
||||
} else {
|
||||
if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
|
||||
failed.add(c.getClass().getSimpleName());
|
||||
notFulfilled = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (notFulfilled != null) {
|
||||
failedActivityConstraints.addAll(failed);
|
||||
return notFulfilled;
|
||||
}
|
||||
|
||||
for (HardActivityConstraint c : constraintManager.getHighPrioHardActivityConstraints()) {
|
||||
ConstraintsStatus status = c.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
|
||||
if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
|
||||
failedActivityConstraints.add(c.getClass().getSimpleName());
|
||||
return status;
|
||||
} else {
|
||||
if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
|
||||
failed.add(c.getClass().getSimpleName());
|
||||
notFulfilled = status;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (notFulfilled != null) {
|
||||
failedActivityConstraints.addAll(failed);
|
||||
return notFulfilled;
|
||||
}
|
||||
|
||||
for (HardActivityConstraint constraint : constraintManager.getLowPrioHardActivityConstraints()) {
|
||||
ConstraintsStatus status = constraint.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
|
||||
if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK) || status.equals(ConstraintsStatus.NOT_FULFILLED)) {
|
||||
failedActivityConstraints.add(constraint.getClass().getSimpleName());
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return ConstraintsStatus.FULFILLED;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public abstract class AbstractInsertionStrategy implements InsertionStrategy {
|
||||
|
|
@ -92,6 +93,10 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy {
|
|||
return badJobs;
|
||||
}
|
||||
|
||||
public void markUnassigned(Job unassigned, List<String> reasons) {
|
||||
insertionsListeners.informJobUnassignedListeners(unassigned, reasons);
|
||||
}
|
||||
|
||||
public abstract Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -66,10 +66,12 @@ public final class BestInsertion extends AbstractInsertionStrategy {
|
|||
sometimesSortPriorities(unassignedJobList);
|
||||
for (Job unassignedJob : unassignedJobList) {
|
||||
Insertion bestInsertion = null;
|
||||
InsertionData empty = new InsertionData.NoInsertionFound();
|
||||
double bestInsertionCost = Double.MAX_VALUE;
|
||||
for (VehicleRoute vehicleRoute : vehicleRoutes) {
|
||||
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if (iData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()) {
|
||||
|
|
@ -84,14 +86,19 @@ public final class BestInsertion extends AbstractInsertionStrategy {
|
|||
bestInsertion = new Insertion(newRoute, newIData);
|
||||
vehicleRoutes.add(newRoute);
|
||||
}
|
||||
} else {
|
||||
empty.getFailedConstraintNames().addAll(newIData.getFailedConstraintNames());
|
||||
}
|
||||
if (bestInsertion == null) {
|
||||
badJobs.add(unassignedJob);
|
||||
markUnassigned(unassignedJob, empty.getFailedConstraintNames());
|
||||
}
|
||||
if (bestInsertion == null) badJobs.add(unassignedJob);
|
||||
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||
// nextInsertion();
|
||||
}
|
||||
return badJobs;
|
||||
}
|
||||
|
||||
|
||||
private void sometimesSortPriorities(List<Job> unassignedJobList) {
|
||||
if(random.nextDouble() < 0.5){
|
||||
Collections.sort(unassignedJobList, new Comparator<Job>() {
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
Collections.shuffle(unassignedJobList, random);
|
||||
sometimesSortPriorities(unassignedJobList);
|
||||
List<Batch> batches = distributeRoutes(vehicleRoutes, nuOfBatches);
|
||||
List<String> failedConstraintNames = new ArrayList<>();
|
||||
for (final Job unassignedJob : unassignedJobList) {
|
||||
Insertion bestInsertion = null;
|
||||
double bestInsertionCost = Double.MAX_VALUE;
|
||||
|
|
@ -118,7 +119,10 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
for (int i = 0; i < batches.size(); i++) {
|
||||
Future<Insertion> futureIData = completionService.take();
|
||||
Insertion insertion = futureIData.get();
|
||||
if (insertion == null) continue;
|
||||
if (insertion.insertionData instanceof NoInsertionFound) {
|
||||
failedConstraintNames.addAll(insertion.getInsertionData().getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) {
|
||||
bestInsertion = insertion;
|
||||
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
|
||||
|
|
@ -136,7 +140,10 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
vehicleRoutes.add(newRoute);
|
||||
batches.get(random.nextInt(batches.size())).routes.add(newRoute);
|
||||
}
|
||||
if (bestInsertion == null) badJobs.add(unassignedJob);
|
||||
if (bestInsertion == null) {
|
||||
badJobs.add(unassignedJob);
|
||||
markUnassigned(unassignedJob, failedConstraintNames);
|
||||
}
|
||||
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||
}
|
||||
return badJobs;
|
||||
|
|
@ -155,10 +162,12 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
|
||||
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
|
||||
Insertion bestInsertion = null;
|
||||
InsertionData empty = new InsertionData.NoInsertionFound();
|
||||
double bestInsertionCost = Double.MAX_VALUE;
|
||||
for (VehicleRoute vehicleRoute : batch.routes) {
|
||||
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||
if (iData instanceof NoInsertionFound) {
|
||||
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if (iData.getInsertionCost() < bestInsertionCost) {
|
||||
|
|
@ -166,6 +175,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
bestInsertionCost = iData.getInsertionCost();
|
||||
}
|
||||
}
|
||||
if (bestInsertion == null) return new Insertion(null, empty);
|
||||
return bestInsertion;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import java.util.List;
|
|||
*/
|
||||
public class InsertionData {
|
||||
|
||||
|
||||
public static class NoInsertionFound extends InsertionData {
|
||||
|
||||
public NoInsertionFound() {
|
||||
|
|
@ -75,6 +76,8 @@ public class InsertionData {
|
|||
return events;
|
||||
}
|
||||
|
||||
private List<String> reasons = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @return the additionalTime
|
||||
*/
|
||||
|
|
@ -82,6 +85,14 @@ public class InsertionData {
|
|||
return additionalTime;
|
||||
}
|
||||
|
||||
public void addFailedConstrainName(String name) {
|
||||
reasons.add(name);
|
||||
}
|
||||
|
||||
public List<String> getFailedConstraintNames() {
|
||||
return reasons;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param additionalTime the additionalTime to set
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class InsertionDataUpdater {
|
|||
|
||||
static boolean update(boolean addAllAvailable, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, TreeSet<VersionedInsertionData> insertionDataSet, int updateRound, Job unassignedJob, Collection<VehicleRoute> routes) {
|
||||
for(VehicleRoute route : routes) {
|
||||
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
||||
Collection<Vehicle> relevantVehicles = new ArrayList<>();
|
||||
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||
relevantVehicles.add(route.getVehicle());
|
||||
if(addAllAvailable && !initialVehicleIds.contains(route.getVehicle().getId())){
|
||||
|
|
@ -71,7 +71,7 @@ class InsertionDataUpdater {
|
|||
};
|
||||
}
|
||||
|
||||
static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<Job> badJobs) {
|
||||
static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<ScoredJob> badJobs) {
|
||||
ScoredJob bestScoredJob = null;
|
||||
for(Job j : unassignedJobList){
|
||||
VehicleRoute bestRoute = null;
|
||||
|
|
@ -79,6 +79,7 @@ class InsertionDataUpdater {
|
|||
InsertionData secondBest = null;
|
||||
TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[j.getIndex()];
|
||||
Iterator<VersionedInsertionData> iterator = priorityQueue.iterator();
|
||||
List<String> failedConstraintNames = new ArrayList<>();
|
||||
while(iterator.hasNext()){
|
||||
VersionedInsertionData versionedIData = iterator.next();
|
||||
if(bestRoute != null){
|
||||
|
|
@ -86,7 +87,10 @@ class InsertionDataUpdater {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if(versionedIData.getiData() instanceof InsertionData.NoInsertionFound) continue;
|
||||
if (versionedIData.getiData() instanceof InsertionData.NoInsertionFound) {
|
||||
failedConstraintNames.addAll(versionedIData.getiData().getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if(!(versionedIData.getRoute().getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||
if (versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) {
|
||||
if (!switchAllowed) continue;
|
||||
|
|
@ -136,9 +140,9 @@ class InsertionDataUpdater {
|
|||
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
|
||||
secondBest = iData;
|
||||
}
|
||||
}
|
||||
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
|
||||
if (best == null) {
|
||||
badJobs.add(j);
|
||||
badJobs.add(new ScoredJob.BadJob(j, failedConstraintNames));
|
||||
continue;
|
||||
}
|
||||
double score = score(j, best, secondBest, scoringFunction);
|
||||
|
|
|
|||
|
|
@ -105,10 +105,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||
List<Job> jobs = new ArrayList<>(unassignedJobs);
|
||||
while (!jobs.isEmpty()) {
|
||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||
List<Job> badJobList = new ArrayList<Job>();
|
||||
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||
List<ScoredJob> badJobList = new ArrayList<>();
|
||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||
if (bestScoredJob != null) {
|
||||
if (bestScoredJob.isNewRoute()) {
|
||||
|
|
@ -117,9 +117,11 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||
jobs.remove(bestScoredJob.getJob());
|
||||
}
|
||||
for (Job bad : badJobList) {
|
||||
jobs.remove(bad);
|
||||
badJobs.add(bad);
|
||||
for (ScoredJob bad : badJobList) {
|
||||
Job unassigned = bad.getJob();
|
||||
jobs.remove(unassigned);
|
||||
badJobs.add(unassigned);
|
||||
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||
}
|
||||
}
|
||||
return badJobs;
|
||||
|
|
@ -132,12 +134,12 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
return null;
|
||||
}
|
||||
|
||||
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<Job> badJobs) {
|
||||
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<ScoredJob> badJobs) {
|
||||
ScoredJob bestScoredJob = null;
|
||||
for (Job unassignedJob : unassignedJobList) {
|
||||
ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
|
||||
if (scoredJob instanceof ScoredJob.BadJob) {
|
||||
badJobs.add(unassignedJob);
|
||||
badJobs.add(scoredJob);
|
||||
continue;
|
||||
}
|
||||
if (bestScoredJob == null) bestScoredJob = scoredJob;
|
||||
|
|
@ -158,14 +160,17 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
InsertionData best = null;
|
||||
InsertionData secondBest = null;
|
||||
VehicleRoute bestRoute = null;
|
||||
|
||||
List<String> failedConstraintNames = new ArrayList<>();
|
||||
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 (iData instanceof InsertionData.NoInsertionFound) {
|
||||
failedConstraintNames.addAll(iData.getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if (best == null) {
|
||||
best = iData;
|
||||
bestRoute = route;
|
||||
|
|
@ -191,9 +196,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
|
||||
secondBest = iData;
|
||||
}
|
||||
}
|
||||
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
|
||||
if (best == null) {
|
||||
return new ScoredJob.BadJob(unassignedJob);
|
||||
ScoredJob.BadJob badJob = new ScoredJob.BadJob(unassignedJob, failedConstraintNames);
|
||||
return badJob;
|
||||
}
|
||||
double score = score(unassignedJob, best, secondBest, scoringFunction);
|
||||
ScoredJob scoredJob;
|
||||
|
|
|
|||
|
|
@ -109,10 +109,10 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||
List<Job> jobs = new ArrayList<>(unassignedJobs);
|
||||
while (!jobs.isEmpty()) {
|
||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||
List<Job> badJobList = new ArrayList<Job>();
|
||||
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||
List<ScoredJob> badJobList = new ArrayList<>();
|
||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||
if (bestScoredJob != null) {
|
||||
if (bestScoredJob.isNewRoute()) {
|
||||
|
|
@ -121,15 +121,17 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||
jobs.remove(bestScoredJob.getJob());
|
||||
}
|
||||
for (Job j : badJobList) {
|
||||
jobs.remove(j);
|
||||
badJobs.add(j);
|
||||
for (ScoredJob bad : badJobList) {
|
||||
Job unassigned = bad.getJob();
|
||||
jobs.remove(unassigned);
|
||||
badJobs.add(unassigned);
|
||||
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||
}
|
||||
}
|
||||
return badJobs;
|
||||
}
|
||||
|
||||
private ScoredJob nextJob(final Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<Job> badJobList) {
|
||||
private ScoredJob nextJob(final Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<ScoredJob> badJobList) {
|
||||
ScoredJob bestScoredJob = null;
|
||||
|
||||
for (final Job unassignedJob : unassignedJobList) {
|
||||
|
|
@ -148,7 +150,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
Future<ScoredJob> fsj = completionService.take();
|
||||
ScoredJob sJob = fsj.get();
|
||||
if (sJob instanceof ScoredJob.BadJob) {
|
||||
badJobList.add(sJob.getJob());
|
||||
badJobList.add(sJob);
|
||||
continue;
|
||||
}
|
||||
if (bestScoredJob == null) {
|
||||
|
|
|
|||
|
|
@ -143,8 +143,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
|||
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>();
|
||||
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||
List<ScoredJob> badJobList = new ArrayList<>();
|
||||
if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
|
||||
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound,firstRun,lastModified,updates);
|
||||
if(firstRun) firstRun = false;
|
||||
|
|
@ -159,9 +159,11 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
|||
lastModified = bestScoredJob.getRoute();
|
||||
}
|
||||
else lastModified = null;
|
||||
for (Job bad : badJobList) {
|
||||
jobs.remove(bad);
|
||||
badJobs.add(bad);
|
||||
for (ScoredJob bad : badJobList) {
|
||||
Job unassigned = bad.getJob();
|
||||
jobs.remove(unassigned);
|
||||
badJobs.add(unassigned);
|
||||
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||
}
|
||||
}
|
||||
return badJobs;
|
||||
|
|
@ -172,7 +174,7 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
|||
boolean updatedAllRoutes = false;
|
||||
for (final Job unassignedJob : unassignedJobList) {
|
||||
if(priorityQueues[unassignedJob.getIndex()] == null){
|
||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
|
||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
|
||||
}
|
||||
if(firstRun) {
|
||||
updatedAllRoutes = true;
|
||||
|
|
|
|||
|
|
@ -131,10 +131,10 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
|
|||
VehicleRoute lastModified = null;
|
||||
boolean firstRun = true;
|
||||
int updateRound = 0;
|
||||
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
|
||||
Map<VehicleRoute, Integer> updates = new HashMap<>();
|
||||
while (!jobs.isEmpty()) {
|
||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||
List<Job> badJobList = new ArrayList<Job>();
|
||||
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||
List<ScoredJob> badJobList = new ArrayList<>();
|
||||
if(!firstRun && lastModified == null) throw new IllegalStateException("last modified route is null. this should not be.");
|
||||
if(firstRun){
|
||||
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates);
|
||||
|
|
@ -156,9 +156,11 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
|
|||
lastModified = bestScoredJob.getRoute();
|
||||
}
|
||||
else lastModified = null;
|
||||
for (Job bad : badJobList) {
|
||||
jobs.remove(bad);
|
||||
badJobs.add(bad);
|
||||
for (ScoredJob bad : badJobList) {
|
||||
Job unassigned = bad.getJob();
|
||||
jobs.remove(unassigned);
|
||||
badJobs.add(unassigned);
|
||||
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||
}
|
||||
}
|
||||
return badJobs;
|
||||
|
|
@ -167,7 +169,7 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
|
|||
private void updateInsertionData(TreeSet<VersionedInsertionData>[] priorityQueues, Collection<VehicleRoute> routes, List<Job> unassignedJobList, int updateRound, boolean firstRun, VehicleRoute lastModified, Map<VehicleRoute, Integer> updates) {
|
||||
for (Job unassignedJob : unassignedJobList) {
|
||||
if(priorityQueues[unassignedJob.getIndex()] == null){
|
||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
|
||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
|
||||
}
|
||||
if(firstRun) {
|
||||
InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ package com.graphhopper.jsprit.core.algorithm.recreate;
|
|||
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 15/10/15.
|
||||
*/
|
||||
|
|
@ -28,8 +30,14 @@ class ScoredJob {
|
|||
|
||||
static class BadJob extends ScoredJob {
|
||||
|
||||
BadJob(Job job) {
|
||||
super(job, 0., null, null, false);
|
||||
BadJob(Job job, List<String> failedConstraintNames) {
|
||||
super(job, 0., getEmptyInsertion(failedConstraintNames), null, false);
|
||||
}
|
||||
|
||||
private static InsertionData getEmptyInsertion(List<String> failedConstraintNames) {
|
||||
InsertionData empty = new InsertionData.NoInsertionFound();
|
||||
empty.getFailedConstraintNames().addAll(failedConstraintNames);
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@
|
|||
package com.graphhopper.jsprit.core.algorithm.recreate;
|
||||
|
||||
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.*;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.SoftActivityConstraint;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
|
||||
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
|
||||
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
||||
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
||||
|
|
@ -36,6 +38,8 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
|
|
@ -43,13 +47,13 @@ import java.util.Iterator;
|
|||
*
|
||||
* @author schroeder
|
||||
*/
|
||||
final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
||||
final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ServiceInsertionCalculator.class);
|
||||
|
||||
private HardRouteConstraint hardRouteLevelConstraint;
|
||||
// private HardRouteConstraint hardRouteLevelConstraint;
|
||||
|
||||
private HardActivityConstraint hardActivityLevelConstraint;
|
||||
// private HardActivityConstraint hardActivityLevelConstraint;
|
||||
|
||||
private SoftRouteConstraint softRouteConstraint;
|
||||
|
||||
|
|
@ -65,12 +69,13 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
|
||||
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
|
||||
|
||||
private ConstraintManager constraintManager;
|
||||
|
||||
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
|
||||
super();
|
||||
this.transportCosts = routingCosts;
|
||||
this.activityCosts = activityCosts;
|
||||
hardRouteLevelConstraint = constraintManager;
|
||||
hardActivityLevelConstraint = constraintManager;
|
||||
this.constraintManager = constraintManager;
|
||||
softActivityConstraint = constraintManager;
|
||||
softRouteConstraint = constraintManager;
|
||||
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
|
||||
|
|
@ -103,9 +108,10 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
/*
|
||||
check hard constraints at route level
|
||||
*/
|
||||
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
|
||||
return InsertionData.createEmptyInsertionData();
|
||||
}
|
||||
InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager);
|
||||
if (noInsertion != null) return noInsertion;
|
||||
|
||||
Collection<String> failedActivityConstraints = new ArrayList<>();
|
||||
|
||||
/*
|
||||
check soft constraints at route level
|
||||
|
|
@ -142,7 +148,7 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
ActivityContext activityContext = new ActivityContext();
|
||||
activityContext.setInsertionIndex(actIndex);
|
||||
insertionContext.setActivityContext(activityContext);
|
||||
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
|
||||
ConstraintsStatus status = fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime, failedActivityConstraints, constraintManager);
|
||||
if (status.equals(ConstraintsStatus.FULFILLED)) {
|
||||
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
|
||||
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
|
||||
|
|
@ -163,7 +169,9 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
actIndex++;
|
||||
}
|
||||
if(insertionIndex == InsertionData.NO_INDEX) {
|
||||
return InsertionData.createEmptyInsertionData();
|
||||
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
|
||||
emptyInsertionData.getFailedConstraintNames().addAll(failedActivityConstraints);
|
||||
return emptyInsertionData;
|
||||
}
|
||||
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
||||
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(bestTimeWindow.getStart());
|
||||
|
|
@ -173,4 +181,6 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||
return insertionData;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@
|
|||
package com.graphhopper.jsprit.core.algorithm.recreate;
|
||||
|
||||
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.*;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.SoftActivityConstraint;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
|
||||
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts;
|
||||
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
||||
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
||||
|
|
@ -36,16 +38,19 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
||||
final class ShipmentInsertionCalculator extends AbstractInsertionCalculator {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShipmentInsertionCalculator.class);
|
||||
|
||||
private HardRouteConstraint hardRouteLevelConstraint;
|
||||
private final ConstraintManager constraintManager;
|
||||
|
||||
private HardActivityConstraint hardActivityLevelConstraint;
|
||||
// private HardRouteConstraint hardRouteLevelConstraint;
|
||||
//
|
||||
// private HardActivityConstraint hardActivityLevelConstraint;
|
||||
|
||||
private SoftRouteConstraint softRouteConstraint;
|
||||
|
||||
|
|
@ -64,8 +69,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager) {
|
||||
super();
|
||||
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
||||
this.hardRouteLevelConstraint = constraintManager;
|
||||
this.hardActivityLevelConstraint = constraintManager;
|
||||
this.constraintManager = constraintManager;
|
||||
this.softActivityConstraint = constraintManager;
|
||||
this.softRouteConstraint = constraintManager;
|
||||
this.transportCosts = routingCosts;
|
||||
|
|
@ -99,9 +103,8 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
/*
|
||||
check hard route constraints
|
||||
*/
|
||||
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
|
||||
return InsertionData.createEmptyInsertionData();
|
||||
}
|
||||
InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager);
|
||||
if (noInsertion != null) return noInsertion;
|
||||
/*
|
||||
check soft route constraints
|
||||
*/
|
||||
|
|
@ -132,6 +135,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
//pickupShipmentLoop
|
||||
List<TourActivity> activities = currentRoute.getTourActivities().getActivities();
|
||||
|
||||
List<String> failedActivityConstraints = new ArrayList<>();
|
||||
while (!tourEnd) {
|
||||
TourActivity nextAct;
|
||||
if (i < activities.size()) {
|
||||
|
|
@ -148,7 +152,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
ActivityContext activityContext = new ActivityContext();
|
||||
activityContext.setInsertionIndex(i);
|
||||
insertionContext.setActivityContext(activityContext);
|
||||
ConstraintsStatus pickupShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime);
|
||||
ConstraintsStatus pickupShipmentConstraintStatus = fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime, failedActivityConstraints, constraintManager);
|
||||
if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED)) {
|
||||
pickupInsertionNotFulfilledBreak = false;
|
||||
continue;
|
||||
|
|
@ -194,7 +198,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
ActivityContext activityContext_ = new ActivityContext();
|
||||
activityContext_.setInsertionIndex(j);
|
||||
insertionContext.setActivityContext(activityContext_);
|
||||
ConstraintsStatus deliverShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
|
||||
ConstraintsStatus deliverShipmentConstraintStatus = fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop, failedActivityConstraints, constraintManager);
|
||||
if (deliverShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)) {
|
||||
double additionalDeliveryICosts = softActivityConstraint.getCosts(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
|
||||
double deliveryAIC = calculate(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
|
||||
|
|
@ -230,7 +234,9 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
|||
i++;
|
||||
}
|
||||
if (pickupInsertionIndex == InsertionData.NO_INDEX) {
|
||||
return InsertionData.createEmptyInsertionData();
|
||||
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
|
||||
emptyInsertionData.getFailedConstraintNames().addAll(failedActivityConstraints);
|
||||
return emptyInsertionData;
|
||||
}
|
||||
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
|
||||
pickupShipment.setTheoreticalEarliestOperationStartTime(bestPickupTimeWindow.getStart());
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
|
|||
}
|
||||
Vehicle selectedVehicle = currentRoute.getVehicle();
|
||||
Driver selectedDriver = currentRoute.getDriver();
|
||||
InsertionData bestIData = InsertionData.createEmptyInsertionData();
|
||||
InsertionData bestIData = new InsertionData.NoInsertionFound();
|
||||
double bestKnownCost_ = bestKnownCost;
|
||||
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
||||
if (!(selectedVehicle instanceof VehicleImpl.NoVehicle)) {
|
||||
|
|
@ -115,6 +115,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
|
|||
else depTime = v.getEarliestDeparture();
|
||||
InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
|
||||
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||
bestIData.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if (iData.getInsertionCost() < bestKnownCost_) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue