diff --git a/CHANGELOG.md b/CHANGELOG.md index fa7957f3..cd6636b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ Change-log ========== +**v1.7** @ 2017-01-12 +- see [Whats new](https://github.com/graphhopper/jsprit/blob/master/WHATS_NEW.md) + **v1.6.2** @ 2016-02-02 new features: diff --git a/WHATS_NEW.md b/WHATS_NEW.md index 462a7cc0..04e27c30 100644 --- a/WHATS_NEW.md +++ b/WHATS_NEW.md @@ -1,15 +1,17 @@ WHATS NEW ========== ------------------------------ -?? new release **v1.7** +2017-01-12 new release **v1.7** - move packages to [graphhopper.com](https://graphhopper.com/) - change license from GPLv3 to [Apache v2](https://github.com/graphhopper/jsprit/blob/master/LICENSE.md) to make it even more attractive for other developers and their commercial applications - pushed binaries to maven central, i.e. made it better accessible and we get rid of our own repo - outsourced various io operations, e.g. reading writing problem/algorithm to a new module called [jsprit-io](https://github.com/graphhopper/jsprit/tree/master/jsprit-io). this way the core is even more lightweight and less dependent on other libraries - switched from log4j to the [logger facade slf4j](http://www.slf4j.org/) to allow developers to plugin the logger of their choice - made it [much more memory efficient](https://github.com/graphhopper/jsprit/issues/230) for large problems +- fixed [memory leak](https://github.com/graphhopper/jsprit/pull/282) - add [priority feature](https://github.com/graphhopper/jsprit/issues/242) - [refine exceptions](https://github.com/graphhopper/jsprit/issues/251) to get a clear separation of IllegalArgument and [IllegalState](https://stackoverflow.com/questions/12698275/whats-the-intended-use-of-illegalstateexception) +- many further improvements (see https://github.com/graphhopper/jsprit/issues?q=is%3Aissue+is%3Aclosed) 2016-02-02 new release **v1.6.2** diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index c49fe090..ac5af692 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -15,10 +15,12 @@ If you want to use the latest release of jsprit-core, add the following lines to
<dependency>
<groupId>com.graphhopper</groupId>
<artifactId>jsprit-core</artifactId>
- <version>1.7-RC1</version>
+ <version>{version}</version>
</dependency>
+Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core).
+
####Build yourself
If you want to build the master branch yourself, do this:
diff --git a/docs/Simple-Example.md b/docs/Simple-Example.md
index 091e8cc6..d61aa27e 100644
--- a/docs/Simple-Example.md
+++ b/docs/Simple-Example.md
@@ -16,7 +16,7 @@ First, build a vehicle with its vehicle-type:
/*
* get a vehicle type-builder and build a type with the typeId "vehicleType" and a capacity of 2
- * you are free to add an arbitrary number of capacity dimensions with .addCacpacityDimension(dimensionIndex,dimensionValue)
+ * you are free to add an arbitrary number of capacity dimensions with .addCapacityDimension(dimensionIndex,dimensionValue)
*/
final int WEIGHT_INDEX = 0;
VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(WEIGHT_INDEX,2);
diff --git a/jsprit-analysis/pom.xml b/jsprit-analysis/pom.xml
index a5707f18..409ef69d 100644
--- a/jsprit-analysis/pom.xml
+++ b/jsprit-analysis/pom.xml
@@ -20,7 +20,7 @@
com.graphhopper
jsprit
- 1.7-SNAPSHOT
+ 1.7.1-SNAPSHOT
4.0.0
jsprit-analysis
diff --git a/jsprit-core/pom.xml b/jsprit-core/pom.xml
index f3d79fc0..d20a01b6 100644
--- a/jsprit-core/pom.xml
+++ b/jsprit-core/pom.xml
@@ -21,7 +21,7 @@
com.graphhopper
jsprit
- 1.7-SNAPSHOT
+ 1.7.1-SNAPSHOT
4.0.0
jsprit-core
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java
index c0a243cc..557bc4cd 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java
@@ -737,7 +737,7 @@ public class Jsprit {
}
}
for(Job j : solution.getUnassignedJobs()){
- costs += maxCosts * 2 * (4 - j.getPriority());
+ costs += maxCosts * 2 * (11 - j.getPriority());
}
return costs;
}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionCalculator.java
new file mode 100644
index 00000000..6f3d54a4
--- /dev/null
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionCalculator.java
@@ -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 failedActivityConstraints, ConstraintManager constraintManager) {
+ ConstraintsStatus notFulfilled = null;
+ List 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;
+ }
+
+}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionStrategy.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionStrategy.java
index 7d794a6d..5f5973f5 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionStrategy.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionStrategy.java
@@ -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 reasons) {
+ insertionsListeners.informJobUnassignedListeners(unassigned, reasons);
+ }
+
public abstract Collection insertUnassignedJobs(Collection vehicleRoutes, Collection unassignedJobs);
@Override
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java
index a78205ae..329a05ff 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java
@@ -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 unassignedJobList) {
if(random.nextDouble() < 0.5){
Collections.sort(unassignedJobList, new Comparator() {
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java
index 52d913df..2b014df0 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java
@@ -101,6 +101,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
Collections.shuffle(unassignedJobList, random);
sometimesSortPriorities(unassignedJobList);
List batches = distributeRoutes(vehicleRoutes, nuOfBatches);
+ List 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 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;
}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionData.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionData.java
index d5b5ef8d..fd78b3e9 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionData.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionData.java
@@ -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 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 getFailedConstraintNames() {
+ return reasons;
+ }
+
/**
* @param additionalTime the additionalTime to set
*/
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java
index ced87182..8d019e2c 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java
@@ -33,7 +33,7 @@ class InsertionDataUpdater {
static boolean update(boolean addAllAvailable, Set initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, TreeSet insertionDataSet, int updateRound, Job unassignedJob, Collection routes) {
for(VehicleRoute route : routes) {
- Collection relevantVehicles = new ArrayList();
+ Collection 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 initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet[] priorityQueues, Map updates, List unassignedJobList, List badJobs) {
+ static ScoredJob getBest(boolean switchAllowed, Set initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet[] priorityQueues, Map updates, List unassignedJobList, List badJobs) {
ScoredJob bestScoredJob = null;
for(Job j : unassignedJobList){
VehicleRoute bestRoute = null;
@@ -79,6 +79,7 @@ class InsertionDataUpdater {
InsertionData secondBest = null;
TreeSet priorityQueue = priorityQueues[j.getIndex()];
Iterator iterator = priorityQueue.iterator();
+ List 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);
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java
index 6e405dec..30a7a98a 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java
@@ -105,10 +105,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
}
}
- List jobs = new ArrayList(unassignedJobs);
+ List jobs = new ArrayList<>(unassignedJobs);
while (!jobs.isEmpty()) {
- List unassignedJobList = new ArrayList(jobs);
- List badJobList = new ArrayList();
+ List unassignedJobList = new ArrayList<>(jobs);
+ List 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 routes, Collection unassignedJobList, List badJobs) {
+ private ScoredJob nextJob(Collection routes, Collection unassignedJobList, List 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 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;
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java
index fe2146ba..b71ac5ab 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java
@@ -109,10 +109,10 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
}
}
- List jobs = new ArrayList(unassignedJobs);
+ List jobs = new ArrayList<>(unassignedJobs);
while (!jobs.isEmpty()) {
- List unassignedJobList = new ArrayList(jobs);
- List badJobList = new ArrayList();
+ List unassignedJobList = new ArrayList<>(jobs);
+ List 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 routes, List unassignedJobList, List badJobList) {
+ private ScoredJob nextJob(final Collection routes, List unassignedJobList, List badJobList) {
ScoredJob bestScoredJob = null;
for (final Job unassignedJob : unassignedJobList) {
@@ -148,7 +150,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
Future fsj = completionService.take();
ScoredJob sJob = fsj.get();
if (sJob instanceof ScoredJob.BadJob) {
- badJobList.add(sJob.getJob());
+ badJobList.add(sJob);
continue;
}
if (bestScoredJob == null) {
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java
index 187145f6..be4f5d11 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java
@@ -143,8 +143,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
int updateRound = 0;
Map updates = new HashMap();
while (!jobs.isEmpty()) {
- List unassignedJobList = new ArrayList(jobs);
- List badJobList = new ArrayList();
+ List unassignedJobList = new ArrayList<>(jobs);
+ List 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(InsertionDataUpdater.getComparator());
+ priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
}
if(firstRun) {
updatedAllRoutes = true;
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java
index 4369dd01..d805e55d 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java
@@ -131,10 +131,10 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
VehicleRoute lastModified = null;
boolean firstRun = true;
int updateRound = 0;
- Map updates = new HashMap();
+ Map updates = new HashMap<>();
while (!jobs.isEmpty()) {
- List unassignedJobList = new ArrayList(jobs);
- List badJobList = new ArrayList();
+ List unassignedJobList = new ArrayList<>(jobs);
+ List 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[] priorityQueues, Collection routes, List unassignedJobList, int updateRound, boolean firstRun, VehicleRoute lastModified, Map updates) {
for (Job unassignedJob : unassignedJobList) {
if(priorityQueues[unassignedJob.getIndex()] == null){
- priorityQueues[unassignedJob.getIndex()] = new TreeSet(InsertionDataUpdater.getComparator());
+ priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
}
if(firstRun) {
InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes);
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoredJob.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoredJob.java
index 48582800..f0f8950f 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoredJob.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoredJob.java
@@ -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 failedConstraintNames) {
+ super(job, 0., getEmptyInsertion(failedConstraintNames), null, false);
+ }
+
+ private static InsertionData getEmptyInsertion(List failedConstraintNames) {
+ InsertionData empty = new InsertionData.NoInsertionFound();
+ empty.getFailedConstraintNames().addAll(failedConstraintNames);
+ return empty;
}
}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java
index 6aabb134..a6607d26 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java
@@ -33,9 +33,9 @@ class Scorer {
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 = (4 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
+ score = (11 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
} else {
- score = (4 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
+ score = (11 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
}
return score;
}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java
index 977ba6ab..9f91ff9b 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java
@@ -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 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;
}
+
+
}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java
index 87c29c0e..e8698483 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java
@@ -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 activities = currentRoute.getTourActivities().getActivities();
+ List 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());
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java
index 9190a2f2..ad522012 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java
@@ -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 relevantVehicles = new ArrayList();
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_) {
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/InsertionListeners.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/InsertionListeners.java
index 37ccd7bb..f0c5e9a8 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/InsertionListeners.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/InsertionListeners.java
@@ -24,6 +24,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
public class InsertionListeners {
@@ -74,6 +75,14 @@ public class InsertionListeners {
}
}
+ public void informJobUnassignedListeners(Job unassigned, List reasons) {
+ for (InsertionListener l : listeners) {
+ if (l instanceof JobUnassignedListener) {
+ ((JobUnassignedListener) l).informJobUnassigned(unassigned, reasons);
+ }
+ }
+ }
+
public void addListener(InsertionListener insertionListener) {
listeners.add(insertionListener);
}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/JobUnassignedListener.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/JobUnassignedListener.java
new file mode 100644
index 00000000..55a2921d
--- /dev/null
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/JobUnassignedListener.java
@@ -0,0 +1,32 @@
+/*
+ * 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.listener;
+
+import com.graphhopper.jsprit.core.problem.job.Job;
+
+import java.util.Collection;
+
+/**
+ * Created by schroeder on 06/02/17.
+ */
+public interface JobUnassignedListener extends InsertionListener {
+
+ void informJobUnassigned(Job unassigned, Collection failedConstraintNames);
+
+}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java
index dcd19cd6..1275f825 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java
@@ -37,6 +37,7 @@ import java.util.List;
*/
public class ConstraintManager implements HardActivityConstraint, HardRouteConstraint, SoftActivityConstraint, SoftRouteConstraint {
+
public static enum Priority {
CRITICAL, HIGH, LOW
}
@@ -45,7 +46,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
private HardActivityLevelConstraintManager actLevelConstraintManager = new HardActivityLevelConstraintManager();
- private HardRouteLevelConstraintManager routeLevelConstraintManager = new HardRouteLevelConstraintManager();
+ private HardRouteLevelConstraintManager hardRouteConstraintManager = new HardRouteLevelConstraintManager();
private SoftActivityConstraintManager softActivityConstraintManager = new SoftActivityConstraintManager();
@@ -76,6 +77,25 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
resolveConstraints(constraints);
}
+ public Collection getHardRouteConstraints() {
+ return hardRouteConstraintManager.getConstraints();
+ }
+
+ public Collection getCriticalHardActivityConstraints() {
+ return actLevelConstraintManager.getCriticalConstraints();
+ }
+
+ public Collection getHighPrioHardActivityConstraints() {
+ return actLevelConstraintManager.getHighPrioConstraints();
+ }
+
+ public Collection getLowPrioHardActivityConstraints() {
+ return actLevelConstraintManager.getLowPrioConstraints();
+ }
+// public Collection getHardActivityConstraints() {
+// return actLevelConstraintManager.g;
+// }
+
public DependencyType[] getDependencyTypes() {
return dependencyTypes;
}
@@ -103,7 +123,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
constraintTypeKnown = true;
}
if (c instanceof HardRouteConstraint) {
- routeLevelConstraintManager.addConstraint((HardRouteConstraint) c);
+ hardRouteConstraintManager.addConstraint((HardRouteConstraint) c);
constraintTypeKnown = true;
}
if (c instanceof SoftRouteConstraint) {
@@ -152,7 +172,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
}
public void addConstraint(HardRouteConstraint routeLevelConstraint) {
- routeLevelConstraintManager.addConstraint(routeLevelConstraint);
+ hardRouteConstraintManager.addConstraint(routeLevelConstraint);
}
public void addConstraint(SoftActivityConstraint softActivityConstraint) {
@@ -165,7 +185,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
@Override
public boolean fulfilled(JobInsertionContext insertionContext) {
- return routeLevelConstraintManager.fulfilled(insertionContext);
+ return hardRouteConstraintManager.fulfilled(insertionContext);
}
@Override
@@ -176,7 +196,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
public Collection getConstraints() {
List constraints = new ArrayList();
constraints.addAll(actLevelConstraintManager.getAllConstraints());
- constraints.addAll(routeLevelConstraintManager.getConstraints());
+ constraints.addAll(hardRouteConstraintManager.getConstraints());
constraints.addAll(softActivityConstraintManager.getConstraints());
constraints.addAll(softRouteConstraintManager.getConstraints());
return Collections.unmodifiableCollection(constraints);
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java
index 38a496b6..11be0994 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java
@@ -212,15 +212,16 @@ public class Service extends AbstractJob {
}
/**
- * Set priority to service. Only 1 = high priority, 2 = medium and 3 = low are allowed.
+ * Set priority to service. Only 1 (very high) to 10 (very low) are allowed.
*
- * Default is 2 = medium.
+ * Default is 2.
*
* @param priority
* @return builder
*/
public Builder setPriority(int priority) {
- if(priority < 1 || priority > 3) throw new IllegalArgumentException("incorrect priority. only 1 = high, 2 = medium and 3 = low is allowed");
+ if (priority < 1 || priority > 10)
+ throw new IllegalArgumentException("incorrect priority. only priority values from 1 to 10 are allowed where 1 = high and 10 is low");
this.priority = priority;
return this;
}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java
index 3275e901..6b8bde5d 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java
@@ -269,7 +269,7 @@ public class Shipment extends AbstractJob {
}
/**
- * Set priority to shipment. Only 1 = high priority, 2 = medium and 3 = low are allowed.
+ * Set priority to shipment. Only 1 (high) to 10 (low) are allowed.
*
* Default is 2 = medium.
*
@@ -277,7 +277,8 @@ public class Shipment extends AbstractJob {
* @return builder
*/
public Builder setPriority(int priority) {
- if(priority < 1 || priority > 3) throw new IllegalArgumentException("incorrect priority. only 1 = high, 2 = medium and 3 = low is allowed");
+ if (priority < 1 || priority > 10)
+ throw new IllegalArgumentException("incorrect priority. only 1 (very high) to 10 (very low) are allowed");
this.priority = priority;
return this;
}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java
index 80742c4c..5e6a5d1d 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java
@@ -45,6 +45,8 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
private double[][][] matrix;
+ private final int noLocations;
+
/**
* Creates a new builder returning the matrix-builder.
*
If you want to consider symmetric matrices, set isSymmetric to true.
@@ -59,6 +61,7 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
private Builder(int noLocations, boolean isSymmetric) {
this.isSymmetric = isSymmetric;
matrix = new double[noLocations][noLocations][2];
+ this.noLocations = noLocations;
}
/**
@@ -74,11 +77,11 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
return this;
}
- private void add(int fromIndex, int toIndex, int indicatorIndex, double distance) {
+ private void add(int fromIndex, int toIndex, int indicatorIndex, double value) {
if (isSymmetric) {
- if (fromIndex < toIndex) matrix[fromIndex][toIndex][indicatorIndex] = distance;
- else matrix[toIndex][fromIndex][indicatorIndex] = distance;
- } else matrix[fromIndex][toIndex][indicatorIndex] = distance;
+ if (fromIndex < toIndex) matrix[fromIndex][toIndex][indicatorIndex] = value;
+ else matrix[toIndex][fromIndex][indicatorIndex] = value;
+ } else matrix[fromIndex][toIndex][indicatorIndex] = value;
}
/**
@@ -115,9 +118,12 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
private final double[][][] matrix;
+ private int noLocations;
+
private FastVehicleRoutingTransportCostsMatrix(Builder builder) {
this.isSymmetric = builder.isSymmetric;
matrix = builder.matrix;
+ noLocations = builder.noLocations;
}
/**
@@ -174,4 +180,9 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
return costParams.perDistanceUnit * getDistance(from.getIndex(), to.getIndex()) + costParams.perTransportTimeUnit * getTransportTime(from, to, departureTime, driver, vehicle);
}
+ public int getNoLocations() {
+ return noLocations;
+ }
+
+
}
diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java
new file mode 100644
index 00000000..34873590
--- /dev/null
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java
@@ -0,0 +1,157 @@
+/*
+ * 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.util;
+
+import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobUnassignedListener;
+import com.graphhopper.jsprit.core.problem.job.Job;
+import org.apache.commons.math3.stat.Frequency;
+
+import java.util.*;
+
+/**
+ * Created by schroeder on 06/02/17.
+ */
+public class UnassignedJobReasonTracker implements JobUnassignedListener {
+
+ Map reasons = new HashMap<>();
+
+ Map codesToReason = new HashMap<>();
+
+ Map failedConstraintNamesToCode = new HashMap<>();
+
+ Set constraintsToBeIgnored = new HashSet<>();
+
+ public UnassignedJobReasonTracker() {
+ codesToReason.put(1, "cannot serve required skill");
+ codesToReason.put(2, "cannot be visited within time window");
+ codesToReason.put(3, "does not fit into any vehicle due to capacity");
+ codesToReason.put(4, "cannot be assigned due to max distance constraint of vehicle");
+
+ failedConstraintNamesToCode.put("HardSkillConstraint", 1);
+ failedConstraintNamesToCode.put("VehicleDependentTimeWindowConstraints", 2);
+ failedConstraintNamesToCode.put("ServiceLoadRouteLevelConstraint", 3);
+ failedConstraintNamesToCode.put("PickupAndDeliverShipmentLoadActivityLevelConstraint", 3);
+ failedConstraintNamesToCode.put("ServiceLoadActivityLevelConstraint", 3);
+ failedConstraintNamesToCode.put("MaxDistanceConstraint", 4);
+ }
+
+ public void ignore(String simpleNameOfConstraint) {
+ constraintsToBeIgnored.add(simpleNameOfConstraint);
+ }
+
+ @Override
+ public void informJobUnassigned(Job unassigned, Collection failedConstraintNames) {
+ if (!this.reasons.containsKey(unassigned.getId())) {
+ this.reasons.put(unassigned.getId(), new Frequency());
+ }
+ for (String r : failedConstraintNames) {
+ if (constraintsToBeIgnored.contains(r)) continue;
+ this.reasons.get(unassigned.getId()).addValue(r);
+ }
+ }
+
+ public void put(String simpleNameOfFailedConstraint, int code, String reason) {
+ if (code <= 20)
+ throw new IllegalArgumentException("first 20 codes are reserved internally. choose a code > 20");
+ codesToReason.put(code, reason);
+ if (failedConstraintNamesToCode.containsKey(simpleNameOfFailedConstraint)) {
+ throw new IllegalArgumentException(simpleNameOfFailedConstraint + " already assigned to code and reason");
+ } else failedConstraintNamesToCode.put(simpleNameOfFailedConstraint, code);
+ }
+
+ /**
+ * For each job id, it returns frequency distribution of failed constraints (simple name of constraint) in an unmodifiable map.
+ *
+ * @return
+ */
+ public Map getReasons() {
+ return Collections.unmodifiableMap(reasons);
+ }
+
+ /**
+ * Returns an unmodifiable map of codes and reason pairs.
+ *
+ * @return
+ */
+ public Map getCodesToReason() {
+ return Collections.unmodifiableMap(codesToReason);
+ }
+
+ /**
+ * Returns an unmodifiable map of constraint names (simple name of constraint) and reason code pairs.
+ *
+ * @return
+ */
+ public Map getFailedConstraintNamesToCode() {
+ return Collections.unmodifiableMap(failedConstraintNamesToCode);
+ }
+
+ /**
+ * Returns the most likely reason code i.e. the reason (failed constraint) being observed most often.
+ *
+ * 1 --> "cannot serve required skill
+ * 2 --> "cannot be visited within time window"
+ * 3 --> "does not fit into any vehicle due to capacity"
+ * 4 --> "cannot be assigned due to max distance constraint of vehicle"
+ *
+ * @param jobId
+ * @return
+ */
+ public int getMostLikelyReasonCode(String jobId) {
+ Frequency reasons = this.reasons.get(jobId);
+ String mostLikelyReason = getMostLikely(reasons);
+ return toCode(mostLikelyReason);
+ }
+
+ /**
+ * Returns the most likely reason i.e. the reason (failed constraint) being observed most often.
+ *
+ * @param jobId
+ * @return
+ */
+ public String getMostLikelyReason(String jobId) {
+ Frequency reasons = this.reasons.get(jobId);
+ String mostLikelyReason = getMostLikely(reasons);
+ int code = toCode(mostLikelyReason);
+ if (code == -1) return mostLikelyReason;
+ else return codesToReason.get(code);
+ }
+
+ private int toCode(String mostLikelyReason) {
+ if (failedConstraintNamesToCode.containsKey(mostLikelyReason))
+ return failedConstraintNamesToCode.get(mostLikelyReason);
+ else return -1;
+ }
+
+ private String getMostLikely(Frequency reasons) {
+ Iterator, Long>> entryIterator = reasons.entrySetIterator();
+ int maxCount = 0;
+ String mostLikely = null;
+ while (entryIterator.hasNext()) {
+ Map.Entry, Long> entry = entryIterator.next();
+ if (entry.getValue() > maxCount) {
+ Comparable> key = entry.getKey();
+ mostLikely = key.toString();
+ }
+ }
+ return mostLikely;
+ }
+
+
+}
diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java
index 70dd2ee3..9713744a 100644
--- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java
+++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java
@@ -178,7 +178,7 @@ public class ShipmentInsertionCalculatorTest {
insertionCalculator.setJobActivityFactory(activityFactory);
InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
- assertEquals(InsertionData.createEmptyInsertionData(), iData);
+ assertTrue(iData instanceof InsertionData.NoInsertionFound);
}
diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java
index bec514e2..f1efce37 100644
--- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java
+++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java
@@ -250,6 +250,13 @@ public class ServiceTest {
Assert.assertEquals(3, s.getPriority());
}
+ @Test
+ public void whenSettingPriorities_itShouldBeSetCorrectly3() {
+ Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
+ .setPriority(10).build();
+ Assert.assertEquals(10, s.getPriority());
+ }
+
@Test
public void whenNotSettingPriorities_defaultShouldBe2(){
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java
index 6c463d04..cbfa1f26 100644
--- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java
+++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java
@@ -401,6 +401,14 @@ public class ShipmentTest {
Assert.assertEquals(3, s.getPriority());
}
+ @Test
+ public void whenSettingPriorities_itShouldBeSetCorrectly3() {
+ Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
+ .setDeliveryLocation(Location.newInstance("loc"))
+ .setPriority(10).build();
+ Assert.assertEquals(10, s.getPriority());
+ }
+
@Test
public void whenNotSettingPriorities_defaultShouldBe2(){
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java
new file mode 100644
index 00000000..aee8a95d
--- /dev/null
+++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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.util;
+
+import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
+import com.graphhopper.jsprit.core.algorithm.box.Jsprit;
+import com.graphhopper.jsprit.core.algorithm.state.StateId;
+import com.graphhopper.jsprit.core.algorithm.state.StateManager;
+import com.graphhopper.jsprit.core.problem.Location;
+import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
+import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
+import com.graphhopper.jsprit.core.problem.constraint.MaxDistanceConstraint;
+import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
+import com.graphhopper.jsprit.core.problem.job.Service;
+import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
+import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
+import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
+import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
+import com.graphhopper.jsprit.core.problem.vehicle.VehicleType;
+import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
+import org.apache.commons.math3.stat.Frequency;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Created by schroeder on 06/02/17.
+ */
+public class UnassignedJobReasonTrackerTest {
+
+ Vehicle vehicle;
+
+ @Before
+ public void doBefore() {
+ VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(0, 1);
+ VehicleType vehicleType = vehicleTypeBuilder.build();
+ VehicleImpl.Builder vehicleBuilder = VehicleImpl.Builder.newInstance("vehicle");
+ vehicleBuilder.setStartLocation(Location.newInstance(10, 10));
+ vehicleBuilder.setType(vehicleType);
+ vehicleBuilder.setEarliestStart(0).setLatestArrival(100);
+ vehicle = vehicleBuilder.build();
+ }
+
+ @Test
+ public void shouldReturnCorrectCapacityReasonCode() {
+ Service service = Service.Builder.newInstance("1").addSizeDimension(0, 5).setLocation(Location.newInstance(5, 7)).build();
+
+ VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service)
+ .build();
+
+ VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
+ UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
+ vra.addListener(reasonTracker);
+
+ VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
+ Assert.assertEquals(1, solution.getUnassignedJobs().size());
+ Assert.assertEquals(3, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
+ }
+
+ @Test
+ public void shouldReturnCorrectSkillReasonCode() {
+ Service service = Service.Builder.newInstance("1").addSizeDimension(0, 1).addRequiredSkill("ice").setLocation(Location.newInstance(5, 7)).build();
+
+ VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service)
+ .build();
+
+ VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
+ UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
+ vra.addListener(reasonTracker);
+
+ VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
+ Assert.assertEquals(1, solution.getUnassignedJobs().size());
+ Assert.assertEquals(1, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
+ }
+
+ @Test
+ public void shouldReturnCorrectTWReasonCode() {
+ Service service = Service.Builder.newInstance("1").addSizeDimension(0, 1).setTimeWindow(TimeWindow.newInstance(110, 200)).setLocation(Location.newInstance(5, 7)).build();
+
+ VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service)
+ .build();
+
+ VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp);
+ UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
+ vra.addListener(reasonTracker);
+
+ VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
+ Assert.assertEquals(1, solution.getUnassignedJobs().size());
+ Assert.assertEquals(2, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
+ }
+
+ @Test
+ public void shouldReturnCorrectMaxDistanceReasonCode() {
+ Service service = Service.Builder.newInstance("1").setLocation(Location.newInstance(51, 0)).build();
+
+ Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0, 0)).build();
+
+ final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service).build();
+
+ StateManager stateManager = new StateManager(vrp);
+ ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
+ StateId maxDistance = stateManager.createStateId("max-distance");
+ Map distMap = new HashMap<>();
+ distMap.put(vehicle, 100d);
+ MaxDistanceConstraint distanceConstraint = new MaxDistanceConstraint(stateManager, maxDistance, new TransportDistance() {
+ @Override
+ public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
+ return vrp.getTransportCosts().getTransportCost(from, to, departureTime, null, vehicle);
+ }
+ }, distMap);
+ constraintManager.addConstraint(distanceConstraint, ConstraintManager.Priority.CRITICAL);
+
+ VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setStateAndConstraintManager(stateManager, constraintManager)
+ .buildAlgorithm();
+ UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker();
+ vra.addListener(reasonTracker);
+
+ VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
+ Assert.assertEquals(1, solution.getUnassignedJobs().size());
+ Assert.assertEquals(4, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
+ }
+
+ @Test
+ public void testFreq() {
+ Frequency frequency = new Frequency();
+ frequency.addValue("VehicleDependentTimeWindowHardActivityConstraint");
+ frequency.addValue("b");
+ frequency.addValue("VehicleDependentTimeWindowHardActivityConstraint");
+
+ Iterator, Long>> entryIterator = frequency.entrySetIterator();
+ while (entryIterator.hasNext()) {
+ Map.Entry, Long> e = entryIterator.next();
+ System.out.println(e.getKey().toString() + " " + e.getValue());
+ }
+ }
+}
diff --git a/jsprit-examples/pom.xml b/jsprit-examples/pom.xml
index 3680ba94..23457bb6 100644
--- a/jsprit-examples/pom.xml
+++ b/jsprit-examples/pom.xml
@@ -20,7 +20,7 @@
com.graphhopper
jsprit
- 1.7-SNAPSHOT
+ 1.7.1-SNAPSHOT
4.0.0
diff --git a/jsprit-instances/pom.xml b/jsprit-instances/pom.xml
index 04a8e8f4..7d31f92e 100644
--- a/jsprit-instances/pom.xml
+++ b/jsprit-instances/pom.xml
@@ -20,7 +20,7 @@
com.graphhopper
jsprit
- 1.7-SNAPSHOT
+ 1.7.1-SNAPSHOT
4.0.0
diff --git a/jsprit-io/pom.xml b/jsprit-io/pom.xml
index 8487e20a..257aed74 100644
--- a/jsprit-io/pom.xml
+++ b/jsprit-io/pom.xml
@@ -23,7 +23,7 @@
com.graphhopper
jsprit
- 1.7-SNAPSHOT
+ 1.7.1-SNAPSHOT
4.0.0
diff --git a/pom.xml b/pom.xml
index ed207968..773d477a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
com.graphhopper
jsprit
- 1.7-SNAPSHOT
+ 1.7.1-SNAPSHOT
pom