mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
Merge branch 'master' into string-removal
This commit is contained in:
commit
fda067811b
37 changed files with 673 additions and 95 deletions
|
|
@ -1,6 +1,9 @@
|
||||||
Change-log
|
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
|
**v1.6.2** @ 2016-02-02
|
||||||
|
|
||||||
new features:
|
new features:
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
WHATS NEW
|
WHATS NEW
|
||||||
==========
|
==========
|
||||||
------------------------------
|
------------------------------
|
||||||
<b>??</b> new release **v1.7**
|
<b>2017-01-12</b> new release **v1.7**
|
||||||
- move packages to [graphhopper.com](https://graphhopper.com/)
|
- 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
|
- 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
|
- 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
|
- 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
|
- 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
|
- 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)
|
- 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)
|
- [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)
|
||||||
|
|
||||||
<b>2016-02-02</b> new release **v1.6.2**
|
<b>2016-02-02</b> new release **v1.6.2**
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,12 @@ If you want to use the latest release of jsprit-core, add the following lines to
|
||||||
<pre><code><dependency>
|
<pre><code><dependency>
|
||||||
<groupId>com.graphhopper</groupId>
|
<groupId>com.graphhopper</groupId>
|
||||||
<artifactId>jsprit-core</artifactId>
|
<artifactId>jsprit-core</artifactId>
|
||||||
<version>1.7-RC1</version>
|
<version>{version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</code></pre>
|
</code></pre>
|
||||||
|
|
||||||
|
Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core).
|
||||||
|
|
||||||
####Build yourself
|
####Build yourself
|
||||||
If you want to build the master branch yourself, do this:
|
If you want to build the master branch yourself, do this:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ First, build a vehicle with its vehicle-type:
|
||||||
|
|
||||||
<pre><code>/*
|
<pre><code>/*
|
||||||
* get a vehicle type-builder and build a type with the typeId "vehicleType" and a capacity of 2
|
* 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;
|
final int WEIGHT_INDEX = 0;
|
||||||
VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(WEIGHT_INDEX,2);
|
VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(WEIGHT_INDEX,2);
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.graphhopper</groupId>
|
<groupId>com.graphhopper</groupId>
|
||||||
<artifactId>jsprit</artifactId>
|
<artifactId>jsprit</artifactId>
|
||||||
<version>1.7-SNAPSHOT</version>
|
<version>1.7.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>jsprit-analysis</artifactId>
|
<artifactId>jsprit-analysis</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.graphhopper</groupId>
|
<groupId>com.graphhopper</groupId>
|
||||||
<artifactId>jsprit</artifactId>
|
<artifactId>jsprit</artifactId>
|
||||||
<version>1.7-SNAPSHOT</version>
|
<version>1.7.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>jsprit-core</artifactId>
|
<artifactId>jsprit-core</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -737,7 +737,7 @@ public class Jsprit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(Job j : solution.getUnassignedJobs()){
|
for(Job j : solution.getUnassignedJobs()){
|
||||||
costs += maxCosts * 2 * (4 - j.getPriority());
|
costs += maxCosts * 2 * (11 - j.getPriority());
|
||||||
}
|
}
|
||||||
return costs;
|
return costs;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
public abstract class AbstractInsertionStrategy implements InsertionStrategy {
|
public abstract class AbstractInsertionStrategy implements InsertionStrategy {
|
||||||
|
|
@ -92,6 +93,10 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy {
|
||||||
return badJobs;
|
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);
|
public abstract Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -66,10 +66,12 @@ public final class BestInsertion extends AbstractInsertionStrategy {
|
||||||
sometimesSortPriorities(unassignedJobList);
|
sometimesSortPriorities(unassignedJobList);
|
||||||
for (Job unassignedJob : unassignedJobList) {
|
for (Job unassignedJob : unassignedJobList) {
|
||||||
Insertion bestInsertion = null;
|
Insertion bestInsertion = null;
|
||||||
|
InsertionData empty = new InsertionData.NoInsertionFound();
|
||||||
double bestInsertionCost = Double.MAX_VALUE;
|
double bestInsertionCost = Double.MAX_VALUE;
|
||||||
for (VehicleRoute vehicleRoute : vehicleRoutes) {
|
for (VehicleRoute vehicleRoute : vehicleRoutes) {
|
||||||
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
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) {
|
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||||
|
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (iData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()) {
|
if (iData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()) {
|
||||||
|
|
@ -84,14 +86,19 @@ public final class BestInsertion extends AbstractInsertionStrategy {
|
||||||
bestInsertion = new Insertion(newRoute, newIData);
|
bestInsertion = new Insertion(newRoute, newIData);
|
||||||
vehicleRoutes.add(newRoute);
|
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());
|
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||||
// nextInsertion();
|
|
||||||
}
|
}
|
||||||
return badJobs;
|
return badJobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void sometimesSortPriorities(List<Job> unassignedJobList) {
|
private void sometimesSortPriorities(List<Job> unassignedJobList) {
|
||||||
if(random.nextDouble() < 0.5){
|
if(random.nextDouble() < 0.5){
|
||||||
Collections.sort(unassignedJobList, new Comparator<Job>() {
|
Collections.sort(unassignedJobList, new Comparator<Job>() {
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
Collections.shuffle(unassignedJobList, random);
|
Collections.shuffle(unassignedJobList, random);
|
||||||
sometimesSortPriorities(unassignedJobList);
|
sometimesSortPriorities(unassignedJobList);
|
||||||
List<Batch> batches = distributeRoutes(vehicleRoutes, nuOfBatches);
|
List<Batch> batches = distributeRoutes(vehicleRoutes, nuOfBatches);
|
||||||
|
List<String> failedConstraintNames = new ArrayList<>();
|
||||||
for (final Job unassignedJob : unassignedJobList) {
|
for (final Job unassignedJob : unassignedJobList) {
|
||||||
Insertion bestInsertion = null;
|
Insertion bestInsertion = null;
|
||||||
double bestInsertionCost = Double.MAX_VALUE;
|
double bestInsertionCost = Double.MAX_VALUE;
|
||||||
|
|
@ -118,7 +119,10 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
for (int i = 0; i < batches.size(); i++) {
|
for (int i = 0; i < batches.size(); i++) {
|
||||||
Future<Insertion> futureIData = completionService.take();
|
Future<Insertion> futureIData = completionService.take();
|
||||||
Insertion insertion = futureIData.get();
|
Insertion insertion = futureIData.get();
|
||||||
if (insertion == null) continue;
|
if (insertion.insertionData instanceof NoInsertionFound) {
|
||||||
|
failedConstraintNames.addAll(insertion.getInsertionData().getFailedConstraintNames());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) {
|
if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) {
|
||||||
bestInsertion = insertion;
|
bestInsertion = insertion;
|
||||||
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
|
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
|
||||||
|
|
@ -136,7 +140,10 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
vehicleRoutes.add(newRoute);
|
vehicleRoutes.add(newRoute);
|
||||||
batches.get(random.nextInt(batches.size())).routes.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());
|
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||||
}
|
}
|
||||||
return badJobs;
|
return badJobs;
|
||||||
|
|
@ -155,10 +162,12 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
|
|
||||||
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
|
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
|
||||||
Insertion bestInsertion = null;
|
Insertion bestInsertion = null;
|
||||||
|
InsertionData empty = new InsertionData.NoInsertionFound();
|
||||||
double bestInsertionCost = Double.MAX_VALUE;
|
double bestInsertionCost = Double.MAX_VALUE;
|
||||||
for (VehicleRoute vehicleRoute : batch.routes) {
|
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);
|
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||||
if (iData instanceof NoInsertionFound) {
|
if (iData instanceof NoInsertionFound) {
|
||||||
|
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (iData.getInsertionCost() < bestInsertionCost) {
|
if (iData.getInsertionCost() < bestInsertionCost) {
|
||||||
|
|
@ -166,6 +175,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
bestInsertionCost = iData.getInsertionCost();
|
bestInsertionCost = iData.getInsertionCost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (bestInsertion == null) return new Insertion(null, empty);
|
||||||
return bestInsertion;
|
return bestInsertion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class InsertionData {
|
public class InsertionData {
|
||||||
|
|
||||||
|
|
||||||
public static class NoInsertionFound extends InsertionData {
|
public static class NoInsertionFound extends InsertionData {
|
||||||
|
|
||||||
public NoInsertionFound() {
|
public NoInsertionFound() {
|
||||||
|
|
@ -75,6 +76,8 @@ public class InsertionData {
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> reasons = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the additionalTime
|
* @return the additionalTime
|
||||||
*/
|
*/
|
||||||
|
|
@ -82,6 +85,14 @@ public class InsertionData {
|
||||||
return additionalTime;
|
return additionalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addFailedConstrainName(String name) {
|
||||||
|
reasons.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getFailedConstraintNames() {
|
||||||
|
return reasons;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param additionalTime the additionalTime to set
|
* @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) {
|
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) {
|
for(VehicleRoute route : routes) {
|
||||||
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
Collection<Vehicle> relevantVehicles = new ArrayList<>();
|
||||||
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||||
relevantVehicles.add(route.getVehicle());
|
relevantVehicles.add(route.getVehicle());
|
||||||
if(addAllAvailable && !initialVehicleIds.contains(route.getVehicle().getId())){
|
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;
|
ScoredJob bestScoredJob = null;
|
||||||
for(Job j : unassignedJobList){
|
for(Job j : unassignedJobList){
|
||||||
VehicleRoute bestRoute = null;
|
VehicleRoute bestRoute = null;
|
||||||
|
|
@ -79,6 +79,7 @@ class InsertionDataUpdater {
|
||||||
InsertionData secondBest = null;
|
InsertionData secondBest = null;
|
||||||
TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[j.getIndex()];
|
TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[j.getIndex()];
|
||||||
Iterator<VersionedInsertionData> iterator = priorityQueue.iterator();
|
Iterator<VersionedInsertionData> iterator = priorityQueue.iterator();
|
||||||
|
List<String> failedConstraintNames = new ArrayList<>();
|
||||||
while(iterator.hasNext()){
|
while(iterator.hasNext()){
|
||||||
VersionedInsertionData versionedIData = iterator.next();
|
VersionedInsertionData versionedIData = iterator.next();
|
||||||
if(bestRoute != null){
|
if(bestRoute != null){
|
||||||
|
|
@ -86,7 +87,10 @@ class InsertionDataUpdater {
|
||||||
continue;
|
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.getRoute().getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||||
if (versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) {
|
if (versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) {
|
||||||
if (!switchAllowed) continue;
|
if (!switchAllowed) continue;
|
||||||
|
|
@ -136,9 +140,9 @@ class InsertionDataUpdater {
|
||||||
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
|
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
|
||||||
secondBest = iData;
|
secondBest = iData;
|
||||||
}
|
}
|
||||||
}
|
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
|
||||||
if (best == null) {
|
if (best == null) {
|
||||||
badJobs.add(j);
|
badJobs.add(new ScoredJob.BadJob(j, failedConstraintNames));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
double score = score(j, best, secondBest, scoringFunction);
|
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()) {
|
while (!jobs.isEmpty()) {
|
||||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||||
List<Job> badJobList = new ArrayList<Job>();
|
List<ScoredJob> badJobList = new ArrayList<>();
|
||||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||||
if (bestScoredJob != null) {
|
if (bestScoredJob != null) {
|
||||||
if (bestScoredJob.isNewRoute()) {
|
if (bestScoredJob.isNewRoute()) {
|
||||||
|
|
@ -117,9 +117,11 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
||||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||||
jobs.remove(bestScoredJob.getJob());
|
jobs.remove(bestScoredJob.getJob());
|
||||||
}
|
}
|
||||||
for (Job bad : badJobList) {
|
for (ScoredJob bad : badJobList) {
|
||||||
jobs.remove(bad);
|
Job unassigned = bad.getJob();
|
||||||
badJobs.add(bad);
|
jobs.remove(unassigned);
|
||||||
|
badJobs.add(unassigned);
|
||||||
|
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return badJobs;
|
return badJobs;
|
||||||
|
|
@ -132,12 +134,12 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
||||||
return null;
|
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;
|
ScoredJob bestScoredJob = null;
|
||||||
for (Job unassignedJob : unassignedJobList) {
|
for (Job unassignedJob : unassignedJobList) {
|
||||||
ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
|
ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
|
||||||
if (scoredJob instanceof ScoredJob.BadJob) {
|
if (scoredJob instanceof ScoredJob.BadJob) {
|
||||||
badJobs.add(unassignedJob);
|
badJobs.add(scoredJob);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (bestScoredJob == null) bestScoredJob = scoredJob;
|
if (bestScoredJob == null) bestScoredJob = scoredJob;
|
||||||
|
|
@ -158,14 +160,17 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
||||||
InsertionData best = null;
|
InsertionData best = null;
|
||||||
InsertionData secondBest = null;
|
InsertionData secondBest = null;
|
||||||
VehicleRoute bestRoute = null;
|
VehicleRoute bestRoute = null;
|
||||||
|
List<String> failedConstraintNames = new ArrayList<>();
|
||||||
double benchmark = Double.MAX_VALUE;
|
double benchmark = Double.MAX_VALUE;
|
||||||
for (VehicleRoute route : routes) {
|
for (VehicleRoute route : routes) {
|
||||||
if (secondBest != null) {
|
if (secondBest != null) {
|
||||||
benchmark = secondBest.getInsertionCost();
|
benchmark = secondBest.getInsertionCost();
|
||||||
}
|
}
|
||||||
InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark);
|
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) {
|
if (best == null) {
|
||||||
best = iData;
|
best = iData;
|
||||||
bestRoute = route;
|
bestRoute = route;
|
||||||
|
|
@ -191,9 +196,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
||||||
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
|
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
|
||||||
secondBest = iData;
|
secondBest = iData;
|
||||||
}
|
}
|
||||||
}
|
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
|
||||||
if (best == null) {
|
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);
|
double score = score(unassignedJob, best, secondBest, scoringFunction);
|
||||||
ScoredJob scoredJob;
|
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()) {
|
while (!jobs.isEmpty()) {
|
||||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||||
List<Job> badJobList = new ArrayList<Job>();
|
List<ScoredJob> badJobList = new ArrayList<>();
|
||||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||||
if (bestScoredJob != null) {
|
if (bestScoredJob != null) {
|
||||||
if (bestScoredJob.isNewRoute()) {
|
if (bestScoredJob.isNewRoute()) {
|
||||||
|
|
@ -121,15 +121,17 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||||
jobs.remove(bestScoredJob.getJob());
|
jobs.remove(bestScoredJob.getJob());
|
||||||
}
|
}
|
||||||
for (Job j : badJobList) {
|
for (ScoredJob bad : badJobList) {
|
||||||
jobs.remove(j);
|
Job unassigned = bad.getJob();
|
||||||
badJobs.add(j);
|
jobs.remove(unassigned);
|
||||||
|
badJobs.add(unassigned);
|
||||||
|
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return badJobs;
|
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;
|
ScoredJob bestScoredJob = null;
|
||||||
|
|
||||||
for (final Job unassignedJob : unassignedJobList) {
|
for (final Job unassignedJob : unassignedJobList) {
|
||||||
|
|
@ -148,7 +150,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
Future<ScoredJob> fsj = completionService.take();
|
Future<ScoredJob> fsj = completionService.take();
|
||||||
ScoredJob sJob = fsj.get();
|
ScoredJob sJob = fsj.get();
|
||||||
if (sJob instanceof ScoredJob.BadJob) {
|
if (sJob instanceof ScoredJob.BadJob) {
|
||||||
badJobList.add(sJob.getJob());
|
badJobList.add(sJob);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (bestScoredJob == null) {
|
if (bestScoredJob == null) {
|
||||||
|
|
|
||||||
|
|
@ -143,8 +143,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
||||||
int updateRound = 0;
|
int updateRound = 0;
|
||||||
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
|
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
|
||||||
while (!jobs.isEmpty()) {
|
while (!jobs.isEmpty()) {
|
||||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||||
List<Job> badJobList = new ArrayList<Job>();
|
List<ScoredJob> badJobList = new ArrayList<>();
|
||||||
if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
|
if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
|
||||||
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound,firstRun,lastModified,updates);
|
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound,firstRun,lastModified,updates);
|
||||||
if(firstRun) firstRun = false;
|
if(firstRun) firstRun = false;
|
||||||
|
|
@ -159,9 +159,11 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
||||||
lastModified = bestScoredJob.getRoute();
|
lastModified = bestScoredJob.getRoute();
|
||||||
}
|
}
|
||||||
else lastModified = null;
|
else lastModified = null;
|
||||||
for (Job bad : badJobList) {
|
for (ScoredJob bad : badJobList) {
|
||||||
jobs.remove(bad);
|
Job unassigned = bad.getJob();
|
||||||
badJobs.add(bad);
|
jobs.remove(unassigned);
|
||||||
|
badJobs.add(unassigned);
|
||||||
|
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return badJobs;
|
return badJobs;
|
||||||
|
|
@ -172,7 +174,7 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
||||||
boolean updatedAllRoutes = false;
|
boolean updatedAllRoutes = false;
|
||||||
for (final Job unassignedJob : unassignedJobList) {
|
for (final Job unassignedJob : unassignedJobList) {
|
||||||
if(priorityQueues[unassignedJob.getIndex()] == null){
|
if(priorityQueues[unassignedJob.getIndex()] == null){
|
||||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
|
priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
|
||||||
}
|
}
|
||||||
if(firstRun) {
|
if(firstRun) {
|
||||||
updatedAllRoutes = true;
|
updatedAllRoutes = true;
|
||||||
|
|
|
||||||
|
|
@ -131,10 +131,10 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
|
||||||
VehicleRoute lastModified = null;
|
VehicleRoute lastModified = null;
|
||||||
boolean firstRun = true;
|
boolean firstRun = true;
|
||||||
int updateRound = 0;
|
int updateRound = 0;
|
||||||
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
|
Map<VehicleRoute, Integer> updates = new HashMap<>();
|
||||||
while (!jobs.isEmpty()) {
|
while (!jobs.isEmpty()) {
|
||||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||||
List<Job> badJobList = new ArrayList<Job>();
|
List<ScoredJob> badJobList = new ArrayList<>();
|
||||||
if(!firstRun && lastModified == null) throw new IllegalStateException("last modified route is null. this should not be.");
|
if(!firstRun && lastModified == null) throw new IllegalStateException("last modified route is null. this should not be.");
|
||||||
if(firstRun){
|
if(firstRun){
|
||||||
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates);
|
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates);
|
||||||
|
|
@ -156,9 +156,11 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
|
||||||
lastModified = bestScoredJob.getRoute();
|
lastModified = bestScoredJob.getRoute();
|
||||||
}
|
}
|
||||||
else lastModified = null;
|
else lastModified = null;
|
||||||
for (Job bad : badJobList) {
|
for (ScoredJob bad : badJobList) {
|
||||||
jobs.remove(bad);
|
Job unassigned = bad.getJob();
|
||||||
badJobs.add(bad);
|
jobs.remove(unassigned);
|
||||||
|
badJobs.add(unassigned);
|
||||||
|
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return badJobs;
|
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) {
|
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) {
|
for (Job unassignedJob : unassignedJobList) {
|
||||||
if(priorityQueues[unassignedJob.getIndex()] == null){
|
if(priorityQueues[unassignedJob.getIndex()] == null){
|
||||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
|
priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
|
||||||
}
|
}
|
||||||
if(firstRun) {
|
if(firstRun) {
|
||||||
InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes);
|
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.job.Job;
|
||||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by schroeder on 15/10/15.
|
* Created by schroeder on 15/10/15.
|
||||||
*/
|
*/
|
||||||
|
|
@ -28,8 +30,14 @@ class ScoredJob {
|
||||||
|
|
||||||
static class BadJob extends ScoredJob {
|
static class BadJob extends ScoredJob {
|
||||||
|
|
||||||
BadJob(Job job) {
|
BadJob(Job job, List<String> failedConstraintNames) {
|
||||||
super(job, 0., null, null, false);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 (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 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
|
//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 {
|
} 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;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,10 @@
|
||||||
package com.graphhopper.jsprit.core.algorithm.recreate;
|
package com.graphhopper.jsprit.core.algorithm.recreate;
|
||||||
|
|
||||||
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
|
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.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.VehicleRoutingActivityCosts;
|
||||||
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
||||||
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -43,13 +47,13 @@ import java.util.Iterator;
|
||||||
*
|
*
|
||||||
* @author schroeder
|
* @author schroeder
|
||||||
*/
|
*/
|
||||||
final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
final class ServiceInsertionCalculator extends AbstractInsertionCalculator {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ServiceInsertionCalculator.class);
|
private static final Logger logger = LoggerFactory.getLogger(ServiceInsertionCalculator.class);
|
||||||
|
|
||||||
private HardRouteConstraint hardRouteLevelConstraint;
|
// private HardRouteConstraint hardRouteLevelConstraint;
|
||||||
|
|
||||||
private HardActivityConstraint hardActivityLevelConstraint;
|
// private HardActivityConstraint hardActivityLevelConstraint;
|
||||||
|
|
||||||
private SoftRouteConstraint softRouteConstraint;
|
private SoftRouteConstraint softRouteConstraint;
|
||||||
|
|
||||||
|
|
@ -65,12 +69,13 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
|
|
||||||
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
|
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
|
||||||
|
|
||||||
|
private ConstraintManager constraintManager;
|
||||||
|
|
||||||
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
|
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
|
||||||
super();
|
super();
|
||||||
this.transportCosts = routingCosts;
|
this.transportCosts = routingCosts;
|
||||||
this.activityCosts = activityCosts;
|
this.activityCosts = activityCosts;
|
||||||
hardRouteLevelConstraint = constraintManager;
|
this.constraintManager = constraintManager;
|
||||||
hardActivityLevelConstraint = constraintManager;
|
|
||||||
softActivityConstraint = constraintManager;
|
softActivityConstraint = constraintManager;
|
||||||
softRouteConstraint = constraintManager;
|
softRouteConstraint = constraintManager;
|
||||||
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
|
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
|
||||||
|
|
@ -103,9 +108,10 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
/*
|
/*
|
||||||
check hard constraints at route level
|
check hard constraints at route level
|
||||||
*/
|
*/
|
||||||
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
|
InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager);
|
||||||
return InsertionData.createEmptyInsertionData();
|
if (noInsertion != null) return noInsertion;
|
||||||
}
|
|
||||||
|
Collection<String> failedActivityConstraints = new ArrayList<>();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
check soft constraints at route level
|
check soft constraints at route level
|
||||||
|
|
@ -142,7 +148,7 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
ActivityContext activityContext = new ActivityContext();
|
ActivityContext activityContext = new ActivityContext();
|
||||||
activityContext.setInsertionIndex(actIndex);
|
activityContext.setInsertionIndex(actIndex);
|
||||||
insertionContext.setActivityContext(activityContext);
|
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)) {
|
if (status.equals(ConstraintsStatus.FULFILLED)) {
|
||||||
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
|
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
|
||||||
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
|
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
|
||||||
|
|
@ -163,7 +169,9 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
actIndex++;
|
actIndex++;
|
||||||
}
|
}
|
||||||
if(insertionIndex == InsertionData.NO_INDEX) {
|
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);
|
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
||||||
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(bestTimeWindow.getStart());
|
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(bestTimeWindow.getStart());
|
||||||
|
|
@ -173,4 +181,6 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
return insertionData;
|
return insertionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,10 @@
|
||||||
package com.graphhopper.jsprit.core.algorithm.recreate;
|
package com.graphhopper.jsprit.core.algorithm.recreate;
|
||||||
|
|
||||||
import com.graphhopper.jsprit.core.problem.JobActivityFactory;
|
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.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.VehicleRoutingActivityCosts;
|
||||||
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
||||||
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
final class ShipmentInsertionCalculator extends AbstractInsertionCalculator {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ShipmentInsertionCalculator.class);
|
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;
|
private SoftRouteConstraint softRouteConstraint;
|
||||||
|
|
||||||
|
|
@ -64,8 +69,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager) {
|
public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager) {
|
||||||
super();
|
super();
|
||||||
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
||||||
this.hardRouteLevelConstraint = constraintManager;
|
this.constraintManager = constraintManager;
|
||||||
this.hardActivityLevelConstraint = constraintManager;
|
|
||||||
this.softActivityConstraint = constraintManager;
|
this.softActivityConstraint = constraintManager;
|
||||||
this.softRouteConstraint = constraintManager;
|
this.softRouteConstraint = constraintManager;
|
||||||
this.transportCosts = routingCosts;
|
this.transportCosts = routingCosts;
|
||||||
|
|
@ -99,9 +103,8 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
/*
|
/*
|
||||||
check hard route constraints
|
check hard route constraints
|
||||||
*/
|
*/
|
||||||
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
|
InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager);
|
||||||
return InsertionData.createEmptyInsertionData();
|
if (noInsertion != null) return noInsertion;
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
check soft route constraints
|
check soft route constraints
|
||||||
*/
|
*/
|
||||||
|
|
@ -132,6 +135,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
//pickupShipmentLoop
|
//pickupShipmentLoop
|
||||||
List<TourActivity> activities = currentRoute.getTourActivities().getActivities();
|
List<TourActivity> activities = currentRoute.getTourActivities().getActivities();
|
||||||
|
|
||||||
|
List<String> failedActivityConstraints = new ArrayList<>();
|
||||||
while (!tourEnd) {
|
while (!tourEnd) {
|
||||||
TourActivity nextAct;
|
TourActivity nextAct;
|
||||||
if (i < activities.size()) {
|
if (i < activities.size()) {
|
||||||
|
|
@ -148,7 +152,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
ActivityContext activityContext = new ActivityContext();
|
ActivityContext activityContext = new ActivityContext();
|
||||||
activityContext.setInsertionIndex(i);
|
activityContext.setInsertionIndex(i);
|
||||||
insertionContext.setActivityContext(activityContext);
|
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)) {
|
if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED)) {
|
||||||
pickupInsertionNotFulfilledBreak = false;
|
pickupInsertionNotFulfilledBreak = false;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -194,7 +198,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
ActivityContext activityContext_ = new ActivityContext();
|
ActivityContext activityContext_ = new ActivityContext();
|
||||||
activityContext_.setInsertionIndex(j);
|
activityContext_.setInsertionIndex(j);
|
||||||
insertionContext.setActivityContext(activityContext_);
|
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)) {
|
if (deliverShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)) {
|
||||||
double additionalDeliveryICosts = softActivityConstraint.getCosts(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
|
double additionalDeliveryICosts = softActivityConstraint.getCosts(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
|
||||||
double deliveryAIC = calculate(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++;
|
i++;
|
||||||
}
|
}
|
||||||
if (pickupInsertionIndex == InsertionData.NO_INDEX) {
|
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);
|
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
|
||||||
pickupShipment.setTheoreticalEarliestOperationStartTime(bestPickupTimeWindow.getStart());
|
pickupShipment.setTheoreticalEarliestOperationStartTime(bestPickupTimeWindow.getStart());
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
|
||||||
}
|
}
|
||||||
Vehicle selectedVehicle = currentRoute.getVehicle();
|
Vehicle selectedVehicle = currentRoute.getVehicle();
|
||||||
Driver selectedDriver = currentRoute.getDriver();
|
Driver selectedDriver = currentRoute.getDriver();
|
||||||
InsertionData bestIData = InsertionData.createEmptyInsertionData();
|
InsertionData bestIData = new InsertionData.NoInsertionFound();
|
||||||
double bestKnownCost_ = bestKnownCost;
|
double bestKnownCost_ = bestKnownCost;
|
||||||
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
||||||
if (!(selectedVehicle instanceof VehicleImpl.NoVehicle)) {
|
if (!(selectedVehicle instanceof VehicleImpl.NoVehicle)) {
|
||||||
|
|
@ -115,6 +115,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
|
||||||
else depTime = v.getEarliestDeparture();
|
else depTime = v.getEarliestDeparture();
|
||||||
InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
|
InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
|
||||||
if (iData instanceof InsertionData.NoInsertionFound) {
|
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||||
|
bestIData.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (iData.getInsertionCost() < bestKnownCost_) {
|
if (iData.getInsertionCost() < bestKnownCost_) {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class InsertionListeners {
|
public class InsertionListeners {
|
||||||
|
|
@ -74,6 +75,14 @@ public class InsertionListeners {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void informJobUnassignedListeners(Job unassigned, List<String> reasons) {
|
||||||
|
for (InsertionListener l : listeners) {
|
||||||
|
if (l instanceof JobUnassignedListener) {
|
||||||
|
((JobUnassignedListener) l).informJobUnassigned(unassigned, reasons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addListener(InsertionListener insertionListener) {
|
public void addListener(InsertionListener insertionListener) {
|
||||||
listeners.add(insertionListener);
|
listeners.add(insertionListener);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<String> failedConstraintNames);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -37,6 +37,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class ConstraintManager implements HardActivityConstraint, HardRouteConstraint, SoftActivityConstraint, SoftRouteConstraint {
|
public class ConstraintManager implements HardActivityConstraint, HardRouteConstraint, SoftActivityConstraint, SoftRouteConstraint {
|
||||||
|
|
||||||
|
|
||||||
public static enum Priority {
|
public static enum Priority {
|
||||||
CRITICAL, HIGH, LOW
|
CRITICAL, HIGH, LOW
|
||||||
}
|
}
|
||||||
|
|
@ -45,7 +46,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
||||||
|
|
||||||
private HardActivityLevelConstraintManager actLevelConstraintManager = new HardActivityLevelConstraintManager();
|
private HardActivityLevelConstraintManager actLevelConstraintManager = new HardActivityLevelConstraintManager();
|
||||||
|
|
||||||
private HardRouteLevelConstraintManager routeLevelConstraintManager = new HardRouteLevelConstraintManager();
|
private HardRouteLevelConstraintManager hardRouteConstraintManager = new HardRouteLevelConstraintManager();
|
||||||
|
|
||||||
private SoftActivityConstraintManager softActivityConstraintManager = new SoftActivityConstraintManager();
|
private SoftActivityConstraintManager softActivityConstraintManager = new SoftActivityConstraintManager();
|
||||||
|
|
||||||
|
|
@ -76,6 +77,25 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
||||||
resolveConstraints(constraints);
|
resolveConstraints(constraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<HardRouteConstraint> getHardRouteConstraints() {
|
||||||
|
return hardRouteConstraintManager.getConstraints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<HardActivityConstraint> getCriticalHardActivityConstraints() {
|
||||||
|
return actLevelConstraintManager.getCriticalConstraints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<HardActivityConstraint> getHighPrioHardActivityConstraints() {
|
||||||
|
return actLevelConstraintManager.getHighPrioConstraints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<HardActivityConstraint> getLowPrioHardActivityConstraints() {
|
||||||
|
return actLevelConstraintManager.getLowPrioConstraints();
|
||||||
|
}
|
||||||
|
// public Collection<HardActivityConstraint> getHardActivityConstraints() {
|
||||||
|
// return actLevelConstraintManager.g;
|
||||||
|
// }
|
||||||
|
|
||||||
public DependencyType[] getDependencyTypes() {
|
public DependencyType[] getDependencyTypes() {
|
||||||
return dependencyTypes;
|
return dependencyTypes;
|
||||||
}
|
}
|
||||||
|
|
@ -103,7 +123,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
||||||
constraintTypeKnown = true;
|
constraintTypeKnown = true;
|
||||||
}
|
}
|
||||||
if (c instanceof HardRouteConstraint) {
|
if (c instanceof HardRouteConstraint) {
|
||||||
routeLevelConstraintManager.addConstraint((HardRouteConstraint) c);
|
hardRouteConstraintManager.addConstraint((HardRouteConstraint) c);
|
||||||
constraintTypeKnown = true;
|
constraintTypeKnown = true;
|
||||||
}
|
}
|
||||||
if (c instanceof SoftRouteConstraint) {
|
if (c instanceof SoftRouteConstraint) {
|
||||||
|
|
@ -152,7 +172,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConstraint(HardRouteConstraint routeLevelConstraint) {
|
public void addConstraint(HardRouteConstraint routeLevelConstraint) {
|
||||||
routeLevelConstraintManager.addConstraint(routeLevelConstraint);
|
hardRouteConstraintManager.addConstraint(routeLevelConstraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConstraint(SoftActivityConstraint softActivityConstraint) {
|
public void addConstraint(SoftActivityConstraint softActivityConstraint) {
|
||||||
|
|
@ -165,7 +185,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean fulfilled(JobInsertionContext insertionContext) {
|
public boolean fulfilled(JobInsertionContext insertionContext) {
|
||||||
return routeLevelConstraintManager.fulfilled(insertionContext);
|
return hardRouteConstraintManager.fulfilled(insertionContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -176,7 +196,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
||||||
public Collection<Constraint> getConstraints() {
|
public Collection<Constraint> getConstraints() {
|
||||||
List<Constraint> constraints = new ArrayList<Constraint>();
|
List<Constraint> constraints = new ArrayList<Constraint>();
|
||||||
constraints.addAll(actLevelConstraintManager.getAllConstraints());
|
constraints.addAll(actLevelConstraintManager.getAllConstraints());
|
||||||
constraints.addAll(routeLevelConstraintManager.getConstraints());
|
constraints.addAll(hardRouteConstraintManager.getConstraints());
|
||||||
constraints.addAll(softActivityConstraintManager.getConstraints());
|
constraints.addAll(softActivityConstraintManager.getConstraints());
|
||||||
constraints.addAll(softRouteConstraintManager.getConstraints());
|
constraints.addAll(softRouteConstraintManager.getConstraints());
|
||||||
return Collections.unmodifiableCollection(constraints);
|
return Collections.unmodifiableCollection(constraints);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
* <p>
|
* <p>
|
||||||
* Default is 2 = medium.
|
* Default is 2.
|
||||||
*
|
*
|
||||||
* @param priority
|
* @param priority
|
||||||
* @return builder
|
* @return builder
|
||||||
*/
|
*/
|
||||||
public Builder<T> setPriority(int priority) {
|
public Builder<T> 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;
|
this.priority = priority;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
* <p>
|
* <p>
|
||||||
* Default is 2 = medium.
|
* Default is 2 = medium.
|
||||||
*
|
*
|
||||||
|
|
@ -277,7 +277,8 @@ public class Shipment extends AbstractJob {
|
||||||
* @return builder
|
* @return builder
|
||||||
*/
|
*/
|
||||||
public Builder setPriority(int priority) {
|
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;
|
this.priority = priority;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
|
||||||
|
|
||||||
private double[][][] matrix;
|
private double[][][] matrix;
|
||||||
|
|
||||||
|
private final int noLocations;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new builder returning the matrix-builder.
|
* Creates a new builder returning the matrix-builder.
|
||||||
* <p>If you want to consider symmetric matrices, set isSymmetric to true.
|
* <p>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) {
|
private Builder(int noLocations, boolean isSymmetric) {
|
||||||
this.isSymmetric = isSymmetric;
|
this.isSymmetric = isSymmetric;
|
||||||
matrix = new double[noLocations][noLocations][2];
|
matrix = new double[noLocations][noLocations][2];
|
||||||
|
this.noLocations = noLocations;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -74,11 +77,11 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
|
||||||
return this;
|
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 (isSymmetric) {
|
||||||
if (fromIndex < toIndex) matrix[fromIndex][toIndex][indicatorIndex] = distance;
|
if (fromIndex < toIndex) matrix[fromIndex][toIndex][indicatorIndex] = value;
|
||||||
else matrix[toIndex][fromIndex][indicatorIndex] = distance;
|
else matrix[toIndex][fromIndex][indicatorIndex] = value;
|
||||||
} else matrix[fromIndex][toIndex][indicatorIndex] = distance;
|
} else matrix[fromIndex][toIndex][indicatorIndex] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -115,9 +118,12 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
|
||||||
|
|
||||||
private final double[][][] matrix;
|
private final double[][][] matrix;
|
||||||
|
|
||||||
|
private int noLocations;
|
||||||
|
|
||||||
private FastVehicleRoutingTransportCostsMatrix(Builder builder) {
|
private FastVehicleRoutingTransportCostsMatrix(Builder builder) {
|
||||||
this.isSymmetric = builder.isSymmetric;
|
this.isSymmetric = builder.isSymmetric;
|
||||||
matrix = builder.matrix;
|
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);
|
return costParams.perDistanceUnit * getDistance(from.getIndex(), to.getIndex()) + costParams.perTransportTimeUnit * getTransportTime(from, to, departureTime, driver, vehicle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getNoLocations() {
|
||||||
|
return noLocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<String, Frequency> reasons = new HashMap<>();
|
||||||
|
|
||||||
|
Map<Integer, String> codesToReason = new HashMap<>();
|
||||||
|
|
||||||
|
Map<String, Integer> failedConstraintNamesToCode = new HashMap<>();
|
||||||
|
|
||||||
|
Set<String> 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<String> 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<String, Frequency> getReasons() {
|
||||||
|
return Collections.unmodifiableMap(reasons);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an unmodifiable map of codes and reason pairs.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Map<Integer, String> getCodesToReason() {
|
||||||
|
return Collections.unmodifiableMap(codesToReason);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an unmodifiable map of constraint names (simple name of constraint) and reason code pairs.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Map<String, Integer> 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<Map.Entry<Comparable<?>, Long>> entryIterator = reasons.entrySetIterator();
|
||||||
|
int maxCount = 0;
|
||||||
|
String mostLikely = null;
|
||||||
|
while (entryIterator.hasNext()) {
|
||||||
|
Map.Entry<Comparable<?>, Long> entry = entryIterator.next();
|
||||||
|
if (entry.getValue() > maxCount) {
|
||||||
|
Comparable<?> key = entry.getKey();
|
||||||
|
mostLikely = key.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mostLikely;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -178,7 +178,7 @@ public class ShipmentInsertionCalculatorTest {
|
||||||
insertionCalculator.setJobActivityFactory(activityFactory);
|
insertionCalculator.setJobActivityFactory(activityFactory);
|
||||||
|
|
||||||
InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
|
InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
|
||||||
assertEquals(InsertionData.createEmptyInsertionData(), iData);
|
assertTrue(iData instanceof InsertionData.NoInsertionFound);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -250,6 +250,13 @@ public class ServiceTest {
|
||||||
Assert.assertEquals(3, s.getPriority());
|
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
|
@Test
|
||||||
public void whenNotSettingPriorities_defaultShouldBe2(){
|
public void whenNotSettingPriorities_defaultShouldBe2(){
|
||||||
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
|
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
|
||||||
|
|
|
||||||
|
|
@ -401,6 +401,14 @@ public class ShipmentTest {
|
||||||
Assert.assertEquals(3, s.getPriority());
|
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
|
@Test
|
||||||
public void whenNotSettingPriorities_defaultShouldBe2(){
|
public void whenNotSettingPriorities_defaultShouldBe2(){
|
||||||
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
|
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
|
||||||
|
|
|
||||||
|
|
@ -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<Vehicle, Double> 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<Map.Entry<Comparable<?>, Long>> entryIterator = frequency.entrySetIterator();
|
||||||
|
while (entryIterator.hasNext()) {
|
||||||
|
Map.Entry<Comparable<?>, Long> e = entryIterator.next();
|
||||||
|
System.out.println(e.getKey().toString() + " " + e.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.graphhopper</groupId>
|
<groupId>com.graphhopper</groupId>
|
||||||
<artifactId>jsprit</artifactId>
|
<artifactId>jsprit</artifactId>
|
||||||
<version>1.7-SNAPSHOT</version>
|
<version>1.7.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.graphhopper</groupId>
|
<groupId>com.graphhopper</groupId>
|
||||||
<artifactId>jsprit</artifactId>
|
<artifactId>jsprit</artifactId>
|
||||||
<version>1.7-SNAPSHOT</version>
|
<version>1.7.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>com.graphhopper</groupId>
|
<groupId>com.graphhopper</groupId>
|
||||||
<artifactId>jsprit</artifactId>
|
<artifactId>jsprit</artifactId>
|
||||||
<version>1.7-SNAPSHOT</version>
|
<version>1.7.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
||||||
2
pom.xml
2
pom.xml
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
<groupId>com.graphhopper</groupId>
|
<groupId>com.graphhopper</groupId>
|
||||||
<artifactId>jsprit</artifactId>
|
<artifactId>jsprit</artifactId>
|
||||||
<version>1.7-SNAPSHOT</version>
|
<version>1.7.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue