mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
Merge remote-tracking branch 'choose_remote_name/relaxAPI' into
PickupAndDelivery Conflicts: jsprit-core/src/main/java/algorithms/CalculatorBuilder.java jsprit-core/src/main/java/algorithms/HardConstraints.java jsprit-core/src/main/java/algorithms/ServiceInsertionCalculator.java jsprit-core/src/main/java/basics/route/TourActivities.java jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertion.java
This commit is contained in:
commit
d63abea764
122 changed files with 3454 additions and 3171 deletions
21
Changelog.md
21
Changelog.md
|
|
@ -1,21 +0,0 @@
|
||||||
Change-log
|
|
||||||
==========
|
|
||||||
**v0.0.4** @ 2013-10-17
|
|
||||||
|
|
||||||
- A number of internal improvements
|
|
||||||
- License change from GPLv2 to LGPLv3
|
|
||||||
- Add premature algorithm termination: PrematureAlgorithmBreaker.java and its implementations
|
|
||||||
- SearchStrategy.java: public SearchStrategy(SolutionSelector,SolutionAcceptor) --> public SearchStratgy(SolutionSelector,SolutionAcceptor,SolutionCostCalculator)
|
|
||||||
- SearchStrategy.java: public boolean run(...) --> public DiscoveredSolution run(...)
|
|
||||||
- VehicleImpl.VehicleType.Builder --> VehicleTypeImpl.Builder
|
|
||||||
- VehicleImpl.VehicleBuilder --> VehicleImpl.Builder
|
|
||||||
|
|
||||||
**v0.0.3** @ 2013-06-04
|
|
||||||
|
|
||||||
- Bug fix - access resources in jar
|
|
||||||
|
|
||||||
**v0.0.2** @ 2013-06-03
|
|
||||||
|
|
||||||
- Bug fix - access resources in jar
|
|
||||||
|
|
||||||
**v0.0.1** @ 2013-06-02
|
|
||||||
|
|
@ -118,8 +118,10 @@ public class AlgorithmSearchProgressChartListener implements IterationEndsListen
|
||||||
XYPlot plot = chart.getXYPlot();
|
XYPlot plot = chart.getXYPlot();
|
||||||
|
|
||||||
NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
|
NumberAxis yAxis = (NumberAxis) plot.getRangeAxis();
|
||||||
Range rangeY = new Range(minValue-0.05*minValue,maxValue + 0.05*maxValue);
|
Range rangeBounds = coll.getRangeBounds(true);
|
||||||
yAxis.setRange(rangeY);
|
double upper = Math.min(rangeBounds.getUpperBound(), rangeBounds.getLowerBound()*5);
|
||||||
|
if(upper == 0.0){ upper = 10000; }
|
||||||
|
yAxis.setRangeWithMargins(rangeBounds.getLowerBound(),upper);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ChartUtilities.saveChartAsJPEG(new File(filename), chart, 1000, 600);
|
ChartUtilities.saveChartAsJPEG(new File(filename), chart, 1000, 600);
|
||||||
|
|
@ -143,9 +145,9 @@ public class AlgorithmSearchProgressChartListener implements IterationEndsListen
|
||||||
double best = Double.MAX_VALUE;
|
double best = Double.MAX_VALUE;
|
||||||
double sum = 0.0;
|
double sum = 0.0;
|
||||||
for(VehicleRoutingProblemSolution sol : solutions){
|
for(VehicleRoutingProblemSolution sol : solutions){
|
||||||
if(sol.getCost() > worst) worst = sol.getCost();
|
if(sol.getCost() > worst) worst = Math.min(sol.getCost(),Double.MAX_VALUE);
|
||||||
if(sol.getCost() < best) best = sol.getCost();
|
if(sol.getCost() < best) best = sol.getCost();
|
||||||
sum += sol.getCost();
|
sum += Math.min(sol.getCost(),Double.MAX_VALUE);
|
||||||
}
|
}
|
||||||
bestResultList.add(best);
|
bestResultList.add(best);
|
||||||
worstResultList.add(worst);
|
worstResultList.add(worst);
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,9 @@ package algorithms;
|
||||||
|
|
||||||
import basics.route.TourActivity;
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
interface ActivityInsertionCostsCalculator {
|
public interface ActivityInsertionCostsCalculator {
|
||||||
|
|
||||||
class ActivityInsertionCosts {
|
public class ActivityInsertionCosts {
|
||||||
|
|
||||||
private double additionalCosts;
|
private double additionalCosts;
|
||||||
private double additionalTime;
|
private double additionalTime;
|
||||||
|
|
@ -50,6 +50,6 @@ interface ActivityInsertionCostsCalculator {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivityInsertionCosts calculate(InsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct);
|
public ActivityInsertionCosts getCosts(InsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ class AvgJobDistance implements JobDistance {
|
||||||
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
|
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public double calculateDistance(Job i, Job j) {
|
public double getDistance(Job i, Job j) {
|
||||||
if (i.equals(j)) return 0.0;
|
if (i.equals(j)) return 0.0;
|
||||||
|
|
||||||
if (i instanceof Service && j instanceof Service) {
|
if (i instanceof Service && j instanceof Service) {
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,28 @@ import basics.route.VehicleRoute;
|
||||||
|
|
||||||
final class BestInsertion implements InsertionStrategy{
|
final class BestInsertion implements InsertionStrategy{
|
||||||
|
|
||||||
|
class Insertion {
|
||||||
|
|
||||||
|
private final VehicleRoute route;
|
||||||
|
|
||||||
|
private final InsertionData insertionData;
|
||||||
|
|
||||||
|
public Insertion(VehicleRoute vehicleRoute, InsertionData insertionData) {
|
||||||
|
super();
|
||||||
|
this.route = vehicleRoute;
|
||||||
|
this.insertionData = insertionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoute getRoute() {
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InsertionData getInsertionData() {
|
||||||
|
return insertionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private static Logger logger = Logger.getLogger(BestInsertion.class);
|
private static Logger logger = Logger.getLogger(BestInsertion.class);
|
||||||
|
|
||||||
private Random random = RandomNumberGeneration.getRandom();
|
private Random random = RandomNumberGeneration.getRandom();
|
||||||
|
|
@ -56,7 +78,7 @@ final class BestInsertion implements InsertionStrategy{
|
||||||
|
|
||||||
private Inserter inserter;
|
private Inserter inserter;
|
||||||
|
|
||||||
private JobInsertionCalculator bestInsertionCostCalculator;
|
private JobInsertionCostsCalculator bestInsertionCostCalculator;
|
||||||
|
|
||||||
private boolean minVehiclesFirst = false;
|
private boolean minVehiclesFirst = false;
|
||||||
|
|
||||||
|
|
@ -64,7 +86,7 @@ final class BestInsertion implements InsertionStrategy{
|
||||||
this.random = random;
|
this.random = random;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BestInsertion(JobInsertionCalculator jobInsertionCalculator) {
|
public BestInsertion(JobInsertionCostsCalculator jobInsertionCalculator) {
|
||||||
super();
|
super();
|
||||||
this.insertionsListeners = new InsertionListeners();
|
this.insertionsListeners = new InsertionListeners();
|
||||||
inserter = new Inserter(insertionsListeners);
|
inserter = new Inserter(insertionsListeners);
|
||||||
|
|
@ -86,7 +108,7 @@ final class BestInsertion implements InsertionStrategy{
|
||||||
Insertion bestInsertion = null;
|
Insertion bestInsertion = null;
|
||||||
double bestInsertionCost = Double.MAX_VALUE;
|
double bestInsertionCost = Double.MAX_VALUE;
|
||||||
for(VehicleRoute vehicleRoute : vehicleRoutes){
|
for(VehicleRoute vehicleRoute : vehicleRoutes){
|
||||||
InsertionData iData = bestInsertionCostCalculator.calculate(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||||
if(iData instanceof NoInsertionFound) {
|
if(iData instanceof NoInsertionFound) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +119,7 @@ final class BestInsertion implements InsertionStrategy{
|
||||||
}
|
}
|
||||||
if(!minVehiclesFirst){
|
if(!minVehiclesFirst){
|
||||||
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
||||||
InsertionData newIData = bestInsertionCostCalculator.calculate(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
InsertionData newIData = bestInsertionCostCalculator.getInsertionData(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||||
if(newIData.getInsertionCost() < bestInsertionCost){
|
if(newIData.getInsertionCost() < bestInsertionCost){
|
||||||
bestInsertion = new Insertion(newRoute,newIData);
|
bestInsertion = new Insertion(newRoute,newIData);
|
||||||
bestInsertionCost = newIData.getInsertionCost();
|
bestInsertionCost = newIData.getInsertionCost();
|
||||||
|
|
@ -106,7 +128,7 @@ final class BestInsertion implements InsertionStrategy{
|
||||||
}
|
}
|
||||||
if(bestInsertion == null){
|
if(bestInsertion == null){
|
||||||
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
||||||
InsertionData bestI = bestInsertionCostCalculator.calculate(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
|
InsertionData bestI = bestInsertionCostCalculator.getInsertionData(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
|
||||||
if(bestI instanceof InsertionData.NoInsertionFound){
|
if(bestI instanceof InsertionData.NoInsertionFound){
|
||||||
throw new IllegalStateException(getErrorMsg(unassignedJob));
|
throw new IllegalStateException(getErrorMsg(unassignedJob));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
129
jsprit-core/src/main/java/algorithms/BestInsertionBuilder.java
Normal file
129
jsprit-core/src/main/java/algorithms/BestInsertionBuilder.java
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblem.Constraint;
|
||||||
|
import basics.algo.InsertionListener;
|
||||||
|
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
|
|
||||||
|
public class BestInsertionBuilder implements InsertionStrategyBuilder{
|
||||||
|
|
||||||
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
|
private StateManager stateManager;
|
||||||
|
|
||||||
|
private boolean local = true;
|
||||||
|
|
||||||
|
private ConstraintManager constraintManager;
|
||||||
|
|
||||||
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
|
private double weightOfFixedCosts;
|
||||||
|
|
||||||
|
private boolean considerFixedCosts = false;
|
||||||
|
|
||||||
|
private ActivityInsertionCostsCalculator actInsertionCostsCalculator = null;
|
||||||
|
|
||||||
|
private int forwaredLooking;
|
||||||
|
|
||||||
|
private int memory;
|
||||||
|
|
||||||
|
public BestInsertionBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager) {
|
||||||
|
super();
|
||||||
|
this.vrp = vrp;
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
this.constraintManager = new ConstraintManager();
|
||||||
|
this.fleetManager = vehicleFleetManager;
|
||||||
|
addCoreStateUpdaters();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCoreStateUpdaters(){
|
||||||
|
stateManager.addListener(new UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts(stateManager));
|
||||||
|
stateManager.addListener(new UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted(stateManager));
|
||||||
|
|
||||||
|
stateManager.addActivityVisitor(new UpdateMaxLoad(stateManager));
|
||||||
|
stateManager.addActivityVisitor(new UpdateActivityTimes(vrp.getTransportCosts()));
|
||||||
|
stateManager.addActivityVisitor(new UpdateCostsAtAllLevels(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager));
|
||||||
|
}
|
||||||
|
|
||||||
|
public BestInsertionBuilder addHardLoadConstraints(){
|
||||||
|
constraintManager.addConstraint(new HardPickupAndDeliveryLoadRouteLevelConstraint(stateManager));
|
||||||
|
if(vrp.getProblemConstraints().contains(Constraint.DELIVERIES_FIRST)){
|
||||||
|
constraintManager.addConstraint(new HardPickupAndDeliveryBackhaulActivityLevelConstraint(stateManager));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
constraintManager.addConstraint(new HardPickupAndDeliveryActivityLevelConstraint(stateManager));
|
||||||
|
}
|
||||||
|
stateManager.addActivityVisitor(new UpdateOccuredDeliveriesAtActivityLevel(stateManager));
|
||||||
|
stateManager.addActivityVisitor(new UpdateFuturePickupsAtActivityLevel(stateManager));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BestInsertionBuilder addHardTimeWindowConstraint(){
|
||||||
|
constraintManager.addConstraint(new HardTimeWindowActivityLevelConstraint(stateManager, vrp.getTransportCosts()));
|
||||||
|
// stateManager.addActivityVisitor(new UpdateEarliestStartTimeWindowAtActLocations(stateManager, vrp.getTransportCosts()));
|
||||||
|
stateManager.addActivityVisitor(new UpdateLatestOperationStartTimeAtActLocations(stateManager, vrp.getTransportCosts()));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public BestInsertionBuilder addConstraint(HardActivityLevelConstraint hardActvitiyLevelConstraint){
|
||||||
|
constraintManager.addConstraint(hardActvitiyLevelConstraint);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
public BestInsertionBuilder addConstraint(HardRouteLevelConstraint hardRouteLevelConstraint){
|
||||||
|
constraintManager.addConstraint(hardRouteLevelConstraint);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
public void setRouteLevel(int forwardLooking, int memory){
|
||||||
|
local = false;
|
||||||
|
this.forwaredLooking = forwardLooking;
|
||||||
|
this.memory = memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
public BestInsertionBuilder setLocalLevel(){
|
||||||
|
local = true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
public BestInsertionBuilder considerFixedCosts(double weightOfFixedCosts){
|
||||||
|
this.weightOfFixedCosts = weightOfFixedCosts;
|
||||||
|
this.considerFixedCosts = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){
|
||||||
|
this.actInsertionCostsCalculator = activityInsertionCostsCalculator;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertionStrategy build() {
|
||||||
|
List<InsertionListener> iListeners = new ArrayList<InsertionListener>();
|
||||||
|
List<PrioritizedVRAListener> algorithmListeners = new ArrayList<PrioritizedVRAListener>();
|
||||||
|
CalculatorBuilder calcBuilder = new CalculatorBuilder(iListeners, algorithmListeners);
|
||||||
|
if(local){
|
||||||
|
calcBuilder.setLocalLevel();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
calcBuilder.setRouteLevel(forwaredLooking, memory);
|
||||||
|
}
|
||||||
|
calcBuilder.setConstraintManager(constraintManager);
|
||||||
|
calcBuilder.setStates(stateManager);
|
||||||
|
calcBuilder.setVehicleRoutingProblem(vrp);
|
||||||
|
calcBuilder.setVehicleFleetManager(fleetManager);
|
||||||
|
calcBuilder.setActivityInsertionCostsCalculator(actInsertionCostsCalculator);
|
||||||
|
if(considerFixedCosts) {
|
||||||
|
calcBuilder.considerFixedCosts(weightOfFixedCosts);
|
||||||
|
}
|
||||||
|
JobInsertionCostsCalculator jobInsertions = calcBuilder.build();
|
||||||
|
BestInsertion bestInsertion = new BestInsertion(jobInsertions);
|
||||||
|
for(InsertionListener l : iListeners) bestInsertion.addListener(l);
|
||||||
|
return bestInsertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
|
||||||
|
public class BestInsertionStrategyFactory implements InsertionStrategyFactory{
|
||||||
|
|
||||||
|
private JobInsertionCostsCalculator jobInsertionCalculator;
|
||||||
|
|
||||||
|
public BestInsertionStrategyFactory(JobInsertionCostsCalculator jobInsertionCalculator) {
|
||||||
|
super();
|
||||||
|
this.jobInsertionCalculator = jobInsertionCalculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertionStrategy createStrategy(VehicleRoutingProblem vrp) {
|
||||||
|
return new BestInsertion(jobInsertionCalculator);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -27,11 +27,11 @@ import basics.route.Driver;
|
||||||
import basics.route.Vehicle;
|
import basics.route.Vehicle;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCalculator{
|
class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsCalculator{
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(CalculatesServiceInsertionWithTimeScheduling.class);
|
private static Logger log = Logger.getLogger(CalculatesServiceInsertionWithTimeScheduling.class);
|
||||||
|
|
||||||
private JobInsertionCalculator jic;
|
private JobInsertionCostsCalculator jic;
|
||||||
|
|
||||||
private Random random = new Random();
|
private Random random = new Random();
|
||||||
|
|
||||||
|
|
@ -39,7 +39,7 @@ class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCalcul
|
||||||
|
|
||||||
private double timeSlice = 900.0;
|
private double timeSlice = 900.0;
|
||||||
|
|
||||||
public CalculatesServiceInsertionWithTimeScheduling(JobInsertionCalculator jic, double timeSlice, int neighbors) {
|
public CalculatesServiceInsertionWithTimeScheduling(JobInsertionCostsCalculator jic, double timeSlice, int neighbors) {
|
||||||
super();
|
super();
|
||||||
this.jic = jic;
|
this.jic = jic;
|
||||||
this.timeSlice = timeSlice;
|
this.timeSlice = timeSlice;
|
||||||
|
|
@ -53,7 +53,7 @@ class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCalcul
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InsertionData calculate(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
|
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
|
||||||
List<Double> vehicleDepartureTimes = new ArrayList<Double>();
|
List<Double> vehicleDepartureTimes = new ArrayList<Double>();
|
||||||
double currentStart;
|
double currentStart;
|
||||||
if(currentRoute.getStart() == null){
|
if(currentRoute.getStart() == null){
|
||||||
|
|
@ -74,7 +74,7 @@ class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCalcul
|
||||||
|
|
||||||
InsertionData bestIData = null;
|
InsertionData bestIData = null;
|
||||||
for(Double departureTime : vehicleDepartureTimes){
|
for(Double departureTime : vehicleDepartureTimes){
|
||||||
InsertionData iData = jic.calculate(currentRoute, jobToInsert, newVehicle, departureTime, newDriver, bestKnownScore);
|
InsertionData iData = jic.getInsertionData(currentRoute, jobToInsert, newVehicle, departureTime, newDriver, bestKnownScore);
|
||||||
if(bestIData == null) bestIData = iData;
|
if(bestIData == null) bestIData = iData;
|
||||||
else if(iData.getInsertionCost() < bestIData.getInsertionCost()){
|
else if(iData.getInsertionCost() < bestIData.getInsertionCost()){
|
||||||
iData.setVehicleDepartureTime(departureTime);
|
iData.setVehicleDepartureTime(departureTime);
|
||||||
|
|
|
||||||
38
jsprit-core/src/main/java/algorithms/CalculationUtils.java
Normal file
38
jsprit-core/src/main/java/algorithms/CalculationUtils.java
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
|
class CalculationUtils {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates actEndTime assuming that activity can at earliest start at act.getTheoreticalEarliestOperationStartTime().
|
||||||
|
*
|
||||||
|
* @param actArrTime
|
||||||
|
* @param act
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static double getActivityEndTime(double actArrTime, TourActivity act){
|
||||||
|
return Math.max(actArrTime, act.getTheoreticalEarliestOperationStartTime()) + act.getOperationTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,10 +19,10 @@ package algorithms;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import algorithms.HardConstraints.ConstraintManager;
|
|
||||||
import basics.VehicleRoutingProblem;
|
import basics.VehicleRoutingProblem;
|
||||||
import basics.algo.InsertionListener;
|
import basics.algo.InsertionListener;
|
||||||
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -30,16 +30,16 @@ class CalculatorBuilder {
|
||||||
|
|
||||||
private static class CalculatorPlusListeners {
|
private static class CalculatorPlusListeners {
|
||||||
|
|
||||||
private JobInsertionCalculator calculator;
|
private JobInsertionCostsCalculator calculator;
|
||||||
|
|
||||||
public JobInsertionCalculator getCalculator() {
|
public JobInsertionCostsCalculator getCalculator() {
|
||||||
return calculator;
|
return calculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PrioritizedVRAListener> algorithmListener = new ArrayList<PrioritizedVRAListener>();
|
private List<PrioritizedVRAListener> algorithmListener = new ArrayList<PrioritizedVRAListener>();
|
||||||
private List<InsertionListener> insertionListener = new ArrayList<InsertionListener>();
|
private List<InsertionListener> insertionListener = new ArrayList<InsertionListener>();
|
||||||
|
|
||||||
public CalculatorPlusListeners(JobInsertionCalculator calculator) {
|
public CalculatorPlusListeners(JobInsertionCostsCalculator calculator) {
|
||||||
super();
|
super();
|
||||||
this.calculator = calculator;
|
this.calculator = calculator;
|
||||||
}
|
}
|
||||||
|
|
@ -59,7 +59,7 @@ class CalculatorBuilder {
|
||||||
|
|
||||||
private VehicleRoutingProblem vrp;
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
private StateManager states;
|
private StateGetter states;
|
||||||
|
|
||||||
private boolean local = true;
|
private boolean local = true;
|
||||||
|
|
||||||
|
|
@ -81,6 +81,8 @@ class CalculatorBuilder {
|
||||||
|
|
||||||
private ConstraintManager constraintManager;
|
private ConstraintManager constraintManager;
|
||||||
|
|
||||||
|
private ActivityInsertionCostsCalculator activityInsertionCostCalculator = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the builder.
|
* Constructs the builder.
|
||||||
*
|
*
|
||||||
|
|
@ -102,7 +104,7 @@ class CalculatorBuilder {
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public CalculatorBuilder setStates(StateManager states){
|
public CalculatorBuilder setStates(StateGetter states){
|
||||||
this.states = states;
|
this.states = states;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
@ -138,6 +140,10 @@ class CalculatorBuilder {
|
||||||
local = true;
|
local = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setActivityInsertionCostsCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){
|
||||||
|
this.activityInsertionCostCalculator = activityInsertionCostsCalculator;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a flag to build a calculator that evaluates job insertion on route-level.
|
* Sets a flag to build a calculator that evaluates job insertion on route-level.
|
||||||
*
|
*
|
||||||
|
|
@ -173,11 +179,11 @@ class CalculatorBuilder {
|
||||||
* @return jobInsertionCalculator.
|
* @return jobInsertionCalculator.
|
||||||
* @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null.
|
* @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null.
|
||||||
*/
|
*/
|
||||||
public JobInsertionCalculator build(){
|
public JobInsertionCostsCalculator build(){
|
||||||
if(vrp == null) throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))");
|
if(vrp == null) throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))");
|
||||||
if(states == null) throw new IllegalStateException("states is null, but is must be set (this.setStates(states))");
|
if(states == null) throw new IllegalStateException("states is null, but is must be set (this.setStates(states))");
|
||||||
if(fleetManager == null) throw new IllegalStateException("fleetManager is null, but it must be set (this.setVehicleFleetManager(fleetManager))");
|
if(fleetManager == null) throw new IllegalStateException("fleetManager is null, but it must be set (this.setVehicleFleetManager(fleetManager))");
|
||||||
JobInsertionCalculator baseCalculator = null;
|
JobInsertionCostsCalculator baseCalculator = null;
|
||||||
CalculatorPlusListeners standardLocal = null;
|
CalculatorPlusListeners standardLocal = null;
|
||||||
if(local){
|
if(local){
|
||||||
standardLocal = createStandardLocal(vrp, states);
|
standardLocal = createStandardLocal(vrp, states);
|
||||||
|
|
@ -212,40 +218,58 @@ class CalculatorBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, StateManager statesManager){
|
private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, StateGetter statesManager){
|
||||||
if(constraintManager == null) throw new IllegalStateException("constraint-manager is null");
|
if(constraintManager == null) throw new IllegalStateException("constraint-manager is null");
|
||||||
|
|
||||||
ActivityInsertionCostsCalculator defaultCalc = new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), constraintManager);
|
//<<<<<<< HEAD
|
||||||
JobInsertionCalculator standardServiceInsertion = new ServiceInsertionCalculator(vrp.getTransportCosts(), defaultCalc, constraintManager);
|
// ActivityInsertionCostsCalculator defaultCalc = new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), constraintManager);
|
||||||
|
// JobInsertionCalculator standardServiceInsertion = new ServiceInsertionCalculator(vrp.getTransportCosts(), defaultCalc, constraintManager);
|
||||||
|
//
|
||||||
|
//=======
|
||||||
|
ActivityInsertionCostsCalculator actInsertionCalc;
|
||||||
|
if(activityInsertionCostCalculator == null){
|
||||||
|
actInsertionCalc = new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
actInsertionCalc = activityInsertionCostCalculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
JobInsertionCostsCalculator standardServiceInsertion = new ServiceInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager, constraintManager);
|
||||||
|
//>>>>>>> refs/remotes/choose_remote_name/relaxAPI
|
||||||
((ServiceInsertionCalculator) standardServiceInsertion).setNeighborhood(vrp.getNeighborhood());
|
((ServiceInsertionCalculator) standardServiceInsertion).setNeighborhood(vrp.getNeighborhood());
|
||||||
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(standardServiceInsertion);
|
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(standardServiceInsertion);
|
||||||
|
|
||||||
return calcPlusListeners;
|
return calcPlusListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCalculator baseCalculator, StateManager activityStates2, double weightOfFixedCosts){
|
private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCostsCalculator baseCalculator, StateGetter activityStates2, double weightOfFixedCosts){
|
||||||
final CalculatesServiceInsertionConsideringFixCost withFixCost = new CalculatesServiceInsertionConsideringFixCost(baseCalculator, activityStates2);
|
final JobInsertionConsideringFixCostsCalculator withFixCost = new JobInsertionConsideringFixCostsCalculator(baseCalculator, activityStates2);
|
||||||
withFixCost.setWeightOfFixCost(weightOfFixedCosts);
|
withFixCost.setWeightOfFixCost(weightOfFixedCosts);
|
||||||
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost);
|
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost);
|
||||||
calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost));
|
calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost));
|
||||||
return calcPlusListeners;
|
return calcPlusListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalculatorPlusListeners createStandardRoute(VehicleRoutingProblem vrp, StateManager activityStates2, int forwardLooking, int solutionMemory){
|
private CalculatorPlusListeners createStandardRoute(VehicleRoutingProblem vrp, StateGetter activityStates2, int forwardLooking, int solutionMemory){
|
||||||
int after = forwardLooking;
|
int after = forwardLooking;
|
||||||
ActivityInsertionCostsCalculator routeLevelCostEstimator = new RouteLevelActivityInsertionCostsEstimator(vrp.getTransportCosts(), vrp.getActivityCosts(), constraintManager, activityStates2);
|
ActivityInsertionCostsCalculator routeLevelCostEstimator;
|
||||||
JobInsertionCalculator jobInsertionCalculator = new CalculatesServiceInsertionOnRouteLevel(vrp.getTransportCosts(), vrp.getActivityCosts(), constraintManager, routeLevelCostEstimator);
|
if(activityInsertionCostCalculator == null){
|
||||||
((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setNuOfActsForwardLooking(after);
|
routeLevelCostEstimator = new RouteLevelActivityInsertionCostsEstimator(vrp.getTransportCosts(), vrp.getActivityCosts(), activityStates2);
|
||||||
((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setMemorySize(solutionMemory);
|
}
|
||||||
((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setNeighborhood(vrp.getNeighborhood());
|
else{
|
||||||
((CalculatesServiceInsertionOnRouteLevel) jobInsertionCalculator).setStates(activityStates2);
|
routeLevelCostEstimator = activityInsertionCostCalculator;
|
||||||
|
}
|
||||||
|
JobInsertionCostsCalculator jobInsertionCalculator = new ServiceInsertionOnRouteLevelCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), routeLevelCostEstimator, constraintManager, constraintManager);
|
||||||
|
((ServiceInsertionOnRouteLevelCalculator)jobInsertionCalculator).setNuOfActsForwardLooking(after);
|
||||||
|
((ServiceInsertionOnRouteLevelCalculator)jobInsertionCalculator).setMemorySize(solutionMemory);
|
||||||
|
((ServiceInsertionOnRouteLevelCalculator)jobInsertionCalculator).setNeighborhood(vrp.getNeighborhood());
|
||||||
|
((ServiceInsertionOnRouteLevelCalculator) jobInsertionCalculator).setStates(activityStates2);
|
||||||
CalculatorPlusListeners calcPlusListener = new CalculatorPlusListeners(jobInsertionCalculator);
|
CalculatorPlusListeners calcPlusListener = new CalculatorPlusListeners(jobInsertionCalculator);
|
||||||
return calcPlusListener;
|
return calcPlusListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JobInsertionCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCalculator baseCalc, StateManager activityStates2){
|
private JobInsertionCostsCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCostsCalculator baseCalc, StateGetter activityStates2){
|
||||||
return new CalculatesVehTypeDepServiceInsertion(fleetManager, baseCalc);
|
return new VehicleTypeDependentJobInsertionCalculator(fleetManager, baseCalc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setConstraintManager(ConstraintManager constraintManager) {
|
public void setConstraintManager(ConstraintManager constraintManager) {
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,11 @@ final class ConfigureFixCostCalculator implements InsertionStartsListener, JobIn
|
||||||
|
|
||||||
VehicleRoutingProblem vrp;
|
VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
CalculatesServiceInsertionConsideringFixCost calcConsideringFix;
|
JobInsertionConsideringFixCostsCalculator calcConsideringFix;
|
||||||
|
|
||||||
private int nuOfJobsToRecreate;
|
private int nuOfJobsToRecreate;
|
||||||
|
|
||||||
public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, CalculatesServiceInsertionConsideringFixCost calcConsideringFix) {
|
public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, JobInsertionConsideringFixCostsCalculator calcConsideringFix) {
|
||||||
super();
|
super();
|
||||||
this.vrp = vrp;
|
this.vrp = vrp;
|
||||||
this.calcConsideringFix = calcConsideringFix;
|
this.calcConsideringFix = calcConsideringFix;
|
||||||
|
|
|
||||||
29
jsprit-core/src/main/java/algorithms/ConstraintManager.java
Normal file
29
jsprit-core/src/main/java/algorithms/ConstraintManager.java
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
|
class ConstraintManager implements HardActivityLevelConstraint, HardRouteLevelConstraint{
|
||||||
|
|
||||||
|
private HardActivityLevelConstraintManager actLevelConstraintManager = new HardActivityLevelConstraintManager();
|
||||||
|
|
||||||
|
private HardRouteLevelConstraintManager routeLevelConstraintManager = new HardRouteLevelConstraintManager();
|
||||||
|
|
||||||
|
public void addConstraint(HardActivityLevelConstraint actLevelConstraint){
|
||||||
|
actLevelConstraintManager.addConstraint(actLevelConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addConstraint(HardRouteLevelConstraint routeLevelConstraint){
|
||||||
|
routeLevelConstraintManager.addConstraint(routeLevelConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean fulfilled(InsertionContext insertionContext) {
|
||||||
|
return routeLevelConstraintManager.fulfilled(insertionContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct,TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||||
|
return actLevelConstraintManager.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -27,7 +27,7 @@ class EuclideanServiceDistance implements JobDistance {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double calculateDistance(Job i, Job j) {
|
public double getDistance(Job i, Job j) {
|
||||||
double avgCost = 0.0;
|
double avgCost = 0.0;
|
||||||
if (i instanceof Service && j instanceof Service) {
|
if (i instanceof Service && j instanceof Service) {
|
||||||
if (i.equals(j)) {
|
if (i.equals(j)) {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import org.apache.log4j.Logger;
|
||||||
import basics.route.TourActivities;
|
import basics.route.TourActivities;
|
||||||
import basics.route.TourActivity;
|
import basics.route.TourActivity;
|
||||||
import basics.route.Vehicle;
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
import basics.route.VehicleImpl.NoVehicle;
|
import basics.route.VehicleImpl.NoVehicle;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
@ -41,13 +42,13 @@ final class FindCheaperVehicleAlgo {
|
||||||
|
|
||||||
private double weightFixCosts = 1.0;
|
private double weightFixCosts = 1.0;
|
||||||
|
|
||||||
private StateManager states;
|
private StateGetter states;
|
||||||
|
|
||||||
public void setWeightFixCosts(double weightFixCosts) {
|
public void setWeightFixCosts(double weightFixCosts) {
|
||||||
this.weightFixCosts = weightFixCosts;
|
this.weightFixCosts = weightFixCosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStates(StateManager states) {
|
public void setStates(StateGetter states) {
|
||||||
this.states = states;
|
this.states = states;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,11 +80,11 @@ final class FindCheaperVehicleAlgo {
|
||||||
if(vehicle.getType().getTypeId().equals(vehicleRoute.getVehicle().getType().getTypeId())){
|
if(vehicle.getType().getTypeId().equals(vehicleRoute.getVehicle().getType().getTypeId())){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(states.getRouteState(vehicleRoute,StateTypes.LOAD).toDouble() <= vehicle.getCapacity()){
|
if(states.getRouteState(vehicleRoute,StateFactory.LOAD).toDouble() <= vehicle.getCapacity()){
|
||||||
double fixCostSaving = vehicleRoute.getVehicle().getType().getVehicleCostParams().fix - vehicle.getType().getVehicleCostParams().fix;
|
double fixCostSaving = vehicleRoute.getVehicle().getType().getVehicleCostParams().fix - vehicle.getType().getVehicleCostParams().fix;
|
||||||
double departureTime = vehicleRoute.getStart().getEndTime();
|
double departureTime = vehicleRoute.getStart().getEndTime();
|
||||||
double newCost = auxilliaryCostCalculator.costOfPath(path, departureTime, vehicleRoute.getDriver(), vehicle);
|
double newCost = auxilliaryCostCalculator.costOfPath(path, departureTime, vehicleRoute.getDriver(), vehicle);
|
||||||
double varCostSaving = states.getRouteState(vehicleRoute, StateTypes.COSTS).toDouble() - newCost;
|
double varCostSaving = states.getRouteState(vehicleRoute, StateFactory.COSTS).toDouble() - newCost;
|
||||||
double totalCostSaving = varCostSaving + weightFixCosts*fixCostSaving;
|
double totalCostSaving = varCostSaving + weightFixCosts*fixCostSaving;
|
||||||
if(totalCostSaving > bestSaving){
|
if(totalCostSaving > bestSaving){
|
||||||
bestSaving = totalCostSaving;
|
bestSaving = totalCostSaving;
|
||||||
|
|
|
||||||
|
|
@ -28,14 +28,15 @@ import java.util.Set;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import util.RandomNumberGeneration;
|
import util.RandomNumberGeneration;
|
||||||
import algorithms.RuinStrategy.RuinListener;
|
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
import basics.VehicleRoutingProblem;
|
import basics.VehicleRoutingProblem;
|
||||||
import basics.VehicleRoutingProblemSolution;
|
import basics.VehicleRoutingProblemSolution;
|
||||||
import basics.algo.InsertionListener;
|
import basics.algo.InsertionListener;
|
||||||
|
import basics.algo.RuinListener;
|
||||||
import basics.algo.SearchStrategyModule;
|
import basics.algo.SearchStrategyModule;
|
||||||
import basics.algo.SearchStrategyModuleListener;
|
import basics.algo.SearchStrategyModuleListener;
|
||||||
import basics.route.TourActivity;
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
import basics.route.TourActivity.JobActivity;
|
import basics.route.TourActivity.JobActivity;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
|
public interface HardActivityLevelConstraint {
|
||||||
|
|
||||||
|
static enum ConstraintsStatus {
|
||||||
|
|
||||||
|
NOT_FULFILLED_BREAK, NOT_FULFILLED, FULFILLED;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
|
class HardActivityLevelConstraintManager implements HardActivityLevelConstraint {
|
||||||
|
|
||||||
|
private Collection<HardActivityLevelConstraint> hardConstraints = new ArrayList<HardActivityLevelConstraint>();
|
||||||
|
|
||||||
|
public void addConstraint(HardActivityLevelConstraint constraint){
|
||||||
|
hardConstraints.add(constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||||
|
for(HardActivityLevelConstraint constraint : hardConstraints){
|
||||||
|
ConstraintsStatus status = constraint.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
|
||||||
|
if(status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK) || status.equals(ConstraintsStatus.NOT_FULFILLED)){
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ConstraintsStatus.FULFILLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,382 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (C) 2013 Stefan Schroeder
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 3.0 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
******************************************************************************/
|
|
||||||
package algorithms;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import basics.Delivery;
|
|
||||||
import basics.Pickup;
|
|
||||||
import basics.Service;
|
|
||||||
import basics.costs.VehicleRoutingTransportCosts;
|
|
||||||
import basics.route.DeliverService;
|
|
||||||
import basics.route.DeliverShipment;
|
|
||||||
import basics.route.DeliveryActivity;
|
|
||||||
import basics.route.PickupActivity;
|
|
||||||
import basics.route.PickupService;
|
|
||||||
import basics.route.PickupShipment;
|
|
||||||
import basics.route.ServiceActivity;
|
|
||||||
import basics.route.Start;
|
|
||||||
import basics.route.TourActivity;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* collection of hard constrainters bot at activity and at route level.
|
|
||||||
*
|
|
||||||
* <p>HardPickupAndDeliveryLoadConstraint requires LOAD_AT_DEPOT and LOAD (i.e. load at end) at route-level
|
|
||||||
*
|
|
||||||
* <p>HardTimeWindowConstraint requires LATEST_OPERATION_START_TIME
|
|
||||||
*
|
|
||||||
* <p>HardPickupAndDeliveryConstraint requires LOAD_AT_DEPOT and LOAD at route-level and FUTURE_PICKS and PAST_DELIVIERS on activity-level
|
|
||||||
*
|
|
||||||
* <p>HardPickupAndDeliveryBackhaulConstraint requires LOAD_AT_DEPOT and LOAD at route-level and FUTURE_PICKS and PAST_DELIVIERS on activity-level
|
|
||||||
*
|
|
||||||
* @author stefan
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class HardConstraints {
|
|
||||||
|
|
||||||
interface HardRouteLevelConstraint {
|
|
||||||
|
|
||||||
public boolean fulfilled(InsertionContext insertionContext);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
interface HardActivityLevelConstraint {
|
|
||||||
|
|
||||||
public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class HardRouteLevelConstraintManager implements HardRouteLevelConstraint {
|
|
||||||
|
|
||||||
private Collection<HardRouteLevelConstraint> hardConstraints = new ArrayList<HardRouteLevelConstraint>();
|
|
||||||
|
|
||||||
public void addConstraint(HardRouteLevelConstraint constraint){
|
|
||||||
hardConstraints.add(constraint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionContext insertionContext) {
|
|
||||||
for(HardRouteLevelConstraint constraint : hardConstraints){
|
|
||||||
if(!constraint.fulfilled(insertionContext)){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ConstraintManager implements HardActivityLevelConstraint, HardRouteLevelConstraint{
|
|
||||||
|
|
||||||
private HardActivityLevelConstraintManager actLevelConstraintManager = new HardActivityLevelConstraintManager();
|
|
||||||
|
|
||||||
private HardRouteLevelConstraintManager routeLevelConstraintManager = new HardRouteLevelConstraintManager();
|
|
||||||
|
|
||||||
public void addConstraint(HardActivityLevelConstraint actLevelConstraint){
|
|
||||||
actLevelConstraintManager.addConstraint(actLevelConstraint);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addConstraint(HardRouteLevelConstraint routeLevelConstraint){
|
|
||||||
routeLevelConstraintManager.addConstraint(routeLevelConstraint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionContext insertionContext) {
|
|
||||||
return routeLevelConstraintManager.fulfilled(insertionContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct,TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
|
||||||
return actLevelConstraintManager.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class HardActivityLevelConstraintManager implements HardActivityLevelConstraint {
|
|
||||||
|
|
||||||
private Collection<HardActivityLevelConstraint> hardConstraints = new ArrayList<HardActivityLevelConstraint>();
|
|
||||||
|
|
||||||
public void addConstraint(HardActivityLevelConstraint constraint){
|
|
||||||
hardConstraints.add(constraint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
|
||||||
for(HardActivityLevelConstraint constraint : hardConstraints){
|
|
||||||
if(!constraint.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime)){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class HardLoadConstraint implements HardRouteLevelConstraint{
|
|
||||||
|
|
||||||
private StateManager states;
|
|
||||||
|
|
||||||
public HardLoadConstraint(StateManager states) {
|
|
||||||
super();
|
|
||||||
this.states = states;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionContext insertionContext) {
|
|
||||||
int currentLoad = (int) states.getRouteState(insertionContext.getRoute(), StateTypes.LOAD).toDouble();
|
|
||||||
Service service = (Service) insertionContext.getJob();
|
|
||||||
if(currentLoad + service.getCapacityDemand() > insertionContext.getNewVehicle().getCapacity()){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* lsjdfjsdlfjsa
|
|
||||||
*
|
|
||||||
* @author stefan
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static class HardPickupAndDeliveryLoadConstraint implements HardRouteLevelConstraint {
|
|
||||||
|
|
||||||
private StateManager stateManager;
|
|
||||||
|
|
||||||
public HardPickupAndDeliveryLoadConstraint(StateManager stateManager) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionContext insertionContext) {
|
|
||||||
if(insertionContext.getJob() instanceof Delivery){
|
|
||||||
int loadAtDepot = (int) stateManager.getRouteState(insertionContext.getRoute(), StateTypes.LOAD_AT_DEPOT).toDouble();
|
|
||||||
if(loadAtDepot + insertionContext.getJob().getCapacityDemand() > insertionContext.getNewVehicle().getCapacity()){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(insertionContext.getJob() instanceof Pickup || insertionContext.getJob() instanceof Service){
|
|
||||||
int loadAtEnd = (int) stateManager.getRouteState(insertionContext.getRoute(), StateTypes.LOAD).toDouble();
|
|
||||||
if(loadAtEnd + insertionContext.getJob().getCapacityDemand() > insertionContext.getNewVehicle().getCapacity()){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ljsljslfjs
|
|
||||||
* @author stefan
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static class HardTimeWindowActivityLevelConstraint implements HardActivityLevelConstraint {
|
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(HardTimeWindowActivityLevelConstraint.class);
|
|
||||||
|
|
||||||
private StateManager states;
|
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts routingCosts;
|
|
||||||
|
|
||||||
public HardTimeWindowActivityLevelConstraint(StateManager states, VehicleRoutingTransportCosts routingCosts) {
|
|
||||||
super();
|
|
||||||
this.states = states;
|
|
||||||
this.routingCosts = routingCosts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
|
||||||
// log.info("check insertion of " + newAct + " between " + prevAct + " and " + nextAct + ". prevActDepTime=" + prevActDepTime);
|
|
||||||
double arrTimeAtNewAct = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
|
||||||
double latestArrTimeAtNewAct = states.getActivityState(newAct, StateTypes.LATEST_OPERATION_START_TIME).toDouble();
|
|
||||||
if(arrTimeAtNewAct > latestArrTimeAtNewAct){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// log.info(newAct + " arrTime=" + arrTimeAtNewAct);
|
|
||||||
double endTimeAtNewAct = CalcUtils.getActivityEndTime(arrTimeAtNewAct, newAct);
|
|
||||||
double arrTimeAtNextAct = endTimeAtNewAct + routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), endTimeAtNewAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
|
||||||
double latestArrTimeAtNextAct = states.getActivityState(nextAct, StateTypes.LATEST_OPERATION_START_TIME).toDouble();
|
|
||||||
if(arrTimeAtNextAct > latestArrTimeAtNextAct){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// log.info(nextAct + " arrTime=" + arrTimeAtNextAct);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class HardPickupAndDeliveryActivityLevelConstraint implements HardActivityLevelConstraint {
|
|
||||||
|
|
||||||
private StateManager stateManager;
|
|
||||||
|
|
||||||
private boolean backhaul = false;
|
|
||||||
|
|
||||||
public HardPickupAndDeliveryActivityLevelConstraint(StateManager stateManager) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HardPickupAndDeliveryActivityLevelConstraint(StateManager stateManager, boolean backhaul) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
this.backhaul = backhaul;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
|
||||||
if(!(newAct instanceof PickupService) && !(newAct instanceof DeliverService)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if(backhaul){
|
|
||||||
if(newAct instanceof PickupService && nextAct instanceof DeliverService){ return false; }
|
|
||||||
if(newAct instanceof DeliverService && prevAct instanceof PickupService){ return false; }
|
|
||||||
}
|
|
||||||
int loadAtPrevAct;
|
|
||||||
int futurePicks;
|
|
||||||
int pastDeliveries;
|
|
||||||
if(prevAct instanceof Start){
|
|
||||||
loadAtPrevAct = (int)stateManager.getRouteState(iFacts.getRoute(), StateTypes.LOAD_AT_DEPOT).toDouble();
|
|
||||||
futurePicks = (int)stateManager.getRouteState(iFacts.getRoute(), StateTypes.LOAD).toDouble();
|
|
||||||
pastDeliveries = 0;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
loadAtPrevAct = (int) stateManager.getActivityState(prevAct, StateTypes.LOAD).toDouble();
|
|
||||||
futurePicks = (int) stateManager.getActivityState(prevAct, StateTypes.FUTURE_PICKS).toDouble();
|
|
||||||
pastDeliveries = (int) stateManager.getActivityState(prevAct, StateTypes.PAST_DELIVERIES).toDouble();
|
|
||||||
}
|
|
||||||
if(newAct instanceof PickupService){
|
|
||||||
if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(newAct instanceof DeliverService){
|
|
||||||
if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) + pastDeliveries > iFacts.getNewVehicle().getCapacity()){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class HardPickupAndDeliveryShipmentActivityLevelConstraint implements HardActivityLevelConstraint {
|
|
||||||
|
|
||||||
private StateManager stateManager;
|
|
||||||
|
|
||||||
private boolean backhaul = false;
|
|
||||||
|
|
||||||
public HardPickupAndDeliveryShipmentActivityLevelConstraint(StateManager stateManager) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HardPickupAndDeliveryShipmentActivityLevelConstraint(StateManager stateManager, boolean backhaul) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
this.backhaul = backhaul;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
|
||||||
if(!(newAct instanceof PickupShipment) && !(newAct instanceof DeliverShipment)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if(backhaul){
|
|
||||||
// if(newAct instanceof PickupShipment && nextAct instanceof DeliverShipment){ return false; }
|
|
||||||
if(newAct instanceof DeliverShipment && prevAct instanceof PickupShipment){ return false; }
|
|
||||||
}
|
|
||||||
int loadAtPrevAct;
|
|
||||||
// int futurePicks;
|
|
||||||
// int pastDeliveries;
|
|
||||||
if(prevAct instanceof Start){
|
|
||||||
loadAtPrevAct = (int)stateManager.getRouteState(iFacts.getRoute(), StateTypes.LOAD_AT_DEPOT).toDouble();
|
|
||||||
// futurePicks = (int)stateManager.getRouteState(iFacts.getRoute(), StateTypes.LOAD).toDouble();
|
|
||||||
// pastDeliveries = 0;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
loadAtPrevAct = (int) stateManager.getActivityState(prevAct, StateTypes.LOAD).toDouble();
|
|
||||||
// futurePicks = (int) stateManager.getActivityState(prevAct, StateTypes.FUTURE_PICKS).toDouble();
|
|
||||||
// pastDeliveries = (int) stateManager.getActivityState(prevAct, StateTypes.PAST_DELIVERIES).toDouble();
|
|
||||||
}
|
|
||||||
if(newAct instanceof PickupShipment){
|
|
||||||
if(loadAtPrevAct + newAct.getCapacityDemand() > iFacts.getNewVehicle().getCapacity()){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(newAct instanceof DeliverShipment){
|
|
||||||
if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) > iFacts.getNewVehicle().getCapacity()){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static class HardPickupAndDeliveryBackhaulActivityLevelConstraint implements HardActivityLevelConstraint {
|
|
||||||
|
|
||||||
private StateManager stateManager;
|
|
||||||
|
|
||||||
public HardPickupAndDeliveryBackhaulActivityLevelConstraint(StateManager stateManager) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
|
||||||
if(newAct instanceof PickupService && nextAct instanceof DeliverService){ return false; }
|
|
||||||
// if(newAct instanceof ServiceActivity && nextAct instanceof DeliveryActivity){ return false; }
|
|
||||||
if(newAct instanceof DeliverService && prevAct instanceof PickupService){ return false; }
|
|
||||||
// if(newAct instanceof DeliveryActivity && prevAct instanceof ServiceActivity){ return false; }
|
|
||||||
int loadAtPrevAct;
|
|
||||||
int futurePicks;
|
|
||||||
int pastDeliveries;
|
|
||||||
if(prevAct instanceof Start){
|
|
||||||
loadAtPrevAct = (int)stateManager.getRouteState(iFacts.getRoute(), StateTypes.LOAD_AT_DEPOT).toDouble();
|
|
||||||
futurePicks = (int)stateManager.getRouteState(iFacts.getRoute(), StateTypes.LOAD).toDouble();
|
|
||||||
pastDeliveries = 0;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
loadAtPrevAct = (int) stateManager.getActivityState(prevAct, StateTypes.LOAD).toDouble();
|
|
||||||
futurePicks = (int) stateManager.getActivityState(prevAct, StateTypes.FUTURE_PICKS).toDouble();
|
|
||||||
pastDeliveries = (int) stateManager.getActivityState(prevAct, StateTypes.PAST_DELIVERIES).toDouble();
|
|
||||||
}
|
|
||||||
if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){
|
|
||||||
if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(newAct instanceof DeliveryActivity){
|
|
||||||
if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) + pastDeliveries > iFacts.getNewVehicle().getCapacity()){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
23
jsprit-core/src/main/java/algorithms/HardLoadConstraint.java
Normal file
23
jsprit-core/src/main/java/algorithms/HardLoadConstraint.java
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.Service;
|
||||||
|
|
||||||
|
class HardLoadConstraint implements HardRouteLevelConstraint{
|
||||||
|
|
||||||
|
private StateGetter states;
|
||||||
|
|
||||||
|
public HardLoadConstraint(StateGetter states) {
|
||||||
|
super();
|
||||||
|
this.states = states;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean fulfilled(InsertionContext insertionContext) {
|
||||||
|
int currentLoad = (int) states.getRouteState(insertionContext.getRoute(), StateFactory.LOAD).toDouble();
|
||||||
|
Service service = (Service) insertionContext.getJob();
|
||||||
|
if(currentLoad + service.getCapacityDemand() > insertionContext.getNewVehicle().getCapacity()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.DeliveryActivity;
|
||||||
|
import basics.route.PickupActivity;
|
||||||
|
import basics.route.ServiceActivity;
|
||||||
|
import basics.route.Start;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
|
class HardPickupAndDeliveryActivityLevelConstraint implements HardActivityLevelConstraint {
|
||||||
|
|
||||||
|
private StateGetter stateManager;
|
||||||
|
|
||||||
|
public HardPickupAndDeliveryActivityLevelConstraint(StateGetter stateManager) {
|
||||||
|
super();
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||||
|
int loadAtPrevAct;
|
||||||
|
int futurePicks;
|
||||||
|
int pastDeliveries;
|
||||||
|
if(prevAct instanceof Start){
|
||||||
|
loadAtPrevAct = (int)stateManager.getRouteState(iFacts.getRoute(), StateFactory.LOAD_AT_BEGINNING).toDouble();
|
||||||
|
futurePicks = (int)stateManager.getRouteState(iFacts.getRoute(), StateFactory.LOAD_AT_END).toDouble();
|
||||||
|
pastDeliveries = 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
loadAtPrevAct = (int) stateManager.getActivityState(prevAct, StateFactory.LOAD).toDouble();
|
||||||
|
futurePicks = (int) stateManager.getActivityState(prevAct, StateFactory.FUTURE_PICKS).toDouble();
|
||||||
|
pastDeliveries = (int) stateManager.getActivityState(prevAct, StateFactory.PAST_DELIVERIES).toDouble();
|
||||||
|
}
|
||||||
|
if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){
|
||||||
|
if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(newAct instanceof DeliveryActivity){
|
||||||
|
if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) + pastDeliveries > iFacts.getNewVehicle().getCapacity()){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return ConstraintsStatus.FULFILLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.DeliveryActivity;
|
||||||
|
import basics.route.PickupActivity;
|
||||||
|
import basics.route.ServiceActivity;
|
||||||
|
import basics.route.Start;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
|
class HardPickupAndDeliveryBackhaulActivityLevelConstraint implements HardActivityLevelConstraint {
|
||||||
|
|
||||||
|
private StateGetter stateManager;
|
||||||
|
|
||||||
|
public HardPickupAndDeliveryBackhaulActivityLevelConstraint(StateGetter stateManager) {
|
||||||
|
super();
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||||
|
if(newAct instanceof PickupActivity && nextAct instanceof DeliveryActivity){ return ConstraintsStatus.NOT_FULFILLED; }
|
||||||
|
if(newAct instanceof ServiceActivity && nextAct instanceof DeliveryActivity){ return ConstraintsStatus.NOT_FULFILLED; }
|
||||||
|
if(newAct instanceof DeliveryActivity && prevAct instanceof PickupActivity){ return ConstraintsStatus.NOT_FULFILLED; }
|
||||||
|
if(newAct instanceof DeliveryActivity && prevAct instanceof ServiceActivity){ return ConstraintsStatus.NOT_FULFILLED; }
|
||||||
|
int loadAtPrevAct;
|
||||||
|
int futurePicks;
|
||||||
|
int pastDeliveries;
|
||||||
|
if(prevAct instanceof Start){
|
||||||
|
loadAtPrevAct = (int)stateManager.getRouteState(iFacts.getRoute(), StateFactory.LOAD_AT_BEGINNING).toDouble();
|
||||||
|
futurePicks = (int)stateManager.getRouteState(iFacts.getRoute(), StateFactory.LOAD_AT_END).toDouble();
|
||||||
|
pastDeliveries = 0;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
loadAtPrevAct = (int) stateManager.getActivityState(prevAct, StateFactory.LOAD).toDouble();
|
||||||
|
futurePicks = (int) stateManager.getActivityState(prevAct, StateFactory.FUTURE_PICKS).toDouble();
|
||||||
|
pastDeliveries = (int) stateManager.getActivityState(prevAct, StateFactory.PAST_DELIVERIES).toDouble();
|
||||||
|
}
|
||||||
|
if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){
|
||||||
|
if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(newAct instanceof DeliveryActivity){
|
||||||
|
if(loadAtPrevAct + Math.abs(newAct.getCapacityDemand()) + pastDeliveries > iFacts.getNewVehicle().getCapacity()){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return ConstraintsStatus.FULFILLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.Delivery;
|
||||||
|
import basics.Pickup;
|
||||||
|
import basics.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lsjdfjsdlfjsa
|
||||||
|
*
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class HardPickupAndDeliveryLoadRouteLevelConstraint implements HardRouteLevelConstraint {
|
||||||
|
|
||||||
|
private StateGetter stateManager;
|
||||||
|
|
||||||
|
public HardPickupAndDeliveryLoadRouteLevelConstraint(StateGetter stateManager) {
|
||||||
|
super();
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean fulfilled(InsertionContext insertionContext) {
|
||||||
|
if(insertionContext.getJob() instanceof Delivery){
|
||||||
|
int loadAtDepot = (int) stateManager.getRouteState(insertionContext.getRoute(), StateFactory.LOAD_AT_BEGINNING).toDouble();
|
||||||
|
if(loadAtDepot + insertionContext.getJob().getCapacityDemand() > insertionContext.getNewVehicle().getCapacity()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(insertionContext.getJob() instanceof Pickup || insertionContext.getJob() instanceof Service){
|
||||||
|
int loadAtEnd = (int) stateManager.getRouteState(insertionContext.getRoute(), StateFactory.LOAD_AT_END).toDouble();
|
||||||
|
if(loadAtEnd + insertionContext.getJob().getCapacityDemand() > insertionContext.getNewVehicle().getCapacity()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
|
||||||
|
public interface HardRouteLevelConstraint {
|
||||||
|
|
||||||
|
public boolean fulfilled(InsertionContext insertionContext);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
|
class HardRouteLevelConstraintManager implements HardRouteLevelConstraint {
|
||||||
|
|
||||||
|
private Collection<HardRouteLevelConstraint> hardConstraints = new ArrayList<HardRouteLevelConstraint>();
|
||||||
|
|
||||||
|
public void addConstraint(HardRouteLevelConstraint constraint){
|
||||||
|
hardConstraints.add(constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean fulfilled(InsertionContext insertionContext) {
|
||||||
|
for(HardRouteLevelConstraint constraint : hardConstraints){
|
||||||
|
if(!constraint.fulfilled(insertionContext)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ljsljslfjs
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class HardTimeWindowActivityLevelConstraint implements HardActivityLevelConstraint {
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(HardTimeWindowActivityLevelConstraint.class);
|
||||||
|
|
||||||
|
private StateGetter states;
|
||||||
|
|
||||||
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
|
public HardTimeWindowActivityLevelConstraint(StateGetter states, VehicleRoutingTransportCosts routingCosts) {
|
||||||
|
super();
|
||||||
|
this.states = states;
|
||||||
|
this.routingCosts = routingCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConstraintsStatus fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||||
|
if(newAct.getTheoreticalLatestOperationStartTime() < prevAct.getTheoreticalEarliestOperationStartTime()){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED_BREAK;
|
||||||
|
}
|
||||||
|
if(newAct.getTheoreticalEarliestOperationStartTime() > nextAct.getTheoreticalLatestOperationStartTime()){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
|
// log.info("check insertion of " + newAct + " between " + prevAct + " and " + nextAct + ". prevActDepTime=" + prevActDepTime);
|
||||||
|
double arrTimeAtNewAct = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
double latestArrTimeAtNewAct = states.getActivityState(newAct, StateFactory.LATEST_OPERATION_START_TIME).toDouble();
|
||||||
|
|
||||||
|
if(arrTimeAtNewAct > latestArrTimeAtNewAct){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
|
// log.info(newAct + " arrTime=" + arrTimeAtNewAct);
|
||||||
|
double endTimeAtNewAct = CalculationUtils.getActivityEndTime(arrTimeAtNewAct, newAct);
|
||||||
|
double arrTimeAtNextAct = endTimeAtNewAct + routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), endTimeAtNewAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
double latestArrTimeAtNextAct = states.getActivityState(nextAct, StateFactory.LATEST_OPERATION_START_TIME).toDouble();
|
||||||
|
if(arrTimeAtNextAct > latestArrTimeAtNextAct){
|
||||||
|
return ConstraintsStatus.NOT_FULFILLED;
|
||||||
|
}
|
||||||
|
return ConstraintsStatus.FULFILLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -21,8 +21,8 @@ import basics.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface InitialSolutionFactory {
|
public interface InitialSolutionFactory {
|
||||||
|
|
||||||
public VehicleRoutingProblemSolution createInitialSolution(VehicleRoutingProblem vrp);
|
public VehicleRoutingProblemSolution createSolution(VehicleRoutingProblem vrp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import basics.route.Driver;
|
||||||
import basics.route.Vehicle;
|
import basics.route.Vehicle;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
class InsertionContext {
|
public class InsertionContext {
|
||||||
|
|
||||||
private VehicleRoute route;
|
private VehicleRoute route;
|
||||||
private Job job;
|
private Job job;
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,14 @@ package algorithms;
|
||||||
import basics.route.Driver;
|
import basics.route.Driver;
|
||||||
import basics.route.Vehicle;
|
import basics.route.Vehicle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data object that collects insertion information. It collects insertionCosts, insertionIndeces, vehicle and driver to be employed
|
||||||
class InsertionData {
|
* and departureTime of vehicle at vehicle's start location (e.g. depot).
|
||||||
|
*
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class InsertionData {
|
||||||
|
|
||||||
static class NoInsertionFound extends InsertionData{
|
static class NoInsertionFound extends InsertionData{
|
||||||
|
|
||||||
|
|
@ -33,7 +38,15 @@ class InsertionData {
|
||||||
|
|
||||||
private static InsertionData noInsertion = new NoInsertionFound();
|
private static InsertionData noInsertion = new NoInsertionFound();
|
||||||
|
|
||||||
public static InsertionData noInsertionFound(){
|
/**
|
||||||
|
* Returns an instance of InsertionData that represents an EmptyInsertionData (which might indicate
|
||||||
|
* that no insertion has been found). It is internally instantiated as follows:<br>
|
||||||
|
* <code>new InsertionData(Double.MAX_VALUE, NO_INDEX, NO_INDEX, null, null);</code><br>
|
||||||
|
* where NO_INDEX=-1.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static InsertionData createEmptyInsertionData(){
|
||||||
return noInsertion;
|
return noInsertion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,22 +93,47 @@ class InsertionData {
|
||||||
return "[iCost="+insertionCost+"][iIndex="+deliveryInsertionIndex+"][depTime="+departureTime+"][vehicle="+selectedVehicle+"][driver="+selectedDriver+"]";
|
return "[iCost="+insertionCost+"][iIndex="+deliveryInsertionIndex+"][depTime="+departureTime+"][vehicle="+selectedVehicle+"][driver="+selectedDriver+"]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns insertionIndex of deliveryActivity. If no insertionPosition is found, it returns NO_INDEX (=-1).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public int getDeliveryInsertionIndex(){
|
public int getDeliveryInsertionIndex(){
|
||||||
return deliveryInsertionIndex;
|
return deliveryInsertionIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns insertionIndex of pickkupActivity. If no insertionPosition is found, it returns NO_INDEX (=-1).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public int getPickupInsertionIndex(){
|
public int getPickupInsertionIndex(){
|
||||||
return pickupInsertionIndex;
|
return pickupInsertionIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns insertion costs (which might be the additional costs of inserting the corresponding job).
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public double getInsertionCost() {
|
public double getInsertionCost() {
|
||||||
return insertionCost;
|
return insertionCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the vehicle to be employed.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Vehicle getSelectedVehicle() {
|
public Vehicle getSelectedVehicle() {
|
||||||
return selectedVehicle;
|
return selectedVehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the vehicle to be employed.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public Driver getSelectedDriver(){
|
public Driver getSelectedDriver(){
|
||||||
return selectedDriver;
|
return selectedDriver;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,19 +23,18 @@ import java.util.concurrent.ExecutorService;
|
||||||
import org.apache.commons.configuration.HierarchicalConfiguration;
|
import org.apache.commons.configuration.HierarchicalConfiguration;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import algorithms.HardConstraints.ConstraintManager;
|
|
||||||
import basics.VehicleRoutingProblem;
|
import basics.VehicleRoutingProblem;
|
||||||
import basics.algo.InsertionListener;
|
import basics.algo.InsertionListener;
|
||||||
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
|
|
||||||
class InsertionFactory {
|
class InsertionFactory {
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(InsertionFactory.class);
|
private static Logger log = Logger.getLogger(InsertionFactory.class);
|
||||||
|
|
||||||
public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config,
|
public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config,
|
||||||
VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager){
|
VehicleFleetManager vehicleFleetManager, StateManager routeStates, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager){
|
||||||
boolean concurrentInsertion = false;
|
|
||||||
if(executorService != null) concurrentInsertion = true;
|
|
||||||
if(config.containsKey("[@name]")){
|
if(config.containsKey("[@name]")){
|
||||||
String insertionName = config.getString("[@name]");
|
String insertionName = config.getString("[@name]");
|
||||||
if(!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion")){
|
if(!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion")){
|
||||||
|
|
@ -89,26 +88,13 @@ class InsertionFactory {
|
||||||
calcBuilder.experimentalTimeScheduler(Double.parseDouble(timeSliceString),Integer.parseInt(neighbors));
|
calcBuilder.experimentalTimeScheduler(Double.parseDouble(timeSliceString),Integer.parseInt(neighbors));
|
||||||
}
|
}
|
||||||
|
|
||||||
JobInsertionCalculator jic = calcBuilder.build();
|
JobInsertionCostsCalculator jic = calcBuilder.build();
|
||||||
|
|
||||||
|
|
||||||
if(insertionName.equals("bestInsertion")){
|
if(insertionName.equals("bestInsertion")){
|
||||||
insertionStrategy = new BestInsertion(jic);
|
insertionStrategy = new BestInsertion(jic);
|
||||||
}
|
}
|
||||||
// else if(insertionName.equals("regretInsertion")){
|
|
||||||
// insertionStrategy = RegretInsertion.newInstance(routeAlgorithm);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// insertionStrategy.addListener(new RemoveEmptyVehicles(vehicleFleetManager));
|
|
||||||
// insertionStrategy.addListener(new ResetAndIniFleetManager(vehicleFleetManager));
|
|
||||||
// insertionStrategy.addListener(new VehicleSwitched(vehicleFleetManager));
|
|
||||||
|
|
||||||
// insertionStrategy.addListener(new UpdateLoadAtRouteLevel(routeStates));
|
|
||||||
|
|
||||||
// insertionStrategy.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts()));
|
|
||||||
for(InsertionListener l : insertionListeners) insertionStrategy.addListener(l);
|
for(InsertionListener l : insertionListeners) insertionStrategy.addListener(l);
|
||||||
// insertionStrategy.addListener(new FindCheaperVehicle(
|
|
||||||
// new FindCheaperVehicleAlgoNew(vehicleFleetManager, tourStateCalculator, auxCalculator)));
|
|
||||||
|
|
||||||
algorithmListeners.addAll(algoListeners);
|
algorithmListeners.addAll(algoListeners);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,14 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (C) 2013 Stefan Schroeder
|
* Copyright (c) 2011 Stefan Schroeder.
|
||||||
|
* eMail: stefan.schroeder@kit.edu
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* All rights reserved. This program and the accompanying materials
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* are made available under the terms of the GNU Public License v2.0
|
||||||
* License as published by the Free Software Foundation; either
|
* which accompanies this distribution, and is available at
|
||||||
* version 3.0 of the License, or (at your option) any later version.
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* Contributors:
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* Stefan Schroeder - initial API and implementation
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
/* *********************************************************************** *
|
/* *********************************************************************** *
|
||||||
* project: org.matsim.*
|
* project: org.matsim.*
|
||||||
|
|
@ -45,48 +41,34 @@ import basics.Job;
|
||||||
import basics.VehicleRoutingProblem;
|
import basics.VehicleRoutingProblem;
|
||||||
import basics.VehicleRoutingProblemSolution;
|
import basics.VehicleRoutingProblemSolution;
|
||||||
import basics.algo.SolutionCostCalculator;
|
import basics.algo.SolutionCostCalculator;
|
||||||
import basics.route.DriverImpl;
|
|
||||||
import basics.route.TourActivities;
|
|
||||||
import basics.route.Vehicle;
|
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final class CreateInitialSolution implements InitialSolutionFactory {
|
public final class InsertionInitialSolutionFactory implements InitialSolutionFactory {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(CreateInitialSolution.class);
|
private static final Logger logger = Logger.getLogger(InsertionInitialSolutionFactory.class);
|
||||||
|
|
||||||
private final InsertionStrategy insertion;
|
private final InsertionStrategy insertion;
|
||||||
|
|
||||||
private SolutionCostCalculator solutionCostCalculator;
|
private SolutionCostCalculator solutionCostsCalculator;
|
||||||
|
|
||||||
private boolean generateAsMuchAsRoutesAsVehiclesExist = false;
|
public InsertionInitialSolutionFactory(InsertionStrategy insertionStrategy, SolutionCostCalculator solutionCostCalculator) {
|
||||||
|
|
||||||
public void setGenerateAsMuchAsRoutesAsVehiclesExist(boolean generateAsMuchAsRoutesAsVehiclesExist) {
|
|
||||||
this.generateAsMuchAsRoutesAsVehiclesExist = generateAsMuchAsRoutesAsVehiclesExist;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CreateInitialSolution(InsertionStrategy insertionStrategy, SolutionCostCalculator solutionCostCalculator) {
|
|
||||||
super();
|
super();
|
||||||
this.insertion = insertionStrategy;
|
this.insertion = insertionStrategy;
|
||||||
this.solutionCostCalculator = solutionCostCalculator;
|
this.solutionCostsCalculator = solutionCostCalculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VehicleRoutingProblemSolution createInitialSolution(final VehicleRoutingProblem vrp) {
|
public VehicleRoutingProblemSolution createSolution(final VehicleRoutingProblem vrp) {
|
||||||
logger.info("create initial solution.");
|
logger.info("create initial solution.");
|
||||||
List<VehicleRoute> vehicleRoutes = new ArrayList<VehicleRoute>();
|
List<VehicleRoute> vehicleRoutes = new ArrayList<VehicleRoute>();
|
||||||
if(generateAsMuchAsRoutesAsVehiclesExist){
|
|
||||||
for(Vehicle vehicle : vrp.getVehicles()){
|
|
||||||
vehicleRoutes.add(VehicleRoute.newInstance(TourActivities.emptyTour(), DriverImpl.noDriver(), vehicle));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
insertion.insertJobs(vehicleRoutes, getUnassignedJobs(vrp));
|
insertion.insertJobs(vehicleRoutes, getUnassignedJobs(vrp));
|
||||||
// double totalCost = getTotalCost(vehicleRoutes);
|
VehicleRoutingProblemSolution solution = new VehicleRoutingProblemSolution(vehicleRoutes, Double.MAX_VALUE);
|
||||||
|
double costs = solutionCostsCalculator.getCosts(solution);
|
||||||
|
solution.setCost(costs);
|
||||||
logger.info("creation done");
|
logger.info("creation done");
|
||||||
VehicleRoutingProblemSolution vehicleRoutingProblemSolution = new VehicleRoutingProblemSolution(vehicleRoutes, 0.0);
|
return solution;
|
||||||
solutionCostCalculator.calculateCosts(vehicleRoutingProblemSolution);
|
|
||||||
return vehicleRoutingProblemSolution;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Job> getUnassignedJobs(VehicleRoutingProblem vrp) {
|
private List<Job> getUnassignedJobs(VehicleRoutingProblem vrp) {
|
||||||
|
|
@ -31,33 +31,7 @@ import basics.route.VehicleRoute;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface InsertionStrategy {
|
public interface InsertionStrategy {
|
||||||
|
|
||||||
class Insertion {
|
|
||||||
|
|
||||||
private final VehicleRoute route;
|
|
||||||
|
|
||||||
private final InsertionData insertionData;
|
|
||||||
|
|
||||||
public Insertion(VehicleRoute vehicleRoute, InsertionData insertionData) {
|
|
||||||
super();
|
|
||||||
this.route = vehicleRoute;
|
|
||||||
this.insertionData = insertionData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public VehicleRoute getRoute() {
|
|
||||||
return route;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InsertionData getInsertionData() {
|
|
||||||
return insertionData;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns the unassigned jobs to service-providers
|
* Assigns the unassigned jobs to service-providers
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
public interface InsertionStrategyBuilder {
|
||||||
|
|
||||||
|
public InsertionStrategy build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (C) 2013 Stefan Schroeder
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 3.0 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
******************************************************************************/
|
|
||||||
package algorithms;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import algorithms.BackwardInTimeListeners.BackwardInTimeListener;
|
|
||||||
import basics.costs.BackwardTransportTime;
|
|
||||||
import basics.route.TourActivity;
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author stefan schroeder
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class IterateRouteBackwardInTime implements VehicleRouteUpdater{
|
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(IterateRouteBackwardInTime.class);
|
|
||||||
|
|
||||||
private BackwardTransportTime transportTime;
|
|
||||||
|
|
||||||
private BackwardInTimeListeners listeners;
|
|
||||||
|
|
||||||
public IterateRouteBackwardInTime(BackwardTransportTime transportTime) {
|
|
||||||
super();
|
|
||||||
this.transportTime = transportTime;
|
|
||||||
listeners = new BackwardInTimeListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void iterate(VehicleRoute vehicleRoute) {
|
|
||||||
if(listeners.isEmpty()) return;
|
|
||||||
if(vehicleRoute.isEmpty()) return;
|
|
||||||
listeners.start(vehicleRoute, vehicleRoute.getEnd(), vehicleRoute.getEnd().getTheoreticalLatestOperationStartTime());
|
|
||||||
|
|
||||||
Iterator<TourActivity> reverseActIter = vehicleRoute.getTourActivities().reverseActivityIterator();
|
|
||||||
TourActivity prevAct;
|
|
||||||
prevAct = vehicleRoute.getEnd();
|
|
||||||
double latestArrivalTimeAtPrevAct = prevAct.getTheoreticalLatestOperationStartTime();
|
|
||||||
|
|
||||||
while(reverseActIter.hasNext()){
|
|
||||||
TourActivity currAct = reverseActIter.next();
|
|
||||||
double latestDepTimeAtCurrAct = latestArrivalTimeAtPrevAct - transportTime.getBackwardTransportTime(currAct.getLocationId(), prevAct.getLocationId(), latestArrivalTimeAtPrevAct, vehicleRoute.getDriver(),vehicleRoute.getVehicle());
|
|
||||||
double potentialLatestArrivalTimeAtCurrAct = latestDepTimeAtCurrAct - currAct.getOperationTime();
|
|
||||||
double latestArrivalTime = Math.min(currAct.getTheoreticalLatestOperationStartTime(), potentialLatestArrivalTimeAtCurrAct);
|
|
||||||
|
|
||||||
listeners.prevActivity(currAct, latestDepTimeAtCurrAct, latestArrivalTime);
|
|
||||||
|
|
||||||
prevAct = currAct;
|
|
||||||
latestArrivalTimeAtPrevAct = latestArrivalTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
TourActivity currAct = vehicleRoute.getStart();
|
|
||||||
double latestDepTimeAtCurrAct = latestArrivalTimeAtPrevAct - transportTime.getBackwardTransportTime(currAct.getLocationId(), prevAct.getLocationId(), latestArrivalTimeAtPrevAct, vehicleRoute.getDriver(),vehicleRoute.getVehicle());
|
|
||||||
|
|
||||||
listeners.end(vehicleRoute.getStart(), latestDepTimeAtCurrAct);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addListener(BackwardInTimeListener l){ listeners.addListener(l); }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (C) 2013 Stefan Schroeder
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 3.0 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
******************************************************************************/
|
|
||||||
package algorithms;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import algorithms.ForwardInTimeListeners.ForwardInTimeListener;
|
|
||||||
import basics.costs.ForwardTransportTime;
|
|
||||||
import basics.route.Driver;
|
|
||||||
import basics.route.End;
|
|
||||||
import basics.route.TourActivity;
|
|
||||||
import basics.route.Vehicle;
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author sschroeder
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
class IterateRouteForwardInTime implements VehicleRouteUpdater{
|
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(IterateRouteForwardInTime.class);
|
|
||||||
|
|
||||||
private ForwardTransportTime transportTime;
|
|
||||||
|
|
||||||
private ForwardInTimeListeners listeners;
|
|
||||||
|
|
||||||
public IterateRouteForwardInTime(ForwardTransportTime transportTime) {
|
|
||||||
super();
|
|
||||||
this.transportTime = transportTime;
|
|
||||||
listeners = new ForwardInTimeListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void iterate(VehicleRoute vehicleRoute) {
|
|
||||||
if(listeners.isEmpty()) return;
|
|
||||||
if(vehicleRoute.isEmpty()) return;
|
|
||||||
listeners.start(vehicleRoute, vehicleRoute.getStart(), vehicleRoute.getStart().getEndTime());
|
|
||||||
|
|
||||||
Vehicle vehicle = vehicleRoute.getVehicle();
|
|
||||||
Driver driver = vehicleRoute.getDriver();
|
|
||||||
TourActivity prevAct = vehicleRoute.getStart();
|
|
||||||
double startAtPrevAct = prevAct.getEndTime();
|
|
||||||
|
|
||||||
for(TourActivity currentAct : vehicleRoute.getTourActivities().getActivities()){
|
|
||||||
double transportTime = this.transportTime.getTransportTime(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle);
|
|
||||||
double arrivalTimeAtCurrAct = startAtPrevAct + transportTime;
|
|
||||||
double operationStartTime = Math.max(currentAct.getTheoreticalEarliestOperationStartTime(), arrivalTimeAtCurrAct);
|
|
||||||
double operationEndTime = operationStartTime + currentAct.getOperationTime();
|
|
||||||
|
|
||||||
listeners.nextActivity(currentAct,arrivalTimeAtCurrAct,operationEndTime);
|
|
||||||
|
|
||||||
prevAct = currentAct;
|
|
||||||
startAtPrevAct = operationEndTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
End currentAct = vehicleRoute.getEnd();
|
|
||||||
double transportTime = this.transportTime.getTransportTime(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle);
|
|
||||||
double arrivalTimeAtCurrAct = startAtPrevAct + transportTime;
|
|
||||||
|
|
||||||
listeners.end(vehicleRoute.getEnd(), arrivalTimeAtCurrAct);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addListener(ForwardInTimeListener l){
|
|
||||||
listeners.addListener(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -8,18 +8,18 @@ import basics.route.Driver;
|
||||||
import basics.route.Vehicle;
|
import basics.route.Vehicle;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
public class JobCalculatorSwitcher implements JobInsertionCalculator{
|
public class JobCalculatorSwitcher implements JobInsertionCostsCalculator{
|
||||||
|
|
||||||
private Map<Class<? extends Job>,JobInsertionCalculator> calcMap = new HashMap<Class<? extends Job>, JobInsertionCalculator>();
|
private Map<Class<? extends Job>,JobInsertionCostsCalculator> calcMap = new HashMap<Class<? extends Job>, JobInsertionCostsCalculator>();
|
||||||
|
|
||||||
void put(Class<? extends Job> jobClass, JobInsertionCalculator jic){
|
void put(Class<? extends Job> jobClass, JobInsertionCostsCalculator jic){
|
||||||
calcMap.put(jobClass, jic);
|
calcMap.put(jobClass, jic);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertionData calculate(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore){
|
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore){
|
||||||
JobInsertionCalculator jic = calcMap.get(jobToInsert.getClass());
|
JobInsertionCostsCalculator jic = calcMap.get(jobToInsert.getClass());
|
||||||
if(jic==null) throw new IllegalStateException("cannot find calculator for " + jobToInsert.getClass());
|
if(jic==null) throw new IllegalStateException("cannot find calculator for " + jobToInsert.getClass());
|
||||||
return jic.calculate(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownScore);
|
return jic.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownScore);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ import basics.Job;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface JobDistance {
|
public interface JobDistance {
|
||||||
|
|
||||||
public double calculateDistance(Job i, Job j);
|
public double getDistance(Job i, Job j);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class JobDistanceAvgCosts implements JobDistance {
|
||||||
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
|
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public double calculateDistance(Job i, Job j) {
|
public double getDistance(Job i, Job j) {
|
||||||
double avgCost = 0.0;
|
double avgCost = 0.0;
|
||||||
if (i instanceof Service && j instanceof Service) {
|
if (i instanceof Service && j instanceof Service) {
|
||||||
if (i.equals(j)) {
|
if (i.equals(j)) {
|
||||||
|
|
@ -76,7 +76,7 @@ class JobDistanceAvgCosts implements JobDistance {
|
||||||
// now try the euclidean distance between these two services
|
// now try the euclidean distance between these two services
|
||||||
}
|
}
|
||||||
EuclideanServiceDistance euclidean = new EuclideanServiceDistance();
|
EuclideanServiceDistance euclidean = new EuclideanServiceDistance();
|
||||||
distance = euclidean.calculateDistance(s_i, s_j);
|
distance = euclidean.getDistance(s_i, s_j);
|
||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ class JobDistanceBeeline implements JobDistance {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double calculateDistance(Job i, Job j) {
|
public double getDistance(Job i, Job j) {
|
||||||
double avgCost = 0.0;
|
double avgCost = 0.0;
|
||||||
if (i instanceof Service && j instanceof Service) {
|
if (i instanceof Service && j instanceof Service) {
|
||||||
if (i.equals(j)) {
|
if (i.equals(j)) {
|
||||||
|
|
|
||||||
|
|
@ -27,35 +27,35 @@ import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final class CalculatesServiceInsertionConsideringFixCost implements JobInsertionCalculator{
|
final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCostsCalculator{
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(CalculatesServiceInsertionConsideringFixCost.class);
|
private static final Logger logger = Logger.getLogger(JobInsertionConsideringFixCostsCalculator.class);
|
||||||
|
|
||||||
private final JobInsertionCalculator standardServiceInsertion;
|
private final JobInsertionCostsCalculator standardServiceInsertion;
|
||||||
|
|
||||||
private double weight_deltaFixCost = 0.5;
|
private double weight_deltaFixCost = 0.5;
|
||||||
|
|
||||||
private double solution_completeness_ratio = 0.5;
|
private double solution_completeness_ratio = 0.5;
|
||||||
|
|
||||||
private StateManager states;
|
private StateGetter stateGetter;
|
||||||
|
|
||||||
public CalculatesServiceInsertionConsideringFixCost(final JobInsertionCalculator standardInsertionCalculator, StateManager activityStates2) {
|
public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardInsertionCalculator, StateGetter stateGetter) {
|
||||||
super();
|
super();
|
||||||
this.standardServiceInsertion = standardInsertionCalculator;
|
this.standardServiceInsertion = standardInsertionCalculator;
|
||||||
this.states = activityStates2;
|
this.stateGetter = stateGetter;
|
||||||
logger.info("inialise " + this);
|
logger.info("inialise " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InsertionData calculate(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownPrice) {
|
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownPrice) {
|
||||||
double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert);
|
double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert);
|
||||||
double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert);
|
double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert);
|
||||||
double deltaFixCost = (1-solution_completeness_ratio)*relFixCost + solution_completeness_ratio*absFixCost;
|
double deltaFixCost = (1-solution_completeness_ratio)*relFixCost + solution_completeness_ratio*absFixCost;
|
||||||
double fixcost_contribution = weight_deltaFixCost*solution_completeness_ratio*deltaFixCost;
|
double fixcost_contribution = weight_deltaFixCost*solution_completeness_ratio*deltaFixCost;
|
||||||
if(fixcost_contribution > bestKnownPrice){
|
if(fixcost_contribution > bestKnownPrice){
|
||||||
return InsertionData.noInsertionFound();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
InsertionData iData = standardServiceInsertion.calculate(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice);
|
InsertionData iData = standardServiceInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice);
|
||||||
if(iData instanceof NoInsertionFound){
|
if(iData instanceof NoInsertionFound){
|
||||||
return iData;
|
return iData;
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +80,7 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job) {
|
private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job) {
|
||||||
double load = getCurrentLoad(route) + job.getCapacityDemand();
|
double load = getCurrentMaxLoadInRoute(route) + job.getCapacityDemand();
|
||||||
double currentFix = 0.0;
|
double currentFix = 0.0;
|
||||||
if(route.getVehicle() != null){
|
if(route.getVehicle() != null){
|
||||||
if(!(route.getVehicle() instanceof NoVehicle)){
|
if(!(route.getVehicle() instanceof NoVehicle)){
|
||||||
|
|
@ -94,7 +94,7 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job) {
|
private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job) {
|
||||||
int currentLoad = getCurrentLoad(route);
|
int currentLoad = getCurrentMaxLoadInRoute(route);
|
||||||
double load = currentLoad + job.getCapacityDemand();
|
double load = currentLoad + job.getCapacityDemand();
|
||||||
double currentRelFix = 0.0;
|
double currentRelFix = 0.0;
|
||||||
if(route.getVehicle() != null){
|
if(route.getVehicle() != null){
|
||||||
|
|
@ -109,8 +109,8 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion
|
||||||
return relativeFixCost;
|
return relativeFixCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getCurrentLoad(VehicleRoute route) {
|
private int getCurrentMaxLoadInRoute(VehicleRoute route) {
|
||||||
return (int) states.getRouteState(route, StateTypes.LOAD).toDouble();
|
return (int) stateGetter.getRouteState(route, StateFactory.MAXLOAD).toDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -22,8 +22,8 @@ import basics.route.Vehicle;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
interface JobInsertionCalculator {
|
public interface JobInsertionCostsCalculator {
|
||||||
|
|
||||||
public InsertionData calculate(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore);
|
public InsertionData getInsertionData(VehicleRoute currentRoute, Job newJob, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownCosts);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -20,38 +20,42 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package algorithms;
|
package algorithms;
|
||||||
|
|
||||||
import algorithms.HardConstraints.HardActivityLevelConstraint;
|
|
||||||
import basics.costs.VehicleRoutingActivityCosts;
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
import basics.costs.VehicleRoutingTransportCosts;
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
import basics.route.TourActivity;
|
import basics.route.TourActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates activity insertion costs locally, i.e. by comparing the additional costs of insertion the new activity k between
|
||||||
|
* activity i (prevAct) and j (nextAct).
|
||||||
|
* Additional costs are then basically calculated as delta c = c_ik + c_kj - c_ij.
|
||||||
|
*
|
||||||
|
* <p>Note once time has an effect on costs this class requires activity endTimes.
|
||||||
|
*
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCalculator{
|
class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCalculator{
|
||||||
|
|
||||||
private HardActivityLevelConstraint hardConstraint;
|
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts routingCosts;
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
private VehicleRoutingActivityCosts activityCosts;
|
private VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
public LocalActivityInsertionCostsCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, HardActivityLevelConstraint hardActivityLevelConstraint) {
|
|
||||||
|
public LocalActivityInsertionCostsCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts) {
|
||||||
super();
|
super();
|
||||||
this.routingCosts = routingCosts;
|
this.routingCosts = routingCosts;
|
||||||
this.activityCosts = actCosts;
|
this.activityCosts = actCosts;
|
||||||
this.hardConstraint = hardActivityLevelConstraint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActivityInsertionCosts calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) {
|
public ActivityInsertionCosts getCosts(InsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) {
|
||||||
if(!hardConstraint.fulfilled(iFacts, prevAct, newAct, nextAct, depTimeAtPrevAct)){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
|
||||||
double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct;
|
double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct;
|
||||||
|
|
||||||
double newAct_endTime = CalcUtils.getActivityEndTime(newAct_arrTime, newAct);
|
double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct);
|
||||||
|
|
||||||
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ import basics.algo.VehicleRoutingAlgorithmFactory;
|
||||||
import basics.route.TourActivity;
|
import basics.route.TourActivity;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
public class NeighborhoodThresholdInitialiser implements AlgorithmStartsListener{
|
class NeighborhoodThresholdInitialiser implements AlgorithmStartsListener{
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(NeighborhoodThresholdInitialiser.class);
|
private static Logger log = Logger.getLogger(NeighborhoodThresholdInitialiser.class);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
|
||||||
|
public class RadialRuinStrategyFactory implements RuinStrategyFactory{
|
||||||
|
|
||||||
|
private double fraction;
|
||||||
|
|
||||||
|
private JobDistance jobDistance;
|
||||||
|
|
||||||
|
public RadialRuinStrategyFactory(double fraction, JobDistance jobDistance) {
|
||||||
|
super();
|
||||||
|
this.fraction = fraction;
|
||||||
|
this.jobDistance = jobDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RuinStrategy createStrategy(VehicleRoutingProblem vrp) {
|
||||||
|
return new RuinRadial(vrp,fraction,jobDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
|
||||||
|
public class RandomRuinStrategyFactory implements RuinStrategyFactory{
|
||||||
|
|
||||||
|
private double fraction;
|
||||||
|
|
||||||
|
public RandomRuinStrategyFactory(double fraction) {
|
||||||
|
super();
|
||||||
|
this.fraction = fraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RuinStrategy createStrategy(VehicleRoutingProblem vrp) {
|
||||||
|
return new RuinRandom(vrp, fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -23,6 +23,7 @@ import java.util.List;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import basics.algo.InsertionEndsListener;
|
import basics.algo.InsertionEndsListener;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
class RemoveEmptyVehicles implements InsertionEndsListener{
|
class RemoveEmptyVehicles implements InsertionEndsListener{
|
||||||
|
|
@ -31,7 +32,7 @@ class RemoveEmptyVehicles implements InsertionEndsListener{
|
||||||
|
|
||||||
private VehicleFleetManager fleetManager;
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
RemoveEmptyVehicles(VehicleFleetManager fleetManager) {
|
public RemoveEmptyVehicles(VehicleFleetManager fleetManager) {
|
||||||
super();
|
super();
|
||||||
this.fleetManager = fleetManager;
|
this.fleetManager = fleetManager;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
import basics.algo.InsertionStartsListener;
|
import basics.algo.InsertionStartsListener;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
class ResetAndIniFleetManager implements InsertionStartsListener{
|
class ResetAndIniFleetManager implements InsertionStartsListener{
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ package algorithms;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import algorithms.HardConstraints.HardActivityLevelConstraint;
|
|
||||||
import basics.costs.VehicleRoutingActivityCosts;
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
import basics.costs.VehicleRoutingTransportCosts;
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
import basics.route.End;
|
import basics.route.End;
|
||||||
|
|
@ -33,30 +32,23 @@ import basics.route.VehicleRoute;
|
||||||
|
|
||||||
class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCostsCalculator{
|
class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCostsCalculator{
|
||||||
|
|
||||||
private HardActivityLevelConstraint hardConstraint;
|
|
||||||
|
|
||||||
private VehicleRoutingActivityCosts activityCosts;
|
private VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
private AuxilliaryCostCalculator auxilliaryPathCostCalculator;
|
private AuxilliaryCostCalculator auxilliaryPathCostCalculator;
|
||||||
|
|
||||||
private StateManager stateManager;
|
private StateGetter stateManager;
|
||||||
|
|
||||||
private int nuOfActivities2LookForward = 0;
|
private int nuOfActivities2LookForward = 0;
|
||||||
|
|
||||||
public RouteLevelActivityInsertionCostsEstimator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, HardActivityLevelConstraint hardActivityLevelConstraint, StateManager stateManager) {
|
public RouteLevelActivityInsertionCostsEstimator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, StateGetter stateManager) {
|
||||||
super();
|
super();
|
||||||
this.activityCosts = actCosts;
|
this.activityCosts = actCosts;
|
||||||
this.hardConstraint = hardActivityLevelConstraint;
|
|
||||||
this.stateManager = stateManager;
|
this.stateManager = stateManager;
|
||||||
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(routingCosts, activityCosts);
|
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(routingCosts, activityCosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActivityInsertionCosts calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) {
|
public ActivityInsertionCosts getCosts(InsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) {
|
||||||
if(!hardConstraint.fulfilled(iFacts, prevAct, newAct, nextAct, depTimeAtPrevAct)){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TourActivity> path = new ArrayList<TourActivity>();
|
List<TourActivity> path = new ArrayList<TourActivity>();
|
||||||
path.add(prevAct); path.add(newAct); path.add(nextAct);
|
path.add(prevAct); path.add(newAct); path.add(nextAct);
|
||||||
int actIndex;
|
int actIndex;
|
||||||
|
|
@ -77,9 +69,9 @@ class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCost
|
||||||
|
|
||||||
private double actCostsOld(VehicleRoute vehicleRoute, TourActivity act) {
|
private double actCostsOld(VehicleRoute vehicleRoute, TourActivity act) {
|
||||||
if(act instanceof End){
|
if(act instanceof End){
|
||||||
return stateManager.getRouteState(vehicleRoute,StateTypes.COSTS).toDouble();
|
return stateManager.getRouteState(vehicleRoute,StateFactory.COSTS).toDouble();
|
||||||
}
|
}
|
||||||
return stateManager.getActivityState(act,StateTypes.COSTS).toDouble();
|
return stateManager.getActivityState(act,StateFactory.COSTS).toDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TourActivity> getForwardLookingPath(VehicleRoute route, int actIndex) {
|
private List<TourActivity> getForwardLookingPath(VehicleRoute route, int actIndex) {
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,14 @@ package algorithms;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import algorithms.RuinStrategy.RuinListener;
|
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
import basics.VehicleRoutingProblemSolution;
|
import basics.VehicleRoutingProblemSolution;
|
||||||
import basics.algo.InsertionListener;
|
import basics.algo.InsertionListener;
|
||||||
|
import basics.algo.RuinListener;
|
||||||
import basics.algo.SearchStrategyModule;
|
import basics.algo.SearchStrategyModule;
|
||||||
import basics.algo.SearchStrategyModuleListener;
|
import basics.algo.SearchStrategyModuleListener;
|
||||||
|
|
||||||
class RuinAndRecreateModule implements SearchStrategyModule{
|
public class RuinAndRecreateModule implements SearchStrategyModule{
|
||||||
|
|
||||||
private InsertionStrategy insertion;
|
private InsertionStrategy insertion;
|
||||||
|
|
||||||
|
|
@ -44,9 +44,8 @@ class RuinAndRecreateModule implements SearchStrategyModule{
|
||||||
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
|
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
|
||||||
Collection<Job> ruinedJobs = ruin.ruin(vrpSolution.getRoutes());
|
Collection<Job> ruinedJobs = ruin.ruin(vrpSolution.getRoutes());
|
||||||
insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobs);
|
insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobs);
|
||||||
// double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes());
|
|
||||||
// vrpSolution.setCost(totalCost);
|
|
||||||
return vrpSolution;
|
return vrpSolution;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (C) 2013 Stefan Schroeder
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 3.0 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
******************************************************************************/
|
|
||||||
package algorithms;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
import algorithms.RuinStrategy.RuinListener;
|
|
||||||
import basics.Job;
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
|
|
||||||
class RuinListeners {
|
|
||||||
|
|
||||||
private Collection<RuinListener> ruinListeners = new ArrayList<RuinListener>();
|
|
||||||
|
|
||||||
void ruinStarts(Collection<VehicleRoute> routes){
|
|
||||||
for(RuinListener l : ruinListeners) l.ruinStarts(routes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs){
|
|
||||||
for(RuinListener l : ruinListeners) l.ruinEnds(routes, unassignedJobs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removed(Job job, VehicleRoute fromRoute){
|
|
||||||
for(RuinListener l : ruinListeners) l.removed(job, fromRoute);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addListener(RuinListener ruinListener){
|
|
||||||
ruinListeners.add(ruinListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeListener(RuinListener ruinListener){
|
|
||||||
ruinListeners.remove(ruinListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<RuinListener> getListeners(){
|
|
||||||
return Collections.unmodifiableCollection(ruinListeners);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -33,6 +33,8 @@ import util.RandomNumberGeneration;
|
||||||
import util.StopWatch;
|
import util.StopWatch;
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
import basics.VehicleRoutingProblem;
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.algo.RuinListener;
|
||||||
|
import basics.algo.RuinListeners;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -120,7 +122,7 @@ final class RuinRadial implements RuinStrategy {
|
||||||
});
|
});
|
||||||
distanceNodeTree.put(i.getId(), treeSet);
|
distanceNodeTree.put(i.getId(), treeSet);
|
||||||
for (Job j : vrp.getJobs().values()) {
|
for (Job j : vrp.getJobs().values()) {
|
||||||
double distance = jobDistance.calculateDistance(i, j);
|
double distance = jobDistance.getDistance(i, j);
|
||||||
ReferencedJob refNode = new ReferencedJob(j, distance);
|
ReferencedJob refNode = new ReferencedJob(j, distance);
|
||||||
treeSet.add(refNode);
|
treeSet.add(refNode);
|
||||||
nuOfDistancesStored++;
|
nuOfDistancesStored++;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ import org.apache.log4j.Logger;
|
||||||
import util.RandomNumberGeneration;
|
import util.RandomNumberGeneration;
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
import basics.VehicleRoutingProblem;
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.algo.RuinListener;
|
||||||
|
import basics.algo.RuinListeners;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package algorithms;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
|
import basics.algo.RuinListener;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -30,40 +31,7 @@ import basics.route.VehicleRoute;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface RuinStrategy {
|
public interface RuinStrategy {
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener that listens to the ruin-process. It informs whoever is interested about start, end and about a removal of a job.
|
|
||||||
*
|
|
||||||
* @author schroeder
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static interface RuinListener {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* informs about ruin-start.
|
|
||||||
*
|
|
||||||
* @param routes
|
|
||||||
*/
|
|
||||||
public void ruinStarts(Collection<VehicleRoute> routes);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* informs about ruin-end.
|
|
||||||
*
|
|
||||||
* @param routes
|
|
||||||
* @param unassignedJobs
|
|
||||||
*/
|
|
||||||
public void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* informs if a {@link Job} has been removed from a {@link VehicleRoute}.
|
|
||||||
*
|
|
||||||
* @param job
|
|
||||||
* @param fromRoute
|
|
||||||
*/
|
|
||||||
public void removed(Job job, VehicleRoute fromRoute);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ruins a current solution, i.e. a collection of vehicle-routes and
|
* Ruins a current solution, i.e. a collection of vehicle-routes and
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ package algorithms;
|
||||||
|
|
||||||
import basics.VehicleRoutingProblem;
|
import basics.VehicleRoutingProblem;
|
||||||
|
|
||||||
interface RuinStrategyFactory {
|
public interface RuinStrategyFactory {
|
||||||
|
|
||||||
public RuinStrategy createStrategy(VehicleRoutingProblem vrp);
|
public RuinStrategy createStrategy(VehicleRoutingProblem vrp);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,8 @@ import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import util.Neighborhood;
|
import util.Neighborhood;
|
||||||
import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts;
|
import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts;
|
||||||
import algorithms.HardConstraints.HardRouteLevelConstraint;
|
|
||||||
|
import algorithms.HardActivityLevelConstraint.ConstraintsStatus;
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
import basics.Service;
|
import basics.Service;
|
||||||
import basics.costs.VehicleRoutingTransportCosts;
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
|
@ -36,12 +37,14 @@ import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final class ServiceInsertionCalculator implements JobInsertionCalculator{
|
final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ServiceInsertionCalculator.class);
|
private static final Logger logger = Logger.getLogger(ServiceInsertionCalculator.class);
|
||||||
|
|
||||||
private HardRouteLevelConstraint hardRouteLevelConstraint;
|
private HardRouteLevelConstraint hardRouteLevelConstraint;
|
||||||
|
|
||||||
|
private HardActivityLevelConstraint hardActivityLevelConstraint;
|
||||||
|
|
||||||
private Neighborhood neighborhood = new Neighborhood() {
|
private Neighborhood neighborhood = new Neighborhood() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -61,10 +64,12 @@ final class ServiceInsertionCalculator implements JobInsertionCalculator{
|
||||||
logger.info("initialise neighborhood " + neighborhood);
|
logger.info("initialise neighborhood " + neighborhood);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, HardRouteLevelConstraint hardRouteLevelConstraint) {
|
|
||||||
|
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, HardRouteLevelConstraint hardRouteLevelConstraint, HardActivityLevelConstraint hardActivityLevelConstraint) {
|
||||||
super();
|
super();
|
||||||
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
||||||
this.hardRouteLevelConstraint = hardRouteLevelConstraint;
|
this.hardRouteLevelConstraint = hardRouteLevelConstraint;
|
||||||
|
this.hardActivityLevelConstraint = hardActivityLevelConstraint;
|
||||||
this.transportCosts = routingCosts;
|
this.transportCosts = routingCosts;
|
||||||
activityFactory = new DefaultTourActivityFactory();
|
activityFactory = new DefaultTourActivityFactory();
|
||||||
logger.info("initialise " + this);
|
logger.info("initialise " + this);
|
||||||
|
|
@ -81,13 +86,13 @@ final class ServiceInsertionCalculator implements JobInsertionCalculator{
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public InsertionData calculate(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
|
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
|
||||||
if(jobToInsert == null) throw new IllegalStateException("jobToInsert is missing.");
|
if(jobToInsert == null) throw new IllegalStateException("jobToInsert is missing.");
|
||||||
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("newVehicle is missing.");
|
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("newVehicle is missing.");
|
||||||
|
|
||||||
InsertionContext insertionContext = new InsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
InsertionContext insertionContext = new InsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
||||||
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
|
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
|
||||||
return InsertionData.noInsertionFound();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
|
|
||||||
double bestCost = bestKnownCosts;
|
double bestCost = bestKnownCosts;
|
||||||
|
|
@ -99,36 +104,40 @@ final class ServiceInsertionCalculator implements JobInsertionCalculator{
|
||||||
|
|
||||||
Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
|
Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
|
||||||
start.setEndTime(newVehicleDepartureTime);
|
start.setEndTime(newVehicleDepartureTime);
|
||||||
|
|
||||||
End end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
|
End end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
|
||||||
|
|
||||||
TourActivity prevAct = start;
|
TourActivity prevAct = start;
|
||||||
double prevActStartTime = newVehicleDepartureTime;
|
double prevActStartTime = newVehicleDepartureTime;
|
||||||
int actIndex = 0;
|
int actIndex = 0;
|
||||||
|
boolean loopBroken = false;
|
||||||
for(TourActivity nextAct : currentRoute.getTourActivities().getActivities()){
|
for(TourActivity nextAct : currentRoute.getTourActivities().getActivities()){
|
||||||
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
|
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
|
||||||
|
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
|
||||||
|
if(status.equals(ConstraintsStatus.FULFILLED)){
|
||||||
ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
|
ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
|
||||||
if(mc != null){
|
|
||||||
if(mc.getAdditionalCosts() < bestCost){
|
if(mc.getAdditionalCosts() < bestCost){
|
||||||
bestCost = mc.getAdditionalCosts();
|
bestCost = mc.getAdditionalCosts();
|
||||||
bestMarginals = mc;
|
bestMarginals = mc;
|
||||||
insertionIndex = actIndex;
|
insertionIndex = actIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){
|
||||||
|
loopBroken = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActStartTime, newDriver, newVehicle);
|
double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActStartTime, newDriver, newVehicle);
|
||||||
double nextActEndTime = CalcUtils.getActivityEndTime(nextActArrTime, nextAct);
|
double nextActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct);
|
||||||
|
|
||||||
prevActStartTime = nextActEndTime;
|
prevActStartTime = nextActEndTime;
|
||||||
|
|
||||||
prevAct = nextAct;
|
prevAct = nextAct;
|
||||||
actIndex++;
|
actIndex++;
|
||||||
}
|
}
|
||||||
End nextAct = end;
|
End nextAct = end;
|
||||||
|
if(!loopBroken){
|
||||||
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
|
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
|
||||||
|
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
|
||||||
|
if(status.equals(ConstraintsStatus.FULFILLED)){
|
||||||
ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
|
ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
|
||||||
if(mc != null) {
|
|
||||||
if(mc.getAdditionalCosts() < bestCost){
|
if(mc.getAdditionalCosts() < bestCost){
|
||||||
bestCost = mc.getAdditionalCosts();
|
bestCost = mc.getAdditionalCosts();
|
||||||
bestMarginals = mc;
|
bestMarginals = mc;
|
||||||
|
|
@ -136,9 +145,10 @@ final class ServiceInsertionCalculator implements JobInsertionCalculator{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(insertionIndex == InsertionData.NO_INDEX) {
|
if(insertionIndex == InsertionData.NO_INDEX) {
|
||||||
return InsertionData.noInsertionFound();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
|
|
@ -147,7 +157,6 @@ final class ServiceInsertionCalculator implements JobInsertionCalculator{
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActivityInsertionCosts calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double departureTimeAtPrevAct) {
|
public ActivityInsertionCosts calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double departureTimeAtPrevAct) {
|
||||||
return activityInsertionCostsCalculator.calculate(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct);
|
return activityInsertionCostsCalculator.getCosts(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import util.Neighborhood;
|
import util.Neighborhood;
|
||||||
import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts;
|
import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts;
|
||||||
import algorithms.HardConstraints.HardRouteLevelConstraint;
|
import algorithms.HardActivityLevelConstraint.ConstraintsStatus;
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
import basics.Service;
|
import basics.Service;
|
||||||
import basics.costs.VehicleRoutingActivityCosts;
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
|
@ -45,9 +45,9 @@ import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalculator{
|
final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsCalculator{
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(CalculatesServiceInsertionOnRouteLevel.class);
|
private static final Logger logger = Logger.getLogger(ServiceInsertionOnRouteLevelCalculator.class);
|
||||||
|
|
||||||
private final VehicleRoutingTransportCosts transportCosts;
|
private final VehicleRoutingTransportCosts transportCosts;
|
||||||
|
|
||||||
|
|
@ -57,10 +57,12 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
|
|
||||||
private TourActivityFactory tourActivityFactory = new DefaultTourActivityFactory();
|
private TourActivityFactory tourActivityFactory = new DefaultTourActivityFactory();
|
||||||
|
|
||||||
private StateManager stateManager;
|
private StateGetter stateManager;
|
||||||
|
|
||||||
private HardRouteLevelConstraint hardRouteLevelConstraint;
|
private HardRouteLevelConstraint hardRouteLevelConstraint;
|
||||||
|
|
||||||
|
private HardActivityLevelConstraint hardActivityLevelConstraint;
|
||||||
|
|
||||||
private ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
|
private ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
|
||||||
|
|
||||||
private int nuOfActsForwardLooking = 0;
|
private int nuOfActsForwardLooking = 0;
|
||||||
|
|
@ -94,18 +96,19 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
logger.info("set [solutionMemory="+memorySize+"]");
|
logger.info("set [solutionMemory="+memorySize+"]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public CalculatesServiceInsertionOnRouteLevel(VehicleRoutingTransportCosts vehicleRoutingCosts, VehicleRoutingActivityCosts costFunc, HardRouteLevelConstraint hardRouteLevelConstraint, ActivityInsertionCostsCalculator activityInsertionCostsCalculator) {
|
public ServiceInsertionOnRouteLevelCalculator(VehicleRoutingTransportCosts vehicleRoutingCosts, VehicleRoutingActivityCosts costFunc, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, HardRouteLevelConstraint hardRouteLevelConstraint, HardActivityLevelConstraint hardActivityLevelConstraint) {
|
||||||
super();
|
super();
|
||||||
this.transportCosts = vehicleRoutingCosts;
|
this.transportCosts = vehicleRoutingCosts;
|
||||||
this.activityCosts = costFunc;
|
this.activityCosts = costFunc;
|
||||||
this.hardRouteLevelConstraint = hardRouteLevelConstraint;
|
|
||||||
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
||||||
|
this.hardRouteLevelConstraint = hardRouteLevelConstraint;
|
||||||
|
this.hardActivityLevelConstraint = hardActivityLevelConstraint;
|
||||||
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(transportCosts, activityCosts);
|
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(transportCosts, activityCosts);
|
||||||
logger.info("initialise " + this);
|
logger.info("initialise " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setStates(StateManager stateManager){
|
public void setStates(StateGetter stateManager){
|
||||||
this.stateManager = stateManager;
|
this.stateManager = stateManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,13 +131,13 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public InsertionData calculate(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double best_known_insertion_costs) {
|
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double best_known_insertion_costs) {
|
||||||
if(jobToInsert == null) throw new IllegalStateException("job is null. cannot calculate the insertion of a null-job.");
|
if(jobToInsert == null) throw new IllegalStateException("job is null. cannot calculate the insertion of a null-job.");
|
||||||
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("no vehicle given. set para vehicle!");
|
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("no vehicle given. set para vehicle!");
|
||||||
|
|
||||||
InsertionContext insertionContext = new InsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
InsertionContext insertionContext = new InsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
||||||
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
|
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
|
||||||
return InsertionData.noInsertionFound();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -151,6 +154,7 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
double best_insertion_costs = best_known_insertion_costs;
|
double best_insertion_costs = best_known_insertion_costs;
|
||||||
Service service = (Service)jobToInsert;
|
Service service = (Service)jobToInsert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* some inis
|
* some inis
|
||||||
*/
|
*/
|
||||||
|
|
@ -164,6 +168,7 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
double sumOf_prevCosts_newVehicle = 0.0;
|
double sumOf_prevCosts_newVehicle = 0.0;
|
||||||
double prevActDepTime_newVehicle = start.getEndTime();
|
double prevActDepTime_newVehicle = start.getEndTime();
|
||||||
|
|
||||||
|
boolean loopBroken = false;
|
||||||
/**
|
/**
|
||||||
* inserting serviceAct2Insert in route r={0,1,...,i-1,i,j,j+1,...,n(r),n(r)+1}
|
* inserting serviceAct2Insert in route r={0,1,...,i-1,i,j,j+1,...,n(r),n(r)+1}
|
||||||
* i=prevAct
|
* i=prevAct
|
||||||
|
|
@ -172,12 +177,13 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
*/
|
*/
|
||||||
for(TourActivity nextAct : tour.getActivities()){
|
for(TourActivity nextAct : tour.getActivities()){
|
||||||
if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){
|
if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){
|
||||||
|
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle);
|
||||||
|
if(status.equals(ConstraintsStatus.FULFILLED)){
|
||||||
/**
|
/**
|
||||||
* builds a path on this route forwardPath={i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking}
|
* builds a path on this route forwardPath={i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking}
|
||||||
*/
|
*/
|
||||||
InsertionContext iContext = new InsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, prevActDepTime_newVehicle);
|
ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.getCosts(insertionContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle);
|
||||||
ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.calculate(iContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle);
|
|
||||||
if(actInsertionCosts != null){
|
|
||||||
/**
|
/**
|
||||||
* insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle)
|
* insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle)
|
||||||
*/
|
*/
|
||||||
|
|
@ -190,6 +196,10 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation, InsertionData.NO_INDEX, actIndex, newVehicle, newDriver));
|
bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation, InsertionData.NO_INDEX, actIndex, newVehicle, newDriver));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){
|
||||||
|
loopBroken = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -219,11 +229,12 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
|
|
||||||
actIndex++;
|
actIndex++;
|
||||||
}
|
}
|
||||||
|
if(!loopBroken){
|
||||||
End nextAct = end;
|
End nextAct = end;
|
||||||
if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){
|
if(neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(serviceAct2Insert.getLocationId(), nextAct.getLocationId())){
|
||||||
|
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle);
|
||||||
InsertionContext iContext = new InsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, prevActDepTime_newVehicle);
|
if(status.equals(ConstraintsStatus.FULFILLED)){
|
||||||
ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.calculate(iContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle);
|
ActivityInsertionCosts actInsertionCosts = activityInsertionCostsCalculator.getCosts(insertionContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle);
|
||||||
if(actInsertionCosts != null){
|
if(actInsertionCosts != null){
|
||||||
/**
|
/**
|
||||||
* insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle)
|
* insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle)
|
||||||
|
|
@ -238,6 +249,8 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -254,6 +267,7 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|
||||||
for(int i=0;i<memorySize;i++){
|
for(int i=0;i<memorySize;i++){
|
||||||
InsertionData data = bestInsertionsQueue.poll();
|
InsertionData data = bestInsertionsQueue.poll();
|
||||||
if(data == null){
|
if(data == null){
|
||||||
|
|
@ -271,7 +285,7 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
/**
|
/**
|
||||||
* compute cost-diff of tour with and without new activity --> insertion_costs
|
* compute cost-diff of tour with and without new activity --> insertion_costs
|
||||||
*/
|
*/
|
||||||
double insertion_costs = auxilliaryPathCostCalculator.costOfPath(wholeTour, start.getEndTime(), newDriver, newVehicle) - stateManager.getRouteState(currentRoute,StateTypes.COSTS).toDouble();
|
double insertion_costs = auxilliaryPathCostCalculator.costOfPath(wholeTour, start.getEndTime(), newDriver, newVehicle) - stateManager.getRouteState(currentRoute,StateFactory.COSTS).toDouble();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if better than best known, make it the best known
|
* if better than best known, make it the best known
|
||||||
|
|
@ -282,7 +296,7 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(best_insertion_index == InsertionData.NO_INDEX) return InsertionData.noInsertionFound();
|
if(best_insertion_index == InsertionData.NO_INDEX) return InsertionData.createEmptyInsertionData();
|
||||||
return new InsertionData(best_insertion_costs, InsertionData.NO_INDEX, best_insertion_index, newVehicle, newDriver);
|
return new InsertionData(best_insertion_costs, InsertionData.NO_INDEX, best_insertion_index, newVehicle, newDriver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,9 +330,9 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
|
||||||
|
|
||||||
private double sumOf_prevCosts_oldVehicle(VehicleRoute vehicleRoute, TourActivity act) {
|
private double sumOf_prevCosts_oldVehicle(VehicleRoute vehicleRoute, TourActivity act) {
|
||||||
if(act instanceof End){
|
if(act instanceof End){
|
||||||
return stateManager.getRouteState(vehicleRoute,StateTypes.COSTS).toDouble();
|
return stateManager.getRouteState(vehicleRoute,StateFactory.COSTS).toDouble();
|
||||||
}
|
}
|
||||||
return stateManager.getActivityState(act,StateTypes.COSTS).toDouble();
|
return stateManager.getActivityState(act,StateFactory.COSTS).toDouble();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -22,7 +22,7 @@ import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import util.Neighborhood;
|
import util.Neighborhood;
|
||||||
import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts;
|
import algorithms.ActivityInsertionCostsCalculator.ActivityInsertionCosts;
|
||||||
import algorithms.HardConstraints.HardRouteLevelConstraint;
|
import algorithms.HardActivityLevelConstraint.ConstraintsStatus;
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
import basics.Shipment;
|
import basics.Shipment;
|
||||||
import basics.costs.VehicleRoutingTransportCosts;
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
|
@ -38,12 +38,14 @@ import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(ShipmentInsertionCalculator.class);
|
private static final Logger logger = Logger.getLogger(ShipmentInsertionCalculator.class);
|
||||||
|
|
||||||
private HardRouteLevelConstraint hardRouteLevelConstraint;
|
private HardRouteLevelConstraint hardRouteLevelConstraint;
|
||||||
|
|
||||||
|
private HardActivityLevelConstraint hardActivityLevelConstraint;
|
||||||
|
|
||||||
private Neighborhood neighborhood = new Neighborhood() {
|
private Neighborhood neighborhood = new Neighborhood() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -63,10 +65,11 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
||||||
logger.info("initialise neighborhood " + neighborhood);
|
logger.info("initialise neighborhood " + neighborhood);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, HardRouteLevelConstraint hardRouteLevelConstraint) {
|
public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, HardRouteLevelConstraint hardRouteLevelConstraint, HardActivityLevelConstraint hardActivityLevelConstraint) {
|
||||||
super();
|
super();
|
||||||
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
||||||
this.hardRouteLevelConstraint = hardRouteLevelConstraint;
|
this.hardRouteLevelConstraint = hardRouteLevelConstraint;
|
||||||
|
this.hardActivityLevelConstraint = hardActivityLevelConstraint;
|
||||||
this.transportCosts = routingCosts;
|
this.transportCosts = routingCosts;
|
||||||
activityFactory = new DefaultShipmentActivityFactory();
|
activityFactory = new DefaultShipmentActivityFactory();
|
||||||
logger.info("initialise " + this);
|
logger.info("initialise " + this);
|
||||||
|
|
@ -83,25 +86,24 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public InsertionData calculate(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
|
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
|
||||||
if(jobToInsert == null) throw new IllegalStateException("jobToInsert is missing.");
|
if(jobToInsert == null) throw new IllegalStateException("jobToInsert is missing.");
|
||||||
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("newVehicle is missing.");
|
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("newVehicle is missing.");
|
||||||
if(!(jobToInsert instanceof Shipment)) throw new IllegalStateException("jobToInsert should be of type Shipment!");
|
if(!(jobToInsert instanceof Shipment)) throw new IllegalStateException("jobToInsert should be of type Shipment!");
|
||||||
|
|
||||||
InsertionContext insertionContext = new InsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
InsertionContext insertionContext = new InsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
||||||
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
|
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
|
||||||
return InsertionData.noInsertionFound();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
|
|
||||||
double bestCost = bestKnownCosts;
|
double bestCost = bestKnownCosts;
|
||||||
Shipment shipment = (Shipment)jobToInsert;
|
Shipment shipment = (Shipment)jobToInsert;
|
||||||
TourActivity pickupShipment = activityFactory.createPickup(shipment);
|
TourActivity pickupShipment = activityFactory.createPickup(shipment);
|
||||||
TourActivity deliveryShipment = activityFactory.createDelivery(shipment);
|
TourActivity deliverShipment = activityFactory.createDelivery(shipment);
|
||||||
|
|
||||||
int pickupInsertionIndex = InsertionData.NO_INDEX;
|
int pickupInsertionIndex = InsertionData.NO_INDEX;
|
||||||
int deliveryInsertionIndex = InsertionData.NO_INDEX;
|
int deliveryInsertionIndex = InsertionData.NO_INDEX;
|
||||||
|
|
||||||
// int insertionIndex = 0;
|
|
||||||
Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
|
Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
|
||||||
start.setEndTime(newVehicleDepartureTime);
|
start.setEndTime(newVehicleDepartureTime);
|
||||||
|
|
||||||
|
|
@ -109,23 +111,32 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
||||||
|
|
||||||
TourActivity prevAct = start;
|
TourActivity prevAct = start;
|
||||||
double prevActEndTime = newVehicleDepartureTime;
|
double prevActEndTime = newVehicleDepartureTime;
|
||||||
|
boolean pickupShipmentLoopBroken = false;
|
||||||
//pickupShipmentLoop
|
//pickupShipmentLoop
|
||||||
List<TourActivity> activities = currentRoute.getTourActivities().getActivities();
|
List<TourActivity> activities = currentRoute.getTourActivities().getActivities();
|
||||||
for(int i=0;i<activities.size();i++){
|
for(int i=0;i<activities.size();i++){
|
||||||
ActivityInsertionCosts pickupAIC = calculate(insertionContext,prevAct,pickupShipment,activities.get(i),prevActEndTime);
|
ConstraintsStatus pickupShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, pickupShipment, activities.get(i), prevActEndTime);
|
||||||
if(pickupAIC == null){
|
if(pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED)){
|
||||||
double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), activities.get(i).getLocationId(), prevActEndTime, newDriver, newVehicle);
|
double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), activities.get(i).getLocationId(), prevActEndTime, newDriver, newVehicle);
|
||||||
prevActEndTime = CalcUtils.getActivityEndTime(nextActArrTime, activities.get(i));
|
prevActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, activities.get(i));
|
||||||
|
prevAct = activities.get(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if(pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){
|
||||||
|
pickupShipmentLoopBroken = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ActivityInsertionCosts pickupAIC = calculate(insertionContext,prevAct,pickupShipment,activities.get(i),prevActEndTime);
|
||||||
TourActivity prevAct_deliveryLoop = pickupShipment;
|
TourActivity prevAct_deliveryLoop = pickupShipment;
|
||||||
double shipmentPickupArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), pickupShipment.getLocationId(), prevActEndTime, newDriver, newVehicle);
|
double shipmentPickupArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), pickupShipment.getLocationId(), prevActEndTime, newDriver, newVehicle);
|
||||||
double shipmentPickupEndTime = CalcUtils.getActivityEndTime(shipmentPickupArrTime, pickupShipment);
|
double shipmentPickupEndTime = CalculationUtils.getActivityEndTime(shipmentPickupArrTime, pickupShipment);
|
||||||
double prevActEndTime_deliveryLoop = shipmentPickupEndTime;
|
double prevActEndTime_deliveryLoop = shipmentPickupEndTime;
|
||||||
|
boolean deliverShipmentLoopBroken = false;
|
||||||
//deliverShipmentLoop
|
//deliverShipmentLoop
|
||||||
for(int j=i;j<activities.size();j++){
|
for(int j=i;j<activities.size();j++){
|
||||||
ActivityInsertionCosts deliveryAIC = calculate(insertionContext,prevAct_deliveryLoop,deliveryShipment,activities.get(j),prevActEndTime_deliveryLoop);
|
ConstraintsStatus deliverShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, activities.get(j), prevActEndTime_deliveryLoop);
|
||||||
if(deliveryAIC != null){
|
if(deliverShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)){
|
||||||
|
ActivityInsertionCosts deliveryAIC = calculate(insertionContext,prevAct_deliveryLoop,deliverShipment,activities.get(j),prevActEndTime_deliveryLoop);
|
||||||
double totalActivityInsertionCosts = pickupAIC.getAdditionalCosts() + deliveryAIC.getAdditionalCosts();
|
double totalActivityInsertionCosts = pickupAIC.getAdditionalCosts() + deliveryAIC.getAdditionalCosts();
|
||||||
if(totalActivityInsertionCosts < bestCost){
|
if(totalActivityInsertionCosts < bestCost){
|
||||||
bestCost = totalActivityInsertionCosts;
|
bestCost = totalActivityInsertionCosts;
|
||||||
|
|
@ -133,13 +144,17 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
||||||
deliveryInsertionIndex = j;
|
deliveryInsertionIndex = j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(deliverShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){
|
||||||
|
deliverShipmentLoopBroken = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
//update prevAct and endTime
|
//update prevAct and endTime
|
||||||
double nextActArrTime = prevActEndTime_deliveryLoop + transportCosts.getTransportTime(prevAct_deliveryLoop.getLocationId(), activities.get(j).getLocationId(), prevActEndTime_deliveryLoop, newDriver, newVehicle);
|
double nextActArrTime = prevActEndTime_deliveryLoop + transportCosts.getTransportTime(prevAct_deliveryLoop.getLocationId(), activities.get(j).getLocationId(), prevActEndTime_deliveryLoop, newDriver, newVehicle);
|
||||||
prevActEndTime_deliveryLoop = CalcUtils.getActivityEndTime(nextActArrTime, activities.get(j));
|
prevActEndTime_deliveryLoop = CalculationUtils.getActivityEndTime(nextActArrTime, activities.get(j));
|
||||||
prevAct_deliveryLoop = activities.get(j);
|
prevAct_deliveryLoop = activities.get(j);
|
||||||
}
|
}
|
||||||
//endInsertion
|
if(!deliverShipmentLoopBroken){ //check insertion between lastAct and endOfTour
|
||||||
ActivityInsertionCosts deliveryAIC = calculate(insertionContext,prevAct_deliveryLoop,deliveryShipment,end,prevActEndTime_deliveryLoop);
|
ActivityInsertionCosts deliveryAIC = calculate(insertionContext,prevAct_deliveryLoop,deliverShipment,end,prevActEndTime_deliveryLoop);
|
||||||
if(deliveryAIC != null){
|
if(deliveryAIC != null){
|
||||||
double totalActivityInsertionCosts = pickupAIC.getAdditionalCosts() + deliveryAIC.getAdditionalCosts();
|
double totalActivityInsertionCosts = pickupAIC.getAdditionalCosts() + deliveryAIC.getAdditionalCosts();
|
||||||
if(totalActivityInsertionCosts < bestCost){
|
if(totalActivityInsertionCosts < bestCost){
|
||||||
|
|
@ -148,21 +163,21 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
||||||
deliveryInsertionIndex = activities.size();
|
deliveryInsertionIndex = activities.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//update prevAct and endTime
|
//update prevAct and endTime
|
||||||
double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), activities.get(i).getLocationId(), prevActEndTime, newDriver, newVehicle);
|
double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), activities.get(i).getLocationId(), prevActEndTime, newDriver, newVehicle);
|
||||||
prevActEndTime = CalcUtils.getActivityEndTime(nextActArrTime, activities.get(i));
|
prevActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, activities.get(i));
|
||||||
prevAct = activities.get(i);
|
prevAct = activities.get(i);
|
||||||
}
|
}
|
||||||
//endInsertion
|
if(!pickupShipmentLoopBroken){ //check insertion of pickupShipment and deliverShipment at just before tour ended
|
||||||
ActivityInsertionCosts pickupAIC = calculate(insertionContext,prevAct,pickupShipment,end,prevActEndTime);
|
ActivityInsertionCosts pickupAIC = calculate(insertionContext,prevAct,pickupShipment,end,prevActEndTime);
|
||||||
if(pickupAIC != null){ //evaluate delivery
|
if(pickupAIC != null){ //evaluate delivery
|
||||||
TourActivity prevAct_deliveryLoop = pickupShipment;
|
TourActivity prevAct_deliveryLoop = pickupShipment;
|
||||||
double shipmentPickupArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), pickupShipment.getLocationId(), prevActEndTime, newDriver, newVehicle);
|
double shipmentPickupArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), pickupShipment.getLocationId(), prevActEndTime, newDriver, newVehicle);
|
||||||
double shipmentPickupEndTime = CalcUtils.getActivityEndTime(shipmentPickupArrTime, pickupShipment);
|
double shipmentPickupEndTime = CalculationUtils.getActivityEndTime(shipmentPickupArrTime, pickupShipment);
|
||||||
double prevActEndTime_deliveryLoop = shipmentPickupEndTime;
|
double prevActEndTime_deliveryLoop = shipmentPickupEndTime;
|
||||||
|
|
||||||
ActivityInsertionCosts deliveryAIC = calculate(insertionContext,prevAct_deliveryLoop,deliveryShipment,end,prevActEndTime_deliveryLoop);
|
ActivityInsertionCosts deliveryAIC = calculate(insertionContext,prevAct_deliveryLoop,deliverShipment,end,prevActEndTime_deliveryLoop);
|
||||||
if(deliveryAIC != null){
|
|
||||||
double totalActivityInsertionCosts = pickupAIC.getAdditionalCosts() + deliveryAIC.getAdditionalCosts();
|
double totalActivityInsertionCosts = pickupAIC.getAdditionalCosts() + deliveryAIC.getAdditionalCosts();
|
||||||
if(totalActivityInsertionCosts < bestCost){
|
if(totalActivityInsertionCosts < bestCost){
|
||||||
bestCost = totalActivityInsertionCosts;
|
bestCost = totalActivityInsertionCosts;
|
||||||
|
|
@ -172,7 +187,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pickupInsertionIndex == InsertionData.NO_INDEX) {
|
if(pickupInsertionIndex == InsertionData.NO_INDEX) {
|
||||||
return InsertionData.noInsertionFound();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
|
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
|
|
@ -180,7 +195,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
|
||||||
}
|
}
|
||||||
|
|
||||||
private ActivityInsertionCosts calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double departureTimeAtPrevAct) {
|
private ActivityInsertionCosts calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double departureTimeAtPrevAct) {
|
||||||
return activityInsertionCostsCalculator.calculate(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct);
|
return activityInsertionCostsCalculator.getCosts(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
114
jsprit-core/src/main/java/algorithms/StateFactory.java
Normal file
114
jsprit-core/src/main/java/algorithms/StateFactory.java
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import algorithms.StateGetter.State;
|
||||||
|
import algorithms.StateGetter.StateId;
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
|
||||||
|
public class StateFactory {
|
||||||
|
|
||||||
|
final static StateId MAXLOAD = new StateIdImpl("maxload");
|
||||||
|
|
||||||
|
final static StateId LOAD = new StateIdImpl("load");
|
||||||
|
|
||||||
|
final static StateId COSTS = new StateIdImpl("costs");
|
||||||
|
|
||||||
|
final static StateId LOAD_AT_BEGINNING = new StateIdImpl("loadAtBeginning");
|
||||||
|
|
||||||
|
final static StateId LOAD_AT_END = new StateIdImpl("loadAtEnd");
|
||||||
|
|
||||||
|
final static StateId DURATION = new StateIdImpl("duration");
|
||||||
|
|
||||||
|
final static StateId LATEST_OPERATION_START_TIME = new StateIdImpl("latestOST");
|
||||||
|
|
||||||
|
final static StateId EARLIEST_OPERATION_START_TIME = new StateIdImpl("earliestOST");
|
||||||
|
|
||||||
|
final static StateId FUTURE_PICKS = new StateIdImpl("futurePicks");
|
||||||
|
|
||||||
|
final static StateId PAST_DELIVERIES = new StateIdImpl("pastDeliveries");
|
||||||
|
|
||||||
|
final static List<String> reservedIds = Arrays.asList("maxload","load","costs","loadAtBeginning","loadAtEnd","duration","latestOST","earliestOST"
|
||||||
|
,"futurePicks","pastDeliveries");
|
||||||
|
|
||||||
|
|
||||||
|
public static StateId createId(String name){
|
||||||
|
if(reservedIds.contains(name)){ throwException(name); }
|
||||||
|
return new StateIdImpl(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static State createState(double value){
|
||||||
|
return new StateImpl(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void throwException(String name) {
|
||||||
|
throw new IllegalStateException("state-id with name '" + name + "' cannot be created. it is already reserved internally.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class StateIdImpl implements StateId {
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
StateIdImpl other = (StateIdImpl) obj;
|
||||||
|
if (name == null) {
|
||||||
|
if (other.name != null)
|
||||||
|
return false;
|
||||||
|
} else if (!name.equals(other.name))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public StateIdImpl(String name) {
|
||||||
|
super();
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString(){
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,18 +17,22 @@
|
||||||
package algorithms;
|
package algorithms;
|
||||||
|
|
||||||
import basics.route.TourActivity;
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
class CalcUtils {
|
public interface StateGetter {
|
||||||
|
|
||||||
|
public interface StateId {
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates actEndTime assuming that activity can at earliest start at act.getTheoreticalEarliestOperationStartTime().
|
|
||||||
*
|
|
||||||
* @param actArrTime
|
|
||||||
* @param act
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static double getActivityEndTime(double actArrTime, TourActivity act){
|
|
||||||
return Math.max(actArrTime, act.getTheoreticalEarliestOperationStartTime()) + act.getOperationTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface State {
|
||||||
|
double toDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
State getActivityState(TourActivity act, StateId stateId);
|
||||||
|
|
||||||
|
State getRouteState(VehicleRoute route, StateId stateId);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -16,16 +16,42 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package algorithms;
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.InsertionEndsListener;
|
||||||
|
import basics.algo.InsertionListener;
|
||||||
|
import basics.algo.InsertionListeners;
|
||||||
|
import basics.algo.InsertionStartsListener;
|
||||||
|
import basics.algo.IterationStartsListener;
|
||||||
|
import basics.algo.JobInsertedListener;
|
||||||
|
import basics.algo.RuinListener;
|
||||||
|
import basics.algo.RuinListeners;
|
||||||
|
import basics.route.ActivityVisitor;
|
||||||
|
import basics.route.ReverseActivityVisitor;
|
||||||
|
import basics.route.ReverseRouteActivityVisitor;
|
||||||
|
import basics.route.RouteActivityVisitor;
|
||||||
|
import basics.route.RouteVisitor;
|
||||||
import basics.route.TourActivity;
|
import basics.route.TourActivity;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
interface StateManager {
|
public class StateManager implements StateGetter, IterationStartsListener, RuinListener, InsertionStartsListener, JobInsertedListener, InsertionEndsListener {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private interface States {
|
||||||
|
|
||||||
|
State getState(StateId key);
|
||||||
|
|
||||||
interface State {
|
|
||||||
double toDouble();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StateImpl implements State{
|
static class StateImpl implements State{
|
||||||
double state;
|
double state;
|
||||||
|
|
||||||
public StateImpl(double state) {
|
public StateImpl(double state) {
|
||||||
|
|
@ -40,14 +66,225 @@ interface StateManager {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface States {
|
private static class StatesImpl implements States{
|
||||||
|
|
||||||
State getState(String key);
|
private Map<StateId,State> states = new HashMap<StateId, State>();
|
||||||
|
|
||||||
|
public void putState(StateId key, State state) {
|
||||||
|
states.put(key, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public State getState(StateId key) {
|
||||||
|
return states.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
State getActivityState(TourActivity act, String stateType);
|
private Map<VehicleRoute,States> vehicleRouteStates = new HashMap<VehicleRoute, States>();
|
||||||
|
|
||||||
State getRouteState(VehicleRoute route, String stateType);
|
private Map<TourActivity,States> activityStates = new HashMap<TourActivity, States>();
|
||||||
|
|
||||||
|
private RouteActivityVisitor routeActivityVisitor = new RouteActivityVisitor();
|
||||||
|
|
||||||
|
private ReverseRouteActivityVisitor revRouteActivityVisitor = new ReverseRouteActivityVisitor();
|
||||||
|
|
||||||
|
private Collection<RouteVisitor> routeVisitors = new ArrayList<RouteVisitor>();
|
||||||
|
|
||||||
|
private RuinListeners ruinListeners = new RuinListeners();
|
||||||
|
|
||||||
|
private InsertionListeners insertionListeners = new InsertionListeners();
|
||||||
|
|
||||||
|
private Collection<StateUpdater> updaters = new ArrayList<StateUpdater>();
|
||||||
|
|
||||||
|
private Map<StateId,State> defaultRouteStates = new HashMap<StateGetter.StateId, StateGetter.State>();
|
||||||
|
|
||||||
|
private Map<StateId,State> defaultActivityStates = new HashMap<StateId, State>();
|
||||||
|
|
||||||
|
public void addDefaultRouteState(StateId stateId, State defaultState){
|
||||||
|
defaultRouteStates.put(stateId, defaultState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDefaultActivityState(StateId stateId, State defaultState){
|
||||||
|
defaultActivityStates.put(stateId, defaultState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear(){
|
||||||
|
vehicleRouteStates.clear();
|
||||||
|
activityStates.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public State getActivityState(TourActivity act, StateId stateId) {
|
||||||
|
if(!activityStates.containsKey(act)){
|
||||||
|
return getDefaultActState(stateId,act);
|
||||||
|
}
|
||||||
|
StatesImpl actStates = (StatesImpl) activityStates.get(act);
|
||||||
|
State state = actStates.getState(stateId);
|
||||||
|
if(state == null){
|
||||||
|
return getDefaultActState(stateId,act);
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putActivityState(TourActivity act, StateId stateId, State state){
|
||||||
|
if(!activityStates.containsKey(act)){
|
||||||
|
activityStates.put(act, new StatesImpl());
|
||||||
|
}
|
||||||
|
StatesImpl actStates = (StatesImpl) activityStates.get(act);
|
||||||
|
actStates.putState(stateId, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void putRouteState(VehicleRoute route, StateId stateId, State state){
|
||||||
|
if(!vehicleRouteStates.containsKey(route)){
|
||||||
|
vehicleRouteStates.put(route, new StatesImpl());
|
||||||
|
}
|
||||||
|
StatesImpl routeStates = (StatesImpl) vehicleRouteStates.get(route);
|
||||||
|
routeStates.putState(stateId, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public State getRouteState(VehicleRoute route, StateId stateId) {
|
||||||
|
if(!vehicleRouteStates.containsKey(route)){
|
||||||
|
return getDefaultRouteState(stateId,route);
|
||||||
|
}
|
||||||
|
StatesImpl routeStates = (StatesImpl) vehicleRouteStates.get(route);
|
||||||
|
State state = routeStates.getState(stateId);
|
||||||
|
if(state == null){
|
||||||
|
return getDefaultRouteState(stateId, route);
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds state updater.
|
||||||
|
*
|
||||||
|
* <p>Note that a state update occurs if route and/or activity states change, i.e. if jobs are removed
|
||||||
|
* or inserted into a route. Thus here, it is assumed that a state updater is either of type InsertionListener,
|
||||||
|
* RuinListener, ActivityVisitor, ReverseActivityVisitor, RouteVisitor, ReverseRouteVisitor.
|
||||||
|
*
|
||||||
|
* <p>The following rule pertain for activity/route visitors:These visitors visits all activities/route in a route subsequently in two cases. First, if insertionStart (after ruinStrategies have removed activities from routes)
|
||||||
|
* and, second, if a job has been inserted and thus if a route has changed.
|
||||||
|
*
|
||||||
|
* @param updater
|
||||||
|
*/
|
||||||
|
public void addStateUpdater(StateUpdater updater){
|
||||||
|
if(updater instanceof ActivityVisitor) addActivityVisitor((ActivityVisitor) updater);
|
||||||
|
if(updater instanceof ReverseActivityVisitor) addActivityVisitor((ReverseActivityVisitor)updater);
|
||||||
|
if(updater instanceof RouteVisitor) addRouteVisitor((RouteVisitor) updater);
|
||||||
|
if(updater instanceof InsertionListener) addListener((InsertionListener) updater);
|
||||||
|
if(updater instanceof RuinListener) addListener((RuinListener) updater);
|
||||||
|
updaters.add(updater);
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<StateUpdater> getStateUpdaters(){
|
||||||
|
return Collections.unmodifiableCollection(updaters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an activityVisitor.
|
||||||
|
* <p>This visitor visits all activities in a route subsequently in two cases. First, if insertionStart (after ruinStrategies have removed activities from routes)
|
||||||
|
* and, second, if a job has been inserted and thus if a route has changed.
|
||||||
|
*
|
||||||
|
* @param activityVistor
|
||||||
|
*/
|
||||||
|
void addActivityVisitor(ActivityVisitor activityVistor){
|
||||||
|
routeActivityVisitor.addActivityVisitor(activityVistor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an reverseActivityVisitor.
|
||||||
|
* <p>This reverseVisitor visits all activities in a route subsequently (starting from the end of the route) in two cases. First, if insertionStart (after ruinStrategies have removed activities from routes)
|
||||||
|
* and, second, if a job has been inserted and thus if a route has changed.
|
||||||
|
*
|
||||||
|
* @param reverseActivityVistor
|
||||||
|
*/
|
||||||
|
void addActivityVisitor(ReverseActivityVisitor activityVistor){
|
||||||
|
revRouteActivityVisitor.addActivityVisitor(activityVistor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addRouteVisitor(RouteVisitor routeVisitor){
|
||||||
|
routeVisitors.add(routeVisitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addListener(RuinListener ruinListener){
|
||||||
|
ruinListeners.addListener(ruinListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeListener(RuinListener ruinListener){
|
||||||
|
ruinListeners.removeListener(ruinListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addListener(InsertionListener insertionListener){
|
||||||
|
insertionListeners.addListener(insertionListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeListener(InsertionListener insertionListener){
|
||||||
|
insertionListeners.removeListener(insertionListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private State getDefaultActState(StateId stateId, TourActivity act){
|
||||||
|
if(stateId.equals(StateFactory.LOAD)) return new StateImpl(0);
|
||||||
|
if(stateId.equals(StateFactory.COSTS)) return new StateImpl(0);
|
||||||
|
if(stateId.equals(StateFactory.DURATION)) return new StateImpl(0);
|
||||||
|
if(stateId.equals(StateFactory.EARLIEST_OPERATION_START_TIME)) return new StateImpl(act.getTheoreticalEarliestOperationStartTime());
|
||||||
|
if(stateId.equals(StateFactory.LATEST_OPERATION_START_TIME)) return new StateImpl(act.getTheoreticalLatestOperationStartTime());
|
||||||
|
if(stateId.equals(StateFactory.FUTURE_PICKS)) return new StateImpl(0);
|
||||||
|
if(stateId.equals(StateFactory.PAST_DELIVERIES)) return new StateImpl(0);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private State getDefaultRouteState(StateId stateId, VehicleRoute route){
|
||||||
|
if(stateId.equals(StateFactory.MAXLOAD)) return new StateImpl(0);
|
||||||
|
if(stateId.equals(StateFactory.LOAD)) return new StateImpl(0);
|
||||||
|
if(stateId.equals(StateFactory.LOAD_AT_END)) return new StateImpl(0);
|
||||||
|
if(stateId.equals(StateFactory.LOAD_AT_BEGINNING)) return new StateImpl(0);
|
||||||
|
if(stateId.equals(StateFactory.COSTS)) return new StateImpl(0);
|
||||||
|
if(stateId.equals(StateFactory.DURATION)) return new StateImpl(0);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
||||||
|
insertionListeners.jobInserted(job2insert, inRoute, additionalCosts, additionalTime);
|
||||||
|
for(RouteVisitor v : routeVisitors){ v.visit(inRoute); }
|
||||||
|
routeActivityVisitor.visit(inRoute);
|
||||||
|
revRouteActivityVisitor.visit(inRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes,Collection<Job> unassignedJobs) {
|
||||||
|
insertionListeners.insertionStarts(vehicleRoutes, unassignedJobs);
|
||||||
|
for(VehicleRoute route : vehicleRoutes){
|
||||||
|
for(RouteVisitor v : routeVisitors){ v.visit(route); }
|
||||||
|
routeActivityVisitor.visit(route);
|
||||||
|
revRouteActivityVisitor.visit(route);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ruinStarts(Collection<VehicleRoute> routes) {
|
||||||
|
ruinListeners.ruinStarts(routes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
||||||
|
ruinListeners.ruinEnds(routes, unassignedJobs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removed(Job job, VehicleRoute fromRoute) {
|
||||||
|
ruinListeners.removed(job, fromRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
|
insertionListeners.insertionEnds(vehicleRoutes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,151 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (C) 2013 Stefan Schroeder
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 3.0 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
******************************************************************************/
|
|
||||||
package algorithms;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import basics.Job;
|
|
||||||
import basics.algo.InsertionStartsListener;
|
|
||||||
import basics.algo.JobInsertedListener;
|
|
||||||
import basics.route.TourActivity;
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
|
|
||||||
class StateManagerImpl implements StateManager, InsertionStartsListener, JobInsertedListener {
|
|
||||||
|
|
||||||
static class StatesImpl implements States{
|
|
||||||
|
|
||||||
private Map<String,State> states = new HashMap<String, State>();
|
|
||||||
|
|
||||||
public void putState(String key, State state) {
|
|
||||||
states.put(key, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public State getState(String key) {
|
|
||||||
return states.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<VehicleRoute,States> vehicleRouteStates = new HashMap<VehicleRoute, StateManager.States>();
|
|
||||||
|
|
||||||
private Map<TourActivity,States> activityStates = new HashMap<TourActivity, StateManager.States>();
|
|
||||||
|
|
||||||
private RouteActivityVisitor routeActivityVisitor = new RouteActivityVisitor();
|
|
||||||
|
|
||||||
private ReverseRouteActivityVisitor revRouteActivityVisitor = new ReverseRouteActivityVisitor();
|
|
||||||
|
|
||||||
private Collection<RouteVisitor> routeVisitors = new ArrayList<RouteVisitor>();
|
|
||||||
|
|
||||||
public void clear(){
|
|
||||||
vehicleRouteStates.clear();
|
|
||||||
activityStates.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public State getActivityState(TourActivity act, String stateType) {
|
|
||||||
if(!activityStates.containsKey(act)){
|
|
||||||
return getDefaultActState(stateType,act);
|
|
||||||
}
|
|
||||||
StatesImpl actStates = (StatesImpl) activityStates.get(act);
|
|
||||||
State state = actStates.getState(stateType);
|
|
||||||
if(state == null){
|
|
||||||
return getDefaultActState(stateType,act);
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putActivityState(TourActivity act, String stateType, State state){
|
|
||||||
if(!activityStates.containsKey(act)){
|
|
||||||
activityStates.put(act, new StatesImpl());
|
|
||||||
}
|
|
||||||
StatesImpl actStates = (StatesImpl) activityStates.get(act);
|
|
||||||
actStates.putState(stateType, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private State getDefaultActState(String stateType, TourActivity act){
|
|
||||||
if(stateType.equals(StateTypes.LOAD)) return new StateImpl(0);
|
|
||||||
if(stateType.equals(StateTypes.COSTS)) return new StateImpl(0);
|
|
||||||
if(stateType.equals(StateTypes.DURATION)) return new StateImpl(0);
|
|
||||||
if(stateType.equals(StateTypes.EARLIEST_OPERATION_START_TIME)) return new StateImpl(act.getTheoreticalEarliestOperationStartTime());
|
|
||||||
if(stateType.equals(StateTypes.LATEST_OPERATION_START_TIME)) return new StateImpl(act.getTheoreticalLatestOperationStartTime());
|
|
||||||
if(stateType.equals(StateTypes.FUTURE_PICKS)) return new StateImpl(0);
|
|
||||||
if(stateType.equals(StateTypes.PAST_DELIVERIES)) return new StateImpl(0);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private State getDefaultRouteState(String stateType, VehicleRoute route){
|
|
||||||
if(stateType.equals(StateTypes.LOAD)) return new StateImpl(0);
|
|
||||||
if(stateType.equals(StateTypes.LOAD_AT_DEPOT)) return new StateImpl(0);
|
|
||||||
if(stateType.equals(StateTypes.COSTS)) return new StateImpl(0);
|
|
||||||
if(stateType.equals(StateTypes.DURATION)) return new StateImpl(0);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public State getRouteState(VehicleRoute route, String stateType) {
|
|
||||||
if(!vehicleRouteStates.containsKey(route)){
|
|
||||||
return getDefaultRouteState(stateType,route);
|
|
||||||
}
|
|
||||||
StatesImpl routeStates = (StatesImpl) vehicleRouteStates.get(route);
|
|
||||||
State state = routeStates.getState(stateType);
|
|
||||||
if(state == null){
|
|
||||||
return getDefaultRouteState(stateType, route);
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putRouteState(VehicleRoute route, String stateType, State state){
|
|
||||||
if(!vehicleRouteStates.containsKey(route)){
|
|
||||||
vehicleRouteStates.put(route, new StatesImpl());
|
|
||||||
}
|
|
||||||
StatesImpl routeStates = (StatesImpl) vehicleRouteStates.get(route);
|
|
||||||
routeStates.putState(stateType, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
|
||||||
for(RouteVisitor v : routeVisitors){ v.visit(inRoute); }
|
|
||||||
routeActivityVisitor.visit(inRoute);
|
|
||||||
revRouteActivityVisitor.visit(inRoute);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes,Collection<Job> unassignedJobs) {
|
|
||||||
for(VehicleRoute route : vehicleRoutes){
|
|
||||||
for(RouteVisitor v : routeVisitors){ v.visit(route); }
|
|
||||||
routeActivityVisitor.visit(route);
|
|
||||||
revRouteActivityVisitor.visit(route);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addActivityVisitor(ActivityVisitor activityVistor){
|
|
||||||
routeActivityVisitor.addActivityVisitor(activityVistor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addActivityVisitor(ReverseActivityVisitor activityVistor){
|
|
||||||
revRouteActivityVisitor.addActivityVisitor(activityVistor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addRouteVisitor(RouteVisitor routeVisitor){
|
|
||||||
routeVisitors.add(routeVisitor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
5
jsprit-core/src/main/java/algorithms/StateUpdater.java
Normal file
5
jsprit-core/src/main/java/algorithms/StateUpdater.java
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
public interface StateUpdater {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,633 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (C) 2013 Stefan Schroeder
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 3.0 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
******************************************************************************/
|
|
||||||
package algorithms;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import algorithms.RuinStrategy.RuinListener;
|
|
||||||
import algorithms.StateManager.StateImpl;
|
|
||||||
import basics.Delivery;
|
|
||||||
import basics.Job;
|
|
||||||
import basics.Pickup;
|
|
||||||
import basics.Service;
|
|
||||||
import basics.VehicleRoutingProblem;
|
|
||||||
import basics.VehicleRoutingProblemSolution;
|
|
||||||
import basics.algo.InsertionEndsListener;
|
|
||||||
import basics.algo.InsertionStartsListener;
|
|
||||||
import basics.algo.IterationStartsListener;
|
|
||||||
import basics.algo.JobInsertedListener;
|
|
||||||
import basics.costs.ForwardTransportCost;
|
|
||||||
import basics.costs.ForwardTransportTime;
|
|
||||||
import basics.costs.VehicleRoutingActivityCosts;
|
|
||||||
import basics.costs.VehicleRoutingTransportCosts;
|
|
||||||
import basics.route.DeliveryActivity;
|
|
||||||
import basics.route.PickupActivity;
|
|
||||||
import basics.route.ServiceActivity;
|
|
||||||
import basics.route.TourActivity;
|
|
||||||
import basics.route.Vehicle;
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
import basics.route.VehicleType;
|
|
||||||
|
|
||||||
class StateUpdates {
|
|
||||||
|
|
||||||
static class UpdateCostsAtRouteLevel implements JobInsertedListener, InsertionStartsListener, InsertionEndsListener{
|
|
||||||
|
|
||||||
private StateManagerImpl states;
|
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts tpCosts;
|
|
||||||
|
|
||||||
private VehicleRoutingActivityCosts actCosts;
|
|
||||||
|
|
||||||
public UpdateCostsAtRouteLevel(StateManagerImpl states, VehicleRoutingTransportCosts tpCosts, VehicleRoutingActivityCosts actCosts) {
|
|
||||||
super();
|
|
||||||
this.states = states;
|
|
||||||
this.tpCosts = tpCosts;
|
|
||||||
this.actCosts = actCosts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
|
||||||
// inRoute.getVehicleRouteCostCalculator().addTransportCost(additionalCosts);
|
|
||||||
double oldCosts = states.getRouteState(inRoute, StateTypes.COSTS).toDouble();
|
|
||||||
oldCosts += additionalCosts;
|
|
||||||
states.putRouteState(inRoute, StateTypes.COSTS, new StateImpl(oldCosts));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
|
||||||
RouteActivityVisitor forwardInTime = new RouteActivityVisitor();
|
|
||||||
forwardInTime.addActivityVisitor(new UpdateCostsAtAllLevels(actCosts, tpCosts, states));
|
|
||||||
for(VehicleRoute route : vehicleRoutes){
|
|
||||||
forwardInTime.visit(route);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
|
||||||
|
|
||||||
// IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(tpCosts);
|
|
||||||
// forwardInTime.addListener(new UpdateCostsAtAllLevels(actCosts, tpCosts, states));
|
|
||||||
// for(VehicleRoute route : vehicleRoutes){
|
|
||||||
// if(route.isEmpty()) continue;
|
|
||||||
// route.getVehicleRouteCostCalculator().reset();
|
|
||||||
// route.getVehicleRouteCostCalculator().addOtherCost(states.getRouteState(route, StateTypes.COSTS).toDouble());
|
|
||||||
// route.getVehicleRouteCostCalculator().price(route.getVehicle());
|
|
||||||
// forwardInTime.iterate(route);
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateActivityTimes implements ActivityVisitor{
|
|
||||||
|
|
||||||
private Logger log = Logger.getLogger(UpdateActivityTimes.class);
|
|
||||||
|
|
||||||
private ActivityTimeTracker timeTracker;
|
|
||||||
|
|
||||||
private VehicleRoute route;
|
|
||||||
|
|
||||||
public UpdateActivityTimes(ForwardTransportTime transportTime) {
|
|
||||||
super();
|
|
||||||
timeTracker = new ActivityTimeTracker(transportTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin(VehicleRoute route) {
|
|
||||||
timeTracker.begin(route);
|
|
||||||
this.route = route;
|
|
||||||
route.getStart().setEndTime(timeTracker.getActEndTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(TourActivity activity) {
|
|
||||||
timeTracker.visit(activity);
|
|
||||||
activity.setArrTime(timeTracker.getActArrTime());
|
|
||||||
activity.setEndTime(timeTracker.getActEndTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {
|
|
||||||
timeTracker.finish();
|
|
||||||
route.getEnd().setArrTime(timeTracker.getActArrTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateCostsAtAllLevels implements ActivityVisitor{
|
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(UpdateCostsAtAllLevels.class);
|
|
||||||
|
|
||||||
private VehicleRoutingActivityCosts activityCost;
|
|
||||||
|
|
||||||
private ForwardTransportCost transportCost;
|
|
||||||
|
|
||||||
private StateManagerImpl states;
|
|
||||||
|
|
||||||
private double totalOperationCost = 0.0;
|
|
||||||
|
|
||||||
private VehicleRoute vehicleRoute = null;
|
|
||||||
|
|
||||||
private TourActivity prevAct = null;
|
|
||||||
|
|
||||||
private double startTimeAtPrevAct = 0.0;
|
|
||||||
|
|
||||||
private ActivityTimeTracker timeTracker;
|
|
||||||
|
|
||||||
public UpdateCostsAtAllLevels(VehicleRoutingActivityCosts activityCost, VehicleRoutingTransportCosts transportCost, StateManagerImpl states) {
|
|
||||||
super();
|
|
||||||
this.activityCost = activityCost;
|
|
||||||
this.transportCost = transportCost;
|
|
||||||
this.states = states;
|
|
||||||
timeTracker = new ActivityTimeTracker(transportCost);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin(VehicleRoute route) {
|
|
||||||
vehicleRoute = route;
|
|
||||||
vehicleRoute.getVehicleRouteCostCalculator().reset();
|
|
||||||
timeTracker.begin(route);
|
|
||||||
prevAct = route.getStart();
|
|
||||||
startTimeAtPrevAct = timeTracker.getActEndTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(TourActivity act) {
|
|
||||||
timeTracker.visit(act);
|
|
||||||
|
|
||||||
double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), act.getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle());
|
|
||||||
double actCost = activityCost.getActivityCost(act, timeTracker.getActArrTime(), vehicleRoute.getDriver(), vehicleRoute.getVehicle());
|
|
||||||
|
|
||||||
vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost);
|
|
||||||
vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost);
|
|
||||||
|
|
||||||
totalOperationCost += transportCost;
|
|
||||||
totalOperationCost += actCost;
|
|
||||||
|
|
||||||
states.putActivityState(act, StateTypes.COSTS, new StateImpl(totalOperationCost));
|
|
||||||
|
|
||||||
prevAct = act;
|
|
||||||
startTimeAtPrevAct = timeTracker.getActEndTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {
|
|
||||||
timeTracker.finish();
|
|
||||||
double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), vehicleRoute.getEnd().getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle());
|
|
||||||
double actCost = activityCost.getActivityCost(vehicleRoute.getEnd(), timeTracker.getActEndTime(), vehicleRoute.getDriver(), vehicleRoute.getVehicle());
|
|
||||||
|
|
||||||
vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost);
|
|
||||||
vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost);
|
|
||||||
|
|
||||||
totalOperationCost += transportCost;
|
|
||||||
totalOperationCost += actCost;
|
|
||||||
// totalOperationCost += getFixCosts();
|
|
||||||
|
|
||||||
states.putRouteState(vehicleRoute, StateTypes.COSTS, new StateImpl(totalOperationCost));
|
|
||||||
|
|
||||||
// this is rather strange and likely to change
|
|
||||||
vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getDriver());
|
|
||||||
vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getVehicle());
|
|
||||||
vehicleRoute.getVehicleRouteCostCalculator().finish();
|
|
||||||
|
|
||||||
startTimeAtPrevAct = 0.0;
|
|
||||||
prevAct = null;
|
|
||||||
vehicleRoute = null;
|
|
||||||
totalOperationCost = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private double getFixCosts() {
|
|
||||||
Vehicle vehicle = vehicleRoute.getVehicle();
|
|
||||||
if(vehicle == null) return 0.0;
|
|
||||||
VehicleType type = vehicle.getType();
|
|
||||||
if(type == null) return 0.0;
|
|
||||||
return type.getVehicleCostParams().fix;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateEarliestStartTimeWindowAtActLocations implements ActivityVisitor{
|
|
||||||
|
|
||||||
private StateManagerImpl states;
|
|
||||||
|
|
||||||
private ActivityTimeTracker timeTracker;
|
|
||||||
|
|
||||||
public UpdateEarliestStartTimeWindowAtActLocations(StateManagerImpl states, VehicleRoutingTransportCosts transportCosts) {
|
|
||||||
super();
|
|
||||||
this.states = states;
|
|
||||||
timeTracker = new ActivityTimeTracker(transportCosts);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin(VehicleRoute route) {
|
|
||||||
timeTracker.begin(route);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(TourActivity activity) {
|
|
||||||
timeTracker.visit(activity);
|
|
||||||
states.putActivityState(activity, StateTypes.EARLIEST_OPERATION_START_TIME, new StateImpl(Math.max(timeTracker.getActArrTime(), activity.getTheoreticalEarliestOperationStartTime())));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateLatestOperationStartTimeAtActLocations implements ReverseActivityVisitor{
|
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(UpdateLatestOperationStartTimeAtActLocations.class);
|
|
||||||
|
|
||||||
private StateManagerImpl states;
|
|
||||||
|
|
||||||
private VehicleRoute route;
|
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts transportCosts;
|
|
||||||
|
|
||||||
private double latestArrTimeAtPrevAct;
|
|
||||||
|
|
||||||
private TourActivity prevAct;
|
|
||||||
|
|
||||||
public UpdateLatestOperationStartTimeAtActLocations(StateManagerImpl states, VehicleRoutingTransportCosts tpCosts) {
|
|
||||||
super();
|
|
||||||
this.states = states;
|
|
||||||
this.transportCosts = tpCosts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin(VehicleRoute route) {
|
|
||||||
this.route = route;
|
|
||||||
latestArrTimeAtPrevAct = route.getEnd().getTheoreticalLatestOperationStartTime();
|
|
||||||
prevAct = route.getEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(TourActivity activity) {
|
|
||||||
double potentialLatestArrivalTimeAtCurrAct = latestArrTimeAtPrevAct - transportCosts.getBackwardTransportTime(activity.getLocationId(), prevAct.getLocationId(), latestArrTimeAtPrevAct, route.getDriver(),route.getVehicle()) - activity.getOperationTime();
|
|
||||||
double latestArrivalTime = Math.min(activity.getTheoreticalLatestOperationStartTime(), potentialLatestArrivalTimeAtCurrAct);
|
|
||||||
|
|
||||||
states.putActivityState(activity, StateTypes.LATEST_OPERATION_START_TIME, new StateImpl(latestArrivalTime));
|
|
||||||
|
|
||||||
latestArrTimeAtPrevAct = latestArrivalTime;
|
|
||||||
prevAct = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateLoadAtAllLevels implements ActivityVisitor{
|
|
||||||
|
|
||||||
private double load = 0.0;
|
|
||||||
|
|
||||||
private StateManagerImpl states;
|
|
||||||
|
|
||||||
private VehicleRoute vehicleRoute;
|
|
||||||
|
|
||||||
public UpdateLoadAtAllLevels(StateManagerImpl states) {
|
|
||||||
super();
|
|
||||||
this.states = states;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin(VehicleRoute route) {
|
|
||||||
vehicleRoute = route;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(TourActivity activity) {
|
|
||||||
load += (double)activity.getCapacityDemand();
|
|
||||||
states.putActivityState(activity, StateTypes.LOAD, new StateImpl(load));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {
|
|
||||||
states.putRouteState(vehicleRoute, StateTypes.LOAD, new StateImpl(load));
|
|
||||||
load=0;
|
|
||||||
vehicleRoute = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateLoadAtRouteLevel implements JobInsertedListener, InsertionStartsListener{
|
|
||||||
|
|
||||||
private StateManagerImpl states;
|
|
||||||
|
|
||||||
public UpdateLoadAtRouteLevel(StateManagerImpl states) {
|
|
||||||
super();
|
|
||||||
this.states = states;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
|
||||||
if(!(job2insert instanceof Service)){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
double oldLoad = states.getRouteState(inRoute, StateTypes.LOAD).toDouble();
|
|
||||||
states.putRouteState(inRoute, StateTypes.LOAD, new StateImpl(oldLoad + job2insert.getCapacityDemand()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
|
||||||
for(VehicleRoute route : vehicleRoutes){
|
|
||||||
int load = 0;
|
|
||||||
for(Job j : route.getTourActivities().getJobs()){
|
|
||||||
load += j.getCapacityDemand();
|
|
||||||
}
|
|
||||||
states.putRouteState(route, StateTypes.LOAD, new StateImpl(load));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateStates implements JobInsertedListener, RuinListener{
|
|
||||||
|
|
||||||
private RouteActivityVisitor routeActivityVisitor;
|
|
||||||
|
|
||||||
private ReverseRouteActivityVisitor revRouteActivityVisitor;
|
|
||||||
|
|
||||||
public UpdateStates(StateManagerImpl states, VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts) {
|
|
||||||
routeActivityVisitor = new RouteActivityVisitor();
|
|
||||||
routeActivityVisitor.addActivityVisitor(new UpdateActivityTimes(routingCosts));
|
|
||||||
routeActivityVisitor.addActivityVisitor(new UpdateCostsAtAllLevels(activityCosts, routingCosts, states));
|
|
||||||
routeActivityVisitor.addActivityVisitor(new UpdateLoadAtAllLevels(states));
|
|
||||||
|
|
||||||
revRouteActivityVisitor = new ReverseRouteActivityVisitor();
|
|
||||||
revRouteActivityVisitor.addActivityVisitor(new UpdateLatestOperationStartTimeAtActLocations(states, routingCosts));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update(VehicleRoute route){
|
|
||||||
routeActivityVisitor.visit(route);
|
|
||||||
revRouteActivityVisitor.visit(route);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
|
||||||
routeActivityVisitor.visit(inRoute);
|
|
||||||
revRouteActivityVisitor.visit(inRoute);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void ruinStarts(Collection<VehicleRoute> routes) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void ruinEnds(Collection<VehicleRoute> routes,Collection<Job> unassignedJobs) {
|
|
||||||
for(VehicleRoute route : routes) {
|
|
||||||
routeActivityVisitor.visit(route);
|
|
||||||
revRouteActivityVisitor.visit(route);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removed(Job job, VehicleRoute fromRoute) {}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateFuturePickupsAtActivityLevel implements ReverseActivityVisitor {
|
|
||||||
private StateManagerImpl stateManager;
|
|
||||||
private int futurePicks = 0;
|
|
||||||
private VehicleRoute route;
|
|
||||||
|
|
||||||
public UpdateFuturePickupsAtActivityLevel(StateManagerImpl stateManager) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin(VehicleRoute route) {
|
|
||||||
this.route = route;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(TourActivity act) {
|
|
||||||
stateManager.putActivityState(act, StateTypes.FUTURE_PICKS, new StateImpl(futurePicks));
|
|
||||||
if(act instanceof PickupActivity || act instanceof ServiceActivity){
|
|
||||||
futurePicks += act.getCapacityDemand();
|
|
||||||
}
|
|
||||||
assert futurePicks <= route.getVehicle().getCapacity() : "sum of pickups must not be > vehicleCap";
|
|
||||||
assert futurePicks >= 0 : "sum of pickups must not < 0";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {
|
|
||||||
futurePicks = 0;
|
|
||||||
route = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateOccuredDeliveriesAtActivityLevel implements ActivityVisitor {
|
|
||||||
private StateManagerImpl stateManager;
|
|
||||||
private int deliveries = 0;
|
|
||||||
private VehicleRoute route;
|
|
||||||
|
|
||||||
public UpdateOccuredDeliveriesAtActivityLevel(StateManagerImpl stateManager) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin(VehicleRoute route) {
|
|
||||||
this.route = route;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(TourActivity act) {
|
|
||||||
if(act instanceof DeliveryActivity){
|
|
||||||
deliveries += Math.abs(act.getCapacityDemand());
|
|
||||||
}
|
|
||||||
stateManager.putActivityState(act, StateTypes.PAST_DELIVERIES, new StateImpl(deliveries));
|
|
||||||
assert deliveries >= 0 : "deliveries < 0";
|
|
||||||
assert deliveries <= route.getVehicle().getCapacity() : "deliveries > vehicleCap";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {
|
|
||||||
deliveries = 0;
|
|
||||||
route = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates load at activity level. Note that this assumed that StateTypes.LOAD_AT_DEPOT is already updated, i.e. it starts by setting loadAtDepot to StateTypes.LOAD_AT_DEPOT.
|
|
||||||
* If StateTypes.LOAD_AT_DEPOT is not set, it starts with 0 load at depot.
|
|
||||||
*
|
|
||||||
* @author stefan
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static class UpdateLoadAtActivityLevel implements ActivityVisitor {
|
|
||||||
private StateManagerImpl stateManager;
|
|
||||||
private int currentLoad = 0;
|
|
||||||
private VehicleRoute route;
|
|
||||||
|
|
||||||
public UpdateLoadAtActivityLevel(StateManagerImpl stateManager) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void begin(VehicleRoute route) {
|
|
||||||
currentLoad = (int) stateManager.getRouteState(route, StateTypes.LOAD_AT_DEPOT).toDouble();
|
|
||||||
this.route = route;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visit(TourActivity act) {
|
|
||||||
currentLoad += act.getCapacityDemand();
|
|
||||||
stateManager.putActivityState(act, StateTypes.LOAD, new StateImpl(currentLoad));
|
|
||||||
assert currentLoad <= route.getVehicle().getCapacity() : "currentLoad at activity must not be > vehicleCapacity";
|
|
||||||
assert currentLoad >= 0 : "currentLoad at act must not be < 0";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void finish() {
|
|
||||||
currentLoad = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ResetStateManager implements IterationStartsListener {
|
|
||||||
|
|
||||||
private StateManagerImpl stateManager;
|
|
||||||
|
|
||||||
public ResetStateManager(StateManagerImpl stateManager) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
|
||||||
stateManager.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static interface InsertionStarts {
|
|
||||||
|
|
||||||
void insertionStarts(VehicleRoute route);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts implements InsertionStarts {
|
|
||||||
|
|
||||||
private StateManagerImpl stateManager;
|
|
||||||
|
|
||||||
public UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts(StateManagerImpl stateManager) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insertionStarts(VehicleRoute route) {
|
|
||||||
int loadAtDepot = 0;
|
|
||||||
int loadAtEnd = 0;
|
|
||||||
for(Job j : route.getTourActivities().getJobs()){
|
|
||||||
if(j instanceof Delivery){
|
|
||||||
loadAtDepot += j.getCapacityDemand();
|
|
||||||
}
|
|
||||||
else if(j instanceof Pickup || j instanceof Service){
|
|
||||||
loadAtEnd += j.getCapacityDemand();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stateManager.putRouteState(route, StateTypes.LOAD_AT_DEPOT, new StateImpl(loadAtDepot));
|
|
||||||
stateManager.putRouteState(route, StateTypes.LOAD, new StateImpl(loadAtEnd));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted implements JobInsertedListener {
|
|
||||||
|
|
||||||
private StateManagerImpl stateManager;
|
|
||||||
|
|
||||||
public UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted(StateManagerImpl stateManager) {
|
|
||||||
super();
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
|
||||||
if(job2insert instanceof Delivery){
|
|
||||||
int loadAtDepot = (int) stateManager.getRouteState(inRoute, StateTypes.LOAD_AT_DEPOT).toDouble();
|
|
||||||
// log.info("loadAtDepot="+loadAtDepot);
|
|
||||||
stateManager.putRouteState(inRoute, StateTypes.LOAD_AT_DEPOT, new StateImpl(loadAtDepot + job2insert.getCapacityDemand()));
|
|
||||||
}
|
|
||||||
else if(job2insert instanceof Pickup || job2insert instanceof Service){
|
|
||||||
int loadAtEnd = (int) stateManager.getRouteState(inRoute, StateTypes.LOAD).toDouble();
|
|
||||||
// log.info("loadAtEnd="+loadAtEnd);
|
|
||||||
stateManager.putRouteState(inRoute, StateTypes.LOAD, new StateImpl(loadAtEnd + job2insert.getCapacityDemand()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class UpdateRouteStatesOnceTheRouteHasBeenChanged implements InsertionStartsListener, JobInsertedListener {
|
|
||||||
|
|
||||||
private RouteActivityVisitor forwardInTimeIterator;
|
|
||||||
|
|
||||||
private ReverseRouteActivityVisitor backwardInTimeIterator;
|
|
||||||
|
|
||||||
private Collection<InsertionStarts> insertionStartsListeners;
|
|
||||||
|
|
||||||
private Collection<JobInsertedListener> jobInsertionListeners;
|
|
||||||
|
|
||||||
public UpdateRouteStatesOnceTheRouteHasBeenChanged(VehicleRoutingTransportCosts routingCosts) {
|
|
||||||
forwardInTimeIterator = new RouteActivityVisitor();
|
|
||||||
backwardInTimeIterator = new ReverseRouteActivityVisitor();
|
|
||||||
insertionStartsListeners = new ArrayList<InsertionStarts>();
|
|
||||||
jobInsertionListeners = new ArrayList<JobInsertedListener>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void addVisitor(ActivityVisitor vis){
|
|
||||||
forwardInTimeIterator.addActivityVisitor(vis);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addVisitor(ReverseActivityVisitor revVis){
|
|
||||||
backwardInTimeIterator.addActivityVisitor(revVis);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addInsertionStartsListener(InsertionStarts insertionStartListener){
|
|
||||||
insertionStartsListeners.add(insertionStartListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addJobInsertedListener(JobInsertedListener jobInsertedListener){
|
|
||||||
jobInsertionListeners.add(jobInsertedListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
|
||||||
for(JobInsertedListener l : jobInsertionListeners){ l.informJobInserted(job2insert, inRoute, additionalCosts, additionalTime); }
|
|
||||||
forwardInTimeIterator.visit(inRoute);
|
|
||||||
backwardInTimeIterator.visit(inRoute);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
|
||||||
for(VehicleRoute route : vehicleRoutes){
|
|
||||||
for(InsertionStarts insertionsStartsHandler : insertionStartsListeners){
|
|
||||||
insertionsStartsHandler.insertionStarts(route);
|
|
||||||
}
|
|
||||||
forwardInTimeIterator.visit(route);
|
|
||||||
backwardInTimeIterator.visit(route);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
24
jsprit-core/src/main/java/algorithms/StateUtils.java
Normal file
24
jsprit-core/src/main/java/algorithms/StateUtils.java
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
|
||||||
|
class StateUtils {
|
||||||
|
|
||||||
|
public static void addCoreStateUpdaters(VehicleRoutingProblem vrp, StateManager stateManager){
|
||||||
|
stateManager.addListener(new UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts(stateManager));
|
||||||
|
stateManager.addListener(new UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted(stateManager));
|
||||||
|
|
||||||
|
stateManager.addActivityVisitor(new UpdateActivityTimes(vrp.getTransportCosts()));
|
||||||
|
stateManager.addActivityVisitor(new UpdateLoadAtActivityLevel(stateManager));
|
||||||
|
|
||||||
|
stateManager.addActivityVisitor(new UpdateCostsAtAllLevels(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager));
|
||||||
|
|
||||||
|
stateManager.addActivityVisitor(new UpdateOccuredDeliveriesAtActivityLevel(stateManager));
|
||||||
|
|
||||||
|
stateManager.addActivityVisitor(new UpdateLatestOperationStartTimeAtActLocations(stateManager, vrp.getTransportCosts()));
|
||||||
|
|
||||||
|
stateManager.addActivityVisitor(new UpdateFuturePickupsAtActivityLevel(stateManager));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.ActivityTimeTracker;
|
||||||
|
|
||||||
|
import basics.costs.ForwardTransportTime;
|
||||||
|
import basics.route.ActivityVisitor;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates arrival and end times of activities.
|
||||||
|
*
|
||||||
|
* <p>Note that this modifies arrTime and endTime of each activity in a route.
|
||||||
|
*
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class UpdateActivityTimes implements ActivityVisitor, StateUpdater{
|
||||||
|
|
||||||
|
private Logger log = Logger.getLogger(UpdateActivityTimes.class);
|
||||||
|
|
||||||
|
private ActivityTimeTracker timeTracker;
|
||||||
|
|
||||||
|
private VehicleRoute route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates arrival and end times of activities.
|
||||||
|
*
|
||||||
|
* <p>Note that this modifies arrTime and endTime of each activity in a route.
|
||||||
|
*
|
||||||
|
* <p>ArrTimes and EndTimes can be retrieved by <br>
|
||||||
|
* <code>activity.getArrTime()</code> and
|
||||||
|
* <code>activity.getEndTime()</code>
|
||||||
|
*
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public UpdateActivityTimes(ForwardTransportTime transportTime) {
|
||||||
|
super();
|
||||||
|
timeTracker = new ActivityTimeTracker(transportTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
timeTracker.begin(route);
|
||||||
|
this.route = route;
|
||||||
|
route.getStart().setEndTime(timeTracker.getActEndTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity activity) {
|
||||||
|
timeTracker.visit(activity);
|
||||||
|
activity.setArrTime(timeTracker.getActArrTime());
|
||||||
|
activity.setEndTime(timeTracker.getActEndTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
timeTracker.finish();
|
||||||
|
route.getEnd().setArrTime(timeTracker.getActArrTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
126
jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java
Normal file
126
jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import util.ActivityTimeTracker;
|
||||||
|
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
import basics.costs.ForwardTransportCost;
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.ActivityVisitor;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates total costs (i.e. transport and activity costs) at route and activity level.
|
||||||
|
*
|
||||||
|
* <p>Thus it modifies <code>stateManager.getRouteState(route, StateTypes.COSTS)</code> and <br>
|
||||||
|
* <code>stateManager.getActivityState(activity, StateTypes.COSTS)</code>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param activityCost
|
||||||
|
* @param transportCost
|
||||||
|
* @param states
|
||||||
|
*/
|
||||||
|
class UpdateCostsAtAllLevels implements ActivityVisitor,StateUpdater{
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(UpdateCostsAtAllLevels.class);
|
||||||
|
|
||||||
|
private VehicleRoutingActivityCosts activityCost;
|
||||||
|
|
||||||
|
private ForwardTransportCost transportCost;
|
||||||
|
|
||||||
|
private StateManager states;
|
||||||
|
|
||||||
|
private double totalOperationCost = 0.0;
|
||||||
|
|
||||||
|
private VehicleRoute vehicleRoute = null;
|
||||||
|
|
||||||
|
private TourActivity prevAct = null;
|
||||||
|
|
||||||
|
private double startTimeAtPrevAct = 0.0;
|
||||||
|
|
||||||
|
private ActivityTimeTracker timeTracker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates total costs (i.e. transport and activity costs) at route and activity level.
|
||||||
|
*
|
||||||
|
* <p>Thus it modifies <code>stateManager.getRouteState(route, StateTypes.COSTS)</code> and <br>
|
||||||
|
* <code>stateManager.getActivityState(activity, StateTypes.COSTS)</code>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param activityCost
|
||||||
|
* @param transportCost
|
||||||
|
* @param states
|
||||||
|
*/
|
||||||
|
public UpdateCostsAtAllLevels(VehicleRoutingActivityCosts activityCost, VehicleRoutingTransportCosts transportCost, StateManager states) {
|
||||||
|
super();
|
||||||
|
this.activityCost = activityCost;
|
||||||
|
this.transportCost = transportCost;
|
||||||
|
this.states = states;
|
||||||
|
timeTracker = new ActivityTimeTracker(transportCost);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
vehicleRoute = route;
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().reset();
|
||||||
|
timeTracker.begin(route);
|
||||||
|
prevAct = route.getStart();
|
||||||
|
startTimeAtPrevAct = timeTracker.getActEndTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity act) {
|
||||||
|
timeTracker.visit(act);
|
||||||
|
|
||||||
|
double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), act.getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle());
|
||||||
|
double actCost = activityCost.getActivityCost(act, timeTracker.getActArrTime(), vehicleRoute.getDriver(), vehicleRoute.getVehicle());
|
||||||
|
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost);
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost);
|
||||||
|
|
||||||
|
totalOperationCost += transportCost;
|
||||||
|
totalOperationCost += actCost;
|
||||||
|
|
||||||
|
states.putActivityState(act, StateFactory.COSTS, new StateImpl(totalOperationCost));
|
||||||
|
|
||||||
|
prevAct = act;
|
||||||
|
startTimeAtPrevAct = timeTracker.getActEndTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
timeTracker.finish();
|
||||||
|
double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), vehicleRoute.getEnd().getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle());
|
||||||
|
double actCost = activityCost.getActivityCost(vehicleRoute.getEnd(), timeTracker.getActEndTime(), vehicleRoute.getDriver(), vehicleRoute.getVehicle());
|
||||||
|
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost);
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost);
|
||||||
|
|
||||||
|
totalOperationCost += transportCost;
|
||||||
|
totalOperationCost += actCost;
|
||||||
|
// totalOperationCost += getFixCosts(vehicleRoute.getVehicle());
|
||||||
|
|
||||||
|
states.putRouteState(vehicleRoute, StateFactory.COSTS, new StateImpl(totalOperationCost));
|
||||||
|
|
||||||
|
//this is rather strange and likely to change
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getDriver());
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getVehicle());
|
||||||
|
vehicleRoute.getVehicleRouteCostCalculator().finish();
|
||||||
|
|
||||||
|
startTimeAtPrevAct = 0.0;
|
||||||
|
prevAct = null;
|
||||||
|
vehicleRoute = null;
|
||||||
|
totalOperationCost = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getFixCosts(Vehicle vehicle) {
|
||||||
|
if(vehicle == null) return 0.0;
|
||||||
|
if(vehicle.getType() == null) return 0.0;
|
||||||
|
return vehicle.getType().getVehicleCostParams().fix;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.algo.InsertionEndsListener;
|
||||||
|
import basics.algo.InsertionStartsListener;
|
||||||
|
import basics.algo.JobInsertedListener;
|
||||||
|
import basics.costs.VehicleRoutingActivityCosts;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.RouteActivityVisitor;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class UpdateCostsAtRouteLevel implements StateUpdater,JobInsertedListener, InsertionStartsListener, InsertionEndsListener{
|
||||||
|
|
||||||
|
private StateManager states;
|
||||||
|
|
||||||
|
private VehicleRoutingTransportCosts tpCosts;
|
||||||
|
|
||||||
|
private VehicleRoutingActivityCosts actCosts;
|
||||||
|
|
||||||
|
public UpdateCostsAtRouteLevel(StateManager states, VehicleRoutingTransportCosts tpCosts, VehicleRoutingActivityCosts actCosts) {
|
||||||
|
super();
|
||||||
|
this.states = states;
|
||||||
|
this.tpCosts = tpCosts;
|
||||||
|
this.actCosts = actCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
||||||
|
// inRoute.getVehicleRouteCostCalculator().addTransportCost(additionalCosts);
|
||||||
|
double oldCosts = states.getRouteState(inRoute, StateFactory.COSTS).toDouble();
|
||||||
|
oldCosts += additionalCosts;
|
||||||
|
states.putRouteState(inRoute, StateFactory.COSTS, new StateImpl(oldCosts));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||||
|
RouteActivityVisitor forwardInTime = new RouteActivityVisitor();
|
||||||
|
forwardInTime.addActivityVisitor(new UpdateCostsAtAllLevels(actCosts, tpCosts, states));
|
||||||
|
for(VehicleRoute route : vehicleRoutes){
|
||||||
|
forwardInTime.visit(route);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
|
|
||||||
|
// IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(tpCosts);
|
||||||
|
// forwardInTime.addListener(new UpdateCostsAtAllLevels(actCosts, tpCosts, states));
|
||||||
|
for(VehicleRoute route : vehicleRoutes){
|
||||||
|
if(route.isEmpty()) continue;
|
||||||
|
route.getVehicleRouteCostCalculator().reset();
|
||||||
|
route.getVehicleRouteCostCalculator().addOtherCost(states.getRouteState(route, StateFactory.COSTS).toDouble());
|
||||||
|
route.getVehicleRouteCostCalculator().price(route.getVehicle());
|
||||||
|
// forwardInTime.iterate(route);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import util.ActivityTimeTracker;
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.ActivityVisitor;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class UpdateEarliestStartTimeWindowAtActLocations implements ActivityVisitor,StateUpdater{
|
||||||
|
|
||||||
|
private StateManager states;
|
||||||
|
|
||||||
|
private ActivityTimeTracker timeTracker;
|
||||||
|
|
||||||
|
public UpdateEarliestStartTimeWindowAtActLocations(StateManager states, VehicleRoutingTransportCosts transportCosts) {
|
||||||
|
super();
|
||||||
|
this.states = states;
|
||||||
|
timeTracker = new ActivityTimeTracker(transportCosts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
timeTracker.begin(route);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity activity) {
|
||||||
|
timeTracker.visit(activity);
|
||||||
|
states.putActivityState(activity, StateFactory.EARLIEST_OPERATION_START_TIME, new StateImpl(Math.max(timeTracker.getActArrTime(), activity.getTheoreticalEarliestOperationStartTime())));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.PickupActivity;
|
||||||
|
import basics.route.ReverseActivityVisitor;
|
||||||
|
import basics.route.ServiceActivity;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class UpdateFuturePickupsAtActivityLevel implements ReverseActivityVisitor, StateUpdater {
|
||||||
|
private StateManager stateManager;
|
||||||
|
private int futurePicks = 0;
|
||||||
|
private VehicleRoute route;
|
||||||
|
|
||||||
|
public UpdateFuturePickupsAtActivityLevel(StateManager stateManager) {
|
||||||
|
super();
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
this.route = route;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity act) {
|
||||||
|
stateManager.putActivityState(act, StateFactory.FUTURE_PICKS, StateFactory.createState(futurePicks));
|
||||||
|
if(act instanceof PickupActivity || act instanceof ServiceActivity){
|
||||||
|
futurePicks += act.getCapacityDemand();
|
||||||
|
}
|
||||||
|
assert futurePicks <= route.getVehicle().getCapacity() : "sum of pickups must not be > vehicleCap";
|
||||||
|
assert futurePicks >= 0 : "sum of pickups must not < 0";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
futurePicks = 0;
|
||||||
|
route = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
import basics.costs.VehicleRoutingTransportCosts;
|
||||||
|
import basics.route.ReverseActivityVisitor;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class UpdateLatestOperationStartTimeAtActLocations implements ReverseActivityVisitor, StateUpdater{
|
||||||
|
|
||||||
|
private static Logger log = Logger.getLogger(UpdateLatestOperationStartTimeAtActLocations.class);
|
||||||
|
|
||||||
|
private StateManager states;
|
||||||
|
|
||||||
|
private VehicleRoute route;
|
||||||
|
|
||||||
|
private VehicleRoutingTransportCosts transportCosts;
|
||||||
|
|
||||||
|
private double latestArrTimeAtPrevAct;
|
||||||
|
|
||||||
|
private TourActivity prevAct;
|
||||||
|
|
||||||
|
public UpdateLatestOperationStartTimeAtActLocations(StateManager states, VehicleRoutingTransportCosts tpCosts) {
|
||||||
|
super();
|
||||||
|
this.states = states;
|
||||||
|
this.transportCosts = tpCosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
this.route = route;
|
||||||
|
latestArrTimeAtPrevAct = route.getEnd().getTheoreticalLatestOperationStartTime();
|
||||||
|
prevAct = route.getEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity activity) {
|
||||||
|
double potentialLatestArrivalTimeAtCurrAct = latestArrTimeAtPrevAct - transportCosts.getBackwardTransportTime(activity.getLocationId(), prevAct.getLocationId(), latestArrTimeAtPrevAct, route.getDriver(),route.getVehicle()) - activity.getOperationTime();
|
||||||
|
double latestArrivalTime = Math.min(activity.getTheoreticalLatestOperationStartTime(), potentialLatestArrivalTimeAtCurrAct);
|
||||||
|
|
||||||
|
states.putActivityState(activity, StateFactory.LATEST_OPERATION_START_TIME, new StateImpl(latestArrivalTime));
|
||||||
|
|
||||||
|
latestArrTimeAtPrevAct = latestArrivalTime;
|
||||||
|
prevAct = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
import basics.route.ActivityVisitor;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates load at activity level.
|
||||||
|
*
|
||||||
|
* <p>Note that this assumes that StateTypes.LOAD_AT_DEPOT is already updated, i.e. it starts by setting loadAtDepot to StateTypes.LOAD_AT_DEPOT.
|
||||||
|
* If StateTypes.LOAD_AT_DEPOT is not set, it starts with 0 load at depot.
|
||||||
|
*
|
||||||
|
* <p>Thus it DEPENDS on StateTypes.LOAD_AT_DEPOT
|
||||||
|
*
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class UpdateLoadAtActivityLevel implements ActivityVisitor, StateUpdater {
|
||||||
|
private StateManager stateManager;
|
||||||
|
private int currentLoad = 0;
|
||||||
|
private VehicleRoute route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates load at activity level.
|
||||||
|
*
|
||||||
|
* <p>Note that this assumes that StateTypes.LOAD_AT_DEPOT is already updated, i.e. it starts by setting loadAtDepot to StateTypes.LOAD_AT_DEPOT.
|
||||||
|
* If StateTypes.LOAD_AT_DEPOT is not set, it starts with 0 load at depot.
|
||||||
|
*
|
||||||
|
* <p>Thus it DEPENDS on StateTypes.LOAD_AT_DEPOT
|
||||||
|
*
|
||||||
|
* <p>If you want to update StateTypes.LOAD_AT_DEPOT see {@link UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts}, {@link UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted}
|
||||||
|
*
|
||||||
|
* <p>The loads can be retrieved by <br>
|
||||||
|
* <code>stateManager.getActivityState(activity,StateTypes.LOAD);</code>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @see {@link UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts}, {@link UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted}
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public UpdateLoadAtActivityLevel(StateManager stateManager) {
|
||||||
|
super();
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
currentLoad = (int) stateManager.getRouteState(route, StateFactory.LOAD_AT_BEGINNING).toDouble();
|
||||||
|
this.route = route;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity act) {
|
||||||
|
currentLoad += act.getCapacityDemand();
|
||||||
|
stateManager.putActivityState(act, StateFactory.LOAD, StateFactory.createState(currentLoad));
|
||||||
|
assert currentLoad <= route.getVehicle().getCapacity() : "currentLoad at activity must not be > vehicleCapacity";
|
||||||
|
assert currentLoad >= 0 : "currentLoad at act must not be < 0";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
// stateManager.putRouteState(route, StateFactory., state)
|
||||||
|
currentLoad = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
import basics.route.ActivityVisitor;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class UpdateLoadAtAllLevels implements ActivityVisitor,StateUpdater{
|
||||||
|
|
||||||
|
private double load = 0.0;
|
||||||
|
|
||||||
|
private StateManager states;
|
||||||
|
|
||||||
|
private VehicleRoute vehicleRoute;
|
||||||
|
|
||||||
|
public UpdateLoadAtAllLevels(StateManager states) {
|
||||||
|
super();
|
||||||
|
this.states = states;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
vehicleRoute = route;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity activity) {
|
||||||
|
load += (double)activity.getCapacityDemand();
|
||||||
|
states.putActivityState(activity, StateFactory.LOAD, new StateImpl(load));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
states.putRouteState(vehicleRoute, StateFactory.LOAD, new StateImpl(load));
|
||||||
|
load=0;
|
||||||
|
vehicleRoute = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.algo.InsertionStartsListener;
|
||||||
|
import basics.algo.JobInsertedListener;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates load at route level, i.e. modifies StateTypes.LOAD for each route.
|
||||||
|
*
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class UpdateLoadAtRouteLevel implements JobInsertedListener, InsertionStartsListener, StateUpdater{
|
||||||
|
|
||||||
|
private StateManager states;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates load at route level, i.e. modifies StateTypes.LOAD for each route.
|
||||||
|
*
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public UpdateLoadAtRouteLevel(StateManager states) {
|
||||||
|
super();
|
||||||
|
this.states = states;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
||||||
|
if(!(job2insert instanceof Service)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double oldLoad = states.getRouteState(inRoute, StateFactory.LOAD).toDouble();
|
||||||
|
states.putRouteState(inRoute, StateFactory.LOAD, StateFactory.createState(oldLoad + job2insert.getCapacityDemand()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||||
|
for(VehicleRoute route : vehicleRoutes){
|
||||||
|
int load = 0;
|
||||||
|
for(Job j : route.getTourActivities().getJobs()){
|
||||||
|
load += j.getCapacityDemand();
|
||||||
|
}
|
||||||
|
states.putRouteState(route, StateFactory.LOAD, new StateImpl(load));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
import basics.Delivery;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Pickup;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.algo.InsertionStartsListener;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the load of each route/vehicle at start- and end-location before insertion starts.
|
||||||
|
*
|
||||||
|
* <p>StateTypes.LOAD_AT_DEPOT and StateTypes.LOAD are modified for each route
|
||||||
|
* <p>These states can be retrieved by <br>
|
||||||
|
* stateManager.getRouteState(route, StateTypes.LOAD_AT_DEPOT) for LOAD_AT_DEPOT and <br>
|
||||||
|
* stateManager.getRouteState(route, StateTypes.LOAD) for LOAD (i.e. load at end)
|
||||||
|
*
|
||||||
|
* @param stateManager
|
||||||
|
*/
|
||||||
|
class UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts implements InsertionStartsListener {
|
||||||
|
|
||||||
|
private StateManager stateManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the load of each route/vehicle at start- and end-location before insertion starts.
|
||||||
|
*
|
||||||
|
* <p>StateTypes.LOAD_AT_DEPOT and StateTypes.LOAD are modified for each route
|
||||||
|
* <p>These states can be retrieved by <br>
|
||||||
|
* stateManager.getRouteState(route, StateTypes.LOAD_AT_DEPOT) for LOAD_AT_DEPOT and <br>
|
||||||
|
* stateManager.getRouteState(route, StateTypes.LOAD) for LOAD (i.e. load at end)
|
||||||
|
*
|
||||||
|
* @param stateManager
|
||||||
|
*/
|
||||||
|
public UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts(StateManager stateManager) {
|
||||||
|
super();
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insertionStarts(VehicleRoute route) {
|
||||||
|
int loadAtDepot = 0;
|
||||||
|
int loadAtEnd = 0;
|
||||||
|
for(Job j : route.getTourActivities().getJobs()){
|
||||||
|
if(j instanceof Delivery){
|
||||||
|
loadAtDepot += j.getCapacityDemand();
|
||||||
|
}
|
||||||
|
else if(j instanceof Pickup || j instanceof Service){
|
||||||
|
loadAtEnd += j.getCapacityDemand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stateManager.putRouteState(route, StateFactory.LOAD_AT_BEGINNING, StateFactory.createState(loadAtDepot));
|
||||||
|
stateManager.putRouteState(route, StateFactory.LOAD_AT_END, StateFactory.createState(loadAtEnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||||
|
for(VehicleRoute route : vehicleRoutes){ insertionStarts(route); }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
import basics.Delivery;
|
||||||
|
import basics.Job;
|
||||||
|
import basics.Pickup;
|
||||||
|
import basics.Service;
|
||||||
|
import basics.algo.JobInsertedListener;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates loads at start and end of a route if a job has been inserted in that route.
|
||||||
|
*
|
||||||
|
* <p>These states can be retrieved by <br>
|
||||||
|
* stateManager.getRouteState(route, StateTypes.LOAD_AT_DEPOT) for LOAD_AT_DEPOT and <br>
|
||||||
|
* stateManager.getRouteState(route, StateTypes.LOAD) for LOAD (i.e. load at end)
|
||||||
|
*
|
||||||
|
* @param stateManager
|
||||||
|
*/
|
||||||
|
class UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted implements JobInsertedListener, StateUpdater {
|
||||||
|
|
||||||
|
private StateManager stateManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates loads at start and end of a route if a job has been inserted in that route.
|
||||||
|
*
|
||||||
|
* <p>These states can be retrieved by <br>
|
||||||
|
* stateManager.getRouteState(route, StateTypes.LOAD_AT_DEPOT) for LOAD_AT_DEPOT and <br>
|
||||||
|
* stateManager.getRouteState(route, StateTypes.LOAD) for LOAD (i.e. load at end)
|
||||||
|
*
|
||||||
|
* @param stateManager
|
||||||
|
*/
|
||||||
|
public UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted(StateManager stateManager) {
|
||||||
|
super();
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
||||||
|
if(job2insert instanceof Delivery){
|
||||||
|
int loadAtDepot = (int) stateManager.getRouteState(inRoute, StateFactory.LOAD_AT_BEGINNING).toDouble();
|
||||||
|
// log.info("loadAtDepot="+loadAtDepot);
|
||||||
|
stateManager.putRouteState(inRoute, StateFactory.LOAD_AT_BEGINNING, StateFactory.createState(loadAtDepot + job2insert.getCapacityDemand()));
|
||||||
|
}
|
||||||
|
else if(job2insert instanceof Pickup || job2insert instanceof Service){
|
||||||
|
int loadAtEnd = (int) stateManager.getRouteState(inRoute, StateFactory.LOAD_AT_END).toDouble();
|
||||||
|
// log.info("loadAtEnd="+loadAtEnd);
|
||||||
|
stateManager.putRouteState(inRoute, StateFactory.LOAD_AT_END, StateFactory.createState(loadAtEnd + job2insert.getCapacityDemand()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
69
jsprit-core/src/main/java/algorithms/UpdateMaxLoad.java
Normal file
69
jsprit-core/src/main/java/algorithms/UpdateMaxLoad.java
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.route.ActivityVisitor;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates load at activity level.
|
||||||
|
*
|
||||||
|
* <p>Note that this assumes that StateTypes.LOAD_AT_DEPOT is already updated, i.e. it starts by setting loadAtDepot to StateTypes.LOAD_AT_DEPOT.
|
||||||
|
* If StateTypes.LOAD_AT_DEPOT is not set, it starts with 0 load at depot.
|
||||||
|
*
|
||||||
|
* <p>Thus it DEPENDS on StateTypes.LOAD_AT_DEPOT
|
||||||
|
*
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class UpdateMaxLoad implements ActivityVisitor, StateUpdater {
|
||||||
|
private StateManager stateManager;
|
||||||
|
private int currentLoad = 0;
|
||||||
|
private VehicleRoute route;
|
||||||
|
private int maxLoad = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates load at activity level.
|
||||||
|
*
|
||||||
|
* <p>Note that this assumes that StateTypes.LOAD_AT_DEPOT is already updated, i.e. it starts by setting loadAtDepot to StateTypes.LOAD_AT_DEPOT.
|
||||||
|
* If StateTypes.LOAD_AT_DEPOT is not set, it starts with 0 load at depot.
|
||||||
|
*
|
||||||
|
* <p>Thus it DEPENDS on StateTypes.LOAD_AT_DEPOT
|
||||||
|
*
|
||||||
|
* <p>If you want to update StateTypes.LOAD_AT_DEPOT see {@link UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts}, {@link UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted}
|
||||||
|
*
|
||||||
|
* <p>The loads can be retrieved by <br>
|
||||||
|
* <code>stateManager.getActivityState(activity,StateTypes.LOAD);</code>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @see {@link UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts}, {@link UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted}
|
||||||
|
* @author stefan
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public UpdateMaxLoad(StateManager stateManager) {
|
||||||
|
super();
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
currentLoad = (int) stateManager.getRouteState(route, StateFactory.LOAD_AT_BEGINNING).toDouble();
|
||||||
|
maxLoad = currentLoad;
|
||||||
|
this.route = route;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity act) {
|
||||||
|
currentLoad += act.getCapacityDemand();
|
||||||
|
maxLoad = Math.max(maxLoad, currentLoad);
|
||||||
|
assert currentLoad <= route.getVehicle().getCapacity() : "currentLoad at activity must not be > vehicleCapacity";
|
||||||
|
assert currentLoad >= 0 : "currentLoad at act must not be < 0";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
stateManager.putRouteState(route, StateFactory.MAXLOAD, StateFactory.createState(maxLoad));
|
||||||
|
currentLoad = 0;
|
||||||
|
maxLoad = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import algorithms.StateManager.StateImpl;
|
||||||
|
import basics.route.ActivityVisitor;
|
||||||
|
import basics.route.DeliveryActivity;
|
||||||
|
import basics.route.TourActivity;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
class UpdateOccuredDeliveriesAtActivityLevel implements ActivityVisitor, StateUpdater {
|
||||||
|
private StateManager stateManager;
|
||||||
|
private int deliveries = 0;
|
||||||
|
private VehicleRoute route;
|
||||||
|
|
||||||
|
public UpdateOccuredDeliveriesAtActivityLevel(StateManager stateManager) {
|
||||||
|
super();
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(VehicleRoute route) {
|
||||||
|
this.route = route;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(TourActivity act) {
|
||||||
|
if(act instanceof DeliveryActivity){
|
||||||
|
deliveries += Math.abs(act.getCapacityDemand());
|
||||||
|
}
|
||||||
|
stateManager.putActivityState(act, StateFactory.PAST_DELIVERIES, StateFactory.createState(deliveries));
|
||||||
|
assert deliveries >= 0 : "deliveries < 0";
|
||||||
|
assert deliveries <= route.getVehicle().getCapacity() : "deliveries > vehicleCap";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
deliveries = 0;
|
||||||
|
route = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingProblemSolution;
|
||||||
|
import basics.algo.SolutionCostCalculator;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
public class VariablePlusFixedSolutionCostCalculatorFactory {
|
||||||
|
|
||||||
|
private StateManager stateManager;
|
||||||
|
|
||||||
|
public VariablePlusFixedSolutionCostCalculatorFactory(StateManager stateManager) {
|
||||||
|
super();
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SolutionCostCalculator createCalculator(){
|
||||||
|
return new SolutionCostCalculator() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getCosts(VehicleRoutingProblemSolution solution) {
|
||||||
|
double c = 0.0;
|
||||||
|
for(VehicleRoute r : solution.getRoutes()){
|
||||||
|
c += stateManager.getRouteState(r, StateFactory.COSTS).toDouble();
|
||||||
|
c += r.getVehicle().getType().getVehicleCostParams().fix;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (C) 2013 Stefan Schroeder
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 3.0 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
******************************************************************************/
|
|
||||||
package algorithms;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import basics.route.Vehicle;
|
|
||||||
|
|
||||||
interface VehicleFleetManager {
|
|
||||||
|
|
||||||
static class TypeKey {
|
|
||||||
|
|
||||||
public final String type;
|
|
||||||
public final String locationId;
|
|
||||||
|
|
||||||
public TypeKey(String typeId, String locationId) {
|
|
||||||
super();
|
|
||||||
this.type = typeId;
|
|
||||||
this.locationId = locationId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result
|
|
||||||
+ ((locationId == null) ? 0 : locationId.hashCode());
|
|
||||||
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj)
|
|
||||||
return true;
|
|
||||||
if (obj == null)
|
|
||||||
return false;
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
return false;
|
|
||||||
TypeKey other = (TypeKey) obj;
|
|
||||||
if (locationId == null) {
|
|
||||||
if (other.locationId != null)
|
|
||||||
return false;
|
|
||||||
} else if (!locationId.equals(other.locationId))
|
|
||||||
return false;
|
|
||||||
if (type == null) {
|
|
||||||
if (other.type != null)
|
|
||||||
return false;
|
|
||||||
} else if (!type.equals(other.type))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void lock(Vehicle vehicle);
|
|
||||||
|
|
||||||
abstract void unlock(Vehicle vehicle);
|
|
||||||
|
|
||||||
abstract boolean isLocked(Vehicle vehicle);
|
|
||||||
|
|
||||||
abstract void unlockAll();
|
|
||||||
|
|
||||||
abstract Collection<Vehicle> getAvailableVehicles();
|
|
||||||
|
|
||||||
Collection<Vehicle> getAvailableVehicles(String withoutThisType, String locationId);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package algorithms;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.VehicleRoutingAlgorithm;
|
||||||
|
import basics.VehicleRoutingProblem;
|
||||||
|
import basics.algo.SearchStrategyManager;
|
||||||
|
import basics.algo.VehicleRoutingAlgorithmListener;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
|
|
||||||
|
public class VehicleRoutingAlgorithmBuilder {
|
||||||
|
|
||||||
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
|
private SearchStrategyManager searchStrategyManager;
|
||||||
|
|
||||||
|
private StateManager stateManager;
|
||||||
|
|
||||||
|
private Collection<VehicleRoutingAlgorithmListener> listeners = new ArrayList<VehicleRoutingAlgorithmListener>();
|
||||||
|
|
||||||
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
|
public VehicleRoutingAlgorithmBuilder(VehicleRoutingProblem vrp, SearchStrategyManager searchStrategyManager, StateManager stateManager, VehicleFleetManager vehicleFleetManager) {
|
||||||
|
super();
|
||||||
|
this.vrp = vrp;
|
||||||
|
this.searchStrategyManager = searchStrategyManager;
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
this.fleetManager = vehicleFleetManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(VehicleRoutingAlgorithmListener listener){
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoutingAlgorithm build(){
|
||||||
|
VehicleRoutingAlgorithm algorithm = new VehicleRoutingAlgorithm(vrp, searchStrategyManager);
|
||||||
|
algorithm.getAlgorithmListeners().addListener(stateManager);
|
||||||
|
algorithm.getSearchStrategyManager().addSearchStrategyModuleListener(stateManager);
|
||||||
|
algorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new RemoveEmptyVehicles(fleetManager));
|
||||||
|
return algorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -31,7 +31,6 @@ import org.apache.commons.configuration.HierarchicalConfiguration;
|
||||||
import org.apache.commons.configuration.XMLConfiguration;
|
import org.apache.commons.configuration.XMLConfiguration;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import algorithms.HardConstraints.ConstraintManager;
|
|
||||||
import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractKey;
|
import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractKey;
|
||||||
import algorithms.VehicleRoutingAlgorithms.TypedMap.AcceptorKey;
|
import algorithms.VehicleRoutingAlgorithms.TypedMap.AcceptorKey;
|
||||||
import algorithms.VehicleRoutingAlgorithms.TypedMap.InsertionStrategyKey;
|
import algorithms.VehicleRoutingAlgorithms.TypedMap.InsertionStrategyKey;
|
||||||
|
|
@ -65,7 +64,10 @@ import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
|
||||||
import basics.algo.VehicleRoutingAlgorithmListeners.Priority;
|
import basics.algo.VehicleRoutingAlgorithmListeners.Priority;
|
||||||
import basics.io.AlgorithmConfig;
|
import basics.io.AlgorithmConfig;
|
||||||
import basics.io.AlgorithmConfigXmlReader;
|
import basics.io.AlgorithmConfigXmlReader;
|
||||||
|
import basics.route.FiniteFleetManagerFactory;
|
||||||
|
import basics.route.InfiniteFleetManagerFactory;
|
||||||
import basics.route.Vehicle;
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -437,23 +439,23 @@ public class VehicleRoutingAlgorithms {
|
||||||
final VehicleFleetManager vehicleFleetManager = createFleetManager(vrp);
|
final VehicleFleetManager vehicleFleetManager = createFleetManager(vrp);
|
||||||
|
|
||||||
//create state-manager
|
//create state-manager
|
||||||
final StateManagerImpl stateManager = new StateManagerImpl();
|
final StateManager stateManager = new StateManager();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* define constraints
|
* define constraints
|
||||||
*/
|
*/
|
||||||
//constraint manager
|
//constraint manager
|
||||||
ConstraintManager constraintManager = new ConstraintManager();
|
ConstraintManager constraintManager = new ConstraintManager();
|
||||||
constraintManager.addConstraint(new HardConstraints.HardTimeWindowActivityLevelConstraint(stateManager, vrp.getTransportCosts()));
|
constraintManager.addConstraint(new HardTimeWindowActivityLevelConstraint(stateManager, vrp.getTransportCosts()));
|
||||||
|
|
||||||
if(vrp.getProblemConstraints().contains(Constraint.DELIVERIES_FIRST)){
|
if(vrp.getProblemConstraints().contains(Constraint.DELIVERIES_FIRST)){
|
||||||
constraintManager.addConstraint(new HardConstraints.HardPickupAndDeliveryBackhaulActivityLevelConstraint(stateManager));
|
constraintManager.addConstraint(new HardPickupAndDeliveryBackhaulActivityLevelConstraint(stateManager));
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
constraintManager.addConstraint(new HardConstraints.HardPickupAndDeliveryActivityLevelConstraint(stateManager));
|
constraintManager.addConstraint(new HardPickupAndDeliveryActivityLevelConstraint(stateManager));
|
||||||
}
|
}
|
||||||
|
|
||||||
constraintManager.addConstraint(new HardConstraints.HardPickupAndDeliveryLoadConstraint(stateManager));
|
constraintManager.addConstraint(new HardPickupAndDeliveryLoadRouteLevelConstraint(stateManager));
|
||||||
|
|
||||||
//construct initial solution creator
|
//construct initial solution creator
|
||||||
AlgorithmStartsListener createInitialSolution = createInitialSolution(config,vrp,vehicleFleetManager,stateManager,algorithmListeners,definedClasses,executorService,nuOfThreads,constraintManager);
|
AlgorithmStartsListener createInitialSolution = createInitialSolution(config,vrp,vehicleFleetManager,stateManager,algorithmListeners,definedClasses,executorService,nuOfThreads,constraintManager);
|
||||||
|
|
@ -491,24 +493,22 @@ public class VehicleRoutingAlgorithms {
|
||||||
* define stateUpdates
|
* define stateUpdates
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//reset stateManager
|
stateManager.addListener(new UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts(stateManager));
|
||||||
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, new StateUpdates.ResetStateManager(stateManager)));
|
stateManager.addListener(new UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted(stateManager));
|
||||||
//update states
|
|
||||||
// metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new UpdateStates(stateManager, vrp.getTransportCosts(), vrp.getActivityCosts()));
|
|
||||||
StateUpdates.UpdateRouteStatesOnceTheRouteHasBeenChanged routeChangedListener = new StateUpdates.UpdateRouteStatesOnceTheRouteHasBeenChanged(vrp.getTransportCosts());
|
|
||||||
|
|
||||||
routeChangedListener.addInsertionStartsListener(new StateUpdates.UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts(stateManager));
|
stateManager.addActivityVisitor(new UpdateActivityTimes(vrp.getTransportCosts()));
|
||||||
routeChangedListener.addJobInsertedListener(new StateUpdates.UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted(stateManager));
|
stateManager.addActivityVisitor(new UpdateLoadAtActivityLevel(stateManager));
|
||||||
|
|
||||||
routeChangedListener.addVisitor(new StateUpdates.UpdateActivityTimes(vrp.getTransportCosts()));
|
stateManager.addActivityVisitor(new UpdateCostsAtAllLevels(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager));
|
||||||
routeChangedListener.addVisitor(new StateUpdates.UpdateLoadAtActivityLevel(stateManager));
|
|
||||||
routeChangedListener.addVisitor(new StateUpdates.UpdateCostsAtAllLevels(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager));
|
|
||||||
|
|
||||||
routeChangedListener.addVisitor(new StateUpdates.UpdateOccuredDeliveriesAtActivityLevel(stateManager));
|
stateManager.addActivityVisitor(new UpdateOccuredDeliveriesAtActivityLevel(stateManager));
|
||||||
routeChangedListener.addVisitor(new StateUpdates.UpdateLatestOperationStartTimeAtActLocations(stateManager, vrp.getTransportCosts()));
|
stateManager.addActivityVisitor(new UpdateLatestOperationStartTimeAtActLocations(stateManager, vrp.getTransportCosts()));
|
||||||
routeChangedListener.addVisitor(new StateUpdates.UpdateFuturePickupsAtActivityLevel(stateManager));
|
stateManager.addActivityVisitor(new UpdateFuturePickupsAtActivityLevel(stateManager));
|
||||||
|
|
||||||
|
|
||||||
|
metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(stateManager);
|
||||||
|
metaAlgorithm.getAlgorithmListeners().addListener(stateManager);
|
||||||
|
|
||||||
metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(routeChangedListener);
|
|
||||||
metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new RemoveEmptyVehicles(vehicleFleetManager));
|
metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new RemoveEmptyVehicles(vehicleFleetManager));
|
||||||
metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new ResetAndIniFleetManager(vehicleFleetManager));
|
metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new ResetAndIniFleetManager(vehicleFleetManager));
|
||||||
metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new VehicleSwitched(vehicleFleetManager));
|
metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new VehicleSwitched(vehicleFleetManager));
|
||||||
|
|
@ -526,16 +526,16 @@ public class VehicleRoutingAlgorithms {
|
||||||
return metaAlgorithm;
|
return metaAlgorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SolutionCostCalculator getCostCalculator(final StateManagerImpl stateManager) {
|
private static SolutionCostCalculator getCostCalculator(final StateManager stateManager) {
|
||||||
SolutionCostCalculator calc = new SolutionCostCalculator() {
|
SolutionCostCalculator calc = new SolutionCostCalculator() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void calculateCosts(VehicleRoutingProblemSolution solution) {
|
public double getCosts(VehicleRoutingProblemSolution solution) {
|
||||||
double costs = 0.0;
|
double costs = 0.0;
|
||||||
for(VehicleRoute route : solution.getRoutes()){
|
for(VehicleRoute route : solution.getRoutes()){
|
||||||
costs += stateManager.getRouteState(route, StateTypes.COSTS).toDouble() + getFixedCosts(route.getVehicle());
|
costs += stateManager.getRouteState(route, StateFactory.COSTS).toDouble() + getFixedCosts(route.getVehicle());
|
||||||
}
|
}
|
||||||
solution.setCost(costs);
|
return costs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getFixedCosts(Vehicle vehicle) {
|
private double getFixedCosts(Vehicle vehicle) {
|
||||||
|
|
@ -549,11 +549,11 @@ public class VehicleRoutingAlgorithms {
|
||||||
|
|
||||||
private static VehicleFleetManager createFleetManager(final VehicleRoutingProblem vrp) {
|
private static VehicleFleetManager createFleetManager(final VehicleRoutingProblem vrp) {
|
||||||
if(vrp.getFleetSize().equals(FleetSize.INFINITE)){
|
if(vrp.getFleetSize().equals(FleetSize.INFINITE)){
|
||||||
return new InfiniteVehicles(vrp.getVehicles());
|
return new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(vrp.getFleetSize().equals(FleetSize.FINITE)){
|
else if(vrp.getFleetSize().equals(FleetSize.FINITE)){
|
||||||
return new VehicleFleetManagerImpl(vrp.getVehicles());
|
return new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("fleet size can only be infinite or finite. " +
|
throw new IllegalStateException("fleet size can only be infinite or finite. " +
|
||||||
"makes sure your config file contains one of these options");
|
"makes sure your config file contains one of these options");
|
||||||
|
|
@ -626,7 +626,7 @@ public class VehicleRoutingAlgorithms {
|
||||||
metaAlgorithm.getAlgorithmListeners().addAll(algorithmListeners);
|
metaAlgorithm.getAlgorithmListeners().addAll(algorithmListeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, final StateManagerImpl routeStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) {
|
private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, final StateManager routeStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) {
|
||||||
List<HierarchicalConfiguration> modConfigs = config.configurationsAt("construction.insertion");
|
List<HierarchicalConfiguration> modConfigs = config.configurationsAt("construction.insertion");
|
||||||
if(modConfigs == null) return null;
|
if(modConfigs == null) return null;
|
||||||
if(modConfigs.isEmpty()) return null;
|
if(modConfigs.isEmpty()) return null;
|
||||||
|
|
@ -651,9 +651,11 @@ public class VehicleRoutingAlgorithms {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
CreateInitialSolution createInitialSolution = new CreateInitialSolution(finalInsertionStrategy, getCostCalculator(routeStates));
|
InsertionInitialSolutionFactory insertionInitialSolutionFactory = new InsertionInitialSolutionFactory(finalInsertionStrategy, getCostCalculator(routeStates));
|
||||||
createInitialSolution.setGenerateAsMuchAsRoutesAsVehiclesExist(false);
|
// CreateInitialSolution createInitialSolution = new CreateInitialSolution(finalInsertionStrategy, getCostCalculator(routeStates));
|
||||||
VehicleRoutingProblemSolution vrpSol = createInitialSolution.createInitialSolution(vrp);
|
//
|
||||||
|
// createInitialSolution.setGenerateAsMuchAsRoutesAsVehiclesExist(false);
|
||||||
|
VehicleRoutingProblemSolution vrpSol = insertionInitialSolutionFactory.createSolution(vrp);
|
||||||
solutions.add(vrpSol);
|
solutions.add(vrpSol);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -721,7 +723,7 @@ public class VehicleRoutingAlgorithms {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SearchStrategyModule buildModule(HierarchicalConfiguration moduleConfig, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager,
|
private static SearchStrategyModule buildModule(HierarchicalConfiguration moduleConfig, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager,
|
||||||
final StateManagerImpl routeStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) {
|
final StateManager routeStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) {
|
||||||
String moduleName = moduleConfig.getString("[@name]");
|
String moduleName = moduleConfig.getString("[@name]");
|
||||||
if(moduleName == null) throw new IllegalStateException("module(-name) is missing.");
|
if(moduleName == null) throw new IllegalStateException("module(-name) is missing.");
|
||||||
String moduleId = moduleConfig.getString("[@id]");
|
String moduleId = moduleConfig.getString("[@id]");
|
||||||
|
|
@ -823,7 +825,7 @@ public class VehicleRoutingAlgorithms {
|
||||||
"\n\tgendreauPostOpt");
|
"\n\tgendreauPostOpt");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RuinStrategy getRadialRuin(final VehicleRoutingProblem vrp, final StateManagerImpl routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) {
|
private static RuinStrategy getRadialRuin(final VehicleRoutingProblem vrp, final StateManager routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) {
|
||||||
RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
|
RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
|
||||||
RuinStrategy ruin = definedClasses.get(stratKey);
|
RuinStrategy ruin = definedClasses.get(stratKey);
|
||||||
if(ruin == null){
|
if(ruin == null){
|
||||||
|
|
@ -833,7 +835,7 @@ public class VehicleRoutingAlgorithms {
|
||||||
return ruin;
|
return ruin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RuinStrategy getRandomRuin(final VehicleRoutingProblem vrp, final StateManagerImpl routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin) {
|
private static RuinStrategy getRandomRuin(final VehicleRoutingProblem vrp, final StateManager routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin) {
|
||||||
RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
|
RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
|
||||||
RuinStrategy ruin = definedClasses.get(stratKey);
|
RuinStrategy ruin = definedClasses.get(stratKey);
|
||||||
if(ruin == null){
|
if(ruin == null){
|
||||||
|
|
@ -843,10 +845,12 @@ public class VehicleRoutingAlgorithms {
|
||||||
return ruin;
|
return ruin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InsertionStrategy createInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp,VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) {
|
private static InsertionStrategy createInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp,VehicleFleetManager vehicleFleetManager, StateManager routeStates, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) {
|
||||||
InsertionStrategy insertion = InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, routeStates, algorithmListeners, executorService, nuOfThreads, constraintManager);
|
InsertionStrategy insertion = InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, routeStates, algorithmListeners, executorService, nuOfThreads, constraintManager);
|
||||||
return insertion;
|
return insertion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package algorithms;
|
package algorithms;
|
||||||
|
|
||||||
import basics.route.Vehicle;
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,20 +25,21 @@ import algorithms.InsertionData.NoInsertionFound;
|
||||||
import basics.Job;
|
import basics.Job;
|
||||||
import basics.route.Driver;
|
import basics.route.Driver;
|
||||||
import basics.route.Vehicle;
|
import basics.route.Vehicle;
|
||||||
|
import basics.route.VehicleFleetManager;
|
||||||
import basics.route.VehicleImpl.NoVehicle;
|
import basics.route.VehicleImpl.NoVehicle;
|
||||||
import basics.route.VehicleRoute;
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
final class CalculatesVehTypeDepServiceInsertion implements JobInsertionCalculator{
|
final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCostsCalculator{
|
||||||
|
|
||||||
private Logger logger = Logger.getLogger(CalculatesVehTypeDepServiceInsertion.class);
|
private Logger logger = Logger.getLogger(VehicleTypeDependentJobInsertionCalculator.class);
|
||||||
|
|
||||||
private final VehicleFleetManager fleetManager;
|
private final VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
private final JobInsertionCalculator insertionCalculator;
|
private final JobInsertionCostsCalculator insertionCalculator;
|
||||||
|
|
||||||
public CalculatesVehTypeDepServiceInsertion(final VehicleFleetManager fleetManager, final JobInsertionCalculator jobInsertionCalc) {
|
public VehicleTypeDependentJobInsertionCalculator(final VehicleFleetManager fleetManager, final JobInsertionCostsCalculator jobInsertionCalc) {
|
||||||
this.fleetManager = fleetManager;
|
this.fleetManager = fleetManager;
|
||||||
this.insertionCalculator = jobInsertionCalc;
|
this.insertionCalculator = jobInsertionCalc;
|
||||||
logger.info("inialise " + this);
|
logger.info("inialise " + this);
|
||||||
|
|
@ -49,10 +50,10 @@ final class CalculatesVehTypeDepServiceInsertion implements JobInsertionCalculat
|
||||||
return "[name=vehicleTypeDependentServiceInsertion]";
|
return "[name=vehicleTypeDependentServiceInsertion]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertionData calculate(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle vehicle, double newVehicleDepartureTime, final Driver driver, final double bestKnownCost) {
|
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle vehicle, double newVehicleDepartureTime, final Driver driver, final double bestKnownCost) {
|
||||||
Vehicle selectedVehicle = currentRoute.getVehicle();
|
Vehicle selectedVehicle = currentRoute.getVehicle();
|
||||||
Driver selectedDriver = currentRoute.getDriver();
|
Driver selectedDriver = currentRoute.getDriver();
|
||||||
InsertionData bestIData = InsertionData.noInsertionFound();
|
InsertionData bestIData = InsertionData.createEmptyInsertionData();
|
||||||
double bestKnownCost_ = bestKnownCost;
|
double bestKnownCost_ = bestKnownCost;
|
||||||
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
||||||
if(!(selectedVehicle instanceof NoVehicle)) {
|
if(!(selectedVehicle instanceof NoVehicle)) {
|
||||||
|
|
@ -65,7 +66,7 @@ final class CalculatesVehTypeDepServiceInsertion implements JobInsertionCalculat
|
||||||
|
|
||||||
for(Vehicle v : relevantVehicles){
|
for(Vehicle v : relevantVehicles){
|
||||||
double depTime = v.getEarliestDeparture();
|
double depTime = v.getEarliestDeparture();
|
||||||
InsertionData iData = insertionCalculator.calculate(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
|
InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
|
||||||
if(iData instanceof NoInsertionFound) {
|
if(iData instanceof NoInsertionFound) {
|
||||||
if(bestIData instanceof NoInsertionFound) bestIData = iData;
|
if(bestIData instanceof NoInsertionFound) bestIData = iData;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
public class InsertionListeners {
|
||||||
|
|
||||||
|
private Collection<InsertionStartsListener> startListeners = new ArrayList<InsertionStartsListener>();
|
||||||
|
|
||||||
|
private Collection<JobInsertedListener> jobInsertedListeners = new ArrayList<JobInsertedListener>();
|
||||||
|
|
||||||
|
private Collection<InsertionEndsListener> endListeners = new ArrayList<InsertionEndsListener>();
|
||||||
|
|
||||||
|
public void addListener(InsertionListener insertionListener){
|
||||||
|
if(insertionListener instanceof InsertionStartsListener) startListeners.add((InsertionStartsListener) insertionListener);
|
||||||
|
else if(insertionListener instanceof JobInsertedListener) jobInsertedListeners.add((JobInsertedListener) insertionListener);
|
||||||
|
else if(insertionListener instanceof InsertionEndsListener) endListeners.add((InsertionEndsListener) insertionListener);
|
||||||
|
else throw new IllegalStateException("cannot add this type of insertionListener");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener(InsertionListener insertionListener){
|
||||||
|
if(insertionListener instanceof InsertionStartsListener) startListeners.remove((InsertionStartsListener) insertionListener);
|
||||||
|
else if(insertionListener instanceof JobInsertedListener) jobInsertedListeners.remove((JobInsertedListener) insertionListener);
|
||||||
|
else if(insertionListener instanceof InsertionEndsListener) endListeners.remove((InsertionEndsListener) insertionListener);
|
||||||
|
else throw new IllegalStateException("cannot remove this type of insertionListener");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs){
|
||||||
|
for(InsertionStartsListener l : startListeners) l.informInsertionStarts(vehicleRoutes, unassignedJobs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void jobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime){
|
||||||
|
for(JobInsertedListener l : jobInsertedListeners) l.informJobInserted(job2insert, inRoute, additionalCosts, additionalTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void insertionEnds(Collection<VehicleRoute> vehicleRoutes){
|
||||||
|
for(InsertionEndsListener l : endListeners){ l.informInsertionEnds(vehicleRoutes); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,4 +25,5 @@ import basics.route.VehicleRoute;
|
||||||
public interface InsertionStartsListener extends InsertionListener {
|
public interface InsertionStartsListener extends InsertionListener {
|
||||||
|
|
||||||
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
jsprit-core/src/main/java/basics/algo/RuinListener.java
Normal file
39
jsprit-core/src/main/java/basics/algo/RuinListener.java
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener that listens to the ruin-process. It informs whoever is interested about start, end and about a removal of a job.
|
||||||
|
*
|
||||||
|
* @author schroeder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface RuinListener extends SearchStrategyModuleListener{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* informs about ruin-start.
|
||||||
|
*
|
||||||
|
* @param routes
|
||||||
|
*/
|
||||||
|
public void ruinStarts(Collection<VehicleRoute> routes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* informs about ruin-end.
|
||||||
|
*
|
||||||
|
* @param routes
|
||||||
|
* @param unassignedJobs
|
||||||
|
*/
|
||||||
|
public void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* informs if a {@link Job} has been removed from a {@link VehicleRoute}.
|
||||||
|
*
|
||||||
|
* @param job
|
||||||
|
* @param fromRoute
|
||||||
|
*/
|
||||||
|
public void removed(Job job, VehicleRoute fromRoute);
|
||||||
|
|
||||||
|
}
|
||||||
57
jsprit-core/src/main/java/basics/algo/RuinListeners.java
Normal file
57
jsprit-core/src/main/java/basics/algo/RuinListeners.java
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2013 Stefan Schroeder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Stefan Schroeder - initial API and implementation
|
||||||
|
******************************************************************************/
|
||||||
|
package basics.algo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import basics.Job;
|
||||||
|
import basics.route.VehicleRoute;
|
||||||
|
|
||||||
|
public class RuinListeners {
|
||||||
|
|
||||||
|
private Collection<RuinListener> ruinListeners = new ArrayList<RuinListener>();
|
||||||
|
|
||||||
|
public void ruinStarts(Collection<VehicleRoute> routes){
|
||||||
|
for(RuinListener l : ruinListeners) l.ruinStarts(routes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs){
|
||||||
|
for(RuinListener l : ruinListeners) l.ruinEnds(routes, unassignedJobs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removed(Job job, VehicleRoute fromRoute){
|
||||||
|
for(RuinListener l : ruinListeners) l.removed(job, fromRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(RuinListener ruinListener){
|
||||||
|
ruinListeners.add(ruinListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener(RuinListener ruinListener){
|
||||||
|
ruinListeners.remove(ruinListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<RuinListener> getListeners(){
|
||||||
|
return Collections.unmodifiableCollection(ruinListeners);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -125,7 +125,8 @@ public class SearchStrategy {
|
||||||
VehicleRoutingProblemSolution newSolution = module.runAndGetSolution(lastSolution);
|
VehicleRoutingProblemSolution newSolution = module.runAndGetSolution(lastSolution);
|
||||||
lastSolution = newSolution;
|
lastSolution = newSolution;
|
||||||
}
|
}
|
||||||
solutionCostCalculator.calculateCosts(lastSolution);
|
double costs = solutionCostCalculator.getCosts(lastSolution);
|
||||||
|
lastSolution.setCost(costs);
|
||||||
boolean solutionAccepted = solutionAcceptor.acceptSolution(solutions, lastSolution);
|
boolean solutionAccepted = solutionAcceptor.acceptSolution(solutions, lastSolution);
|
||||||
DiscoveredSolution discoveredSolution = new DiscoveredSolution(lastSolution, solutionAccepted, getName());
|
DiscoveredSolution discoveredSolution = new DiscoveredSolution(lastSolution, solutionAccepted, getName());
|
||||||
return discoveredSolution;
|
return discoveredSolution;
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,11 @@ import basics.VehicleRoutingProblemSolution;
|
||||||
public interface SolutionCostCalculator {
|
public interface SolutionCostCalculator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This assumes that the solution is modified by setting its costs <br>
|
* Returns costs of solution.
|
||||||
* <code>solution.setCost(costs);</code>
|
*
|
||||||
* @param solution
|
* @param solution
|
||||||
|
* @return TODO
|
||||||
*/
|
*/
|
||||||
public void calculateCosts(VehicleRoutingProblemSolution solution);
|
public double getCosts(VehicleRoutingProblemSolution solution);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,10 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package algorithms;
|
package basics.route;
|
||||||
|
|
||||||
import basics.route.TourActivity;
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
|
|
||||||
interface ActivityVisitor {
|
public interface ActivityVisitor {
|
||||||
|
|
||||||
public void begin(VehicleRoute route);
|
public void begin(VehicleRoute route);
|
||||||
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package basics.route;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
|
public class FiniteFleetManagerFactory implements VehicleFleetManagerFactory{
|
||||||
|
|
||||||
|
private Collection<Vehicle> vehicles;
|
||||||
|
|
||||||
|
public FiniteFleetManagerFactory(Collection<Vehicle> vehicles) {
|
||||||
|
super();
|
||||||
|
this.vehicles = vehicles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleFleetManager createFleetManager() {
|
||||||
|
return new VehicleFleetManagerImpl(vehicles);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package basics.route;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
|
public class InfiniteFleetManagerFactory implements VehicleFleetManagerFactory{
|
||||||
|
|
||||||
|
private Collection<Vehicle> vehicles;
|
||||||
|
|
||||||
|
public InfiniteFleetManagerFactory(Collection<Vehicle> vehicles) {
|
||||||
|
super();
|
||||||
|
this.vehicles = vehicles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VehicleFleetManager createFleetManager() {
|
||||||
|
return new InfiniteVehicles(vehicles);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package algorithms;
|
package basics.route;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
@ -24,26 +24,14 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import basics.route.Vehicle;
|
|
||||||
|
|
||||||
class InfiniteVehicles implements VehicleFleetManager{
|
class InfiniteVehicles implements VehicleFleetManager{
|
||||||
|
|
||||||
// static class TypeKeyComparator implements Comparator<TypeKey>{
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public int compare(TypeKey k1, TypeKey k2) {
|
|
||||||
// double k1_fix = k1.type.getVehicleCostParams().fix;
|
|
||||||
// double k2_fix = k2.type.getVehicleCostParams().fix;
|
|
||||||
// return (int)(k1_fix - k2_fix);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static Logger logger = Logger.getLogger(InfiniteVehicles.class);
|
private static Logger logger = Logger.getLogger(InfiniteVehicles.class);
|
||||||
|
|
||||||
private Map<TypeKey,Vehicle> types = new HashMap<TypeKey, Vehicle>();
|
private Map<VehicleTypeKey,Vehicle> types = new HashMap<VehicleTypeKey, Vehicle>();
|
||||||
|
|
||||||
private List<TypeKey> sortedTypes = new ArrayList<VehicleFleetManager.TypeKey>();
|
private List<VehicleTypeKey> sortedTypes = new ArrayList<VehicleTypeKey>();
|
||||||
|
|
||||||
public InfiniteVehicles(Collection<Vehicle> vehicles){
|
public InfiniteVehicles(Collection<Vehicle> vehicles){
|
||||||
extractTypes(vehicles);
|
extractTypes(vehicles);
|
||||||
|
|
@ -57,12 +45,11 @@ class InfiniteVehicles implements VehicleFleetManager{
|
||||||
|
|
||||||
private void extractTypes(Collection<Vehicle> vehicles) {
|
private void extractTypes(Collection<Vehicle> vehicles) {
|
||||||
for(Vehicle v : vehicles){
|
for(Vehicle v : vehicles){
|
||||||
TypeKey typeKey = new TypeKey(v.getType().getTypeId(),v.getLocationId());
|
VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(),v.getLocationId());
|
||||||
types.put(typeKey,v);
|
types.put(typeKey,v);
|
||||||
sortedTypes.add(typeKey);
|
sortedTypes.add(typeKey);
|
||||||
|
|
||||||
}
|
}
|
||||||
// Collections.sort(sortedTypes, new TypeKeyComparator());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -95,8 +82,8 @@ class InfiniteVehicles implements VehicleFleetManager{
|
||||||
@Override
|
@Override
|
||||||
public Collection<Vehicle> getAvailableVehicles(String withoutThisType, String locationId) {
|
public Collection<Vehicle> getAvailableVehicles(String withoutThisType, String locationId) {
|
||||||
Collection<Vehicle> vehicles = new ArrayList<Vehicle>();
|
Collection<Vehicle> vehicles = new ArrayList<Vehicle>();
|
||||||
TypeKey thisKey = new TypeKey(withoutThisType,locationId);
|
VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType,locationId);
|
||||||
for(TypeKey key : types.keySet()){
|
for(VehicleTypeKey key : types.keySet()){
|
||||||
if(!key.equals(thisKey)){
|
if(!key.equals(thisKey)){
|
||||||
vehicles.add(types.get(key));
|
vehicles.add(types.get(key));
|
||||||
}
|
}
|
||||||
|
|
@ -14,12 +14,10 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package algorithms;
|
package basics.route;
|
||||||
|
|
||||||
import basics.route.TourActivity;
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
|
|
||||||
interface ReverseActivityVisitor {
|
public interface ReverseActivityVisitor {
|
||||||
|
|
||||||
public void begin(VehicleRoute route);
|
public void begin(VehicleRoute route);
|
||||||
|
|
||||||
|
|
@ -14,16 +14,14 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package algorithms;
|
package basics.route;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import basics.route.TourActivity;
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
|
|
||||||
class ReverseRouteActivityVisitor implements RouteVisitor{
|
public class ReverseRouteActivityVisitor implements RouteVisitor{
|
||||||
|
|
||||||
private Collection<ReverseActivityVisitor> visitors = new ArrayList<ReverseActivityVisitor>();
|
private Collection<ReverseActivityVisitor> visitors = new ArrayList<ReverseActivityVisitor>();
|
||||||
|
|
||||||
|
|
@ -14,15 +14,13 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package algorithms;
|
package basics.route;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import basics.route.TourActivity;
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
|
|
||||||
class RouteActivityVisitor implements RouteVisitor{
|
public class RouteActivityVisitor implements RouteVisitor{
|
||||||
|
|
||||||
private Collection<ActivityVisitor> visitors = new ArrayList<ActivityVisitor>();
|
private Collection<ActivityVisitor> visitors = new ArrayList<ActivityVisitor>();
|
||||||
|
|
||||||
|
|
@ -14,11 +14,10 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package algorithms;
|
package basics.route;
|
||||||
|
|
||||||
import basics.route.VehicleRoute;
|
|
||||||
|
|
||||||
interface RouteVisitor {
|
public interface RouteVisitor {
|
||||||
|
|
||||||
public void visit(VehicleRoute route);
|
public void visit(VehicleRoute route);
|
||||||
|
|
||||||
|
|
@ -113,6 +113,12 @@ public class TourActivities {
|
||||||
return Collections.unmodifiableSet(jobs);
|
return Collections.unmodifiableSet(jobs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if job is in jobList, otherwise false.
|
||||||
|
*
|
||||||
|
* @param job
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean servesJob(Job job) {
|
public boolean servesJob(Job job) {
|
||||||
return jobs.contains(job);
|
return jobs.contains(job);
|
||||||
}
|
}
|
||||||
|
|
@ -146,13 +152,24 @@ public class TourActivities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(jobRemoved != activityRemoved) throw new IllegalStateException("job removed, but belonging activity not.");
|
assert jobRemoved == activityRemoved : "job removed, but belonging activity not.";
|
||||||
return activityRemoved;
|
return activityRemoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the specified activity add the specified insertionIndex. Shifts the element currently at that position (if any) and
|
||||||
|
* any subsequent elements to the right (adds one to their indices).
|
||||||
|
* <p>If specified activity instanceof JobActivity, it adds job to jobList.
|
||||||
|
* <p>If insertionIndex > tourActivitiies.size(), it just adds the specified act at the end.
|
||||||
|
*
|
||||||
|
* @param insertionIndex
|
||||||
|
* @param act
|
||||||
|
* @throws IndexOutOfBoundsException if insertionIndex < 0;
|
||||||
|
*/
|
||||||
public void addActivity(int insertionIndex, TourActivity act) {
|
public void addActivity(int insertionIndex, TourActivity act) {
|
||||||
assert insertionIndex >= 0 : "insertionIndex == 0, this cannot be";
|
|
||||||
if(tourActivities.contains(act)) throw new IllegalStateException("act " + act + " already in tour. cannot add act twice.");
|
assert insertionIndex >= 0 : "insertionIndex < 0, this cannot be";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if 1 --> between start and act(0) --> act(0)
|
* if 1 --> between start and act(0) --> act(0)
|
||||||
* if 2 && 2 <= acts.size --> between act(0) and act(1) --> act(1)
|
* if 2 && 2 <= acts.size --> between act(0) and act(1) --> act(1)
|
||||||
|
|
@ -166,9 +183,15 @@ public class TourActivities {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
<<<<<<< HEAD
|
||||||
* adds activity.
|
* adds activity.
|
||||||
*
|
*
|
||||||
* @throw {@link IllegalStateException} if same activity is added twice.
|
* @throw {@link IllegalStateException} if same activity is added twice.
|
||||||
|
=======
|
||||||
|
* Adds specified activity at the end of activity-list.
|
||||||
|
* <p>If act instanceof JobActivity, it adds underlying job also.
|
||||||
|
* @throws IllegalStateException if activity-list already contains act.
|
||||||
|
>>>>>>> refs/remotes/choose_remote_name/relaxAPI
|
||||||
* @param act
|
* @param act
|
||||||
*/
|
*/
|
||||||
public void addActivity(TourActivity act){
|
public void addActivity(TourActivity act){
|
||||||
|
|
@ -184,6 +207,11 @@ public class TourActivities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns number of jobs.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public int jobSize() {
|
public int jobSize() {
|
||||||
return jobs.size();
|
return jobs.size();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,27 +14,23 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package algorithms;
|
package basics.route;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
class StateTypes {
|
public interface VehicleFleetManager {
|
||||||
|
|
||||||
// final static StateId LOAD = new StateIdImpl("load");
|
public abstract void lock(Vehicle vehicle);
|
||||||
|
|
||||||
final static String LOAD = "load";
|
public abstract void unlock(Vehicle vehicle);
|
||||||
|
|
||||||
final static String LOAD_AT_DEPOT = "loadAtDepot";
|
public abstract boolean isLocked(Vehicle vehicle);
|
||||||
|
|
||||||
final static String DURATION = "duration";
|
public abstract void unlockAll();
|
||||||
|
|
||||||
final static String LATEST_OPERATION_START_TIME = "latestOST";
|
public abstract Collection<Vehicle> getAvailableVehicles();
|
||||||
|
|
||||||
final static String EARLIEST_OPERATION_START_TIME = "earliestOST";
|
public Collection<Vehicle> getAvailableVehicles(String withoutThisType, String locationId);
|
||||||
|
|
||||||
static final String COSTS = "costs";
|
|
||||||
|
|
||||||
final static String FUTURE_PICKS = "futurePicks";
|
|
||||||
|
|
||||||
final static String PAST_DELIVERIES = "pastDeliveries";
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package basics.route;
|
||||||
|
|
||||||
|
public interface VehicleFleetManagerFactory {
|
||||||
|
|
||||||
|
public VehicleFleetManager createFleetManager();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package algorithms;
|
package basics.route;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
@ -27,12 +27,11 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import basics.route.PenaltyVehicleType;
|
|
||||||
import basics.route.Vehicle;
|
|
||||||
import basics.route.VehicleImpl.NoVehicle;
|
import basics.route.VehicleImpl.NoVehicle;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class VehicleFleetManagerImpl implements VehicleFleetManager {
|
class VehicleFleetManagerImpl implements VehicleFleetManager {
|
||||||
|
|
||||||
public VehicleFleetManagerImpl newInstance(Collection<Vehicle> vehicles){
|
public VehicleFleetManagerImpl newInstance(Collection<Vehicle> vehicles){
|
||||||
|
|
@ -54,11 +53,11 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
|
||||||
|
|
||||||
static class TypeContainer {
|
static class TypeContainer {
|
||||||
|
|
||||||
private TypeKey type;
|
private VehicleTypeKey type;
|
||||||
|
|
||||||
private ArrayList<Vehicle> vehicleList;
|
private ArrayList<Vehicle> vehicleList;
|
||||||
|
|
||||||
public TypeContainer(TypeKey type) {
|
public TypeContainer(VehicleTypeKey type) {
|
||||||
super();
|
super();
|
||||||
this.type = type;
|
this.type = type;
|
||||||
vehicleList = new ArrayList<Vehicle>();
|
vehicleList = new ArrayList<Vehicle>();
|
||||||
|
|
@ -92,9 +91,9 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
|
||||||
|
|
||||||
private Set<Vehicle> lockedVehicles;
|
private Set<Vehicle> lockedVehicles;
|
||||||
|
|
||||||
private Map<TypeKey,TypeContainer> typeMapOfAvailableVehicles;
|
private Map<VehicleTypeKey,TypeContainer> typeMapOfAvailableVehicles;
|
||||||
|
|
||||||
private Map<TypeKey,Vehicle> penaltyVehicles = new HashMap<VehicleFleetManager.TypeKey, Vehicle>();
|
private Map<VehicleTypeKey,Vehicle> penaltyVehicles = new HashMap<VehicleTypeKey, Vehicle>();
|
||||||
|
|
||||||
// private Map<TypeKey,TypeContainer> typeMapOfAvailablePenaltyVehicles;
|
// private Map<TypeKey,TypeContainer> typeMapOfAvailablePenaltyVehicles;
|
||||||
|
|
||||||
|
|
@ -122,8 +121,8 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void makeMap() {
|
private void makeMap() {
|
||||||
typeMapOfAvailableVehicles = new HashMap<TypeKey, TypeContainer>();
|
typeMapOfAvailableVehicles = new HashMap<VehicleTypeKey, TypeContainer>();
|
||||||
penaltyVehicles = new HashMap<VehicleFleetManager.TypeKey, Vehicle>();
|
penaltyVehicles = new HashMap<VehicleTypeKey, Vehicle>();
|
||||||
for(Vehicle v : vehicles){
|
for(Vehicle v : vehicles){
|
||||||
addVehicle(v);
|
addVehicle(v);
|
||||||
}
|
}
|
||||||
|
|
@ -135,11 +134,11 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
|
||||||
}
|
}
|
||||||
String typeId = v.getType().getTypeId();
|
String typeId = v.getType().getTypeId();
|
||||||
if(v.getType() instanceof PenaltyVehicleType){
|
if(v.getType() instanceof PenaltyVehicleType){
|
||||||
TypeKey typeKey = new TypeKey(typeId,v.getLocationId());
|
VehicleTypeKey typeKey = new VehicleTypeKey(typeId,v.getLocationId());
|
||||||
penaltyVehicles.put(typeKey, v);
|
penaltyVehicles.put(typeKey, v);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
TypeKey typeKey = new TypeKey(v.getType().getTypeId(),v.getLocationId());
|
VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(),v.getLocationId());
|
||||||
if(!typeMapOfAvailableVehicles.containsKey(typeKey)){
|
if(!typeMapOfAvailableVehicles.containsKey(typeKey)){
|
||||||
typeMapOfAvailableVehicles.put(typeKey, new TypeContainer(typeKey));
|
typeMapOfAvailableVehicles.put(typeKey, new TypeContainer(typeKey));
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +149,7 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
|
||||||
private void removeVehicle(Vehicle v){
|
private void removeVehicle(Vehicle v){
|
||||||
//it might be better to introduce a class PenaltyVehicle
|
//it might be better to introduce a class PenaltyVehicle
|
||||||
if(!(v.getType() instanceof PenaltyVehicleType)){
|
if(!(v.getType() instanceof PenaltyVehicleType)){
|
||||||
TypeKey key = new TypeKey(v.getType().getTypeId(),v.getLocationId());
|
VehicleTypeKey key = new VehicleTypeKey(v.getType().getTypeId(),v.getLocationId());
|
||||||
if(typeMapOfAvailableVehicles.containsKey(key)){
|
if(typeMapOfAvailableVehicles.containsKey(key)){
|
||||||
typeMapOfAvailableVehicles.get(key).remove(v);
|
typeMapOfAvailableVehicles.get(key).remove(v);
|
||||||
}
|
}
|
||||||
|
|
@ -167,7 +166,7 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
|
||||||
@Override
|
@Override
|
||||||
public Collection<Vehicle> getAvailableVehicles() {
|
public Collection<Vehicle> getAvailableVehicles() {
|
||||||
List<Vehicle> vehicles = new ArrayList<Vehicle>();
|
List<Vehicle> vehicles = new ArrayList<Vehicle>();
|
||||||
for(TypeKey key : typeMapOfAvailableVehicles.keySet()){
|
for(VehicleTypeKey key : typeMapOfAvailableVehicles.keySet()){
|
||||||
if(!typeMapOfAvailableVehicles.get(key).isEmpty()){
|
if(!typeMapOfAvailableVehicles.get(key).isEmpty()){
|
||||||
vehicles.add(typeMapOfAvailableVehicles.get(key).getVehicle());
|
vehicles.add(typeMapOfAvailableVehicles.get(key).getVehicle());
|
||||||
}
|
}
|
||||||
|
|
@ -193,8 +192,8 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
|
||||||
@Override
|
@Override
|
||||||
public Collection<Vehicle> getAvailableVehicles(String withoutThisType, String withThisLocationId) {
|
public Collection<Vehicle> getAvailableVehicles(String withoutThisType, String withThisLocationId) {
|
||||||
List<Vehicle> vehicles = new ArrayList<Vehicle>();
|
List<Vehicle> vehicles = new ArrayList<Vehicle>();
|
||||||
TypeKey thisKey = new TypeKey(withoutThisType,withThisLocationId);
|
VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType,withThisLocationId);
|
||||||
for(TypeKey key : typeMapOfAvailableVehicles.keySet()){
|
for(VehicleTypeKey key : typeMapOfAvailableVehicles.keySet()){
|
||||||
if(key.equals(thisKey)) continue;
|
if(key.equals(thisKey)) continue;
|
||||||
if(!typeMapOfAvailableVehicles.get(key).isEmpty()){
|
if(!typeMapOfAvailableVehicles.get(key).isEmpty()){
|
||||||
vehicles.add(typeMapOfAvailableVehicles.get(key).getVehicle());
|
vehicles.add(typeMapOfAvailableVehicles.get(key).getVehicle());
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue