mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
Merge branch 'master' into job-activity-refactoring
# Conflicts: # jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionData.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculator.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/SolutionCompletenessRatio.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java # jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java # jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ConfigureFixCostCalculatorTest.java # jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculatorTest.java # jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java # jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java # jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java # jsprit-io/pom.xml
This commit is contained in:
commit
9fe0b3315e
44 changed files with 1285 additions and 528 deletions
|
|
@ -1,6 +1,9 @@
|
|||
Change-log
|
||||
==========
|
||||
|
||||
**v1.7** @ 2017-01-12
|
||||
- see [Whats new](https://github.com/graphhopper/jsprit/blob/master/WHATS_NEW.md)
|
||||
|
||||
**v1.6.2** @ 2016-02-02
|
||||
|
||||
new features:
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
The following people have contributed code, bug fixes and ideas.
|
||||
|
||||
* [Abraham Gausachs](https://github.com/agausachs)
|
||||
* [Balage1551](https://github.com/balage1551)
|
||||
* [Giulio Collura](https://github.com/gcollura)
|
||||
* [Gwénaël Rault](https://github.com/braktar)
|
||||
* [Heinrich Filter](https://github.com/HeinrichFilter)
|
||||
* [jie31best](https://github.com/jie31best)
|
||||
* Josh Pilkington
|
||||
* [Julia Loikova](https://github.com/Jullil)
|
||||
* [muzuro](https://github.com/muzuro)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
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/)
|
||||
- change license from GPLv3 to [Apache v2](https://github.com/graphhopper/jsprit/blob/master/LICENSE.md) to make it even more attractive for other developers and their commercial applications
|
||||
- pushed binaries to maven central, i.e. made it better accessible and we get rid of our own repo
|
||||
- outsourced various io operations, e.g. reading writing problem/algorithm to a new module called [jsprit-io](https://github.com/graphhopper/jsprit/tree/master/jsprit-io). this way the core is even more lightweight and less dependent on other libraries
|
||||
- switched from log4j to the [logger facade slf4j](http://www.slf4j.org/) to allow developers to plugin the logger of their choice
|
||||
- made it [much more memory efficient](https://github.com/graphhopper/jsprit/issues/230) for large problems
|
||||
- fixed [memory leak](https://github.com/graphhopper/jsprit/pull/282)
|
||||
- add [priority feature](https://github.com/graphhopper/jsprit/issues/242)
|
||||
- [refine exceptions](https://github.com/graphhopper/jsprit/issues/251) to get a clear separation of IllegalArgument and [IllegalState](https://stackoverflow.com/questions/12698275/whats-the-intended-use-of-illegalstateexception)
|
||||
- many further improvements (see https://github.com/graphhopper/jsprit/issues?q=is%3Aissue+is%3Aclosed)
|
||||
|
||||
<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>
|
||||
<groupId>com.graphhopper</groupId>
|
||||
<artifactId>jsprit-core</artifactId>
|
||||
<version>1.7-RC1</version>
|
||||
<version>{version}</version>
|
||||
</dependency>
|
||||
</code></pre>
|
||||
|
||||
Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core).
|
||||
|
||||
####Build yourself
|
||||
If you want to build the master branch yourself, do this:
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<parent>
|
||||
<groupId>com.graphhopper</groupId>
|
||||
<artifactId>jsprit</artifactId>
|
||||
<version>1.6.3-SNAPSHOT</version>
|
||||
<version>1.7.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jsprit-analysis</artifactId>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<parent>
|
||||
<groupId>com.graphhopper</groupId>
|
||||
<artifactId>jsprit</artifactId>
|
||||
<version>1.6.3-SNAPSHOT</version>
|
||||
<version>1.7.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jsprit-core</artifactId>
|
||||
|
|
|
|||
|
|
@ -18,12 +18,6 @@
|
|||
|
||||
package com.graphhopper.jsprit.core.algorithm.box;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder;
|
||||
import com.graphhopper.jsprit.core.algorithm.SearchStrategy;
|
||||
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
|
||||
|
|
@ -32,24 +26,8 @@ import com.graphhopper.jsprit.core.algorithm.acceptor.SolutionAcceptor;
|
|||
import com.graphhopper.jsprit.core.algorithm.listener.AlgorithmEndsListener;
|
||||
import com.graphhopper.jsprit.core.algorithm.listener.IterationStartsListener;
|
||||
import com.graphhopper.jsprit.core.algorithm.module.RuinAndRecreateModule;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.AbstractInsertionStrategy;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.ActivityInsertionCostsCalculator;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.BestInsertion;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.BestInsertionConcurrent;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.BreakScheduling;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.DefaultScorer;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.InsertionBuilder;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.RegretInsertion;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.RegretInsertionConcurrent;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.RegretInsertionConcurrentFast;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.RegretInsertionFast;
|
||||
import com.graphhopper.jsprit.core.algorithm.ruin.JobNeighborhoods;
|
||||
import com.graphhopper.jsprit.core.algorithm.ruin.JobNeighborhoodsFactory;
|
||||
import com.graphhopper.jsprit.core.algorithm.ruin.RuinClusters;
|
||||
import com.graphhopper.jsprit.core.algorithm.ruin.RuinRadial;
|
||||
import com.graphhopper.jsprit.core.algorithm.ruin.RuinRandom;
|
||||
import com.graphhopper.jsprit.core.algorithm.ruin.RuinShareFactory;
|
||||
import com.graphhopper.jsprit.core.algorithm.ruin.RuinWorst;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.*;
|
||||
import com.graphhopper.jsprit.core.algorithm.ruin.*;
|
||||
import com.graphhopper.jsprit.core.algorithm.ruin.distance.DefaultJobDistance;
|
||||
import com.graphhopper.jsprit.core.algorithm.selector.SelectBest;
|
||||
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
|
||||
|
|
@ -68,6 +46,12 @@ import com.graphhopper.jsprit.core.util.NoiseMaker;
|
|||
import com.graphhopper.jsprit.core.util.RandomNumberGeneration;
|
||||
import com.graphhopper.jsprit.core.util.Solutions;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
||||
public class Jsprit {
|
||||
|
||||
|
|
@ -180,6 +164,8 @@ public class Jsprit {
|
|||
|
||||
private SolutionAcceptor solutionAcceptor;
|
||||
|
||||
private ScoringFunction regretScorer = null;
|
||||
|
||||
public static Builder newInstance(VehicleRoutingProblem vrp) {
|
||||
return new Builder(vrp);
|
||||
}
|
||||
|
|
@ -285,6 +271,11 @@ public class Jsprit {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setRegretScorer(ScoringFunction scoringFunction) {
|
||||
this.regretScorer = scoringFunction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public VehicleRoutingAlgorithm buildAlgorithm() {
|
||||
return new Jsprit(this).create(vrp);
|
||||
}
|
||||
|
|
@ -349,20 +340,28 @@ public class Jsprit {
|
|||
|
||||
private SolutionAcceptor acceptor;
|
||||
|
||||
private ScoringFunction regretScorer;
|
||||
|
||||
private Jsprit(Builder builder) {
|
||||
stateManager = builder.stateManager;
|
||||
constraintManager = builder.constraintManager;
|
||||
es = builder.es;
|
||||
noThreads = builder.noThreads;
|
||||
addCoreConstraints = builder.addConstraints;
|
||||
properties = builder.properties;
|
||||
objectiveFunction = builder.objectiveFunction;
|
||||
random = builder.random;
|
||||
activityInsertion = builder.activityInsertionCalculator;
|
||||
acceptor = builder.solutionAcceptor;
|
||||
this.stateManager = builder.stateManager;
|
||||
this.constraintManager = builder.constraintManager;
|
||||
this.es = builder.es;
|
||||
this.noThreads = builder.noThreads;
|
||||
this.addCoreConstraints = builder.addConstraints;
|
||||
this.properties = builder.properties;
|
||||
this.objectiveFunction = builder.objectiveFunction;
|
||||
this.random = builder.random;
|
||||
this.activityInsertion = builder.activityInsertionCalculator;
|
||||
this.acceptor = builder.solutionAcceptor;
|
||||
regretScorer = builder.regretScorer;
|
||||
}
|
||||
|
||||
private void ini(VehicleRoutingProblem vrp) {
|
||||
if (regretScorer == null) regretScorer = getRegretScorer(vrp);
|
||||
}
|
||||
|
||||
private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
|
||||
ini(vrp);
|
||||
VehicleFleetManager fm;
|
||||
if (vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)) {
|
||||
fm = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
||||
|
|
@ -389,6 +388,14 @@ public class Jsprit {
|
|||
}
|
||||
}
|
||||
|
||||
double fixedCostParam = toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()));
|
||||
IncreasingAbsoluteFixedCosts increasingAbsoluteFixedCosts = null;
|
||||
if (fixedCostParam > 0d) {
|
||||
increasingAbsoluteFixedCosts = new IncreasingAbsoluteFixedCosts(vrp.getJobs().size());
|
||||
increasingAbsoluteFixedCosts.setWeightOfFixCost(fixedCostParam);
|
||||
constraintManager.addConstraint(increasingAbsoluteFixedCosts);
|
||||
}
|
||||
|
||||
double noiseLevel = toDouble(getProperty(Parameter.INSERTION_NOISE_LEVEL.toString()));
|
||||
double noiseProbability = toDouble(getProperty(Parameter.INSERTION_NOISE_PROB.toString()));
|
||||
|
||||
|
|
@ -473,56 +480,56 @@ public class Jsprit {
|
|||
);
|
||||
|
||||
AbstractInsertionStrategy regret;
|
||||
final DefaultScorer scorer;
|
||||
final ScoringFunction scorer;
|
||||
|
||||
boolean fastRegret = Boolean.parseBoolean(getProperty(Parameter.FAST_REGRET.toString()));
|
||||
if (es != null) {
|
||||
if (fastRegret) {
|
||||
RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||
.setConcurrentMode(es, noThreads)
|
||||
.setFastRegret(true)
|
||||
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
||||
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
|
||||
.setActivityInsertionCostCalculator(activityInsertion)
|
||||
.build();
|
||||
scorer = getRegretScorer(vrp);
|
||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||
.setConcurrentMode(es, noThreads)
|
||||
.setFastRegret(true)
|
||||
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
||||
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
|
||||
.setActivityInsertionCostCalculator(activityInsertion)
|
||||
.build();
|
||||
scorer = regretScorer;
|
||||
regretInsertion.setScoringFunction(scorer);
|
||||
regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes());
|
||||
regret = regretInsertion;
|
||||
} else {
|
||||
RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||
.setConcurrentMode(es, noThreads)
|
||||
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
||||
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
|
||||
.setActivityInsertionCostCalculator(activityInsertion)
|
||||
.build();
|
||||
scorer = getRegretScorer(vrp);
|
||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||
.setConcurrentMode(es, noThreads)
|
||||
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
||||
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
|
||||
.setActivityInsertionCostCalculator(activityInsertion)
|
||||
.build();
|
||||
scorer = regretScorer;
|
||||
regretInsertion.setScoringFunction(scorer);
|
||||
regret = regretInsertion;
|
||||
}
|
||||
} else {
|
||||
if (fastRegret) {
|
||||
RegretInsertionFast regretInsertion = (RegretInsertionFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||
.setFastRegret(true)
|
||||
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
|
||||
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
||||
.setActivityInsertionCostCalculator(activityInsertion)
|
||||
.build();
|
||||
scorer = getRegretScorer(vrp);
|
||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||
.setFastRegret(true)
|
||||
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
|
||||
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
||||
.setActivityInsertionCostCalculator(activityInsertion)
|
||||
.build();
|
||||
scorer = regretScorer;
|
||||
regretInsertion.setScoringFunction(scorer);
|
||||
regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes());
|
||||
regret = regretInsertion;
|
||||
} else {
|
||||
RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
|
||||
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
||||
.setActivityInsertionCostCalculator(activityInsertion)
|
||||
.build();
|
||||
scorer = getRegretScorer(vrp);
|
||||
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
|
||||
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
|
||||
.setActivityInsertionCostCalculator(activityInsertion)
|
||||
.build();
|
||||
scorer = regretScorer;
|
||||
regretInsertion.setScoringFunction(scorer);
|
||||
regret = regretInsertion;
|
||||
}
|
||||
|
|
@ -619,6 +626,7 @@ public class Jsprit {
|
|||
vra.addListener(noiseConfigurator);
|
||||
vra.addListener(noise);
|
||||
vra.addListener(clusters);
|
||||
if (increasingAbsoluteFixedCosts != null) vra.addListener(increasingAbsoluteFixedCosts);
|
||||
|
||||
if (toBoolean(getProperty(Parameter.BREAK_SCHEDULING.toString()))) {
|
||||
vra.addListener(new BreakScheduling(vrp, stateManager, constraintManager));
|
||||
|
|
@ -726,8 +734,8 @@ public class Jsprit {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (Job j : solution.getUnassignedJobs()) {
|
||||
costs += maxCosts * 2 * (4 - j.getPriority());
|
||||
for(Job j : solution.getUnassignedJobs()){
|
||||
costs += maxCosts * 2 * (11 - j.getPriority());
|
||||
}
|
||||
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.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public abstract class AbstractInsertionStrategy implements InsertionStrategy {
|
||||
|
|
@ -92,6 +93,10 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy {
|
|||
return badJobs;
|
||||
}
|
||||
|
||||
public void markUnassigned(Job unassigned, List<String> reasons) {
|
||||
insertionsListeners.informJobUnassignedListeners(unassigned, reasons);
|
||||
}
|
||||
|
||||
public abstract Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -66,10 +66,12 @@ public final class BestInsertion extends AbstractInsertionStrategy {
|
|||
sometimesSortPriorities(unassignedJobList);
|
||||
for (Job unassignedJob : unassignedJobList) {
|
||||
Insertion bestInsertion = null;
|
||||
InsertionData empty = new InsertionData.NoInsertionFound();
|
||||
double bestInsertionCost = Double.MAX_VALUE;
|
||||
for (VehicleRoute vehicleRoute : vehicleRoutes) {
|
||||
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if (iData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()) {
|
||||
|
|
@ -84,14 +86,19 @@ public final class BestInsertion extends AbstractInsertionStrategy {
|
|||
bestInsertion = new Insertion(newRoute, newIData);
|
||||
vehicleRoutes.add(newRoute);
|
||||
}
|
||||
} else {
|
||||
empty.getFailedConstraintNames().addAll(newIData.getFailedConstraintNames());
|
||||
}
|
||||
if (bestInsertion == null) {
|
||||
badJobs.add(unassignedJob);
|
||||
markUnassigned(unassignedJob, empty.getFailedConstraintNames());
|
||||
}
|
||||
if (bestInsertion == null) badJobs.add(unassignedJob);
|
||||
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||
// nextInsertion();
|
||||
}
|
||||
return badJobs;
|
||||
}
|
||||
|
||||
|
||||
private void sometimesSortPriorities(List<Job> unassignedJobList) {
|
||||
if (random.nextDouble() < 0.5) {
|
||||
Collections.sort(unassignedJobList, new Comparator<Job>() {
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
Collections.shuffle(unassignedJobList, random);
|
||||
sometimesSortPriorities(unassignedJobList);
|
||||
List<Batch> batches = distributeRoutes(vehicleRoutes, nuOfBatches);
|
||||
List<String> failedConstraintNames = new ArrayList<>();
|
||||
for (final Job unassignedJob : unassignedJobList) {
|
||||
Insertion bestInsertion = null;
|
||||
double bestInsertionCost = Double.MAX_VALUE;
|
||||
|
|
@ -118,7 +119,10 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
for (int i = 0; i < batches.size(); i++) {
|
||||
Future<Insertion> futureIData = completionService.take();
|
||||
Insertion insertion = futureIData.get();
|
||||
if (insertion == null) continue;
|
||||
if (insertion.insertionData instanceof NoInsertionFound) {
|
||||
failedConstraintNames.addAll(insertion.getInsertionData().getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) {
|
||||
bestInsertion = insertion;
|
||||
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
|
||||
|
|
@ -136,7 +140,10 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
vehicleRoutes.add(newRoute);
|
||||
batches.get(random.nextInt(batches.size())).routes.add(newRoute);
|
||||
}
|
||||
if (bestInsertion == null) badJobs.add(unassignedJob);
|
||||
if (bestInsertion == null) {
|
||||
badJobs.add(unassignedJob);
|
||||
markUnassigned(unassignedJob, failedConstraintNames);
|
||||
}
|
||||
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||
}
|
||||
return badJobs;
|
||||
|
|
@ -155,10 +162,12 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
|
||||
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
|
||||
Insertion bestInsertion = null;
|
||||
InsertionData empty = new InsertionData.NoInsertionFound();
|
||||
double bestInsertionCost = Double.MAX_VALUE;
|
||||
for (VehicleRoute vehicleRoute : batch.routes) {
|
||||
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||
if (iData instanceof NoInsertionFound) {
|
||||
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if (iData.getInsertionCost() < bestInsertionCost) {
|
||||
|
|
@ -166,6 +175,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
bestInsertionCost = iData.getInsertionCost();
|
||||
}
|
||||
}
|
||||
if (bestInsertion == null) return new Insertion(null, empty);
|
||||
return bestInsertion;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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.algorithm.state.InternalStates;
|
||||
import com.graphhopper.jsprit.core.problem.Capacity;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
|
||||
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public final class DecreasingRelativeFixedCosts extends SolutionCompletenessRatio implements SoftRouteConstraint {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DecreasingRelativeFixedCosts.class);
|
||||
|
||||
private double weightDeltaFixCost = 0.5;
|
||||
|
||||
private RouteAndActivityStateGetter stateGetter;
|
||||
|
||||
public DecreasingRelativeFixedCosts(RouteAndActivityStateGetter stateGetter, int noJobs) {
|
||||
super(noJobs);
|
||||
this.stateGetter = stateGetter;
|
||||
logger.debug("initialise {}", this);
|
||||
}
|
||||
|
||||
|
||||
public void setWeightOfFixCost(double weight) {
|
||||
weightDeltaFixCost = weight;
|
||||
logger.debug("set weightOfFixCostSaving to {}", weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[name=DecreasingRelativeFixedCosts][weightOfFixedCostSavings=" + weightDeltaFixCost + "]";
|
||||
}
|
||||
|
||||
private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) {
|
||||
Capacity maxLoad = stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class);
|
||||
if (maxLoad == null) maxLoad = Capacity.Builder.newInstance().build();
|
||||
return maxLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCosts(JobInsertionContext insertionContext) {
|
||||
VehicleRoute route = insertionContext.getRoute();
|
||||
Capacity currentLoad = getCurrentMaxLoadInRoute(route);
|
||||
Capacity load = Capacity.addup(currentLoad, insertionContext.getJob().getSize());
|
||||
double currentRelFix = 0d;
|
||||
if (route.getVehicle() != null && !(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||
currentRelFix = route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions());
|
||||
}
|
||||
double newRelFix = insertionContext.getNewVehicle().getType().getVehicleCostParams().fix * (Capacity.divide(load, insertionContext.getNewVehicle().getType().getCapacityDimensions()));
|
||||
double decreasingRelativeFixedCosts = (1 - solutionCompletenessRatio) * (newRelFix - currentRelFix);
|
||||
return weightDeltaFixCost * solutionCompletenessRatio * decreasingRelativeFixedCosts;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -31,14 +31,14 @@ public class DellAmicoFixCostCalculator implements SoftRouteConstraint, Insertio
|
|||
|
||||
private int nuOfJobsToRecreate;
|
||||
|
||||
private final JobInsertionConsideringFixCostsCalculator calculator;
|
||||
private final IncreasingAbsoluteFixedCosts calculator;
|
||||
|
||||
private final int nuOfJobs;
|
||||
|
||||
public DellAmicoFixCostCalculator(final int nuOfJobs, final RouteAndActivityStateGetter stateGetter) {
|
||||
super();
|
||||
this.nuOfJobs = nuOfJobs;
|
||||
calculator = new JobInsertionConsideringFixCostsCalculator(null, stateGetter);
|
||||
calculator = new IncreasingAbsoluteFixedCosts(nuOfJobs);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.SoftRouteConstraint;
|
||||
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public final class IncreasingAbsoluteFixedCosts extends SolutionCompletenessRatio implements SoftRouteConstraint {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(IncreasingAbsoluteFixedCosts.class);
|
||||
|
||||
private double weightDeltaFixCost = 0.5;
|
||||
|
||||
public IncreasingAbsoluteFixedCosts(int noJobs) {
|
||||
super(noJobs);
|
||||
logger.debug("initialise {}", this);
|
||||
}
|
||||
|
||||
|
||||
public void setWeightOfFixCost(double weight) {
|
||||
weightDeltaFixCost = weight;
|
||||
logger.debug("set weightOfFixCostSaving to {}", weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[name=IncreasingAbsoluteFixedCosts][weightOfFixedCostSavings=" + weightDeltaFixCost + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCosts(JobInsertionContext insertionContext) {
|
||||
final VehicleRoute currentRoute = insertionContext.getRoute();
|
||||
double currentFix = 0d;
|
||||
if (currentRoute.getVehicle() != null && !(currentRoute.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||
currentFix = currentRoute.getVehicle().getType().getVehicleCostParams().fix;
|
||||
}
|
||||
double increasingAbsoluteFixedCosts = solutionCompletenessRatio * (insertionContext.getNewVehicle().getType().getVehicleCostParams().fix - currentFix);
|
||||
return weightDeltaFixCost * solutionCompletenessRatio * increasingAbsoluteFixedCosts;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ import java.util.List;
|
|||
*/
|
||||
public class InsertionData {
|
||||
|
||||
|
||||
public static class NoInsertionFound extends InsertionData {
|
||||
|
||||
public NoInsertionFound() {
|
||||
|
|
@ -72,6 +73,8 @@ public class InsertionData {
|
|||
|
||||
private List<Event> events = new ArrayList<>();
|
||||
|
||||
private List<String> reasons = new ArrayList<>();
|
||||
|
||||
List<Event> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
|
@ -97,6 +100,14 @@ public class InsertionData {
|
|||
return additionalTime;
|
||||
}
|
||||
|
||||
public void addFailedConstrainName(String name) {
|
||||
reasons.add(name);
|
||||
}
|
||||
|
||||
public List<String> getFailedConstraintNames() {
|
||||
return reasons;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param additionalTime the additionalTime to set
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ import java.util.*;
|
|||
class InsertionDataUpdater {
|
||||
|
||||
static boolean update(boolean addAllAvailable, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, TreeSet<VersionedInsertionData> insertionDataSet, int updateRound, Job unassignedJob, Collection<VehicleRoute> routes) {
|
||||
for (VehicleRoute route : routes) {
|
||||
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
||||
for(VehicleRoute route : routes) {
|
||||
Collection<Vehicle> relevantVehicles = new ArrayList<>();
|
||||
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||
relevantVehicles.add(route.getVehicle());
|
||||
if (addAllAvailable && !initialVehicleIds.contains(route.getVehicle().getId())) {
|
||||
|
|
@ -67,7 +67,7 @@ class InsertionDataUpdater {
|
|||
};
|
||||
}
|
||||
|
||||
static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<Job> badJobs) {
|
||||
static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<ScoredJob> badJobs) {
|
||||
ScoredJob bestScoredJob = null;
|
||||
for (Job j : unassignedJobList) {
|
||||
VehicleRoute bestRoute = null;
|
||||
|
|
@ -75,15 +75,19 @@ class InsertionDataUpdater {
|
|||
InsertionData secondBest = null;
|
||||
TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[j.getIndex()];
|
||||
Iterator<VersionedInsertionData> iterator = priorityQueue.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
List<String> failedConstraintNames = new ArrayList<>();
|
||||
while(iterator.hasNext()){
|
||||
VersionedInsertionData versionedIData = iterator.next();
|
||||
if (bestRoute != null) {
|
||||
if (versionedIData.getRoute() == bestRoute) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (versionedIData.getiData() instanceof InsertionData.NoInsertionFound) continue;
|
||||
if (!(versionedIData.getRoute().getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||
if (versionedIData.getiData() instanceof InsertionData.NoInsertionFound) {
|
||||
failedConstraintNames.addAll(versionedIData.getiData().getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if(!(versionedIData.getRoute().getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||
if (versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) {
|
||||
if (!switchAllowed) continue;
|
||||
if (initialVehicleIds.contains(versionedIData.getRoute().getVehicle().getId())) continue;
|
||||
|
|
@ -128,9 +132,9 @@ class InsertionDataUpdater {
|
|||
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
|
||||
secondBest = iData;
|
||||
}
|
||||
}
|
||||
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
|
||||
if (best == null) {
|
||||
badJobs.add(j);
|
||||
badJobs.add(new ScoredJob.BadJob(j, failedConstraintNames));
|
||||
continue;
|
||||
}
|
||||
double score = score(j, best, secondBest, scoringFunction);
|
||||
|
|
|
|||
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* 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.algorithm.state.InternalStates;
|
||||
import com.graphhopper.jsprit.core.problem.SizeDimension;
|
||||
import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint;
|
||||
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
||||
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCostsCalculator, SoftRouteConstraint {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JobInsertionConsideringFixCostsCalculator.class);
|
||||
|
||||
private final JobInsertionCostsCalculator standardServiceInsertion;
|
||||
|
||||
private double weight_deltaFixCost = 0.5;
|
||||
|
||||
private double solution_completeness_ratio = 0.5;
|
||||
|
||||
private RouteAndActivityStateGetter stateGetter;
|
||||
|
||||
public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardInsertionCalculator, RouteAndActivityStateGetter stateGetter) {
|
||||
super();
|
||||
standardServiceInsertion = standardInsertionCalculator;
|
||||
this.stateGetter = stateGetter;
|
||||
logger.debug("inialise {}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownPrice) {
|
||||
double fixcost_contribution = getFixCostContribution(currentRoute, jobToInsert, newVehicle);
|
||||
if (fixcost_contribution > bestKnownPrice) {
|
||||
return InsertionData.createEmptyInsertionData();
|
||||
}
|
||||
InsertionData iData = standardServiceInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice);
|
||||
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||
return iData;
|
||||
}
|
||||
double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution;
|
||||
InsertionData insertionData = new InsertionData(totalInsertionCost, newVehicleDepartureTime, newVehicle, newDriver);
|
||||
insertionData.getEvents().addAll(iData.getEvents());
|
||||
return insertionData;
|
||||
}
|
||||
|
||||
private double getFixCostContribution(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle) {
|
||||
SizeDimension currentMaxLoadInRoute = getCurrentMaxLoadInRoute(currentRoute);
|
||||
double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert, currentMaxLoadInRoute);
|
||||
double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert, currentMaxLoadInRoute);
|
||||
double deltaFixCost = (1 - solution_completeness_ratio) * relFixCost + solution_completeness_ratio * absFixCost;
|
||||
double fixcost_contribution = weight_deltaFixCost * solution_completeness_ratio * deltaFixCost;
|
||||
return fixcost_contribution;
|
||||
}
|
||||
|
||||
public void setWeightOfFixCost(double weight) {
|
||||
weight_deltaFixCost = weight;
|
||||
logger.debug("set weightOfFixCostSaving to {}", weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weight_deltaFixCost + "]";
|
||||
}
|
||||
|
||||
public void setSolutionCompletenessRatio(double ratio) {
|
||||
solution_completeness_ratio = ratio;
|
||||
}
|
||||
|
||||
public double getSolutionCompletenessRatio() {
|
||||
return solution_completeness_ratio;
|
||||
}
|
||||
|
||||
private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job, SizeDimension currentMaxLoadInRoute) {
|
||||
SizeDimension load = currentMaxLoadInRoute.add(job.getSize());
|
||||
double currentFix = 0.0;
|
||||
if (route.getVehicle() != null) {
|
||||
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||
currentFix += route.getVehicle().getType().getVehicleCostParams().fix;
|
||||
}
|
||||
}
|
||||
if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) {
|
||||
return Double.MAX_VALUE;
|
||||
}
|
||||
return newVehicle.getType().getVehicleCostParams().fix - currentFix;
|
||||
}
|
||||
|
||||
private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job, SizeDimension currentLoad) {
|
||||
SizeDimension load = currentLoad.add(job.getSize());
|
||||
double currentRelFix = 0.0;
|
||||
if (route.getVehicle() != null) {
|
||||
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||
currentRelFix += route.getVehicle().getType().getVehicleCostParams().fix * SizeDimension.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions());
|
||||
}
|
||||
}
|
||||
if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) {
|
||||
return Double.MAX_VALUE;
|
||||
}
|
||||
double relativeFixCost = newVehicle.getType().getVehicleCostParams().fix * (SizeDimension.divide(load, newVehicle.getType().getCapacityDimensions())) - currentRelFix;
|
||||
return relativeFixCost;
|
||||
}
|
||||
|
||||
private SizeDimension getCurrentMaxLoadInRoute(VehicleRoute route) {
|
||||
SizeDimension maxLoad = stateGetter.getRouteState(route, InternalStates.MAXLOAD, SizeDimension.class);
|
||||
if (maxLoad == null) {
|
||||
maxLoad = SizeDimension.Builder.newInstance().build();
|
||||
}
|
||||
return maxLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getCosts(JobInsertionContext insertionContext) {
|
||||
return getFixCostContribution(insertionContext.getRoute(), insertionContext.getJob(), insertionContext.getNewVehicle());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -221,10 +221,10 @@ public class JobInsertionCostsCalculatorBuilder {
|
|||
addAlgorithmListeners(standardLocal.getAlgorithmListener());
|
||||
addInsertionListeners(standardLocal.getInsertionListener());
|
||||
if (considerFixedCost) {
|
||||
CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost);
|
||||
baseCalculator = withFixed.getCalculator();
|
||||
addAlgorithmListeners(withFixed.getAlgorithmListener());
|
||||
addInsertionListeners(withFixed.getInsertionListener());
|
||||
// CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost);
|
||||
// baseCalculator = withFixed.getCalculator();
|
||||
// addAlgorithmListeners(withFixed.getAlgorithmListener());
|
||||
// addInsertionListeners(withFixed.getInsertionListener());
|
||||
}
|
||||
if (timeScheduling) {
|
||||
// baseCalculator = new CalculatesServiceInsertionWithTimeSchedulingInSlices(baseCalculator,timeSlice,neighbors);
|
||||
|
|
@ -291,14 +291,6 @@ public class JobInsertionCostsCalculatorBuilder {
|
|||
return calculatorPlusListeners;
|
||||
}
|
||||
|
||||
private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCostsCalculator baseCalculator, RouteAndActivityStateGetter activityStates2, double weightOfFixedCosts) {
|
||||
final JobInsertionConsideringFixCostsCalculator withFixCost = new JobInsertionConsideringFixCostsCalculator(baseCalculator, activityStates2);
|
||||
withFixCost.setWeightOfFixCost(weightOfFixedCosts);
|
||||
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost);
|
||||
calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost));
|
||||
return calcPlusListeners;
|
||||
}
|
||||
|
||||
private CalculatorPlusListeners createStandardRoute(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter activityStates2, int forwardLooking, int solutionMemory) {
|
||||
throw new UnsupportedOperationException("route level insertion calculation is not supported anymore");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,10 +103,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||
List<Job> jobs = new ArrayList<>(unassignedJobs);
|
||||
while (!jobs.isEmpty()) {
|
||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||
List<Job> badJobList = new ArrayList<Job>();
|
||||
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||
List<ScoredJob> badJobList = new ArrayList<>();
|
||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||
if (bestScoredJob != null) {
|
||||
if (bestScoredJob.isNewRoute()) {
|
||||
|
|
@ -115,9 +115,11 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||
jobs.remove(bestScoredJob.getJob());
|
||||
}
|
||||
for (Job bad : badJobList) {
|
||||
jobs.remove(bad);
|
||||
badJobs.add(bad);
|
||||
for (ScoredJob bad : badJobList) {
|
||||
Job unassigned = bad.getJob();
|
||||
jobs.remove(unassigned);
|
||||
badJobs.add(unassigned);
|
||||
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||
}
|
||||
}
|
||||
return badJobs;
|
||||
|
|
@ -130,12 +132,12 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
return null;
|
||||
}
|
||||
|
||||
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<Job> badJobs) {
|
||||
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<ScoredJob> badJobs) {
|
||||
ScoredJob bestScoredJob = null;
|
||||
for (Job unassignedJob : unassignedJobList) {
|
||||
ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
|
||||
if (scoredJob instanceof ScoredJob.BadJob) {
|
||||
badJobs.add(unassignedJob);
|
||||
badJobs.add(scoredJob);
|
||||
continue;
|
||||
}
|
||||
if (bestScoredJob == null) bestScoredJob = scoredJob;
|
||||
|
|
@ -156,14 +158,17 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
InsertionData best = null;
|
||||
InsertionData secondBest = null;
|
||||
VehicleRoute bestRoute = null;
|
||||
|
||||
List<String> failedConstraintNames = new ArrayList<>();
|
||||
double benchmark = Double.MAX_VALUE;
|
||||
for (VehicleRoute route : routes) {
|
||||
if (secondBest != null) {
|
||||
benchmark = secondBest.getInsertionCost();
|
||||
}
|
||||
InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark);
|
||||
if (iData instanceof InsertionData.NoInsertionFound) continue;
|
||||
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||
failedConstraintNames.addAll(iData.getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if (best == null) {
|
||||
best = iData;
|
||||
bestRoute = route;
|
||||
|
|
@ -189,9 +194,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
|
||||
secondBest = iData;
|
||||
}
|
||||
}
|
||||
} else failedConstraintNames.addAll(iData.getFailedConstraintNames());
|
||||
if (best == null) {
|
||||
return new ScoredJob.BadJob(unassignedJob);
|
||||
ScoredJob.BadJob badJob = new ScoredJob.BadJob(unassignedJob, failedConstraintNames);
|
||||
return badJob;
|
||||
}
|
||||
double score = score(unassignedJob, best, secondBest, scoringFunction);
|
||||
ScoredJob scoredJob;
|
||||
|
|
|
|||
|
|
@ -108,10 +108,10 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
}
|
||||
}
|
||||
|
||||
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
|
||||
List<Job> jobs = new ArrayList<>(unassignedJobs);
|
||||
while (!jobs.isEmpty()) {
|
||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||
List<Job> badJobList = new ArrayList<Job>();
|
||||
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||
List<ScoredJob> badJobList = new ArrayList<>();
|
||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||
if (bestScoredJob != null) {
|
||||
if (bestScoredJob.isNewRoute()) {
|
||||
|
|
@ -120,15 +120,17 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||
jobs.remove(bestScoredJob.getJob());
|
||||
}
|
||||
for (Job j : badJobList) {
|
||||
jobs.remove(j);
|
||||
badJobs.add(j);
|
||||
for (ScoredJob bad : badJobList) {
|
||||
Job unassigned = bad.getJob();
|
||||
jobs.remove(unassigned);
|
||||
badJobs.add(unassigned);
|
||||
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||
}
|
||||
}
|
||||
return badJobs;
|
||||
}
|
||||
|
||||
private ScoredJob nextJob(final Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<Job> badJobList) {
|
||||
private ScoredJob nextJob(final Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<ScoredJob> badJobList) {
|
||||
ScoredJob bestScoredJob = null;
|
||||
|
||||
for (final Job unassignedJob : unassignedJobList) {
|
||||
|
|
@ -147,7 +149,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
|||
Future<ScoredJob> fsj = completionService.take();
|
||||
ScoredJob sJob = fsj.get();
|
||||
if (sJob instanceof ScoredJob.BadJob) {
|
||||
badJobList.add(sJob.getJob());
|
||||
badJobList.add(sJob);
|
||||
continue;
|
||||
}
|
||||
if (bestScoredJob == null) {
|
||||
|
|
|
|||
|
|
@ -142,11 +142,11 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
|||
int updateRound = 0;
|
||||
Map<VehicleRoute, Integer> updates = new HashMap<VehicleRoute, Integer>();
|
||||
while (!jobs.isEmpty()) {
|
||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||
List<Job> badJobList = new ArrayList<Job>();
|
||||
if (!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
|
||||
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates);
|
||||
if (firstRun) firstRun = false;
|
||||
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||
List<ScoredJob> badJobList = new ArrayList<>();
|
||||
if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
|
||||
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound,firstRun,lastModified,updates);
|
||||
if(firstRun) firstRun = false;
|
||||
updateRound++;
|
||||
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, scoringFunction, priorityQueues, updates, unassignedJobList, badJobList);
|
||||
if (bestScoredJob != null) {
|
||||
|
|
@ -156,10 +156,13 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
|||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||
jobs.remove(bestScoredJob.getJob());
|
||||
lastModified = bestScoredJob.getRoute();
|
||||
} else lastModified = null;
|
||||
for (Job bad : badJobList) {
|
||||
jobs.remove(bad);
|
||||
badJobs.add(bad);
|
||||
}
|
||||
else lastModified = null;
|
||||
for (ScoredJob bad : badJobList) {
|
||||
Job unassigned = bad.getJob();
|
||||
jobs.remove(unassigned);
|
||||
badJobs.add(unassigned);
|
||||
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||
}
|
||||
}
|
||||
return badJobs;
|
||||
|
|
@ -169,8 +172,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
|
|||
List<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>();
|
||||
boolean updatedAllRoutes = false;
|
||||
for (final Job unassignedJob : unassignedJobList) {
|
||||
if (priorityQueues[unassignedJob.getIndex()] == null) {
|
||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
|
||||
if(priorityQueues[unassignedJob.getIndex()] == null){
|
||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
|
||||
}
|
||||
if (firstRun) {
|
||||
updatedAllRoutes = true;
|
||||
|
|
|
|||
|
|
@ -131,13 +131,12 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
|
|||
VehicleRoute lastModified = null;
|
||||
boolean firstRun = true;
|
||||
int updateRound = 0;
|
||||
Map<VehicleRoute, Integer> updates = new HashMap<VehicleRoute, Integer>();
|
||||
Map<VehicleRoute, Integer> updates = new HashMap<>();
|
||||
while (!jobs.isEmpty()) {
|
||||
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
|
||||
List<Job> badJobList = new ArrayList<Job>();
|
||||
if (!firstRun && lastModified == null)
|
||||
throw new IllegalStateException("last modified route is null. this should not be.");
|
||||
if (firstRun) {
|
||||
List<Job> unassignedJobList = new ArrayList<>(jobs);
|
||||
List<ScoredJob> badJobList = new ArrayList<>();
|
||||
if(!firstRun && lastModified == null) throw new IllegalStateException("last modified route is null. this should not be.");
|
||||
if(firstRun){
|
||||
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates);
|
||||
firstRun = false;
|
||||
} else {
|
||||
|
|
@ -154,10 +153,13 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
|
|||
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||
jobs.remove(bestScoredJob.getJob());
|
||||
lastModified = bestScoredJob.getRoute();
|
||||
} else lastModified = null;
|
||||
for (Job bad : badJobList) {
|
||||
jobs.remove(bad);
|
||||
badJobs.add(bad);
|
||||
}
|
||||
else lastModified = null;
|
||||
for (ScoredJob bad : badJobList) {
|
||||
Job unassigned = bad.getJob();
|
||||
jobs.remove(unassigned);
|
||||
badJobs.add(unassigned);
|
||||
markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames());
|
||||
}
|
||||
}
|
||||
return badJobs;
|
||||
|
|
@ -165,8 +167,8 @@ public class RegretInsertionFast extends AbstractInsertionStrategy {
|
|||
|
||||
private void updateInsertionData(TreeSet<VersionedInsertionData>[] priorityQueues, Collection<VehicleRoute> routes, List<Job> unassignedJobList, int updateRound, boolean firstRun, VehicleRoute lastModified, Map<VehicleRoute, Integer> updates) {
|
||||
for (Job unassignedJob : unassignedJobList) {
|
||||
if (priorityQueues[unassignedJob.getIndex()] == null) {
|
||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
|
||||
if(priorityQueues[unassignedJob.getIndex()] == null){
|
||||
priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator());
|
||||
}
|
||||
if (firstRun) {
|
||||
InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ package com.graphhopper.jsprit.core.algorithm.recreate;
|
|||
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 15/10/15.
|
||||
*/
|
||||
|
|
@ -28,8 +30,14 @@ class ScoredJob {
|
|||
|
||||
static class BadJob extends ScoredJob {
|
||||
|
||||
BadJob(Job job) {
|
||||
super(job, 0., null, null, false);
|
||||
BadJob(Job job, List<String> failedConstraintNames) {
|
||||
super(job, 0., getEmptyInsertion(failedConstraintNames), null, false);
|
||||
}
|
||||
|
||||
private static InsertionData getEmptyInsertion(List<String> failedConstraintNames) {
|
||||
InsertionData empty = new InsertionData.NoInsertionFound();
|
||||
empty.getFailedConstraintNames().addAll(failedConstraintNames);
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ class Scorer {
|
|||
if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob
|
||||
//if only one vehicle, I want the job to be inserted with min iCosts
|
||||
//if there are more vehicles, I want this job to be prioritized since there are no alternatives
|
||||
score = (4 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
|
||||
score = (11 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
|
||||
} else {
|
||||
score = (4 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
|
||||
score = (11 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,50 +15,48 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.graphhopper.jsprit.core.algorithm.recreate;
|
||||
|
||||
package com.graphhopper.jsprit.core.algorithm.recreate;
|
||||
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionStartsListener;
|
||||
import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobInsertedListener;
|
||||
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
|
||||
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 11/01/17.
|
||||
*/
|
||||
class SolutionCompletenessRatio implements InsertionStartsListener, JobInsertedListener {
|
||||
|
||||
final class ConfigureFixCostCalculator implements InsertionStartsListener, JobInsertedListener {
|
||||
protected double solutionCompletenessRatio = 0.5;
|
||||
|
||||
private final VehicleRoutingProblem vrp;
|
||||
|
||||
private final JobInsertionConsideringFixCostsCalculator calcConsideringFix;
|
||||
|
||||
private final double minRatio = 0.5;
|
||||
private final int nuOfJobs;
|
||||
|
||||
private int nuOfJobsToRecreate;
|
||||
|
||||
public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, JobInsertionConsideringFixCostsCalculator calcConsideringFix) {
|
||||
super();
|
||||
this.vrp = vrp;
|
||||
this.calcConsideringFix = calcConsideringFix;
|
||||
public SolutionCompletenessRatio(int nuOfJobs) {
|
||||
this.nuOfJobs = nuOfJobs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[name=configureFixCostCalculator]";
|
||||
public void setSolutionCompletenessRatio(double ratio) {
|
||||
solutionCompletenessRatio = ratio;
|
||||
}
|
||||
|
||||
public double getSolutionCompletenessRatio() {
|
||||
return solutionCompletenessRatio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
||||
this.nuOfJobsToRecreate = unassignedJobs.size();
|
||||
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
|
||||
calcConsideringFix.setSolutionCompletenessRatio(Math.max(minRatio, completenessRatio));
|
||||
solutionCompletenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
||||
nuOfJobsToRecreate--;
|
||||
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
|
||||
calcConsideringFix.setSolutionCompletenessRatio(Math.max(minRatio, completenessRatio));
|
||||
solutionCompletenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs));
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
|
|||
}
|
||||
Vehicle selectedVehicle = currentRoute.getVehicle();
|
||||
Driver selectedDriver = currentRoute.getDriver();
|
||||
InsertionData bestIData = InsertionData.createEmptyInsertionData();
|
||||
InsertionData bestIData = new InsertionData.NoInsertionFound();
|
||||
double bestKnownCost_ = bestKnownCost;
|
||||
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
||||
if (!(selectedVehicle instanceof VehicleImpl.NoVehicle)) {
|
||||
|
|
@ -115,6 +115,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
|
|||
else depTime = v.getEarliestDeparture();
|
||||
InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
|
||||
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||
bestIData.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
if (iData.getInsertionCost() < bestKnownCost_) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class InsertionListeners {
|
||||
|
|
@ -74,6 +75,14 @@ public class InsertionListeners {
|
|||
}
|
||||
}
|
||||
|
||||
public void informJobUnassignedListeners(Job unassigned, List<String> reasons) {
|
||||
for (InsertionListener l : listeners) {
|
||||
if (l instanceof JobUnassignedListener) {
|
||||
((JobUnassignedListener) l).informJobUnassigned(unassigned, reasons);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener(InsertionListener 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 static enum Priority {
|
||||
CRITICAL, HIGH, LOW
|
||||
}
|
||||
|
|
@ -45,7 +46,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
|||
|
||||
private HardActivityLevelConstraintManager actLevelConstraintManager = new HardActivityLevelConstraintManager();
|
||||
|
||||
private HardRouteLevelConstraintManager routeLevelConstraintManager = new HardRouteLevelConstraintManager();
|
||||
private HardRouteLevelConstraintManager hardRouteConstraintManager = new HardRouteLevelConstraintManager();
|
||||
|
||||
private SoftActivityConstraintManager softActivityConstraintManager = new SoftActivityConstraintManager();
|
||||
|
||||
|
|
@ -76,6 +77,25 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
|||
resolveConstraints(constraints);
|
||||
}
|
||||
|
||||
public Collection<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() {
|
||||
return dependencyTypes;
|
||||
}
|
||||
|
|
@ -103,7 +123,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
|||
constraintTypeKnown = true;
|
||||
}
|
||||
if (c instanceof HardRouteConstraint) {
|
||||
routeLevelConstraintManager.addConstraint((HardRouteConstraint) c);
|
||||
hardRouteConstraintManager.addConstraint((HardRouteConstraint) c);
|
||||
constraintTypeKnown = true;
|
||||
}
|
||||
if (c instanceof SoftRouteConstraint) {
|
||||
|
|
@ -152,7 +172,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
|||
}
|
||||
|
||||
public void addConstraint(HardRouteConstraint routeLevelConstraint) {
|
||||
routeLevelConstraintManager.addConstraint(routeLevelConstraint);
|
||||
hardRouteConstraintManager.addConstraint(routeLevelConstraint);
|
||||
}
|
||||
|
||||
public void addConstraint(SoftActivityConstraint softActivityConstraint) {
|
||||
|
|
@ -165,7 +185,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
|||
|
||||
@Override
|
||||
public boolean fulfilled(JobInsertionContext insertionContext) {
|
||||
return routeLevelConstraintManager.fulfilled(insertionContext);
|
||||
return hardRouteConstraintManager.fulfilled(insertionContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -176,7 +196,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst
|
|||
public Collection<Constraint> getConstraints() {
|
||||
List<Constraint> constraints = new ArrayList<Constraint>();
|
||||
constraints.addAll(actLevelConstraintManager.getAllConstraints());
|
||||
constraints.addAll(routeLevelConstraintManager.getConstraints());
|
||||
constraints.addAll(hardRouteConstraintManager.getConstraints());
|
||||
constraints.addAll(softActivityConstraintManager.getConstraints());
|
||||
constraints.addAll(softRouteConstraintManager.getConstraints());
|
||||
return Collections.unmodifiableCollection(constraints);
|
||||
|
|
|
|||
|
|
@ -88,9 +88,7 @@ public class MaxDistanceConstraint implements HardActivityConstraint{
|
|||
double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
|
||||
double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle());
|
||||
double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle());
|
||||
if(routeIsEmpty) {
|
||||
distancePrevAct2NextAct = 0;
|
||||
}
|
||||
if(prevAct instanceof Start && nextAct instanceof End) distancePrevAct2NextAct = 0;
|
||||
if(nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()){
|
||||
distanceNewAct2nextAct = 0;
|
||||
distancePrevAct2NextAct = 0;
|
||||
|
|
@ -105,17 +103,22 @@ public class MaxDistanceConstraint implements HardActivityConstraint{
|
|||
int iIndexOfPickup = iFacts.getRelatedActivityContext().getInsertionIndex();
|
||||
TourActivity pickup = iFacts.getAssociatedActivities().get(0);
|
||||
TourActivity actBeforePickup;
|
||||
if(iIndexOfPickup > 0) {
|
||||
actBeforePickup = iFacts.getRoute().getActivities().get(iIndexOfPickup-1);
|
||||
} else {
|
||||
actBeforePickup = new Start(iFacts.getNewVehicle().getStartLocation(),0,Double.MAX_VALUE);
|
||||
}
|
||||
TourActivity actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup);
|
||||
//ToDo account here fore End and returnToDepot
|
||||
if(iIndexOfPickup > 0) actBeforePickup = iFacts.getRoute().getActivities().get(iIndexOfPickup-1);
|
||||
else actBeforePickup = new Start(iFacts.getNewVehicle().getStartLocation(),0,Double.MAX_VALUE);
|
||||
TourActivity actAfterPickup;
|
||||
if (iIndexOfPickup < iFacts.getRoute().getActivities().size())
|
||||
actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup);
|
||||
else
|
||||
actAfterPickup = nextAct;
|
||||
double distanceActBeforePickup2Pickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), pickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle());
|
||||
double distancePickup2ActAfterPickup = distanceCalculator.getDistance(pickup.getLocation(), actAfterPickup.getLocation(), iFacts.getRelatedActivityContext().getEndTime(), iFacts.getNewVehicle());
|
||||
double distanceBeforePickup2AfterPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle());
|
||||
additionalDistanceOfPickup = distanceActBeforePickup2Pickup + distancePickup2ActAfterPickup - distanceBeforePickup2AfterPickup;
|
||||
if (routeIsEmpty) distanceBeforePickup2AfterPickup = 0;
|
||||
if (actAfterPickup instanceof End && !iFacts.getNewVehicle().isReturnToDepot()) {
|
||||
distancePickup2ActAfterPickup = 0;
|
||||
distanceBeforePickup2AfterPickup = 0;
|
||||
}
|
||||
additionalDistanceOfPickup = distanceActBeforePickup2Pickup + distancePickup2ActAfterPickup - distanceBeforePickup2AfterPickup;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* 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.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 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<>();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@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) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 getCode(String jobId) {
|
||||
Frequency reasons = this.reasons.get(jobId);
|
||||
String mostLikelyReason = getMostLikely(reasons);
|
||||
return toCode(mostLikelyReason);
|
||||
}
|
||||
|
||||
public String getReason(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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* 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 static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
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.job.Job;
|
||||
import com.graphhopper.jsprit.core.problem.job.Service;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 15/08/16.
|
||||
*/
|
||||
public class ConfigureFixCostCalculatorTest {
|
||||
|
||||
VehicleRoutingProblem vrp;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Service service = new Service.Builder("" + i).setLocation(Location.newInstance(0)).build();
|
||||
vrpBuilder.addJob(service);
|
||||
}
|
||||
vrp = vrpBuilder.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCalculateCorrectly() {
|
||||
List<Job> unassigned = new ArrayList<>();
|
||||
int count = 1;
|
||||
for (String key : vrp.getJobs().keySet()) {
|
||||
if (count <= 25) {
|
||||
unassigned.add(vrp.getJobs().get(key));
|
||||
}
|
||||
count++;
|
||||
}
|
||||
JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class), mock(StateManager.class));
|
||||
ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp, jicc);
|
||||
c.informInsertionStarts(new ArrayList<VehicleRoute>(), unassigned);
|
||||
assertEquals(0.75, jicc.getSolutionCompletenessRatio(), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeMinRatio() {
|
||||
List<Job> unassigned = new ArrayList<>();
|
||||
int count = 1;
|
||||
for (String key : vrp.getJobs().keySet()) {
|
||||
if (count <= 75) {
|
||||
unassigned.add(vrp.getJobs().get(key));
|
||||
}
|
||||
count++;
|
||||
}
|
||||
JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class), mock(StateManager.class));
|
||||
ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp, jicc);
|
||||
c.informInsertionStarts(new ArrayList<VehicleRoute>(), unassigned);
|
||||
assertEquals(0.5, jicc.getSolutionCompletenessRatio(), 0.001);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeOne() {
|
||||
List<Job> unassigned = new ArrayList<>();
|
||||
JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class), mock(StateManager.class));
|
||||
ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp, jicc);
|
||||
c.informInsertionStarts(new ArrayList<VehicleRoute>(), unassigned);
|
||||
assertEquals(1.0, jicc.getSolutionCompletenessRatio(), 0.001);
|
||||
}
|
||||
}
|
||||
|
|
@ -146,7 +146,7 @@ public class GeneralJobInsertionWithShipmentsTest {
|
|||
createInsertionCalculator(insertionContext -> false);
|
||||
|
||||
InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
|
||||
assertEquals(InsertionData.createEmptyInsertionData(), iData);
|
||||
assertTrue(iData instanceof InsertionData.NoInsertionFound);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.junit.Test;
|
|||
import com.graphhopper.jsprit.core.algorithm.state.InternalStates;
|
||||
import com.graphhopper.jsprit.core.problem.SizeDimension;
|
||||
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||
|
|
@ -35,11 +36,15 @@ import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
|
|||
|
||||
public class JobInsertionConsideringFixCostsCalculatorTest {
|
||||
|
||||
private JobInsertionConsideringFixCostsCalculator calc;
|
||||
private IncreasingAbsoluteFixedCosts absFixedCosts;
|
||||
|
||||
private Vehicle oVehicle;
|
||||
private DecreasingRelativeFixedCosts relFixedCosts;
|
||||
|
||||
private Vehicle nVehicle;
|
||||
private Vehicle small;
|
||||
|
||||
private Vehicle medium;
|
||||
|
||||
private Vehicle large;
|
||||
|
||||
private Job job;
|
||||
|
||||
|
|
@ -53,195 +58,304 @@ public class JobInsertionConsideringFixCostsCalculatorTest {
|
|||
job = mock(Job.class);
|
||||
when(job.getSize()).thenReturn(SizeDimension.Builder.newInstance().addDimension(0, 50).build());
|
||||
|
||||
oVehicle = mock(Vehicle.class);
|
||||
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).setFixedCost(50.0).build();
|
||||
when(oVehicle.getType()).thenReturn(oType);
|
||||
small = mock(Vehicle.class);
|
||||
VehicleType smallType = VehicleTypeImpl.Builder.newInstance("smallType").addCapacityDimension(0, 50).setFixedCost(50.0).build();
|
||||
when(small.getType()).thenReturn(smallType);
|
||||
|
||||
nVehicle = mock(Vehicle.class);
|
||||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).setFixedCost(100.0).build();
|
||||
when(nVehicle.getType()).thenReturn(type);
|
||||
medium = mock(Vehicle.class);
|
||||
VehicleType mediumType = VehicleTypeImpl.Builder.newInstance("mediumType").addCapacityDimension(0, 100).setFixedCost(100.0).build();
|
||||
when(medium.getType()).thenReturn(mediumType);
|
||||
|
||||
InsertionData iData = new InsertionData(0.0, 1, 1, nVehicle, null);
|
||||
large = mock(Vehicle.class);
|
||||
VehicleType largeType = VehicleTypeImpl.Builder.newInstance("largeType").addCapacityDimension(0, 400).setFixedCost(200.0).build();
|
||||
when(large.getType()).thenReturn(largeType);
|
||||
|
||||
InsertionData iData = new InsertionData(0.0, 1, 1, medium, null);
|
||||
route = mock(VehicleRoute.class);
|
||||
|
||||
when(jobInsertionCosts.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE)).thenReturn(iData);
|
||||
when(jobInsertionCosts.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE)).thenReturn(iData);
|
||||
when(jobInsertionCosts.getInsertionData(route, job, large, 0.0, null, Double.MAX_VALUE)).thenReturn(new InsertionData(0.0, 1, 1, large, null));
|
||||
|
||||
stateGetter = mock(RouteAndActivityStateGetter.class);
|
||||
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, SizeDimension.class)).thenReturn(SizeDimension.Builder.newInstance().build());
|
||||
|
||||
calc = new JobInsertionConsideringFixCostsCalculator(jobInsertionCosts, stateGetter);
|
||||
absFixedCosts = new IncreasingAbsoluteFixedCosts(10);
|
||||
relFixedCosts = new DecreasingRelativeFixedCosts(stateGetter, 10);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNullAndSolutionComplete_itShouldReturnFixedCostsOfNewVehicle() {
|
||||
calc.setSolutionCompletenessRatio(1.0);
|
||||
calc.setWeightOfFixCost(1.0);
|
||||
absFixedCosts.setSolutionCompletenessRatio(1.0);
|
||||
absFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(1.0);
|
||||
relFixedCosts.setWeightOfFixCost(1.0);
|
||||
//(1.*absFix + 0.*relFix) * completeness * weight = (1.*100. + 0.*50.) * 1. * 1. = 100.
|
||||
assertEquals(100., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
assertEquals(100., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNullAndSolutionIs0PercentComplete_itShouldReturnNoFixedCosts() {
|
||||
calc.setSolutionCompletenessRatio(0.0);
|
||||
calc.setWeightOfFixCost(1.0);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.0);
|
||||
absFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.0);
|
||||
relFixedCosts.setWeightOfFixCost(1.0);
|
||||
//(0.*absFix + 1.*relFix) * completeness * weight = 0.
|
||||
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
|
||||
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNullAndSolutionIs50PercentComplete_itShouldReturnAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
|
||||
calc.setSolutionCompletenessRatio(0.5);
|
||||
calc.setWeightOfFixCost(1.0);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.5);
|
||||
absFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.5);
|
||||
relFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.5*absFix + 0.5*relFix) * 0.5 * 1. = (0.5*100+0.5*50)*0.5*1. = 37.5
|
||||
assertEquals(37.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(37.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNullAndSolutionIs75PercentComplete_itShouldReturnAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
|
||||
calc.setSolutionCompletenessRatio(0.75);
|
||||
calc.setWeightOfFixCost(1.0);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
absFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
relFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
|
||||
//(0.75*absFix + 0.25*relFix) * 0.75 * 1.= (0.75*100.+0.25*50.)*0.75*1. = 65.625
|
||||
assertEquals(65.625, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(65.625, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNullAndSolutionCompleteAndWeightIs05_itShouldReturnHalfOfFixedCostsOfNewVehicle() {
|
||||
calc.setSolutionCompletenessRatio(1.0);
|
||||
calc.setWeightOfFixCost(.5);
|
||||
absFixedCosts.setSolutionCompletenessRatio(1.0);
|
||||
absFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(1.0);
|
||||
relFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(1.*absFix + 0.*relFix) * 1. * 0.5 = (1.*100. + 0.*50.) * 1. * 0.5 = 5.
|
||||
assertEquals(50., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(50., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNullAndSolutionIs0PercentCompleteAndWeightIs05_itShouldReturnHalfOfNoFixedCosts() {
|
||||
calc.setSolutionCompletenessRatio(0.0);
|
||||
calc.setWeightOfFixCost(.5);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.0);
|
||||
absFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.0);
|
||||
relFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.*absFix + 1.*relFix) * 0. * .5 = 0.
|
||||
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNullAndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnHalfOfAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
|
||||
calc.setSolutionCompletenessRatio(0.5);
|
||||
calc.setWeightOfFixCost(.5);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.5);
|
||||
absFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.5);
|
||||
relFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
|
||||
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*100+0.5*50)*0.5*0.5 = 18.75
|
||||
assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNullAndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnHalfOfAvgOfRelFixedAndAbsFixedCostOfNewVehicle() {
|
||||
calc.setSolutionCompletenessRatio(0.75);
|
||||
calc.setWeightOfFixCost(0.5);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
absFixedCosts.setWeightOfFixCost(0.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
relFixedCosts.setWeightOfFixCost(0.5);
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
|
||||
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*100.+0.25*50.)*0.75*0.5 = 32.8125
|
||||
assertEquals(32.8125, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(32.8125, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndSolutionComplete_itShouldReturnHalfOfFixedCostsOfNewVehicle() {
|
||||
calc.setSolutionCompletenessRatio(1.0);
|
||||
calc.setWeightOfFixCost(1.0);
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
absFixedCosts.setSolutionCompletenessRatio(1.0);
|
||||
absFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(1.0);
|
||||
relFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
|
||||
//(1.*absFix + 0.*relFix) * completeness * weight = (1.*(100.-50.) + 0.*(50.-0.)) * 1. * 1. = 50.
|
||||
assertEquals(50., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(50., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndSolutionIs0PercentComplete_itShouldReturnNoFixedCosts() {
|
||||
calc.setSolutionCompletenessRatio(0.0);
|
||||
calc.setWeightOfFixCost(1.0);
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.0);
|
||||
absFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.0);
|
||||
relFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.*absFix + 1.*relFix) * completeness * weight = 0.
|
||||
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndSolutionIs50PercentComplete_itShouldCorrectVal() {
|
||||
calc.setSolutionCompletenessRatio(0.5);
|
||||
calc.setWeightOfFixCost(1.0);
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.5);
|
||||
absFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.5);
|
||||
relFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.5*absFix + 0.5*relFix) * 0.5 * 1. = (0.5*(100-50)+0.5*(50-0))*0.5*1. = 25.
|
||||
assertEquals(25., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(25., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndSolutionIs75PercentComplete_itShouldReturnCorrectVal() {
|
||||
calc.setSolutionCompletenessRatio(0.75);
|
||||
calc.setWeightOfFixCost(1.0);
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
absFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
relFixedCosts.setWeightOfFixCost(1.0);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.75*absFix + 0.25*relFix) * 0.75 * 1.= (0.75*(100.-50.)+0.25*(50.-0.))*0.75*1. = 37.5
|
||||
assertEquals(37.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(37.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndSolutionCompleteAndWeightIs05_itShouldReturnCorrectVal() {
|
||||
calc.setSolutionCompletenessRatio(1.0);
|
||||
calc.setWeightOfFixCost(.5);
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
absFixedCosts.setSolutionCompletenessRatio(1.0);
|
||||
absFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(1.0);
|
||||
relFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(1.*absFix + 0.*relFix) * 1. * 0.5 = (1.*(100.-50.) + 0.*(50.-0.)) * 1. * 0.5 = 25.
|
||||
assertEquals(25., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(25., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndSolutionIs0PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
|
||||
calc.setSolutionCompletenessRatio(0.0);
|
||||
calc.setWeightOfFixCost(.5);
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.0);
|
||||
absFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.0);
|
||||
relFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.*absFix + 1.*relFix) * 0. * .5 = 0.
|
||||
assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
|
||||
calc.setSolutionCompletenessRatio(0.5);
|
||||
calc.setWeightOfFixCost(.5);
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.5);
|
||||
absFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.5);
|
||||
relFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(50-0))*0.5*0.5 = 12.5
|
||||
assertEquals(12.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(12.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
|
||||
calc.setSolutionCompletenessRatio(0.75);
|
||||
calc.setWeightOfFixCost(0.5);
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
absFixedCosts.setWeightOfFixCost(0.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
relFixedCosts.setWeightOfFixCost(0.5);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*(50.-0.))*0.75*0.5 = 18.75
|
||||
assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
|
||||
calc.setSolutionCompletenessRatio(0.5);
|
||||
calc.setWeightOfFixCost(.5);
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, SizeDimension.class)).thenReturn(SizeDimension.Builder.newInstance().addDimension(0, 25).build());
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.5);
|
||||
absFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.5);
|
||||
relFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).build());
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5
|
||||
assertEquals(12.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(12.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() {
|
||||
calc.setSolutionCompletenessRatio(0.75);
|
||||
calc.setWeightOfFixCost(0.5);
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
absFixedCosts.setWeightOfFixCost(0.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
relFixedCosts.setWeightOfFixCost(0.5);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*(75.-25.))*0.75*0.5 = 18.75
|
||||
assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs50PercentCompleteAndWeightIs05WithMultipleCapDims_itShouldReturnCorrectVal() {
|
||||
calc.setSolutionCompletenessRatio(.5);
|
||||
calc.setWeightOfFixCost(.5);
|
||||
absFixedCosts.setSolutionCompletenessRatio(.5);
|
||||
absFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(.5);
|
||||
relFixedCosts.setWeightOfFixCost(.5);
|
||||
|
||||
when(job.getSize()).thenReturn(SizeDimension.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
|
||||
|
||||
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
|
||||
when(oVehicle.getType()).thenReturn(oType);
|
||||
when(small.getType()).thenReturn(oType);
|
||||
|
||||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
|
||||
when(nVehicle.getType()).thenReturn(type);
|
||||
when(medium.getType()).thenReturn(type);
|
||||
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, SizeDimension.class)).thenReturn(SizeDimension.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5
|
||||
/*
|
||||
* (0.5*(100-50)+0.5*(
|
||||
|
|
@ -250,26 +364,155 @@ public class JobInsertionConsideringFixCostsCalculatorTest {
|
|||
* = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5
|
||||
* = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125
|
||||
*/
|
||||
assertEquals(7.8125, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(7.8125, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsMoreExpensive() {
|
||||
absFixedCosts.setSolutionCompletenessRatio(1);
|
||||
absFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(1);
|
||||
relFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
when(job.getSize()).thenReturn(SizeDimension.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
|
||||
|
||||
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
|
||||
when(medium.getType()).thenReturn(oType);
|
||||
|
||||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
|
||||
when(small.getType()).thenReturn(type);
|
||||
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, SizeDimension.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
|
||||
//(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5
|
||||
/*
|
||||
* (0.5*(100-50)+0.5*(
|
||||
* relFixNew - relFixOld = (75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.) =
|
||||
* )*0.5*0.5
|
||||
* = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5
|
||||
* = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125
|
||||
*/
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
|
||||
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
|
||||
assertEquals(-50d, insertionCost, 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void smallVSMediumAbsCosts() {
|
||||
absFixedCosts.setSolutionCompletenessRatio(1);
|
||||
absFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(1);
|
||||
relFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
|
||||
assertEquals(50d, insertionCost, 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void smallVSLargeAbsCosts() {
|
||||
absFixedCosts.setSolutionCompletenessRatio(1);
|
||||
absFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(1);
|
||||
relFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, large, null, 0d);
|
||||
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
|
||||
assertEquals(150d, insertionCost, 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void largeVSMediumAbsCosts() {
|
||||
absFixedCosts.setSolutionCompletenessRatio(1);
|
||||
absFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(1);
|
||||
relFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
when(route.getVehicle()).thenReturn(large);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
|
||||
assertEquals(-100d, insertionCost, 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mediumVSLargeAbsCosts() {
|
||||
absFixedCosts.setSolutionCompletenessRatio(1);
|
||||
absFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(1);
|
||||
relFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
when(route.getVehicle()).thenReturn(medium);
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, large, null, 0d);
|
||||
|
||||
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
|
||||
assertEquals(100d, insertionCost, 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsMoreExpensive2() {
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.1);
|
||||
absFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.1);
|
||||
relFixedCosts.setWeightOfFixCost(1);
|
||||
|
||||
when(job.getSize()).thenReturn(SizeDimension.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
|
||||
|
||||
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
|
||||
when(medium.getType()).thenReturn(oType);
|
||||
|
||||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
|
||||
when(small.getType()).thenReturn(type);
|
||||
|
||||
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, SizeDimension.class)).thenReturn(SizeDimension.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
|
||||
/*
|
||||
job = 50
|
||||
abs = (50 - 100) * 0.1 * 0.1 * 1.0 = -0.5
|
||||
rel = ( (75/50+100/100)/2 * 50 - (25/100 + 100/400)/2 * 100) * 0.9 * 0.1 = 3.375
|
||||
c = -0.5 + 3.375 = 2.875
|
||||
|
||||
*/
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
|
||||
double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context);
|
||||
assertEquals(2.875, insertionCost, 0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs75PercentCompleteAndWeightIs05WithMultipleCapDims_itShouldReturnCorrectVal() {
|
||||
calc.setSolutionCompletenessRatio(0.75);
|
||||
calc.setWeightOfFixCost(0.5);
|
||||
absFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
absFixedCosts.setWeightOfFixCost(0.5);
|
||||
|
||||
relFixedCosts.setSolutionCompletenessRatio(0.75);
|
||||
relFixedCosts.setWeightOfFixCost(0.5);
|
||||
|
||||
when(job.getSize()).thenReturn(SizeDimension.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build());
|
||||
|
||||
VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build();
|
||||
when(oVehicle.getType()).thenReturn(oType);
|
||||
when(small.getType()).thenReturn(oType);
|
||||
|
||||
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build();
|
||||
when(nVehicle.getType()).thenReturn(type);
|
||||
when(medium.getType()).thenReturn(type);
|
||||
|
||||
when(route.getVehicle()).thenReturn(oVehicle);
|
||||
when(route.getVehicle()).thenReturn(small);
|
||||
when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, SizeDimension.class)).thenReturn(SizeDimension.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build());
|
||||
|
||||
JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d);
|
||||
//(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*12.5)*0.75*0.5 = 15.234375
|
||||
|
||||
assertEquals(15.234375, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01);
|
||||
assertEquals(15.234375, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import com.graphhopper.jsprit.core.problem.job.Delivery;
|
|||
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||
import com.graphhopper.jsprit.core.problem.job.Pickup;
|
||||
import com.graphhopper.jsprit.core.problem.job.Shipment;
|
||||
import com.graphhopper.jsprit.core.problem.misc.ActivityContext;
|
||||
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
|
||||
|
|
@ -220,52 +221,145 @@ vehicle2 (max distance): 180.0
|
|||
}
|
||||
|
||||
@Test
|
||||
public void distanceOfShipmentInRoute() {
|
||||
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle, traveledDistanceId, Double.class);
|
||||
public void distanceOfShipmentInRoute(){
|
||||
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle,traveledDistanceId, Double.class);
|
||||
double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle, traveledDistanceId, Double.class);
|
||||
assertEquals(90d, traveledDistanceBeforeDelivery - traveledDistanceBeforePickup, 0.01);
|
||||
Assert.assertEquals(90d,traveledDistanceBeforeDelivery-traveledDistanceBeforePickup,0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void distanceOfShipmentInRouteVehicle2() {
|
||||
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle2, traveledDistanceId, Double.class);
|
||||
public void distanceOfShipmentInRouteVehicle2(){
|
||||
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle2,traveledDistanceId, Double.class);
|
||||
double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle2, traveledDistanceId, Double.class);
|
||||
assertEquals(90d, traveledDistanceBeforeDelivery - traveledDistanceBeforePickup, 0.01);
|
||||
Assert.assertEquals(90d,traveledDistanceBeforeDelivery-traveledDistanceBeforePickup,0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void distanceOfPickupInRoute() {
|
||||
public void distanceOfPickupInRoute(){
|
||||
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3), vehicle, traveledDistanceId, Double.class);
|
||||
double total = stateManager.getRouteState(route, vehicle, traveledDistanceId, Double.class);
|
||||
assertEquals(100d, total - traveledDistanceBeforePickup, 0.01);
|
||||
double total = stateManager.getRouteState(route, vehicle,traveledDistanceId, Double.class);
|
||||
Assert.assertEquals(100d,total-traveledDistanceBeforePickup,0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void distanceOfPickupInRouteVehicle2() {
|
||||
public void distanceOfPickupInRouteVehicle2(){
|
||||
double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3), vehicle2, traveledDistanceId, Double.class);
|
||||
double total = stateManager.getRouteState(route, vehicle2, traveledDistanceId, Double.class);
|
||||
assertEquals(80d, total - traveledDistanceBeforePickup, 0.01);
|
||||
double total = stateManager.getRouteState(route, vehicle2,traveledDistanceId, Double.class);
|
||||
Assert.assertEquals(80d,total-traveledDistanceBeforePickup,0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void distanceToTravelShouldBeCorrect() {
|
||||
public void distanceToTravelShouldBeCorrect(){
|
||||
double total = stateManager.getRouteState(route, vehicle, traveledDistanceId, Double.class);
|
||||
assertEquals(180d, total - stateManager.getActivityState(route.getActivities().get(0), vehicle, traveledDistanceId, Double.class), 0.01);
|
||||
assertEquals(165d, total - stateManager.getActivityState(route.getActivities().get(1), vehicle, traveledDistanceId, Double.class), 0.01);
|
||||
assertEquals(135d, total - stateManager.getActivityState(route.getActivities().get(2), vehicle, traveledDistanceId, Double.class), 0.01);
|
||||
assertEquals(100d, total - stateManager.getActivityState(route.getActivities().get(3), vehicle, traveledDistanceId, Double.class), 0.01);
|
||||
assertEquals(45d, total - stateManager.getActivityState(route.getActivities().get(4), vehicle, traveledDistanceId, Double.class), 0.01);
|
||||
Assert.assertEquals(180d,total - stateManager.getActivityState(route.getActivities().get(0),vehicle,traveledDistanceId,Double.class),0.01);
|
||||
Assert.assertEquals(165d, total - stateManager.getActivityState(route.getActivities().get(1), vehicle, traveledDistanceId, Double.class), 0.01);
|
||||
Assert.assertEquals(135d,total - stateManager.getActivityState(route.getActivities().get(2),vehicle,traveledDistanceId,Double.class),0.01);
|
||||
Assert.assertEquals(100d, total - stateManager.getActivityState(route.getActivities().get(3), vehicle, traveledDistanceId, Double.class), 0.01);
|
||||
Assert.assertEquals(45d, total - stateManager.getActivityState(route.getActivities().get(4), vehicle, traveledDistanceId, Double.class), 0.01);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void distanceToTravelShouldBeCorrectVehicle2() {
|
||||
public void distanceToTravelShouldBeCorrectVehicle2(){
|
||||
double total = stateManager.getRouteState(route, vehicle2, traveledDistanceId, Double.class);
|
||||
assertEquals(160d, total - stateManager.getActivityState(route.getActivities().get(0), vehicle2, traveledDistanceId, Double.class), 0.01);
|
||||
assertEquals(145d, total - stateManager.getActivityState(route.getActivities().get(1), vehicle2, traveledDistanceId, Double.class), 0.01);
|
||||
assertEquals(115d, total - stateManager.getActivityState(route.getActivities().get(2), vehicle2, traveledDistanceId, Double.class), 0.01);
|
||||
assertEquals(80d, total - stateManager.getActivityState(route.getActivities().get(3), vehicle2, traveledDistanceId, Double.class), 0.01);
|
||||
assertEquals(25d, total - stateManager.getActivityState(route.getActivities().get(4), vehicle2, traveledDistanceId, Double.class), 0.01);
|
||||
Assert.assertEquals(160d,total - stateManager.getActivityState(route.getActivities().get(0),vehicle2,traveledDistanceId,Double.class),0.01);
|
||||
Assert.assertEquals(145d, total - stateManager.getActivityState(route.getActivities().get(1), vehicle2, traveledDistanceId, Double.class), 0.01);
|
||||
Assert.assertEquals(115d,total - stateManager.getActivityState(route.getActivities().get(2),vehicle2,traveledDistanceId,Double.class),0.01);
|
||||
Assert.assertEquals(80d, total - stateManager.getActivityState(route.getActivities().get(3), vehicle2, traveledDistanceId, Double.class), 0.01);
|
||||
Assert.assertEquals(25d, total - stateManager.getActivityState(route.getActivities().get(4), vehicle2, traveledDistanceId, Double.class), 0.01);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddingDeliverShipment_constraintShouldWork() {
|
||||
Shipment shipment = Shipment.Builder.newInstance("s")
|
||||
.setPickupLocation(Location.newInstance(0, 3))
|
||||
.setDeliveryLocation(Location.newInstance(4, 0))
|
||||
.build();
|
||||
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v")
|
||||
.setStartLocation(Location.newInstance(0, 0))
|
||||
.build();
|
||||
final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(shipment)
|
||||
.addVehicle(vehicle)
|
||||
.build();
|
||||
VehicleRoute route = VehicleRoute.emptyRoute();
|
||||
JobInsertionContext context = new JobInsertionContext(route, shipment, vehicle, null, 0);
|
||||
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(0));
|
||||
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(1));
|
||||
maxDistanceMap = new HashMap<>();
|
||||
maxDistanceMap.put(vehicle,12d);
|
||||
|
||||
StateManager stateManager = new StateManager(vrp);
|
||||
MaxDistanceConstraint maxDistanceConstraint =
|
||||
new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() {
|
||||
@Override
|
||||
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
|
||||
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
|
||||
}
|
||||
},maxDistanceMap);
|
||||
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
|
||||
new Start(vehicle.getStartLocation(), 0, Double.MAX_VALUE),
|
||||
vrp.getActivities(shipment).get(0),
|
||||
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
|
||||
0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
|
||||
|
||||
ActivityContext pickupContext = new ActivityContext();
|
||||
pickupContext.setArrivalTime(3);
|
||||
pickupContext.setEndTime(3);
|
||||
pickupContext.setInsertionIndex(0);
|
||||
context.setRelatedActivityContext(pickupContext);
|
||||
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
|
||||
vrp.getActivities(shipment).get(0),
|
||||
vrp.getActivities(shipment).get(1),
|
||||
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
|
||||
3).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddingDeliverShipmentWithVehDiffStartEndLocs_constraintShouldWork() {
|
||||
Shipment shipment = Shipment.Builder.newInstance("s")
|
||||
.setPickupLocation(Location.newInstance(0, 1))
|
||||
.setDeliveryLocation(Location.newInstance(4, 1))
|
||||
.build();
|
||||
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v")
|
||||
.setStartLocation(Location.newInstance(0, 0))
|
||||
.setEndLocation(Location.newInstance(0, 4))
|
||||
.build();
|
||||
final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(shipment)
|
||||
.addVehicle(vehicle)
|
||||
.build();
|
||||
VehicleRoute route = VehicleRoute.emptyRoute();
|
||||
JobInsertionContext context = new JobInsertionContext(route, shipment, vehicle, null, 0);
|
||||
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(0));
|
||||
context.getAssociatedActivities().add(vrp.getActivities(shipment).get(1));
|
||||
maxDistanceMap = new HashMap<>();
|
||||
maxDistanceMap.put(vehicle,10d);
|
||||
|
||||
StateManager stateManager = new StateManager(vrp);
|
||||
MaxDistanceConstraint maxDistanceConstraint =
|
||||
new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() {
|
||||
@Override
|
||||
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
|
||||
return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle);
|
||||
}
|
||||
},maxDistanceMap);
|
||||
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
|
||||
new Start(vehicle.getStartLocation(), 0, Double.MAX_VALUE),
|
||||
vrp.getActivities(shipment).get(0),
|
||||
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
|
||||
0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
|
||||
|
||||
ActivityContext pickupContext = new ActivityContext();
|
||||
pickupContext.setArrivalTime(1);
|
||||
pickupContext.setEndTime(1);
|
||||
pickupContext.setInsertionIndex(0);
|
||||
context.setRelatedActivityContext(pickupContext);
|
||||
Assert.assertTrue(maxDistanceConstraint.fulfilled(context,
|
||||
vrp.getActivities(shipment).get(0),
|
||||
vrp.getActivities(shipment).get(1),
|
||||
new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE),
|
||||
1).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -263,6 +263,13 @@ public class ServiceTest {
|
|||
assertEquals(3, s.getPriority());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSettingPriorities_itShouldBeSetCorrectly3() {
|
||||
Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
|
||||
.setPriority(10).build();
|
||||
Assert.assertEquals(10, s.getPriority());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNotSettingPriorities_defaultShouldBe2() {
|
||||
Service s = new Service.Builder("s").setLocation(Location.newInstance("loc"))
|
||||
|
|
|
|||
|
|
@ -428,6 +428,14 @@ public class ShipmentTest {
|
|||
assertEquals(3, s.getPriority());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSettingPriorities_itShouldBeSetCorrectly3() {
|
||||
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
|
||||
.setDeliveryLocation(Location.newInstance("loc"))
|
||||
.setPriority(10).build();
|
||||
Assert.assertEquals(10, s.getPriority());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNotSettingPriorities_defaultShouldBe2() {
|
||||
Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc"))
|
||||
|
|
|
|||
|
|
@ -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.getCode(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.getCode(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.getCode(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.getCode(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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
<parent>
|
||||
<groupId>com.graphhopper</groupId>
|
||||
<artifactId>jsprit</artifactId>
|
||||
<version>1.6.3-SNAPSHOT</version>
|
||||
<version>1.7.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<parent>
|
||||
<groupId>com.graphhopper</groupId>
|
||||
<artifactId>jsprit</artifactId>
|
||||
<version>1.6.3-SNAPSHOT</version>
|
||||
<version>1.7.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
<parent>
|
||||
<groupId>com.graphhopper</groupId>
|
||||
<artifactId>jsprit</artifactId>
|
||||
<version>1.6.3-SNAPSHOT</version>
|
||||
<version>1.7.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
|
|
|||
2
pom.xml
2
pom.xml
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
<groupId>com.graphhopper</groupId>
|
||||
<artifactId>jsprit</artifactId>
|
||||
<version>1.6.3-SNAPSHOT</version>
|
||||
<version>1.7.1-SNAPSHOT</version>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue