1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

Merge branch 'master' into vrpWithBackhauls

Conflicts:
	jsprit-examples/src/main/java/examples/SolomonExample.java
This commit is contained in:
oblonski 2013-08-25 18:11:40 +02:00
commit f4a7254036
99 changed files with 4371 additions and 2349 deletions

View file

@ -1,95 +0,0 @@
/*******************************************************************************
* 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.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.log4j.Logger;
import basics.Job;
import basics.algo.InsertionEndsListener;
import basics.algo.InsertionListener;
import basics.algo.InsertionStartsListener;
import basics.algo.JobInsertedListener;
import basics.route.VehicleRoute;
abstract class AbstractInsertionStrategy implements InsertionStrategy{
private static Logger log = Logger.getLogger(AbstractInsertionStrategy.class);
private Collection<InsertionListener> listener = new ArrayList<InsertionListener>();
public abstract RouteAlgorithm getRouteAlgorithm();
public void informJobInserted(int nOfJobs2Recreate, Job insertedJob, VehicleRoute insertedIn){
for(InsertionListener l : listener){
if(l instanceof JobInsertedListener){
((JobInsertedListener)l).informJobInserted(nOfJobs2Recreate, insertedJob, insertedIn);
}
}
}
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route){
for(InsertionListener l : listener){
if(l instanceof BeforeJobInsertionListener){
((BeforeJobInsertionListener)l).informBeforeJobInsertion(job, data, route);
}
}
}
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2Recreate){
for(InsertionListener l : listener){
if(l instanceof InsertionStartsListener){
((InsertionStartsListener)l).informInsertionStarts(vehicleRoutes,nOfJobs2Recreate);
}
}
}
public void informInsertionEndsListeners(Collection<VehicleRoute> vehicleRoutes) {
for(InsertionListener l : listener){
if(l instanceof InsertionEndsListener){
((InsertionEndsListener)l).informInsertionEnds(vehicleRoutes);
}
}
}
public Collection<InsertionListener> getListener() {
return Collections.unmodifiableCollection(listener);
}
public void addListener(InsertionListener l){
log.info("add insertion-listener " + l);
listener.add(l);
}
public void addAllListener(List<InsertionListener> list) {
for(InsertionListener l : list) addListener(l);
}
}

View file

@ -0,0 +1,52 @@
package algorithms;
import java.util.ArrayList;
import java.util.Collection;
import basics.route.End;
import basics.route.Start;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
class BackwardInTimeListeners {
interface BackwardInTimeListener{
public void start(VehicleRoute route, End end, double latestArrivalTime);
public void prevActivity(TourActivity act, double latestDepartureTime, double latestOperationStartTime);
public void end(Start start, double latestDepartureTime);
}
private Collection<BackwardInTimeListener> listeners = new ArrayList<BackwardInTimeListener>();
public void addListener(BackwardInTimeListener l){
listeners.add(l);
}
public void start(VehicleRoute route, End end, double latestArrivalTime){
for(BackwardInTimeListener l : listeners){ l.start(route, end, latestArrivalTime); }
}
/**
* Informs listener about nextActivity.
*
* <p>LatestDepartureTime is the theoretical latest departureTime to meet the latestOperationStartTimeWindow at the nextActivity (forward in time), i.e.
* assume act_i and act_j are two successive activities and the latestDepTime of act_j is 10pm. With a travelTime from act_i to act_j of 1h the latestDepartureTime at act_i is 9pm.
* However, the latestOperationStartTime of act_i is 8pm, then (with a serviceTime of 0) the latestOperationStartTime at act_i amounts to 8pm.
*
* @param act
* @param latestDepartureTime
* @param latestArrivalTime
*/
public void prevActivity(TourActivity act, double latestDepartureTime, double latestArrivalTime){
for(BackwardInTimeListener l : listeners){ l.prevActivity(act,latestDepartureTime,latestArrivalTime); }
}
public void end(Start start, double latestDepartureTime){
for(BackwardInTimeListener l : listeners){ l.end(start, latestDepartureTime); }
}
}

View file

@ -15,9 +15,7 @@ package algorithms;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.log4j.Logger;
@ -25,6 +23,9 @@ import org.apache.log4j.Logger;
import util.RandomNumberGeneration;
import algorithms.InsertionData.NoInsertionFound;
import basics.Job;
import basics.algo.InsertionListener;
import basics.route.Driver;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
@ -35,44 +36,37 @@ import basics.route.VehicleRoute;
*
*/
final class BestInsertion extends AbstractInsertionStrategy{
public static BestInsertion newInstance(RouteAlgorithm routeAlgorithm){
return new BestInsertion(routeAlgorithm);
}
final class BestInsertion implements InsertionStrategy{
private static Logger logger = Logger.getLogger(BestInsertion.class);
private Random random = RandomNumberGeneration.getRandom();
private RouteAlgorithm routeAlgorithm;
private final static double NO_NEW_DEPARTURE_TIME_YET = -12345.12345;
public void setExperimentalPreferredRoute(Map<String, VehicleRoute> experimentalPreferredRoute) {
}
private final static Vehicle NO_NEW_VEHICLE_YET = null;
private final static Driver NO_NEW_DRIVER_YET = null;
private InsertionListeners insertionsListeners;
private Inserter inserter;
private JobInsertionCalculator bestInsertionCostCalculator;
private boolean allowUnassignedJobs = false;
private boolean fixRouteSet = false;
private boolean minVehiclesFirst = false;
public void setFixRouteSet(boolean fixRouteSet) {
this.fixRouteSet = fixRouteSet;
}
public void setRandom(Random random) {
this.random = random;
}
public BestInsertion(RouteAlgorithm routeAlgorithm) {
public BestInsertion(JobInsertionCalculator jobInsertionCalculator) {
super();
this.routeAlgorithm = routeAlgorithm;
this.insertionsListeners = new InsertionListeners();
inserter = new Inserter(insertionsListeners);
bestInsertionCostCalculator = jobInsertionCalculator;
logger.info("initialise " + this);
}
public RouteAlgorithm getRouteAlgorithm(){
return routeAlgorithm;
}
@Override
public String toString() {
@ -80,19 +74,15 @@ final class BestInsertion extends AbstractInsertionStrategy{
}
@Override
public void run(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs, double result2beat) {
public void insertJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
insertionsListeners.informInsertionStarts(vehicleRoutes,unassignedJobs);
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
Collections.shuffle(unassignedJobList, random);
informInsertionStarts(vehicleRoutes,unassignedJobs.size());
int inserted = 0;
List<String> reasons = new ArrayList<String>();
for(Job unassignedJob : unassignedJobList){
VehicleRoute insertIn = null;
for(Job unassignedJob : unassignedJobList){
Insertion bestInsertion = null;
double bestInsertionCost = Double.MAX_VALUE;
for(VehicleRoute vehicleRoute : vehicleRoutes){
InsertionData iData = routeAlgorithm.calculateBestInsertion(vehicleRoute, unassignedJob, bestInsertionCost);
InsertionData iData = bestInsertionCostCalculator.calculate(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
if(iData instanceof NoInsertionFound) {
continue;
}
@ -103,56 +93,54 @@ final class BestInsertion extends AbstractInsertionStrategy{
}
if(!minVehiclesFirst){
VehicleRoute newRoute = VehicleRoute.emptyRoute();
InsertionData newIData = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE);
InsertionData newIData = bestInsertionCostCalculator.calculate(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
if(newIData.getInsertionCost() < bestInsertionCost){
bestInsertion = new Insertion(newRoute,newIData);
bestInsertionCost = newIData.getInsertionCost();
vehicleRoutes.add(newRoute);
}
}
if(bestInsertion != null){
informBeforeJobInsertion(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
insertIn = bestInsertion.getRoute();
// logger.debug("insert job="+unassignedJob+" at index=" + bestInsertion.getInsertionData().getInsertionIndex() + " delta cost=" + bestInsertion.getInsertionData().getInsertionCost());
routeAlgorithm.insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
}
else {
if(fixRouteSet){
if(allowUnassignedJobs) logger.warn("cannot insert job yet " + unassignedJob);
else throw new IllegalStateException("given the vehicles, could not insert job\n");
}
if(bestInsertion == null){
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);
if(bestI instanceof InsertionData.NoInsertionFound){
throw new IllegalStateException(getErrorMsg(unassignedJob));
}
else{
VehicleRoute newRoute = VehicleRoute.emptyRoute();
InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE);
if(bestI instanceof InsertionData.NoInsertionFound){
if(allowUnassignedJobs){
logger.warn("cannot insert job yet " + unassignedJob);
}
else {
for(String s : reasons){
System.out.println("reason="+s);
}
throw new IllegalStateException("given the vehicles, could not insert job\n" +
"\t" + unassignedJob +
"\n\tthis might have the following reasons:\n" +
"\t- no vehicle has the capacity to transport the job [check whether there is at least one vehicle that is capable to transport the job]\n" +
"\t- the time-window cannot be met, even in a commuter tour the time-window is missed [check whether it is possible to reach the time-window on the shortest path or make hard time-windows soft]\n" +
"\t- if you deal with finite vehicles, and the available vehicles are already fully employed, no vehicle can be found anymore to transport the job [add penalty-vehicles]"
);
}
}
else{
insertIn = newRoute;
informBeforeJobInsertion(unassignedJob,bestI,newRoute);
routeAlgorithm.insertJob(unassignedJob,bestI,newRoute);
vehicleRoutes.add(newRoute);
}
bestInsertion = new Insertion(newRoute,bestI);
vehicleRoutes.add(newRoute);
}
}
inserted++;
informJobInserted((unassignedJobList.size()-inserted), unassignedJob, insertIn);
inserter.insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
}
informInsertionEndsListeners(vehicleRoutes);
insertionsListeners.informInsertionEndsListeners(vehicleRoutes);
}
private String getErrorMsg(Job unassignedJob) {
return "given the vehicles, could not insert job\n" +
"\t" + unassignedJob +
"\n\tthis might have the following reasons:\n" +
"\t- no vehicle has the capacity to transport the job [check whether there is at least one vehicle that is capable to transport the job]\n" +
"\t- the time-window cannot be met, even in a commuter tour the time-window is missed [check whether it is possible to reach the time-window on the shortest path or make hard time-windows soft]\n" +
"\t- if you deal with finite vehicles, and the available vehicles are already fully employed, no vehicle can be found anymore to transport the job [add penalty-vehicles]";
}
@Override
public void removeListener(InsertionListener insertionListener) {
insertionsListeners.removeListener(insertionListener);
}
@Override
public Collection<InsertionListener> getListeners() {
return Collections.unmodifiableCollection(insertionsListeners.getListeners());
}
@Override
public void addListener(InsertionListener insertionListener) {
insertionsListeners.addListener(insertionListener);
}
}

View file

@ -30,170 +30,185 @@ import org.apache.log4j.Logger;
import util.RandomNumberGeneration;
import algorithms.InsertionData.NoInsertionFound;
import basics.Job;
import basics.algo.InsertionListener;
import basics.route.VehicleRoute;
/**
*
* @author stefan schroeder
*
*/
final class BestInsertionConcurrent extends AbstractInsertionStrategy{
public static BestInsertionConcurrent newInstance(RouteAlgorithm routeAlgorithm, ExecutorService executor, int nuOfThreads){
return new BestInsertionConcurrent(routeAlgorithm, executor, nuOfThreads);
}
static class Batch {
List<VehicleRoute> routes = new ArrayList<VehicleRoute>();
}
private static Logger logger = Logger.getLogger(BestInsertionConcurrent.class);
private Random random = RandomNumberGeneration.getRandom();
private RouteAlgorithm routeAlgorithm;
// private ExecutorService executor;
private int nuOfBatches;
private ExecutorCompletionService<Insertion> completionService;
public void setRandom(Random random) {
this.random = random;
}
private BestInsertionConcurrent(RouteAlgorithm routeAlgorithm, ExecutorService executor, int nuOfThreads) {
super();
this.routeAlgorithm = routeAlgorithm;
// this.executor = executor;
logger.info("initialise " + this);
this.nuOfBatches = nuOfThreads;
completionService = new ExecutorCompletionService<Insertion>(executor);
}
@Override
public String toString() {
return "[name=concurrentBestInsertion]";
}
@Override
public void run(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs, double result2beat) {
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
Collections.shuffle(unassignedJobList, random);
informInsertionStarts(vehicleRoutes,unassignedJobs.size());
int inserted = 0;
for(final Job unassignedJob : unassignedJobList){
VehicleRoute insertIn = null;
Insertion bestInsertion = null;
double bestInsertionCost = Double.MAX_VALUE;
List<Batch> batches = distributeRoutes(vehicleRoutes,nuOfBatches);
for(final Batch batch : batches){
completionService.submit(new Callable<Insertion>() {
@Override
public Insertion call() throws Exception {
return getBestInsertion(batch,unassignedJob);
}
});
}
try{
for(int i=0;i<batches.size();i++){
Future<Insertion> futureIData = completionService.take();
Insertion insertion = futureIData.get();
if(insertion == null) continue;
if(insertion.getInsertionData().getInsertionCost() < bestInsertionCost){
bestInsertion = insertion;
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
}
}
}
catch(InterruptedException e){
Thread.currentThread().interrupt();
}
catch (ExecutionException e) {
e.printStackTrace();
logger.error(e.getCause().toString());
System.exit(1);
}
if(bestInsertion != null){
informBeforeJobInsertion(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
insertIn = bestInsertion.getRoute();
// logger.debug("insert job="+unassignedJob+" at index=" + bestInsertion.getInsertionData().getInsertionIndex() + " delta cost=" + bestInsertion.getInsertionData().getInsertionCost());
routeAlgorithm.insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
}
else {
// VehicleRoute newRoute = VehicleRoute.emptyRoute();
// InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE);
// if(bestI instanceof InsertionData.NoInsertionFound)
throw new IllegalStateException("given the vehicles, could not create a valid solution.\n\tthe reason might be" +
" inappropriate vehicle capacity.\n\tthe job that does not fit in any vehicle anymore is \n\t" + unassignedJob);
// insertIn = newRoute;
// informBeforeJobInsertion(unassignedJob,bestI,newRoute);
// routeAlgorithm.insertJob(unassignedJob,bestI,newRoute);
// vehicleRoutes.add(newRoute);
}
inserted++;
informJobInserted((unassignedJobList.size()-inserted), unassignedJob, insertIn);
}
informInsertionEndsListeners(vehicleRoutes);
}
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
Insertion bestInsertion = null;
double bestInsertionCost = Double.MAX_VALUE;
for(VehicleRoute vehicleRoute : batch.routes){
InsertionData iData = routeAlgorithm.calculateBestInsertion(vehicleRoute, unassignedJob, bestInsertionCost);
if(iData instanceof NoInsertionFound) continue;
if(iData.getInsertionCost() < bestInsertionCost){
bestInsertion = new Insertion(vehicleRoute,iData);
bestInsertionCost = iData.getInsertionCost();
}
}
return bestInsertion;
}
private List<Batch> distributeRoutes(Collection<VehicleRoute> vehicleRoutes, int nuOfBatches) {
List<Batch> batches = new ArrayList<Batch>();
for(int i=0;i<nuOfBatches;i++) batches.add(new Batch());
/*
* if route.size < nuOfBatches add as much routes as empty batches are available
* else add one empty route anyway
*/
// if(vehicleRoutes.size()<nuOfBatches){
// int nOfNewRoutes = nuOfBatches-vehicleRoutes.size();
// for(int i=0;i<nOfNewRoutes;i++){
// vehicleRoutes.add(VehicleRoute.emptyRoute());
//
//
///**
// *
// * @author stefan schroeder
// *
// */
//
//final class BestInsertionConcurrent implements InsertionStrategy{
//
// public static BestInsertionConcurrent newInstance(RouteAlgorithm routeAlgorithm, ExecutorService executor, int nuOfThreads){
// return new BestInsertionConcurrent(routeAlgorithm, executor, nuOfThreads);
// }
//
// static class Batch {
// List<VehicleRoute> routes = new ArrayList<VehicleRoute>();
//
// }
//
// private static Logger logger = Logger.getLogger(BestInsertionConcurrent.class);
//
// private Random random = RandomNumberGeneration.getRandom();
//
// private RouteAlgorithm routeAlgorithm;
//
//// private ExecutorService executor;
//
// private int nuOfBatches;
//
// private ExecutorCompletionService<Insertion> completionService;
//
// public void setRandom(Random random) {
// this.random = random;
// }
//
// private BestInsertionConcurrent(RouteAlgorithm routeAlgorithm, ExecutorService executor, int nuOfThreads) {
// super();
// this.routeAlgorithm = routeAlgorithm;
//// this.executor = executor;
// logger.info("initialise " + this);
// this.nuOfBatches = nuOfThreads;
// completionService = new ExecutorCompletionService<Insertion>(executor);
// }
//
// @Override
// public String toString() {
// return "[name=concurrentBestInsertion]";
// }
//
// @Override
// public void insertJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
// List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
// Collections.shuffle(unassignedJobList, random);
//// informInsertionStarts(vehicleRoutes,unassignedJobs.size());
// int inserted = 0;
// for(final Job unassignedJob : unassignedJobList){
// VehicleRoute insertIn = null;
// Insertion bestInsertion = null;
// double bestInsertionCost = Double.MAX_VALUE;
//
// List<Batch> batches = distributeRoutes(vehicleRoutes,nuOfBatches);
//
// for(final Batch batch : batches){
// completionService.submit(new Callable<Insertion>() {
//
// @Override
// public Insertion call() throws Exception {
// return getBestInsertion(batch,unassignedJob);
// }
//
// });
//
// }
//
// try{
// for(int i=0;i<batches.size();i++){
// Future<Insertion> futureIData = completionService.take();
// Insertion insertion = futureIData.get();
// if(insertion == null) continue;
// if(insertion.getInsertionData().getInsertionCost() < bestInsertionCost){
// bestInsertion = insertion;
// bestInsertionCost = insertion.getInsertionData().getInsertionCost();
// }
// }
// }
// catch(InterruptedException e){
// Thread.currentThread().interrupt();
// }
// catch (ExecutionException e) {
// e.printStackTrace();
// logger.error(e.getCause().toString());
// System.exit(1);
// }
//
// if(bestInsertion != null){
//// informBeforeJobInsertion(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
// insertIn = bestInsertion.getRoute();
//// logger.debug("insert job="+unassignedJob+" at index=" + bestInsertion.getInsertionData().getInsertionIndex() + " delta cost=" + bestInsertion.getInsertionData().getInsertionCost());
// routeAlgorithm.insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
// }
// else {
//// VehicleRoute newRoute = VehicleRoute.emptyRoute();
//// InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE);
//// if(bestI instanceof InsertionData.NoInsertionFound)
// throw new IllegalStateException("given the vehicles, could not create a valid solution.\n\tthe reason might be" +
// " inappropriate vehicle capacity.\n\tthe job that does not fit in any vehicle anymore is \n\t" + unassignedJob);
//// insertIn = newRoute;
//// informBeforeJobInsertion(unassignedJob,bestI,newRoute);
//// routeAlgorithm.insertJob(unassignedJob,bestI,newRoute);
//// vehicleRoutes.add(newRoute);
// }
// inserted++;
//// informJobInserted((unassignedJobList.size()-inserted), unassignedJob, insertIn);
// }
//// informInsertionEndsListeners(vehicleRoutes);
// }
//
// private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
// Insertion bestInsertion = null;
// double bestInsertionCost = Double.MAX_VALUE;
// for(VehicleRoute vehicleRoute : batch.routes){
// InsertionData iData = routeAlgorithm.calculateBestInsertion(vehicleRoute, unassignedJob, bestInsertionCost);
// if(iData instanceof NoInsertionFound) continue;
// if(iData.getInsertionCost() < bestInsertionCost){
// bestInsertion = new Insertion(vehicleRoute,iData);
// bestInsertionCost = iData.getInsertionCost();
// }
// }
// else{
vehicleRoutes.add(VehicleRoute.emptyRoute());
// return bestInsertion;
// }
//
// private List<Batch> distributeRoutes(Collection<VehicleRoute> vehicleRoutes, int nuOfBatches) {
// List<Batch> batches = new ArrayList<Batch>();
// for(int i=0;i<nuOfBatches;i++) batches.add(new Batch());
// /*
// * if route.size < nuOfBatches add as much routes as empty batches are available
// * else add one empty route anyway
// */
//// if(vehicleRoutes.size()<nuOfBatches){
//// int nOfNewRoutes = nuOfBatches-vehicleRoutes.size();
//// for(int i=0;i<nOfNewRoutes;i++){
//// vehicleRoutes.add(VehicleRoute.emptyRoute());
//// }
//// }
//// else{
// vehicleRoutes.add(VehicleRoute.emptyRoute());
//// }
// /*
// * distribute routes to batches equally
// */
// int count = 0;
// for(VehicleRoute route : vehicleRoutes){
// if(count == nuOfBatches) count=0;
// batches.get(count).routes.add(route);
// count++;
// }
/*
* distribute routes to batches equally
*/
int count = 0;
for(VehicleRoute route : vehicleRoutes){
if(count == nuOfBatches) count=0;
batches.get(count).routes.add(route);
count++;
}
return batches;
}
@Override
public RouteAlgorithm getRouteAlgorithm() {
return routeAlgorithm;
}
}
// return batches;
// }
//
//
// @Override
// public void removeListener(InsertionListener insertionListener) {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// public Collection<InsertionListener> getListeners() {
// // TODO Auto-generated method stub
// return null;
// }
//
// @Override
// public void addListener(InsertionListener insertionListener) {
// // TODO Auto-generated method stub
//
// }
//
//}

View file

@ -0,0 +1,14 @@
package algorithms;
import basics.route.TourActivity;
class CalcUtils {
static double getStartTimeAtAct(double startTimeAtPrevAct, double tpTime_prevAct_nextAct, TourActivity nextAct){
return Math.max(startTimeAtPrevAct + tpTime_prevAct_nextAct, nextAct.getTheoreticalEarliestOperationStartTime()) + nextAct.getOperationTime();
}
static double getStartTimeAtAct(double nextActArrTime, TourActivity nextAct){
return Math.max(nextActArrTime, nextAct.getTheoreticalEarliestOperationStartTime()) + nextAct.getOperationTime();
}
}

View file

@ -1,107 +0,0 @@
/*******************************************************************************
* Copyright (c) 2011 Stefan Schroeder.
* eMail: stefan.schroeder@kit.edu
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/
package algorithms;
import org.apache.log4j.Logger;
import algorithms.RouteStates.ActivityState;
import basics.costs.VehicleRoutingActivityCosts;
import basics.costs.VehicleRoutingTransportCosts;
import basics.route.Driver;
import basics.route.End;
import basics.route.Start;
import basics.route.TourActivity;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
final class CalculatesActivityInsertionWithHardTimeWindows {
private static Logger logger = Logger.getLogger(CalculatesActivityInsertionWithHardTimeWindows.class);
private RouteStates routeStates;
private VehicleRoutingTransportCosts routingCosts;
private VehicleRoutingActivityCosts activityCosts;
public CalculatesActivityInsertionWithHardTimeWindows(RouteStates activityStates, VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts){
this.routeStates = activityStates;
this.routingCosts = routingCosts;
this.activityCosts = activityCosts;
logger.info("initialise " + this);
}
public double calculate(VehicleRoute vehicleRoute, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle) {
boolean prevIsStart = false;
if(prevAct instanceof Start){
prevIsStart = true;
}
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
double newAct_arrTime = prevAct.getEndTime() + tp_time_prevAct_newAct;
double newAct_operationStartTime = Math.max(newAct_arrTime, newAct.getTheoreticalEarliestOperationStartTime());
double newAct_endTime = newAct_operationStartTime + newAct.getOperationTime();
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, driver, vehicle);
double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle);
double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle);
double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct;
double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, driver, vehicle);
double activityInsertionCosts;
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct;
if(nextAct_arrTime > getLatestOperationStart(nextAct)){
activityInsertionCosts = Double.MAX_VALUE;
}
else if(vehicleRoute.isEmpty()){
activityInsertionCosts = totalCosts;
}
else{
double oldCostOfPrevAct;
if(prevIsStart) oldCostOfPrevAct = 0.0;
else oldCostOfPrevAct = state(prevAct).getCurrentCost();
double oldCostOfNextAct;
if(nextAct instanceof End) oldCostOfNextAct = routeStates.getRouteState(vehicleRoute).getCosts();
else oldCostOfNextAct = state(nextAct).getCurrentCost();
activityInsertionCosts = (totalCosts) - (oldCostOfNextAct-oldCostOfPrevAct);
}
return activityInsertionCosts;
}
private ActivityState state(TourActivity act) {
return routeStates.getState(act);
}
private double getLatestOperationStart(TourActivity act) {
if(state(act) != null){
return state(act).getLatestOperationStart();
}
return act.getTheoreticalLatestOperationStartTime();
}
@Override
public String toString() {
return "[name=calculatesHardTimeWindowActivityInsertion]";
}
}

View file

@ -15,37 +15,27 @@ package algorithms;
import org.apache.log4j.Logger;
import util.Neighborhood;
import algorithms.RouteStates.ActivityState;
import algorithms.HardConstraints.HardRouteLevelConstraint;
import algorithms.MarginalsCalculus.Marginals;
import basics.Job;
import basics.Service;
import basics.costs.VehicleRoutingActivityCosts;
import basics.costs.VehicleRoutingTransportCosts;
import basics.route.Driver;
import basics.route.End;
import basics.route.ServiceActivity;
import basics.route.Start;
import basics.route.TourActivities;
import basics.route.TourActivity;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
import basics.route.VehicleImpl.NoVehicle;
import basics.route.VehicleRoute;
final class CalculatesServiceInsertion implements JobInsertionCalculator{
private static final Logger logger = Logger.getLogger(CalculatesServiceInsertion.class);
private RouteStates routeStates;
private VehicleRoutingTransportCosts routingCosts;
private VehicleRoutingActivityCosts activityCosts;
private Start start;
private End end;
private HardRouteLevelConstraint hardRouteLevelConstraint;
private Neighborhood neighborhood = new Neighborhood() {
@ -55,25 +45,20 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{
}
};
private MarginalsCalculus marginalCalculus;
private VehicleRoutingTransportCosts transportCosts;
public void setNeighborhood(Neighborhood neighborhood) {
this.neighborhood = neighborhood;
logger.info("initialise neighborhood " + neighborhood);
}
public void setActivityStates(RouteStates actStates){
this.routeStates = actStates;
}
public ActivityState state(TourActivity act){
return routeStates.getState(act);
}
public CalculatesServiceInsertion(VehicleRoutingTransportCosts vehicleRoutingTransportCosts, VehicleRoutingActivityCosts vehicleRoutingActivityCosts) {
public CalculatesServiceInsertion(VehicleRoutingTransportCosts routingCosts, MarginalsCalculus marginalsCalculus, HardRouteLevelConstraint hardRouteLevelConstraint) {
super();
this.routingCosts = vehicleRoutingTransportCosts;
this.activityCosts = vehicleRoutingActivityCosts;
this.marginalCalculus = marginalsCalculus;
this.hardRouteLevelConstraint = hardRouteLevelConstraint;
this.transportCosts = routingCosts;
logger.info("initialise " + this);
}
@ -92,42 +77,53 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{
if(jobToInsert == null) throw new IllegalStateException("jobToInsert is missing.");
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("newVehicle is missing.");
TourActivities tour = currentRoute.getTourActivities();
double bestCost = bestKnownCosts;
Service service = (Service)jobToInsert;
if(routeStates.getRouteState(currentRoute).getLoad() + service.getCapacityDemand() > newVehicle.getCapacity()){
InsertionContext insertionContext = new InsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
return InsertionData.noInsertionFound();
}
double bestCost = bestKnownCosts;
Marginals bestMarginals = null;
Service service = (Service)jobToInsert;
int insertionIndex = InsertionData.NO_INDEX;
TourActivity deliveryAct2Insert = ServiceActivity.newInstance(service);
// TourActivity deliveryAct2Insert = actStates.getActivity(service, true);
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime);
Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
start.setEndTime(newVehicleDepartureTime);
End end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
TourActivity prevAct = start;
double prevCostInOriginalTour = 0.0;
double prevActStartTime = newVehicleDepartureTime;
int actIndex = 0;
for(TourActivity nextAct : tour.getActivities()){
double nextCostInOriginalTour = state(nextAct).getCurrentCost();
for(TourActivity nextAct : currentRoute.getTourActivities().getActivities()){
if(deliveryAct2Insert.getTheoreticalLatestOperationStartTime() < prevAct.getTheoreticalEarliestOperationStartTime()){
break;
}
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
double mc = calculate(tour, prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, nextCostInOriginalTour - prevCostInOriginalTour);
if(mc < bestCost){
bestCost = mc;
insertionIndex = actIndex;
Marginals mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
if(mc != null){
if(mc.getAdditionalCosts() < bestCost){
bestCost = mc.getAdditionalCosts();
bestMarginals = mc;
insertionIndex = actIndex;
}
}
}
prevCostInOriginalTour = nextCostInOriginalTour;
prevAct = nextAct;
prevActStartTime = CalcUtils.getStartTimeAtAct(prevActStartTime, transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActStartTime, newDriver, newVehicle), nextAct);
actIndex++;
}
End nextAct = end;
if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
double mc = calculate(tour, prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, routeStates.getRouteState(currentRoute).getCosts() - prevCostInOriginalTour);
if(mc < bestCost){
bestCost = mc;
insertionIndex = actIndex;
Marginals mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
if(mc != null) {
if(mc.getAdditionalCosts() < bestCost){
bestCost = mc.getAdditionalCosts();
bestMarginals = mc;
insertionIndex = actIndex;
}
}
}
@ -136,74 +132,12 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{
}
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
insertionData.setAdditionalTime(bestMarginals.getAdditionalTime());
return insertionData;
}
private void initialiseStartAndEnd(final Vehicle newVehicle,
double newVehicleDepartureTime) {
if(start == null){
start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
start.setEndTime(newVehicleDepartureTime);
}
else{
start.setLocationId(newVehicle.getLocationId());
start.setTheoreticalEarliestOperationStartTime(newVehicle.getEarliestDeparture());
start.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
start.setEndTime(newVehicleDepartureTime);
}
public Marginals calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double departureTimeAtPrevAct) {
return marginalCalculus.calculate(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct);
if(end == null){
end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
}
else{
end.setLocationId(newVehicle.getLocationId());
end.setTheoreticalEarliestOperationStartTime(newVehicleDepartureTime);
end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
}
}
public double calculate(TourActivities tour, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle, double bestKnownCosts, double costWithoutNewJob) {
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle);
double newAct_arrTime = prevAct.getEndTime() + tp_time_prevAct_newAct;
double newAct_operationStartTime = Math.max(newAct_arrTime, newAct.getTheoreticalEarliestOperationStartTime());
double newAct_endTime = newAct_operationStartTime + newAct.getOperationTime();
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, driver, vehicle);
if((tp_costs_prevAct_newAct + act_costs_newAct - costWithoutNewJob) > bestKnownCosts){
return Double.MAX_VALUE;
}
double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle);
double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle);
double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct;
double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, driver, vehicle);
double activityInsertionCosts;
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct;
if(totalCosts - costWithoutNewJob > bestKnownCosts){
activityInsertionCosts = Double.MAX_VALUE;
}
if(nextAct_arrTime > getLatestOperationStart(nextAct)){
activityInsertionCosts = Double.MAX_VALUE;
}
else{
activityInsertionCosts = totalCosts - costWithoutNewJob;
}
return activityInsertionCosts;
}
private double getLatestOperationStart(TourActivity act) {
if(state(act) != null){
return state(act).getLatestOperationStart();
}
return act.getTheoreticalLatestOperationStartTime();
}
}

View file

@ -23,6 +23,8 @@ package algorithms;
import org.apache.log4j.Logger;
import algorithms.InsertionData.NoInsertionFound;
import algorithms.StateManager.State;
import algorithms.StateManager.States;
import basics.Job;
import basics.route.Driver;
import basics.route.Vehicle;
@ -41,12 +43,12 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion
private double solution_completeness_ratio = 0.5;
private RouteStates routeStates;
private StateManager states;
public CalculatesServiceInsertionConsideringFixCost(final JobInsertionCalculator standardInsertionCalculator, RouteStates routeStates) {
public CalculatesServiceInsertionConsideringFixCost(final JobInsertionCalculator standardInsertionCalculator, StateManager activityStates2) {
super();
this.standardServiceInsertion = standardInsertionCalculator;
this.routeStates = routeStates;
this.states = activityStates2;
logger.info("inialise " + this);
}
@ -84,7 +86,7 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion
}
private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job) {
double load = routeStates.getRouteState(route).getLoad() + job.getCapacityDemand();
double load = getCurrentLoad(route) + job.getCapacityDemand();
double currentFix = 0.0;
if(route.getVehicle() != null){
if(!(route.getVehicle() instanceof NoVehicle)){
@ -98,7 +100,7 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion
}
private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job) {
int currentLoad = routeStates.getRouteState(route).getLoad();
int currentLoad = getCurrentLoad(route);
double load = currentLoad + job.getCapacityDemand();
double currentRelFix = 0.0;
if(route.getVehicle() != null){
@ -113,4 +115,8 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion
return relativeFixCost;
}
private int getCurrentLoad(VehicleRoute route) {
return (int) states.getRouteState(route, StateTypes.LOAD).toDouble();
}
}

View file

@ -31,6 +31,7 @@ import basics.costs.VehicleRoutingActivityCosts;
import basics.costs.VehicleRoutingTransportCosts;
import basics.route.Driver;
import basics.route.End;
import basics.route.ServiceActivity;
import basics.route.Start;
import basics.route.TourActivities;
import basics.route.TourActivity;
@ -50,7 +51,7 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
private AuxilliaryCostCalculator auxilliaryPathCostCalculator;
private RouteStates routeStates;
private StateManager states;
private int nuOfActsForwardLooking = 0;
@ -89,14 +90,10 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
logger.info("initialise " + this);
}
public void setActivityStates(RouteStates actStates){
this.routeStates = actStates;
}
public ActivityState state(TourActivity act){
return routeStates.getState(act);
public void setStates(StateManager activityStates2){
this.states = activityStates2;
}
void setNuOfActsForwardLooking(int nOfActsForwardLooking) {
this.nuOfActsForwardLooking = nOfActsForwardLooking;
@ -138,14 +135,14 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
/**
* pre-check whether vehicle-capacity of new vehicle is sufficient to load service.
*/
if(routeStates.getRouteState(currentRoute).getLoad() + service.getCapacityDemand() > newVehicle.getCapacity()){
if(states.getRouteState(currentRoute, StateTypes.LOAD).toDouble() + service.getCapacityDemand() > newVehicle.getCapacity()){
return InsertionData.noInsertionFound();
}
/**
* some inis
*/
TourActivity serviceAct2Insert = routeStates.getActivity(service, true);
TourActivity serviceAct2Insert = ServiceActivity.newInstance(service);
int best_insertion_index = InsertionData.NO_INDEX;
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime);
@ -245,6 +242,14 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
*
*/
if(memorySize==0){
InsertionData insertion = bestInsertionsQueue.poll();
if(insertion != null){
best_insertion_index = insertion.getDeliveryInsertionIndex();
best_insertion_costs = insertion.getInsertionCost();
}
}
for(int i=0;i<memorySize;i++){
InsertionData data = bestInsertionsQueue.poll();
if(data == null){
@ -262,7 +267,7 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
/**
* compute cost-diff of tour with and without new activity --> insertion_costs
*/
double insertion_costs = auxilliaryPathCostCalculator.costOfPath(wholeTour, start.getEndTime(), newDriver, newVehicle) - routeStates.getRouteState(currentRoute).getCosts();
double insertion_costs = auxilliaryPathCostCalculator.costOfPath(wholeTour, start.getEndTime(), newDriver, newVehicle) - states.getRouteState(currentRoute,StateTypes.COSTS).toDouble();
/**
* if better than best known, make it the best known
@ -307,9 +312,9 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul
private double pathCost_oldVehicle(VehicleRoute vehicleRoute, List<TourActivity> path) {
TourActivity act = path.get(path.size()-1);
if(act instanceof End){
return routeStates.getRouteState(vehicleRoute).getCosts();
return states.getRouteState(vehicleRoute,StateTypes.COSTS).toDouble();
}
return state(act).getCurrentCost();
return states.getActivityState(act,StateTypes.COSTS).toDouble();
}
/**

View file

@ -67,16 +67,7 @@ final class CalculatesVehTypeDepServiceInsertion implements JobInsertionCalculat
else{
relevantVehicles.addAll(fleetManager.getAvailableVehicles());
}
//
// for(TypeKey typeKey : fleetManager.getAvailableVehicleTypes()){
// if(!(currentRoute.getVehicle() instanceof NoVehicle)){
// TypeKey key = makeTypeKey(currentRoute.getVehicle().getType(),currentRoute.getVehicle().getLocationId());
// if(typeKey.equals(key)){
// continue;
// }
// }
// relevantVehicles.add(fleetManager.getEmptyVehicle(typeKey));
// }
for(Vehicle v : relevantVehicles){
double depTime = v.getEarliestDeparture();
InsertionData iData = insertionCalculator.calculate(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
@ -92,8 +83,4 @@ final class CalculatesVehTypeDepServiceInsertion implements JobInsertionCalculat
return bestIData;
}
// private TypeKey makeTypeKey(VehicleType type, String locationId) {
// return new TypeKey(type,locationId);
// }
}

View file

@ -22,18 +22,10 @@ package algorithms;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.commons.configuration.XMLConfiguration;
import util.NeighborhoodImpl;
import basics.VehicleRoutingProblem;
import basics.VehicleRoutingProblem.FleetComposition;
import basics.algo.InsertionListener;
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
import basics.algo.VehicleRoutingAlgorithmListeners.Priority;
import basics.costs.VehicleRoutingActivityCosts;
@ -70,7 +62,7 @@ class CalculatorBuilder {
private VehicleRoutingProblem vrp;
private RouteStates activityStates;
private StateManager states;
private boolean local = true;
@ -107,12 +99,12 @@ class CalculatorBuilder {
/**
* Sets activityStates. MUST be set.
* @param states TODO
*
* @param activityStates
* @return
*/
public CalculatorBuilder setActivityStates(RouteStates activityStates){
this.activityStates = activityStates;
public CalculatorBuilder setStates(StateManager states){
this.states = states;
return this;
}
@ -184,21 +176,21 @@ class CalculatorBuilder {
*/
public JobInsertionCalculator build(){
if(vrp == null) throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))");
if(activityStates == null) throw new IllegalStateException("activity states is null, but is must be set (this.setActivityStates(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))");
JobInsertionCalculator baseCalculator = null;
CalculatorPlusListeners standardLocal = null;
if(local){
standardLocal = createStandardLocal(vrp, activityStates);
standardLocal = createStandardLocal(vrp, states);
}
else{
standardLocal = createStandardRoute(vrp, activityStates,forwardLooking,memory);
standardLocal = createStandardRoute(vrp, states,forwardLooking,memory);
}
baseCalculator = standardLocal.getCalculator();
addAlgorithmListeners(standardLocal.getAlgorithmListener());
addInsertionListeners(standardLocal.getInsertionListener());
if(considerFixedCost){
CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, activityStates, weightOfFixedCost);
CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost);
baseCalculator = withFixed.getCalculator();
addAlgorithmListeners(withFixed.getAlgorithmListener());
addInsertionListeners(withFixed.getInsertionListener());
@ -206,7 +198,7 @@ class CalculatorBuilder {
if(timeScheduling){
baseCalculator = new CalculatesServiceInsertionWithTimeScheduling(baseCalculator,timeSlice,neighbors);
}
return createFinalInsertion(fleetManager, baseCalculator, activityStates);
return createFinalInsertion(fleetManager, baseCalculator, states);
}
private void addInsertionListeners(List<InsertionListener> list) {
@ -221,35 +213,36 @@ class CalculatorBuilder {
}
}
private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, RouteStates activityStates){
JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), vrp.getActivityCosts());
((CalculatesServiceInsertion) standardServiceInsertion).setActivityStates(activityStates);
private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, StateManager activityStates2){
MarginalsCalculus defaultCalc = new MarginalsCalculusTriangleInequality(vrp.getTransportCosts(), vrp.getActivityCosts(), new HardConstraints.HardTimeWindowConstraint(activityStates2) );
JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), defaultCalc, new HardConstraints.HardLoadConstraint(activityStates2));
((CalculatesServiceInsertion) standardServiceInsertion).setNeighborhood(vrp.getNeighborhood());
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(standardServiceInsertion);
return calcPlusListeners;
}
private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCalculator baseCalculator, RouteStates activityStates, double weightOfFixedCosts){
final CalculatesServiceInsertionConsideringFixCost withFixCost = new CalculatesServiceInsertionConsideringFixCost(baseCalculator, activityStates);
private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCalculator baseCalculator, StateManager activityStates2, double weightOfFixedCosts){
final CalculatesServiceInsertionConsideringFixCost withFixCost = new CalculatesServiceInsertionConsideringFixCost(baseCalculator, activityStates2);
withFixCost.setWeightOfFixCost(weightOfFixedCosts);
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost);
calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost));
return calcPlusListeners;
}
private CalculatorPlusListeners createStandardRoute(VehicleRoutingProblem vrp, RouteStates activityStates, int forwardLooking, int solutionMemory){
private CalculatorPlusListeners createStandardRoute(VehicleRoutingProblem vrp, StateManager activityStates2, int forwardLooking, int solutionMemory){
int after = forwardLooking;
JobInsertionCalculator jobInsertionCalculator = new CalculatesServiceInsertionOnRouteLevel(vrp.getTransportCosts(), vrp.getActivityCosts());
((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setNuOfActsForwardLooking(after);
((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setMemorySize(solutionMemory);
((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setNeighborhood(vrp.getNeighborhood());
((CalculatesServiceInsertionOnRouteLevel) jobInsertionCalculator).setActivityStates(activityStates);
((CalculatesServiceInsertionOnRouteLevel) jobInsertionCalculator).setStates(activityStates2);
CalculatorPlusListeners calcPlusListener = new CalculatorPlusListeners(jobInsertionCalculator);
return calcPlusListener;
}
private JobInsertionCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCalculator baseCalc, RouteStates routeStates){
private JobInsertionCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCalculator baseCalc, StateManager activityStates2){
return new CalculatesVehTypeDepServiceInsertion(fleetManager, baseCalc);
}

View file

@ -42,6 +42,8 @@ final class ConfigureFixCostCalculator implements InsertionStartsListener, JobIn
VehicleRoutingProblem vrp;
CalculatesServiceInsertionConsideringFixCost calcConsideringFix;
private int nuOfJobsToRecreate;
public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, CalculatesServiceInsertionConsideringFixCost calcConsideringFix) {
super();
@ -55,15 +57,17 @@ final class ConfigureFixCostCalculator implements InsertionStartsListener, JobIn
}
@Override
public void informInsertionStarts(Collection<VehicleRoute> routes, int nOfJobs2Recreate) {
double completenessRatio = (1-((double)nOfJobs2Recreate/(double)vrp.getJobs().values().size()));
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
this.nuOfJobsToRecreate = unassignedJobs.size();
double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)vrp.getJobs().values().size()));
calcConsideringFix.setSolutionCompletenessRatio(completenessRatio);
// log.debug("initialise completenessRatio to " + completenessRatio);
}
@Override
public void informJobInserted(int nOfJobsStill2Recreate, Job job2insert, VehicleRoute insertedIn) {
double completenessRatio = (1-((double)nOfJobsStill2Recreate/(double)vrp.getJobs().values().size()));
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
nuOfJobsToRecreate--;
double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)vrp.getJobs().values().size()));
calcConsideringFix.setSolutionCompletenessRatio(completenessRatio);
// log.debug("set completenessRatio to " + completenessRatio);
}

View file

@ -51,7 +51,7 @@ final class CreateInitialSolution implements InitialSolutionFactory {
private static final Logger logger = Logger.getLogger(CreateInitialSolution.class);
private final AbstractInsertionStrategy insertion;
private final InsertionStrategy insertion;
private boolean generateAsMuchAsRoutesAsVehiclesExist = false;
@ -59,9 +59,9 @@ final class CreateInitialSolution implements InitialSolutionFactory {
this.generateAsMuchAsRoutesAsVehiclesExist = generateAsMuchAsRoutesAsVehiclesExist;
}
public CreateInitialSolution(AbstractInsertionStrategy insertion) {
public CreateInitialSolution(InsertionStrategy insertionStrategy) {
super();
this.insertion = insertion;
this.insertion = insertionStrategy;
}
@Override
@ -73,7 +73,7 @@ final class CreateInitialSolution implements InitialSolutionFactory {
vehicleRoutes.add(VehicleRoute.newInstance(TourActivities.emptyTour(), DriverImpl.noDriver(), vehicle));
}
}
insertion.run(vehicleRoutes, getUnassignedJobs(vrp), Double.MAX_VALUE);
insertion.insertJobs(vehicleRoutes, getUnassignedJobs(vrp));
double totalCost = getTotalCost(vehicleRoutes);
logger.info("creation done");
return new VehicleRoutingProblemSolution(vehicleRoutes, totalCost);

View file

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import basics.Job;
import basics.algo.InsertionStartsListener;
import basics.route.VehicleRoute;
@ -37,7 +38,7 @@ class FindCheaperVehicle implements InsertionStartsListener{
}
@Override
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2Recreate) {
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
List<VehicleRoute> newRoutes = new ArrayList<VehicleRoute>();
for(VehicleRoute route : vehicleRoutes){
if(route.isEmpty()) continue;

View file

@ -106,7 +106,7 @@ final class FindCheaperVehicleAlgo {
throw new IllegalStateException(e);
}
TourActivities newTour = TourActivities.copyOf(vehicleRoute.getTourActivities());
tourStateCalculator.updateRoute(vehicleRoute);
tourStateCalculator.iterate(vehicleRoute);
return VehicleRoute.newInstance(newTour,vehicleRoute.getDriver(),bestVehicle);
}
return vehicleRoute;

View file

@ -0,0 +1,41 @@
package algorithms;
import java.util.ArrayList;
import java.util.Collection;
import basics.route.End;
import basics.route.Start;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
class ForwardInTimeListeners {
interface ForwardInTimeListener{
public void start(VehicleRoute route, Start start, double departureTime);
public void nextActivity(TourActivity act, double arrTime,double endTime);
public void end(End end, double arrivalTime);
}
private Collection<ForwardInTimeListener> listeners = new ArrayList<ForwardInTimeListeners.ForwardInTimeListener>();
public void addListener(ForwardInTimeListener l){
listeners.add(l);
}
public void start(VehicleRoute route, Start start, double departureTime){
for(ForwardInTimeListener l : listeners){ l.start(route, start, departureTime); }
}
public void nextActivity(TourActivity act, double arrTime, double endTime){
for(ForwardInTimeListener l : listeners){ l.nextActivity(act,arrTime,endTime); }
}
public void end(End end, double arrivalTime){
for(ForwardInTimeListener l : listeners){ l.end(end, arrivalTime); }
}
}

View file

@ -21,6 +21,7 @@
package algorithms;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@ -30,20 +31,19 @@ import java.util.Set;
import org.apache.log4j.Logger;
import util.RandomNumberGeneration;
import basics.Job;
import basics.VehicleRoutingProblem;
import basics.VehicleRoutingProblemSolution;
import basics.algo.SearchStrategyModule;
import basics.algo.SearchStrategyModuleListener;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
import basics.route.TourActivity.JobActivity;
import basics.route.VehicleRoute;
import util.RandomNumberGeneration;
final class Gendreau implements SearchStrategyModule{
final class GendreauPostOpt implements SearchStrategyModule{
private final static Logger log = Logger.getLogger(GendreauPostOpt.class);
private final static Logger log = Logger.getLogger(Gendreau.class);
private final static String NAME = "gendreauPostOpt";
@ -51,9 +51,9 @@ final class GendreauPostOpt implements SearchStrategyModule{
private final VehicleRoutingProblem vrp;
private final AbstractInsertionStrategy insertionStrategy;
private final InsertionStrategy insertionStrategy;
private final RouteAlgorithm routeAlgorithm;
private final Inserter inserter;
private VehicleFleetManager fleetManager;
@ -67,9 +67,11 @@ final class GendreauPostOpt implements SearchStrategyModule{
this.shareOfJobsToRuin = shareOfJobsToRuin;
}
public GendreauPostOpt(VehicleRoutingProblem vrp, RuinStrategy ruin, AbstractInsertionStrategy insertionStrategy) {
public Gendreau(VehicleRoutingProblem vrp, RuinStrategy ruin, InsertionStrategy insertionStrategy) {
super();
this.routeAlgorithm = insertionStrategy.getRouteAlgorithm();
InsertionListeners insertionListeners = new InsertionListeners();
insertionListeners.addAllListeners(insertionStrategy.getListeners());
inserter = new Inserter(insertionListeners);
this.ruin = ruin;
this.vrp = vrp;
this.insertionStrategy = insertionStrategy;
@ -77,7 +79,7 @@ final class GendreauPostOpt implements SearchStrategyModule{
@Override
public String toString() {
return "[name=gendreauPostOpt][iterations="+nOfIterations+"][share2ruin="+shareOfJobsToRuin+"]";
return "[name=gendreau][iterations="+nOfIterations+"][share2ruin="+shareOfJobsToRuin+"]";
}
public void setRandom(Random random) {
@ -119,16 +121,18 @@ final class GendreauPostOpt implements SearchStrategyModule{
VehicleRoute emptyRoute1 = VehicleRoute.emptyRoute();
copiedRoutes.add(emptyRoute1);
routeAlgorithm.insertJob(targetJob, routeAlgorithm.calculateBestInsertion(emptyRoute1, targetJob, Double.MAX_VALUE), emptyRoute1);
insertionStrategy.insertJobs(Arrays.asList(emptyRoute1), Arrays.asList(targetJob));
// routeAlgorithm.insertJob(targetJob, routeAlgorithm.calculateBestInsertion(emptyRoute1, targetJob, Double.MAX_VALUE), emptyRoute1);
unassignedJobs.remove(targetJob);
VehicleRoute emptyRoute2 = VehicleRoute.emptyRoute();
copiedRoutes.add(emptyRoute2);
Job job2 = jobsInRoute.get(1);
routeAlgorithm.insertJob(job2, routeAlgorithm.calculateBestInsertion(emptyRoute2, job2, Double.MAX_VALUE), emptyRoute2);
insertionStrategy.insertJobs(Arrays.asList(emptyRoute2), Arrays.asList(job2));
// routeAlgorithm.insertJob(job2, routeAlgorithm.calculateBestInsertion(emptyRoute2, job2, Double.MAX_VALUE), emptyRoute2);
unassignedJobs.remove(job2);
insertionStrategy.run(copiedRoutes, unassignedJobs, Double.MAX_VALUE);
insertionStrategy.insertJobs(copiedRoutes, unassignedJobs);
double cost = getCost(copiedRoutes);
if(cost < bestSolution.getCost()){

View file

@ -0,0 +1,59 @@
package algorithms;
import basics.Service;
import basics.route.TourActivity;
class HardConstraints {
interface HardRouteLevelConstraint {
public boolean fulfilled(InsertionContext insertionContext);
}
interface HardActivityLevelConstraint {
public boolean fulfilled(InsertionContext iFacts, TourActivity act, double arrTime);
}
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;
}
}
static class HardTimeWindowConstraint implements HardActivityLevelConstraint {
private StateManager states;
public HardTimeWindowConstraint(StateManager states) {
super();
this.states = states;
}
@Override
public boolean fulfilled(InsertionContext iFacts, TourActivity act, double arrTime) {
if(arrTime > states.getActivityState(act, StateTypes.LATEST_OPERATION_START_TIME).toDouble()){
return false;
}
return true;
}
}
}

View file

@ -0,0 +1,36 @@
package algorithms;
import algorithms.InsertionData.NoInsertionFound;
import basics.Job;
import basics.Service;
import basics.route.ServiceActivity;
import basics.route.VehicleRoute;
class Inserter {
private InsertionListeners insertionListeners;
public Inserter(InsertionListeners insertionListeners) {
this.insertionListeners = insertionListeners;
}
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute){
insertionListeners.informBeforeJobInsertion(job, insertionData, vehicleRoute);
if(insertionData == null || (insertionData instanceof NoInsertionFound)) throw new IllegalStateException("insertionData null. cannot insert job.");
if(job == null) throw new IllegalStateException("cannot insert null-job");
if(!(vehicleRoute.getVehicle().getId().toString().equals(insertionData.getSelectedVehicle().getId().toString()))){
insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle());
vehicleRoute.setVehicle(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
}
// if(vehicleRoute.getDepartureTime() != vehicleRoute.g)
if(job instanceof Service) {
vehicleRoute.getTourActivities().addActivity(insertionData.getDeliveryInsertionIndex(), ServiceActivity.newInstance((Service)job));
vehicleRoute.setDepartureTime(insertionData.getVehicleDepartureTime());
}
else throw new IllegalStateException("neither service nor shipment. this is not supported.");
insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime());
// updateTour(vehicleRoute);
}
}

View file

@ -0,0 +1,63 @@
package algorithms;
import basics.Job;
import basics.route.Driver;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
class InsertionContext {
private VehicleRoute route;
private Job job;
private Vehicle newVehicle;
private Driver newDriver;
private double newDepTime;
/**
* @return the route
*/
public VehicleRoute getRoute() {
return route;
}
/**
* @return the job
*/
public Job getJob() {
return job;
}
/**
* @return the newVehicle
*/
public Vehicle getNewVehicle() {
return newVehicle;
}
/**
* @return the newDriver
*/
public Driver getNewDriver() {
return newDriver;
}
/**
* @return the newDepTime
*/
public double getNewDepTime() {
return newDepTime;
}
public InsertionContext(VehicleRoute route, Job job, Vehicle newVehicle,
Driver newDriver, double newDepTime) {
super();
this.route = route;
this.job = job;
this.newVehicle = newVehicle;
this.newDriver = newDriver;
this.newDepTime = newDepTime;
}
}

View file

@ -55,6 +55,22 @@ class InsertionData {
private double departureTime;
private double additionalTime;
/**
* @return the additionalTime
*/
public double getAdditionalTime() {
return additionalTime;
}
/**
* @param additionalTime the additionalTime to set
*/
public void setAdditionalTime(double additionalTime) {
this.additionalTime = additionalTime;
}
public InsertionData(double insertionCost, int pickupInsertionIndex, int deliveryInsertionIndex, Vehicle vehicle, Driver driver){
this.insertionCost = insertionCost;
this.pickupInsertionIndex = pickupInsertionIndex;

View file

@ -37,8 +37,8 @@ class InsertionFactory {
private static Logger log = Logger.getLogger(InsertionFactory.class);
public static AbstractInsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config,
VehicleFleetManager vehicleFleetManager, RouteStates activityStates, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads){
public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config,
VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads){
boolean concurrentInsertion = false;
if(executorService != null) concurrentInsertion = true;
if(config.containsKey("[@name]")){
@ -46,12 +46,12 @@ class InsertionFactory {
if(!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion")){
new IllegalStateException(insertionName + " is not supported. use either \"bestInsertion\" or \"regretInsertion\"");
}
AbstractInsertionStrategy insertionStrategy = null;
InsertionStrategy insertionStrategy = null;
List<InsertionListener> insertionListeners = new ArrayList<InsertionListener>();
List<PrioritizedVRAListener> algoListeners = new ArrayList<PrioritizedVRAListener>();
CalculatorBuilder calcBuilder = new CalculatorBuilder(insertionListeners, algorithmListeners);
calcBuilder.setActivityStates(activityStates);
calcBuilder.setStates(routeStates);
calcBuilder.setVehicleRoutingProblem(vrp);
calcBuilder.setVehicleFleetManager(vehicleFleetManager);
@ -94,34 +94,23 @@ class InsertionFactory {
}
JobInsertionCalculator jic = calcBuilder.build();
TourStateUpdater tourStateCalculator = new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts());
RouteAlgorithm routeAlgorithm = RouteAlgorithmImpl.newInstance(jic, tourStateCalculator);
routeAlgorithm.getListeners().add(new VehicleSwitched(vehicleFleetManager));
((RouteAlgorithmImpl) routeAlgorithm).setActivityStates(activityStates);
if(insertionName.equals("bestInsertion")){
if(concurrentInsertion){
insertionStrategy = BestInsertionConcurrent.newInstance(routeAlgorithm,executorService,nuOfThreads);
}
else{
insertionStrategy = BestInsertion.newInstance(routeAlgorithm);
}
insertionStrategy = new BestInsertion(jic);
}
else if(insertionName.equals("regretInsertion")){
insertionStrategy = RegretInsertion.newInstance(routeAlgorithm);
}
// else if(insertionName.equals("concurrentBestInsertion")){
// String processorsString = config.getString("[@processors]");
// int processors = 1;
// if(processorsString != null) processors = Integer.parseInt(processorsString);
//// BestInsertionConcurrent.newInstance(routeAlgorithm,)
//
//
// else if(insertionName.equals("regretInsertion")){
// insertionStrategy = RegretInsertion.newInstance(routeAlgorithm);
// }
// insertionStrategy.addListener(new RemoveEmptyVehicles(vehicleFleetManager));
insertionStrategy.addListener(new RemoveEmptyVehicles(vehicleFleetManager));
insertionStrategy.addListener(new ResetAndIniFleetManager(vehicleFleetManager));
insertionStrategy.addAllListener(insertionListeners);
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);
// insertionStrategy.addListener(new FindCheaperVehicle(
// new FindCheaperVehicleAlgoNew(vehicleFleetManager, tourStateCalculator, auxCalculator)));

View file

@ -0,0 +1,74 @@
package algorithms;
import java.util.ArrayList;
import java.util.Collection;
import basics.Job;
import basics.algo.InsertionEndsListener;
import basics.algo.InsertionListener;
import basics.algo.InsertionStartsListener;
import basics.algo.JobInsertedListener;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
class InsertionListeners {
private Collection<InsertionListener> listeners = new ArrayList<InsertionListener>();
public Collection<InsertionListener> getListeners(){
return listeners;
}
public void informJobInserted(Job insertedJob, VehicleRoute inRoute, double additionalCosts, double additionalTime){
for(InsertionListener l : listeners){
if(l instanceof JobInsertedListener){
((JobInsertedListener)l).informJobInserted(insertedJob, inRoute, additionalCosts, additionalTime);
}
}
}
public void informVehicleSwitched(VehicleRoute route, Vehicle oldVehicle, Vehicle newVehicle){
for(InsertionListener l : listeners){
if(l instanceof VehicleSwitchedListener){
((VehicleSwitchedListener) l).vehicleSwitched(route, oldVehicle, newVehicle);
}
}
}
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route){
for(InsertionListener l : listeners){
if(l instanceof BeforeJobInsertionListener){
((BeforeJobInsertionListener)l).informBeforeJobInsertion(job, data, route);
}
}
}
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs){
for(InsertionListener l : listeners){
if(l instanceof InsertionStartsListener){
((InsertionStartsListener)l).informInsertionStarts(vehicleRoutes, unassignedJobs);
}
}
}
public void informInsertionEndsListeners(Collection<VehicleRoute> vehicleRoutes) {
for(InsertionListener l : listeners){
if(l instanceof InsertionEndsListener){
((InsertionEndsListener)l).informInsertionEnds(vehicleRoutes);
}
}
}
public void addListener(InsertionListener insertionListener){
listeners.add(insertionListener);
}
public void removeListener(InsertionListener insertionListener){
listeners.remove(insertionListener);
}
public void addAllListeners(Collection<InsertionListener> listeners) {
for(InsertionListener l : listeners) addListener(l);
}
}

View file

@ -15,6 +15,7 @@ package algorithms;
import java.util.Collection;
import basics.Job;
import basics.algo.InsertionListener;
import basics.route.VehicleRoute;
@ -59,8 +60,13 @@ interface InsertionStrategy {
*
* @param vehicleRoutes
* @param unassignedJobs
* @param result2beat
*/
public void run(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs, double result2beat);
public void insertJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
public void addListener(InsertionListener insertionListener);
public void removeListener(InsertionListener insertionListener);
public Collection<InsertionListener> getListeners();
}

View file

@ -0,0 +1,76 @@
/*******************************************************************************
* Copyright (c) 2011 Stefan Schroeder.
* eMail: stefan.schroeder@kit.edu
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/
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) {
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); }
}

View file

@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2011 Stefan Schroeder.
* eMail: stefan.schroeder@kit.edu
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/
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) {
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);
}
}

View file

@ -76,14 +76,14 @@ class JobObserver implements JobInsertedListener, BeforeJobInsertionListener, Al
Collection<Info> infos = new ArrayList<Info>();
@Override
public void informJobInserted(int nOfJobsStill2Recreate, Job job2insert, VehicleRoute insertedIn) {
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
if(job2insert instanceof Service){
if(((Service) job2insert).getLocationId().equals(locationId)){
double actualMC = insertedIn.getCost()-routeCostBefore;
TourActivity act = getAct(job2insert,insertedIn);
double actualMC = inRoute.getCost()-routeCostBefore;
TourActivity act = getAct(job2insert,inRoute);
double error = (estimatedMC-actualMC);
int tourSize = insertedIn.getTourActivities().getActivities().size();
int insertionIndex = getIndexOf(job2insert, insertedIn);
int tourSize = inRoute.getTourActivities().getActivities().size();
int insertionIndex = getIndexOf(job2insert, inRoute);
// infos.add(new Info())
double depTime = state(act).getEarliestOperationStart()+act.getOperationTime();
infos.add(new Info(depTime,tourSize,insertionIndex,error));

View file

@ -1,36 +0,0 @@
/*******************************************************************************
* 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.Job;
import basics.route.VehicleRoute;
interface JobRemover {
/**
* Removes jobs from vehicRoute and return true if job has been successfully removed.
*
* @return true if job removed successfully, otherwise false
*/
public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute);
}

View file

@ -1,54 +0,0 @@
/*******************************************************************************
* 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.ArrayList;
import java.util.List;
import basics.Job;
import basics.route.VehicleRoute;
class JobRemoverImpl implements JobRemover{
interface RemoverListener {
public void informRemovedJob(Job j, VehicleRoute r);
}
private List<RemoverListener> remListeners = new ArrayList<RemoverListener>();
@Override
public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute) {
boolean jobRemoved = vehicleRoute.getTourActivities().removeJob(job);
if(jobRemoved) informRemovedJob(job,vehicleRoute);
return jobRemoved;
}
private void informRemovedJob(Job job, VehicleRoute vehicleRoute) {
for(RemoverListener l : remListeners) l.informRemovedJob(job, vehicleRoute);
}
public List<RemoverListener> getRemListeners() {
return remListeners;
}
}

View file

@ -0,0 +1,35 @@
package algorithms;
import basics.route.TourActivity;
interface MarginalsCalculus {
class Marginals {
private double additionalCosts;
private double additionalTime;
public Marginals(double additionalCosts, double additionalTime) {
super();
this.additionalCosts = additionalCosts;
this.additionalTime = additionalTime;
}
/**
* @return the additionalCosts
*/
public double getAdditionalCosts() {
return additionalCosts;
}
/**
* @return the additionalTime
*/
public double getAdditionalTime() {
return additionalTime;
}
}
Marginals calculate(InsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct);
}

View file

@ -0,0 +1,71 @@
package algorithms;
import algorithms.HardConstraints.HardActivityLevelConstraint;
import basics.costs.VehicleRoutingActivityCosts;
import basics.costs.VehicleRoutingTransportCosts;
import basics.route.TourActivity;
class MarginalsCalculusTriangleInequality implements MarginalsCalculus{
private HardActivityLevelConstraint hardConstraint;
private VehicleRoutingTransportCosts routingCosts;
private VehicleRoutingActivityCosts activityCosts;
public MarginalsCalculusTriangleInequality(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, HardActivityLevelConstraint hardActivityLevelConstraint) {
super();
this.routingCosts = routingCosts;
this.activityCosts = actCosts;
this.hardConstraint = hardActivityLevelConstraint;
}
@Override
public Marginals calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) {
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 newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct;
if(!hardConstraint.fulfilled(iFacts, newAct, newAct_arrTime)){
return null;
}
double newAct_endTime = CalcUtils.getStartTimeAtAct(newAct_arrTime, newAct);
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct;
if(!hardConstraint.fulfilled(iFacts, nextAct, nextAct_arrTime)){
return null;
}
double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct;
double oldCosts;
double oldTime;
if(iFacts.getRoute().isEmpty()){
oldCosts = 0.0;
oldTime = 0.0;
}
else{
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevAct.getEndTime(), iFacts.getNewDriver(), iFacts.getNewVehicle());
double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct;
oldTime = (nextAct.getArrTime() - iFacts.getRoute().getDepartureTime());
}
double additionalCosts = totalCosts - oldCosts;
double additionalTime = (nextAct_arrTime - iFacts.getNewDepTime()) - oldTime;
return new Marginals(additionalCosts,additionalTime);
}
}

View file

@ -1,210 +1,229 @@
/*******************************************************************************
* Copyright (c) 2011 Stefan Schroeder.
* eMail: stefan.schroeder@kit.edu
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/
package algorithms;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.log4j.Logger;
import algorithms.InsertionData.NoInsertionFound;
import basics.Job;
import basics.Service;
import basics.route.VehicleRoute;
/**
* Insertion based an regret approach.
*
* <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference
* between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction.
* The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this
* customer immediatedly. If difference is not that high, it might not impact solution if this customer is inserted later.
*
* @author stefan schroeder
*
*/
final class RegretInsertion extends AbstractInsertionStrategy{
/**
* Scorer to include other impacts on score such as time-window length or distance to depot.
*
* @author schroeder
*
*/
static interface ScoringFunction {
public double score(Job job);
}
/**
* Scorer that includes the length of the time-window when scoring a job. The wider the time-window, the lower the score.
*
* <p>This is the default scorer, i.e.: score = (secondBest - firstBest) + this.TimeWindowScorer.score(job)
*
* @author schroeder
*
*/
static class TimeWindowScorer implements ScoringFunction {
private double tw_scoringParam = - 0.1;
@Override
public double score(Job job) {
double twStart = 0.0;
double twEnd = 0.0;
// if(job instanceof Shipment){
// twStart = ((Shipment) job).getDeliveryTW().getStart();
// twEnd = ((Shipment) job).getDeliveryTW().getEnd();
///*******************************************************************************
// * Copyright (c) 2011 Stefan Schroeder.
// * eMail: stefan.schroeder@kit.edu
// *
// * All rights reserved. This program and the accompanying materials
// * are made available under the terms of the GNU Public License v2.0
// * which accompanies this distribution, and is available at
// * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
// *
// * Contributors:
// * Stefan Schroeder - initial API and implementation
// ******************************************************************************/
//package algorithms;
//
//import java.util.ArrayList;
//import java.util.Collection;
//import java.util.List;
//
//import org.apache.log4j.Logger;
//
//import algorithms.InsertionData.NoInsertionFound;
//import basics.Job;
//import basics.Service;
//import basics.algo.InsertionListener;
//import basics.route.VehicleRoute;
//
//
///**
// * Insertion based an regret approach.
// *
// * <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference
// * between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction.
// * The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this
// * customer immediatedly. If difference is not that high, it might not impact solution if this customer is inserted later.
// *
// * @author stefan schroeder
// *
// */
//final class RegretInsertion implements InsertionStrategy{
//
// /**
// * Scorer to include other impacts on score such as time-window length or distance to depot.
// *
// * @author schroeder
// *
// */
// static interface ScoringFunction {
//
// public double score(Job job);
//
// }
//
// /**
// * Scorer that includes the length of the time-window when scoring a job. The wider the time-window, the lower the score.
// *
// * <p>This is the default scorer, i.e.: score = (secondBest - firstBest) + this.TimeWindowScorer.score(job)
// *
// * @author schroeder
// *
// */
// static class TimeWindowScorer implements ScoringFunction {
//
// private double tw_scoringParam = - 0.1;
//
// @Override
// public double score(Job job) {
// double twStart = 0.0;
// double twEnd = 0.0;
//// if(job instanceof Shipment){
//// twStart = ((Shipment) job).getDeliveryTW().getStart();
//// twEnd = ((Shipment) job).getDeliveryTW().getEnd();
//// }
//// else
// if(job instanceof Service){
// twStart = ((Service) job).getTimeWindow().getStart();
// twEnd = ((Service) job).getTimeWindow().getEnd();
// }
// else
if(job instanceof Service){
twStart = ((Service) job).getTimeWindow().getStart();
twEnd = ((Service) job).getTimeWindow().getEnd();
}
return (twEnd-twStart)*tw_scoringParam;
}
@Override
public String toString() {
return "[name=timeWindowScorer][scoringParam="+tw_scoringParam+"]";
}
}
public static RegretInsertion newInstance(RouteAlgorithm routeAlgorithm) {
return new RegretInsertion(routeAlgorithm);
}
private Logger logger = Logger.getLogger(RegretInsertion.class);
private RouteAlgorithm routeAlgorithm;
private ScoringFunction scoringFunction = new TimeWindowScorer();
/**
* Sets the scoring function.
*
* <p>By default, the this.TimeWindowScorer is used.
*
* @param scoringFunction
*/
public void setScoringFunction(ScoringFunction scoringFunction) {
this.scoringFunction = scoringFunction;
}
public RegretInsertion(RouteAlgorithm routeAlgorithm) {
super();
this.routeAlgorithm = routeAlgorithm;
logger.info("initialise " + this);
}
@Override
public String toString() {
return "[name=regretInsertion][additionalScorer="+scoringFunction+"]";
}
public RouteAlgorithm getRouteAlgorithm(){
return routeAlgorithm;
}
/**
* Runs insertion.
*
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
*
*/
@Override
public void run(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs, double resultToBeat) {
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
informInsertionStarts(routes,unassignedJobs.size());
int inserted = 0;
while(!jobs.isEmpty()){
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
ScoredJob bestScoredJob = null;
double bestScore = -1*Double.MAX_VALUE;
VehicleRoute insertIn = null;
for(Job unassignedJob : unassignedJobList){
InsertionData best = null;
InsertionData secondBest = null;
VehicleRoute bestRoute = null;
double benchmark = Double.MAX_VALUE;
for(VehicleRoute route : routes){
if(secondBest != null){
benchmark = secondBest.getInsertionCost();
}
InsertionData iData = routeAlgorithm.calculateBestInsertion(route, unassignedJob, benchmark);
if(iData instanceof NoInsertionFound) continue;
if(best == null){
best = iData;
bestRoute = route;
}
else if(iData.getInsertionCost() < best.getInsertionCost()){
secondBest = best;
best = iData;
bestRoute = route;
}
else if(secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())){
secondBest = iData;
}
}
if(best == null){
break;
}
double score = score(unassignedJob,best,secondBest);
if(score > bestScore){
bestScoredJob = new ScoredJob(unassignedJob,score,best,bestRoute);
bestScore = score;
}
}
Job assignedJob;
if(bestScoredJob == null){
Job job = unassignedJobList.get(0);
VehicleRoute newRoute = VehicleRoute.emptyRoute();
InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, job, Double.MAX_VALUE);
if(bestI instanceof InsertionData.NoInsertionFound) throw new IllegalStateException("given the vehicles, could not create a valid solution");
insertIn=newRoute;
assignedJob=job;
routeAlgorithm.insertJob(job,bestI,newRoute);
routes.add(newRoute);
jobs.remove(job);
}
else{
routeAlgorithm.insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
insertIn=bestScoredJob.getRoute();
assignedJob=bestScoredJob.getJob();
jobs.remove(bestScoredJob.getJob());
}
inserted++;
informJobInserted((unassignedJobList.size()-inserted), assignedJob, insertIn);
}
}
private double score(Job unassignedJob, InsertionData best, InsertionData secondBest) {
if(best == null){
throw new IllegalStateException("cannot insert job " + unassignedJob.getId());
}
if(secondBest == null){
return Double.MAX_VALUE;
}
return (secondBest.getInsertionCost()-best.getInsertionCost()) + scoringFunction.score(unassignedJob);
}
}
// return (twEnd-twStart)*tw_scoringParam;
// }
//
// @Override
// public String toString() {
// return "[name=timeWindowScorer][scoringParam="+tw_scoringParam+"]";
// }
//
// }
//
// public static RegretInsertion newInstance(RouteAlgorithm routeAlgorithm) {
// return new RegretInsertion(routeAlgorithm);
// }
//
// private Logger logger = Logger.getLogger(RegretInsertion.class);
//
// private RouteAlgorithm routeAlgorithm;
//
// private ScoringFunction scoringFunction = new TimeWindowScorer();
//
// /**
// * Sets the scoring function.
// *
// * <p>By default, the this.TimeWindowScorer is used.
// *
// * @param scoringFunction
// */
// public void setScoringFunction(ScoringFunction scoringFunction) {
// this.scoringFunction = scoringFunction;
// }
//
// public RegretInsertion(RouteAlgorithm routeAlgorithm) {
// super();
// this.routeAlgorithm = routeAlgorithm;
// logger.info("initialise " + this);
// }
//
// @Override
// public String toString() {
// return "[name=regretInsertion][additionalScorer="+scoringFunction+"]";
// }
//
// public RouteAlgorithm getRouteAlgorithm(){
// return routeAlgorithm;
// }
//
// /**
// * Runs insertion.
// *
// * <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
// *
// */
// @Override
// public void insertJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
// List<Job> jobs = new ArrayList<Job>(unassignedJobs);
//// informInsertionStarts(routes,unassignedJobs);
// int inserted = 0;
// while(!jobs.isEmpty()){
// List<Job> unassignedJobList = new ArrayList<Job>(jobs);
// ScoredJob bestScoredJob = null;
// double bestScore = -1*Double.MAX_VALUE;
// VehicleRoute insertIn = null;
//
// for(Job unassignedJob : unassignedJobList){
// InsertionData best = null;
// InsertionData secondBest = null;
// VehicleRoute bestRoute = null;
//
// double benchmark = Double.MAX_VALUE;
// for(VehicleRoute route : routes){
// if(secondBest != null){
// benchmark = secondBest.getInsertionCost();
// }
// InsertionData iData = routeAlgorithm.calculateBestInsertion(route, unassignedJob, benchmark);
// if(iData instanceof NoInsertionFound) continue;
// if(best == null){
// best = iData;
// bestRoute = route;
// }
// else if(iData.getInsertionCost() < best.getInsertionCost()){
// secondBest = best;
// best = iData;
// bestRoute = route;
// }
// else if(secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())){
// secondBest = iData;
// }
// }
// if(best == null){
// break;
// }
// double score = score(unassignedJob,best,secondBest);
// if(score > bestScore){
// bestScoredJob = new ScoredJob(unassignedJob,score,best,bestRoute);
// bestScore = score;
// }
// }
// Job assignedJob;
// if(bestScoredJob == null){
// Job job = unassignedJobList.get(0);
// VehicleRoute newRoute = VehicleRoute.emptyRoute();
// InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, job, Double.MAX_VALUE);
// if(bestI instanceof InsertionData.NoInsertionFound) throw new IllegalStateException("given the vehicles, could not create a valid solution");
// insertIn=newRoute;
// assignedJob=job;
// routeAlgorithm.insertJob(job,bestI,newRoute);
// routes.add(newRoute);
// jobs.remove(job);
//
// }
// else{
// routeAlgorithm.insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
// insertIn=bestScoredJob.getRoute();
// assignedJob=bestScoredJob.getJob();
// jobs.remove(bestScoredJob.getJob());
// }
// inserted++;
//// informJobInserted(assignedJob, insertIn);
//
// }
// }
//
// private double score(Job unassignedJob, InsertionData best, InsertionData secondBest) {
// if(best == null){
// throw new IllegalStateException("cannot insert job " + unassignedJob.getId());
// }
// if(secondBest == null){
// return Double.MAX_VALUE;
// }
// return (secondBest.getInsertionCost()-best.getInsertionCost()) + scoringFunction.score(unassignedJob);
//
// }
//
// @Override
// public void removeListener(InsertionListener insertionListener) {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// public Collection<InsertionListener> getListeners() {
// // TODO Auto-generated method stub
// return null;
// }
//
// @Override
// public void addListener(InsertionListener insertionListener) {
// // TODO Auto-generated method stub
//
// }
//
//}

View file

@ -26,11 +26,12 @@ import java.util.List;
import org.apache.log4j.Logger;
import basics.Job;
import basics.algo.InsertionEndsListener;
import basics.algo.InsertionStartsListener;
import basics.route.VehicleRoute;
class RemoveEmptyVehicles implements InsertionStartsListener, InsertionEndsListener{
class RemoveEmptyVehicles implements InsertionEndsListener{
private static Logger log = Logger.getLogger(RemoveEmptyVehicles.class);
@ -41,21 +42,6 @@ class RemoveEmptyVehicles implements InsertionStartsListener, InsertionEndsListe
this.fleetManager = fleetManager;
}
@Override
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2Recreate) {
// List<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
// for(VehicleRoute route : routes){
// if(route.isEmpty()) { vehicleRoutes.remove(route); }
// }
// List<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
// for(VehicleRoute route : routes){
// if(route.isEmpty()) {
// fleetManager.unlock(route.getVehicle());
// vehicleRoutes.remove(route);
// }
// }
}
@Override
public String toString() {
return "[name=removeEmptyVehicles]";

View file

@ -25,6 +25,7 @@ import java.util.Collection;
import org.apache.log4j.Logger;
import basics.Job;
import basics.algo.InsertionStartsListener;
import basics.route.VehicleRoute;
@ -40,16 +41,16 @@ class ResetAndIniFleetManager implements InsertionStartsListener{
}
@Override
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2Recreate) {
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
vehicleFleetManager.unlockAll();
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
for(VehicleRoute route : routes){
if(route.isEmpty()){
vehicleRoutes.remove(route);
}
else{
// if(route.isEmpty()){
// vehicleRoutes.remove(route);
// }
// else{
vehicleFleetManager.lock(route.getVehicle());
}
// }
}
}

View file

@ -1,92 +0,0 @@
/*******************************************************************************
* 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.Collection;
import basics.Job;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
interface RouteAlgorithm {
interface RouteAlgorithmListener {
}
interface JobRemovedListener extends RouteAlgorithmListener{
public void removed(VehicleRoute route, Job job);
}
interface JobInsertedListener extends RouteAlgorithmListener{
public void inserted(VehicleRoute route, Job job);
}
interface VehicleSwitchedListener extends RouteAlgorithmListener{
public void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle);
}
/**
* Calculates the best insertion position and the corresponding marginal costs of inserting the job (according to the insertionCostCalculator).
* This does not affect any input parameter, thus the vehicleRoute and its data will not be changed/affected.
*
* @param VehicleRoute, Job, double
* @return InsertionData
*/
public InsertionData calculateBestInsertion(VehicleRoute vehicleRoute, Job job, double bestKnownPrice);
/**
* Removes job from vehicleRoute and does not update the resulting tour. Thus the tour state might not be valid anymore.
* Note that this changes vehicleRoute!
*
* @return true if job removed successfully, otherwise false
*/
public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute);
/**
* Removes job from input parameter vehicleRoute AND updates the state of the resulting tour with tourStateCalc.
* Note that this changes para vehicleRoute!
*/
public boolean removeJob(Job job, VehicleRoute vehicleRoute);
/**
* Inserts job into vehicleRoute.getTour().
* Please note, that this changes the parameter vehicleRoute!
*/
public void insertJobWithoutTourUpdate(VehicleRoute vehicleRoute, Job job, InsertionData insertionData);
/**
* Inserts job into vehicleRoute.getTour().
* Please note, that this changes the parameter vehicleRoute!
*/
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute);
/**
* Updates vehicleRoute, i.e. uses the tourStateCalculator to update for example timeWindows and loads on vehicleRoute.getTour()
* Note that this changes the parameter vehicleRoute!
*/
public void updateTour(VehicleRoute vehicleRoute);
public Collection<RouteAlgorithmListener> getListeners();
}

View file

@ -1,171 +0,0 @@
/*******************************************************************************
* Copyright (c) 2011 Stefan Schroeder.
* eMail: stefan.schroeder@kit.edu
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/
package algorithms;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.log4j.Logger;
import algorithms.RouteStates.ActivityState;
import algorithms.InsertionData.NoInsertionFound;
import basics.Job;
import basics.Service;
import basics.route.ServiceActivity;
import basics.route.TourActivity;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
/**
*
* @author stefan schroeder
*
*/
final class RouteAlgorithmImpl implements RouteAlgorithm {
private static Logger logger = Logger.getLogger(RouteAlgorithmImpl.class);
static double NO_DEPARTURE_TIME = -12345.12345;
private String algoDescription = "algorithm to remove and insert jobs from vehicleRoutes. it also calculates marginal costs of the best insertion of a " +
"job into the given vehicle route";
public static RouteAlgorithmImpl newInstance(JobInsertionCalculator jobInsertionCalculator, VehicleRouteUpdater tourStateCalculator){
return new RouteAlgorithmImpl(jobInsertionCalculator, tourStateCalculator);
}
private Collection<RouteAlgorithmListener> listeners = new ArrayList<RouteAlgorithmListener>();
private VehicleRouteUpdater tourCalculator;
private JobInsertionCalculator insertionCostCalculator;
private RouteStates actStates;
public void setActivityStates(RouteStates actStates){
this.actStates = actStates;
}
public ActivityState state(TourActivity act){
return actStates.getState(act);
}
private RouteAlgorithmImpl(JobInsertionCalculator insertionCostCalculator, VehicleRouteUpdater tourCalculator){
this.tourCalculator = tourCalculator;
this.insertionCostCalculator = insertionCostCalculator;
}
public InsertionData calculateBestInsertion(VehicleRoute vehicleRoute, Job job, double bestKnownCost) {
return insertionCostCalculator.calculate(vehicleRoute, job, null, NO_DEPARTURE_TIME, null, bestKnownCost);
}
public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute) {
boolean removed = vehicleRoute.getTourActivities().removeJob(job);
if(removed){
jobRemoved(vehicleRoute,job);
}
return removed;
}
private void jobRemoved(VehicleRoute vehicleRoute, Job job) {
for(RouteAlgorithmListener l : listeners){
if(l instanceof JobRemovedListener){
((JobRemovedListener) l).removed(vehicleRoute, job);
}
}
}
public boolean removeJob(Job job, VehicleRoute vehicleRoute){
boolean removed = removeJobWithoutTourUpdate(job, vehicleRoute);
if(removed) updateTour(vehicleRoute);
return removed;
}
public void updateTour(VehicleRoute vehicleRoute){
boolean tourIsFeasible = tourCalculator.updateRoute(vehicleRoute);
if(!tourIsFeasible){
throw new IllegalStateException("At this point tour should be feasible. but it is not. \n currentTour=" + vehicleRoute.getTourActivities() +
"\n error sources: check jobInsertionCostCalculators and actInsertionCalculators. somehow an insertion is made, althought a hard constraint is broken. Here, hard constraints refer to \n" +
"hard time-window constraints. If you want to deal with such constraints, make sure a violation is penalized properly (such that it can never be the best insertion position). \n" +
"If you use CalculatesServiceInsertion and CalculatesActivityInsertion, the only hard constraint is the vehicle-capacity constraints. A violation of time-windows must be penalized in \n" +
"the vehicleRouteCostFunction. For example: in handleActivity(....) one can check whether the act start-time is higher than the latestOperationStartTime. If so penalize it with a very high value. \n" +
"For example: \n" +
"public void handleActivity(TourActivity tourAct, double startTime, double endTime) {\n" +
"\tif(startTime > tourAct.getLatestOperationStartTime()){\n" +
"\t\tcost += Double.MAX_VALUE;\n" +
"\t}\n" +
"});");
}
}
@Override
public void insertJobWithoutTourUpdate(VehicleRoute vehicleRoute, Job job, InsertionData insertionData) {
if(insertionData == null || (insertionData instanceof NoInsertionFound)) throw new IllegalStateException("insertionData null. cannot insert job.");
if(job == null) throw new IllegalStateException("cannot insert null-job");
if(!(vehicleRoute.getVehicle().getId().toString().equals(insertionData.getSelectedVehicle().getId().toString()))){
vehicleSwitched(vehicleRoute.getVehicle(),insertionData.getSelectedVehicle());
vehicleRoute.setVehicle(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
}
if(job instanceof Service) {
vehicleRoute.getTourActivities().addActivity(insertionData.getDeliveryInsertionIndex(), ServiceActivity.newInstance((Service)job));
vehicleRoute.setDepartureTime(insertionData.getVehicleDepartureTime());
}
else throw new IllegalStateException("neither service nor shipment. this is not supported.");
jobInserted(vehicleRoute,job);
}
private void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle) {
for(RouteAlgorithmListener l : listeners){
if(l instanceof VehicleSwitchedListener){
((VehicleSwitchedListener) l).vehicleSwitched(oldVehicle,newVehicle);
}
}
}
private void jobInserted(VehicleRoute vehicleRoute, Job job) {
for(RouteAlgorithmListener l : listeners){
if(l instanceof JobInsertedListener){
((JobInsertedListener) l).inserted(vehicleRoute, job);
}
}
}
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute){
insertJobWithoutTourUpdate(vehicleRoute, job, insertionData);
updateTour(vehicleRoute);
}
@Override
public String toString() {
return algoDescription;
}
public Collection<RouteAlgorithmListener> getListeners() {
return listeners;
}
public void setAlgoDescription(String algoDescription) {
this.algoDescription = algoDescription;
}
}

View file

@ -0,0 +1,59 @@
package algorithms;
import java.util.Collection;
import util.RouteUtils;
import algorithms.RuinStrategy.RuinListener;
import basics.Job;
import basics.VehicleRoutingProblemSolution;
import basics.algo.InsertionListener;
import basics.algo.SearchStrategyModule;
import basics.algo.SearchStrategyModuleListener;
class RuinAndRecreateModule implements SearchStrategyModule{
private InsertionStrategy insertion;
private RuinStrategy ruin;
private String moduleName;
public RuinAndRecreateModule(String moduleName, InsertionStrategy insertion, RuinStrategy ruin) {
super();
this.insertion = insertion;
this.ruin = ruin;
this.moduleName = moduleName;
}
@Override
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
Collection<Job> ruinedJobs = ruin.ruin(vrpSolution.getRoutes());
insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobs);
double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes());
vrpSolution.setCost(totalCost);
return vrpSolution;
}
@Override
public String getName() {
return moduleName;
}
@Override
public void addModuleListener(SearchStrategyModuleListener moduleListener) {
if(moduleListener instanceof InsertionListener){
InsertionListener iListener = (InsertionListener) moduleListener;
if(!insertion.getListeners().contains(iListener)){
insertion.addListener(iListener);
}
}
if(moduleListener instanceof RuinListener){
RuinListener rListener = (RuinListener) moduleListener;
if(!ruin.getListeners().contains(rListener)){
ruin.addListener(rListener);
}
}
}
}

View file

@ -0,0 +1,38 @@
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);
}
}

View file

@ -29,29 +29,11 @@ import util.RandomNumberGeneration;
import util.StopWatch;
import basics.Job;
import basics.VehicleRoutingProblem;
import basics.VehicleRoutingProblemSolution;
import basics.algo.SearchStrategyModule;
import basics.route.VehicleRoute;
final class RuinRadial implements RuinStrategy {
private final static String NAME = "radialRuin";
/**
* returns a new creation of instance of ruinRadial
* @param vrp
* @param fraction TODO
* @param jobDistance
* @param jobRemover TODO
* @param routeUpdater TODO
* @return
*/
static RuinRadial newInstance(VehicleRoutingProblem vrp, double fraction, JobDistance jobDistance, JobRemover jobRemover, VehicleRouteUpdater routeUpdater){
return new RuinRadial(vrp, fraction, jobDistance, jobRemover, routeUpdater);
}
static class ReferencedJob {
private Job job;
@ -84,21 +66,18 @@ final class RuinRadial implements RuinStrategy {
private JobDistance jobDistance;
private JobRemover jobRemover;
private RuinListeners ruinListeners;
private VehicleRouteUpdater routeUpdater;
public void setRandom(Random random) {
this.random = random;
}
public RuinRadial(VehicleRoutingProblem vrp, double fraction, JobDistance jobDistance, JobRemover jobRemover, VehicleRouteUpdater routeUpdater) {
public RuinRadial(VehicleRoutingProblem vrp, double fraction, JobDistance jobDistance) {
super();
this.vrp = vrp;
this.jobDistance = jobDistance;
this.jobRemover = jobRemover;
this.routeUpdater = routeUpdater;
this.fractionOfAllNodes2beRuined = fraction;
ruinListeners = new RuinListeners();
calculateDistancesFromJob2Job();
logger.info("intialise " + this);
}
@ -158,6 +137,7 @@ final class RuinRadial implements RuinStrategy {
}
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved){
ruinListeners.ruinStarts(vehicleRoutes);
List<Job> unassignedJobs = new ArrayList<Job>();
TreeSet<ReferencedJob> tree = distanceNodeTree.get(targetJob.getId());
Iterator<ReferencedJob> descendingIterator = tree.descendingIterator();
@ -169,15 +149,14 @@ final class RuinRadial implements RuinStrategy {
counter++;
boolean removed = false;
for (VehicleRoute route : vehicleRoutes) {
removed = jobRemover.removeJobWithoutTourUpdate(job, route);
removed = route.getTourActivities().removeJob(job);;
if (removed) {
ruinListeners.removed(job,route);
break;
}
}
}
for(VehicleRoute route : vehicleRoutes){
routeUpdater.updateRoute(route);
}
ruinListeners.ruinEnds(vehicleRoutes, unassignedJobs);
return unassignedJobs;
}
@ -193,15 +172,20 @@ final class RuinRadial implements RuinStrategy {
* fractionOfAllNodes2beRuined);
}
// @Override
// public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
// ruin(vrpSolution.getRoutes());
// return vrpSolution;
// }
//
// @Override
// public String getName() {
// return NAME;
// }
@Override
public void addListener(RuinListener ruinListener) {
ruinListeners.addListener(ruinListener);
}
@Override
public void removeListener(RuinListener ruinListener) {
ruinListeners.removeListener(ruinListener);
}
@Override
public Collection<RuinListener> getListeners() {
return ruinListeners.getListeners();
}
}

View file

@ -35,10 +35,6 @@ import basics.route.VehicleRoute;
*/
final class RuinRandom implements RuinStrategy {
public static RuinRandom newInstance(VehicleRoutingProblem vrp, double fraction, JobRemover jobRemover, VehicleRouteUpdater routeUpdater){
return new RuinRandom(vrp, fraction, jobRemover, routeUpdater);
}
private Logger logger = Logger.getLogger(RuinRandom.class);
@ -47,10 +43,8 @@ final class RuinRandom implements RuinStrategy {
private double fractionOfAllNodes2beRuined;
private Random random = RandomNumberGeneration.getRandom();
private JobRemover jobRemover;
private VehicleRouteUpdater vehicleRouteUpdater;
private RuinListeners ruinListeners;
public void setRandom(Random random) {
this.random = random;
@ -61,15 +55,12 @@ final class RuinRandom implements RuinStrategy {
*
* @param vrp
* @param fraction which is the fraction of total c
* @param jobRemover
* @param vehicleRouteUpdater
*/
public RuinRandom(VehicleRoutingProblem vrp, double fraction, JobRemover jobRemover, VehicleRouteUpdater vehicleRouteUpdater) {
public RuinRandom(VehicleRoutingProblem vrp, double fraction) {
super();
this.vrp = vrp;
this.jobRemover = jobRemover;
this.vehicleRouteUpdater = vehicleRouteUpdater;
this.fractionOfAllNodes2beRuined = fraction;
ruinListeners = new RuinListeners();
logger.info("initialise " + this);
logger.info("done");
}
@ -81,9 +72,11 @@ final class RuinRandom implements RuinStrategy {
*/
@Override
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes) {
ruinListeners.ruinStarts(vehicleRoutes);
List<Job> unassignedJobs = new ArrayList<Job>();
int nOfJobs2BeRemoved = selectNuOfJobs2BeRemoved();
ruin(vehicleRoutes, nOfJobs2BeRemoved, unassignedJobs);
ruinListeners.ruinEnds(vehicleRoutes, unassignedJobs);
return unassignedJobs;
}
@ -92,19 +85,22 @@ final class RuinRandom implements RuinStrategy {
*/
@Override
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved) {
ruinListeners.ruinStarts(vehicleRoutes);
List<Job> unassignedJobs = new ArrayList<Job>();
if(targetJob != null){
boolean removed = false;
for (VehicleRoute route : vehicleRoutes) {
removed = jobRemover.removeJobWithoutTourUpdate(targetJob, route);
removed = route.getTourActivities().removeJob(targetJob);
if (removed) {
nOfJobs2BeRemoved--;
unassignedJobs.add(targetJob);
ruinListeners.removed(targetJob,route);
break;
}
}
}
ruin(vehicleRoutes, nOfJobs2BeRemoved, unassignedJobs);
ruinListeners.ruinEnds(vehicleRoutes, unassignedJobs);
return unassignedJobs;
}
@ -113,27 +109,23 @@ final class RuinRandom implements RuinStrategy {
logger.info("fraction set " + this);
}
private void ruin(Collection<VehicleRoute> vehicleRoutes,int nOfJobs2BeRemoved, List<Job> unassignedJobs) {
private void ruin(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2BeRemoved, List<Job> unassignedJobs) {
LinkedList<Job> availableJobs = new LinkedList<Job>(vrp.getJobs().values());
for (int i = 0; i < nOfJobs2BeRemoved; i++) {
Job job = pickRandomJob(availableJobs);
unassignedJobs.add(job);
availableJobs.remove(job);
for (VehicleRoute route : vehicleRoutes) {
boolean removed = jobRemover.removeJobWithoutTourUpdate(job, route);
if (removed) break;
boolean removed = route.getTourActivities().removeJob(job);
if (removed) {
ruinListeners.removed(job,route);
break;
}
}
}
updateRoutes(vehicleRoutes);
}
private void updateRoutes(Collection<VehicleRoute> vehicleRoutes) {
for(VehicleRoute route : vehicleRoutes){
vehicleRouteUpdater.updateRoute(route);
}
}
@Override
public String toString() {
return "[name=randomRuin][fraction="+fractionOfAllNodes2beRuined+"]";
@ -148,4 +140,19 @@ final class RuinRandom implements RuinStrategy {
return (int) Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined);
}
@Override
public void addListener(RuinListener ruinListener) {
ruinListeners.addListener(ruinListener);
}
@Override
public void removeListener(RuinListener ruinListener) {
ruinListeners.removeListener(ruinListener);
}
@Override
public Collection<RuinListener> getListeners() {
return ruinListeners.getListeners();
}
}

View file

@ -13,7 +13,6 @@
package algorithms;
import java.util.Collection;
import java.util.List;
import basics.Job;
import basics.route.VehicleRoute;
@ -29,19 +28,62 @@ import basics.route.VehicleRoute;
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. removes jobs from service providers and
* returns a collection of these removed, and thus unassigned, jobs.
* Ruins a current solution, i.e. a collection of vehicle-routes and
* returns a collection of removed and thus unassigned jobs.
*
* @param vehicleRoutes
* @return
* @param {@link VehicleRoute}
* @return Collection of {@link Job}
*/
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes);
/**
* Removes targetJob as well as its neighbors with a size of (nOfJobs2BeRemoved-1).
*/
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved);
/**
* Adds a ruin-listener.
*
* @param {@link RuinListener}
*/
public void addListener(RuinListener ruinListener);
public void removeListener(RuinListener ruinListener);
public Collection<RuinListener> getListeners();
}

View file

@ -0,0 +1,52 @@
package algorithms;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
interface StateManager {
interface State {
double toDouble();
}
class StateImpl implements State{
double state;
public StateImpl(double state) {
super();
this.state = state;
}
@Override
public double toDouble() {
return state;
}
// public void setState(double val){
// state=val;
// }
}
interface States {
// void putState(String key, State state);
State getState(String key);
}
// Map<VehicleRoute, States> getRouteStates();
// void put(VehicleRoute route, States states);
// Map<TourActivity, States> getActivityStates();
// void put(TourActivity act, States states);
State getActivityState(TourActivity act, String stateType);
State getRouteState(VehicleRoute route, String stateType);
}

View file

@ -0,0 +1,121 @@
package algorithms;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
class StateManagerImpl implements StateManager{
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>();
public Map<VehicleRoute, States> getRouteStates() {
return Collections.unmodifiableMap(vehicleRouteStates);
}
public States getRouteStates(VehicleRoute route){
return vehicleRouteStates.get(route);
}
public void put(VehicleRoute route, States states) {
vehicleRouteStates.put(route, states);
}
public Map<TourActivity, States> getActivityStates() {
return Collections.unmodifiableMap(activityStates);
}
public States getActivityStates(TourActivity act){
return activityStates.get(act);
}
public void put(TourActivity act, States states) {
activityStates.put(act, states);
}
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());
return null;
}
private State getDefaultRouteState(String stateType, VehicleRoute route){
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);
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);
}
}

View file

@ -0,0 +1,13 @@
package algorithms;
class StateTypes {
final static String LOAD = "load";
final static String DURATION = "duration";
final static String LATEST_OPERATION_START_TIME = "latestOST";
final static String EARLIEST_OPERATION_START_TIME = "earliestOST";
public static final String COSTS = "costs";
}

View file

@ -1,34 +0,0 @@
/*******************************************************************************
* 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.Job;
import basics.route.VehicleRoute;
class TourConstraintEngine {
// void ini(VehicleRoute route, Job job){
//
// }
//
}

View file

@ -1,91 +0,0 @@
/*******************************************************************************
* Copyright (c) 2011 Stefan Schroeder.
* eMail: stefan.schroeder@kit.edu
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/
package algorithms;
import org.apache.log4j.Logger;
import basics.costs.VehicleRoutingActivityCosts;
import basics.costs.VehicleRoutingTransportCosts;
import basics.route.VehicleRoute;
/**
* Updates tour state, i.e. the tour as well as each activity in that tour has a state such as currentLoad, currentCost, earliestOperationTime and
* latestOperationTime. Each time the tour is changed (for instance by removing or adding an activity), tour and activity states
* might change, thus this updater updates activity states.
* This includes:
* - update load and totalCost at tour-level
* - update currentLoad and currentCost at activity-level
* - update earliest- and latestOperationStart values at activity-level
*
* If ensureFeasibility is true, then it additionally checks whether the earliestOperationStartTime is higher than the latestOperationStartTime.
* If it is, it returns a false value to indicate that the tour is not feasible. This makes only sense for hard-timewindows.
*
* If softTimeWindow is set to true, latestOperationStartTimes are not updated and the tour is always feasible.
*
* @author stefan schroeder
*
*/
class TourStateUpdater implements VehicleRouteUpdater{
// public final static Counter counter = new Counter("#updateTWProcesses: ");
private static Logger logger = Logger.getLogger(TourStateUpdater.class);
private boolean ensureFeasibility = true;
private UpdateTourStatesForwardInTime forwardUpdate;
private UpdateTourStatesBackwardInTime backwardUpdate;
private boolean updateTimeWindows = true;
private RouteStates actStates;
public TourStateUpdater(RouteStates activityStates, VehicleRoutingTransportCosts costs, VehicleRoutingActivityCosts costFunction) {
super();
forwardUpdate = new UpdateTourStatesForwardInTime(costs, costs, costFunction);
backwardUpdate = new UpdateTourStatesBackwardInTime(costs);
actStates=activityStates;
forwardUpdate.setActivityStates(actStates);
backwardUpdate.setActivityStates(actStates);
}
/*
*
*/
public boolean updateRoute(VehicleRoute vehicleRoute) {
if(updateTimeWindows){
backwardUpdate.checkFeasibility = ensureFeasibility;
backwardUpdate.updateRoute(vehicleRoute);
}
forwardUpdate.updateRoute(vehicleRoute);
boolean tourIsFeasible = true;
return tourIsFeasible;
}
public void setTimeWindowUpdate(boolean updateTimeWindows) {
this.updateTimeWindows = updateTimeWindows;
logger.info("set timeWindowUpdate to " + updateTimeWindows);
}
public void setEnsureFeasibility(boolean ensureFeasibility) {
this.ensureFeasibility = ensureFeasibility;
}
}

View file

@ -0,0 +1,62 @@
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.VehicleRoute;
class UdateCostsAtRouteLevel implements JobInsertedListener, InsertionStartsListener, InsertionEndsListener{
private StateManagerImpl states;
private VehicleRoutingTransportCosts tpCosts;
private VehicleRoutingActivityCosts actCosts;
public UdateCostsAtRouteLevel(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) {
IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(tpCosts);
forwardInTime.addListener(new UpdateCostsAtAllLevels(actCosts, tpCosts, states));
for(VehicleRoute route : vehicleRoutes){
forwardInTime.iterate(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);
}
}
}

View file

@ -0,0 +1,31 @@
package algorithms;
import org.apache.log4j.Logger;
import algorithms.ForwardInTimeListeners.ForwardInTimeListener;
import basics.route.End;
import basics.route.Start;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
class UpdateActivityTimes implements ForwardInTimeListener{
private Logger log = Logger.getLogger(UpdateActivityTimes.class);
@Override
public void start(VehicleRoute route, Start start, double departureTime) {
start.setEndTime(departureTime);
}
@Override
public void nextActivity(TourActivity act, double arrTime, double endTime) {
act.setArrTime(arrTime);
act.setEndTime(endTime);
}
@Override
public void end(End end, double arrivalTime) {
end.setArrTime(arrivalTime);
}
}

View file

@ -0,0 +1,84 @@
package algorithms;
import algorithms.ForwardInTimeListeners.ForwardInTimeListener;
import algorithms.StateManager.StateImpl;
import basics.costs.ForwardTransportCost;
import basics.costs.VehicleRoutingActivityCosts;
import basics.route.End;
import basics.route.Start;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
class UpdateCostsAtAllLevels implements ForwardInTimeListener{
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;
public UpdateCostsAtAllLevels(VehicleRoutingActivityCosts activityCost, ForwardTransportCost transportCost, StateManagerImpl states) {
super();
this.activityCost = activityCost;
this.transportCost = transportCost;
this.states = states;
}
@Override
public void start(VehicleRoute route, Start start, double departureTime) {
vehicleRoute = route;
vehicleRoute.getVehicleRouteCostCalculator().reset();
prevAct = start;
startTimeAtPrevAct = departureTime;
}
@Override
public void nextActivity(TourActivity act, double arrTime, double endTime) {
double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), act.getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle());
double actCost = activityCost.getActivityCost(act, arrTime, 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 = endTime;
}
@Override
public void end(End end, double arrivalTime) {
double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), end.getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle());
double actCost = activityCost.getActivityCost(end, arrivalTime, vehicleRoute.getDriver(), vehicleRoute.getVehicle());
vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost);
vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost);
totalOperationCost += transportCost;
totalOperationCost += actCost;
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;
}
}

View file

@ -0,0 +1,30 @@
package algorithms;
import algorithms.ForwardInTimeListeners.ForwardInTimeListener;
import algorithms.StateManager.StateImpl;
import basics.route.End;
import basics.route.Start;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
class UpdateEarliestStartTimeWindowAtActLocations implements ForwardInTimeListener{
private StateManagerImpl states;
public UpdateEarliestStartTimeWindowAtActLocations(StateManagerImpl states) {
super();
this.states = states;
}
@Override
public void start(VehicleRoute route, Start start, double departureTime) {}
@Override
public void nextActivity(TourActivity act, double arrTime, double endTime) {
states.putActivityState(act, StateTypes.EARLIEST_OPERATION_START_TIME, new StateImpl(Math.max(arrTime, act.getTheoreticalEarliestOperationStartTime())));
}
@Override
public void end(End end, double arrivalTime) {}
}

View file

@ -0,0 +1,32 @@
package algorithms;
import algorithms.BackwardInTimeListeners.BackwardInTimeListener;
import algorithms.StateManager.StateImpl;
import basics.route.End;
import basics.route.Start;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
class UpdateLatestOperationStartTimeAtActLocations implements BackwardInTimeListener{
private StateManagerImpl states;
public UpdateLatestOperationStartTimeAtActLocations(StateManagerImpl states) {
super();
this.states = states;
}
@Override
public void start(VehicleRoute route, End end, double latestArrivalTime) {}
@Override
public void prevActivity(TourActivity act,double latestDepartureTime, double latestOperationStartTime) {
states.putActivityState(act, StateTypes.LATEST_OPERATION_START_TIME, new StateImpl(latestOperationStartTime));
}
@Override
public void end(Start start, double latestDepartureTime) {}
}

View file

@ -0,0 +1,45 @@
package algorithms;
import algorithms.ForwardInTimeListeners.ForwardInTimeListener;
import algorithms.StateManager.StateImpl;
import basics.route.End;
import basics.route.Start;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
/**
* It does not update start and end activities.
*
* @author stefan
*
*/
class UpdateLoadAtAllLevels implements ForwardInTimeListener{
private double load = 0.0;
private StateManagerImpl states;
private VehicleRoute vehicleRoute;
public UpdateLoadAtAllLevels(StateManagerImpl states) {
super();
this.states = states;
}
@Override
public void start(VehicleRoute route, Start start, double departureTime) { vehicleRoute = route; }
@Override
public void nextActivity(TourActivity act, double arrTime, double endTime) {
load += (double)act.getCapacityDemand();
states.putActivityState(act, StateTypes.LOAD, new StateImpl(load));
}
@Override
public void end(End end, double arrivalTime) {
states.putRouteState(vehicleRoute, StateTypes.LOAD, new StateImpl(load));
load=0;
vehicleRoute = null;
}
}

View file

@ -0,0 +1,42 @@
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;
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));
}
}
}

View file

@ -0,0 +1,55 @@
package algorithms;
import java.util.Collection;
import algorithms.RuinStrategy.RuinListener;
import basics.Job;
import basics.algo.JobInsertedListener;
import basics.costs.VehicleRoutingActivityCosts;
import basics.costs.VehicleRoutingTransportCosts;
import basics.route.VehicleRoute;
class UpdateStates implements JobInsertedListener, RuinListener{
private IterateRouteForwardInTime iterateForward;
private IterateRouteBackwardInTime iterateBackward;
public UpdateStates(StateManagerImpl states, VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts) {
iterateForward = new IterateRouteForwardInTime(routingCosts);
iterateForward.addListener(new UpdateActivityTimes());
iterateForward.addListener(new UpdateCostsAtAllLevels(activityCosts, routingCosts, states));
iterateForward.addListener(new UpdateLoadAtAllLevels(states));
// iterateForward.addListener(new UpdateEarliestStartTimeWindowAtActLocations(states));
iterateBackward = new IterateRouteBackwardInTime(routingCosts);
iterateBackward.addListener(new UpdateLatestOperationStartTimeAtActLocations(states));
}
public void update(VehicleRoute route){
iterateForward.iterate(route);
iterateBackward.iterate(route);
}
@Override
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
iterateForward.iterate(inRoute);
iterateBackward.iterate(inRoute);
}
@Override
public void ruinStarts(Collection<VehicleRoute> routes) {}
@Override
public void ruinEnds(Collection<VehicleRoute> routes,Collection<Job> unassignedJobs) {
for(VehicleRoute route : routes) {
iterateForward.iterate(route);
iterateBackward.iterate(route);
}
}
@Override
public void removed(Job job, VehicleRoute fromRoute) {}
}

View file

@ -1,105 +0,0 @@
/*******************************************************************************
* Copyright (c) 2011 Stefan Schroeder.
* eMail: stefan.schroeder@kit.edu
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/
package algorithms;
import java.util.Iterator;
import org.apache.log4j.Logger;
import algorithms.RouteStates.ActivityState;
import basics.costs.BackwardTransportTime;
import basics.route.Start;
import basics.route.TourActivities;
import basics.route.TourActivity;
import basics.route.VehicleRoute;
/**
*
* @author stefan schroeder
*
*/
class UpdateTourStatesBackwardInTime implements VehicleRouteUpdater{
// public static Counter counter = new Counter("#updateTWProcesses: ");
private static Logger log = Logger.getLogger(UpdateTourStatesBackwardInTime.class);
public boolean checkFeasibility = true;
private BackwardTransportTime transportTime;
private RouteStates actStates;
public void setActivityStates(RouteStates actStates){
this.actStates = actStates;
}
public ActivityState state(TourActivity act){
return actStates.getState(act);
}
public UpdateTourStatesBackwardInTime(BackwardTransportTime transportTime) {
super();
this.transportTime = transportTime;
}
/*
*
*/
public boolean updateRoute(VehicleRoute vehicleRoute) {
boolean ok = update(vehicleRoute);
return ok;
}
private boolean update(VehicleRoute vehicleRoute) {
TourActivities tour = vehicleRoute.getTourActivities();
int tourSize = tour.getActivities().size();
Iterator<TourActivity> reverseActIter = vehicleRoute.getTourActivities().reverseActivityIterator();
TourActivity prevAct;
boolean feasible = true;
prevAct = vehicleRoute.getEnd();
double startAtPrevAct = prevAct.getTheoreticalLatestOperationStartTime();
int count = 0;
while(reverseActIter.hasNext()){
TourActivity currAct = reverseActIter.next();
double latestOperationStartTime = latestOperationStartTime(vehicleRoute, prevAct, currAct, startAtPrevAct);
ActivityState state = state(currAct);
state.setLatestOperationStart(latestOperationStartTime);
prevAct = currAct;
startAtPrevAct = latestOperationStartTime;
count++;
}
// Start start = vehicleRoute.getStart();
// double latestOperationStartTime = latestOperationStartTime(vehicleRoute, prevAct, start, startAtPrevAct);
assert count == tourSize;
return feasible;
}
private double latestOperationStartTime(VehicleRoute vehicleRoute,
TourActivity prevAct, TourActivity currAct, double startAtPrevAct) {
double latestDepTimeAtCurrAct = startAtPrevAct - transportTime.getBackwardTransportTime(currAct.getLocationId(), prevAct.getLocationId(), startAtPrevAct, vehicleRoute.getDriver(),vehicleRoute.getVehicle());
double potentialLatestOperationStartTimeAtCurrAct = latestDepTimeAtCurrAct - currAct.getOperationTime();
double latestOperationStartTime = Math.min(currAct.getTheoreticalLatestOperationStartTime(), potentialLatestOperationStartTimeAtCurrAct);
return latestOperationStartTime;
}
}

View file

@ -1,156 +0,0 @@
/*******************************************************************************
* Copyright (c) 2011 Stefan Schroeder.
* eMail: stefan.schroeder@kit.edu
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/
package algorithms;
import org.apache.log4j.Logger;
import algorithms.RouteStates.ActivityState;
import basics.costs.ForwardTransportCost;
import basics.costs.ForwardTransportTime;
import basics.costs.VehicleRoutingActivityCosts;
import basics.route.Driver;
import basics.route.End;
import basics.route.ServiceActivity;
import basics.route.TourActivities;
import basics.route.TourActivity;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
/**
*
* @author sschroeder
*
*/
class UpdateTourStatesForwardInTime implements VehicleRouteUpdater{
// public static Counter counter = new Counter("#updateTWProcesses: ");
private static Logger log = Logger.getLogger(UpdateTourStatesForwardInTime.class);
public boolean checkFeasibility = true;
private VehicleRoutingActivityCosts activityCost;
private ForwardTransportTime transportTime;
private ForwardTransportCost transportCost;
private RouteStates routeStates;
private boolean activityStatesSet = false;
public void setActivityStates(RouteStates actStates){
this.routeStates = actStates;
activityStatesSet = true;
}
public ActivityState state(TourActivity act){
return routeStates.getState(act);
}
public UpdateTourStatesForwardInTime(ForwardTransportTime transportTime, ForwardTransportCost transportCost, VehicleRoutingActivityCosts activityCost) {
super();
this.transportTime = transportTime;
this.transportCost = transportCost;
this.activityCost = activityCost;
}
/**
*
*
*/
public boolean updateRoute(VehicleRoute vehicleRoute) {
vehicleRoute.getVehicleRouteCostCalculator().reset();
Vehicle vehicle = vehicleRoute.getVehicle();
Driver driver = vehicleRoute.getDriver();
TourActivity prevAct = vehicleRoute.getStart();
double startAtPrevAct = vehicleRoute.getStart().getEndTime();
double totalOperationCost = 0.0;
int totalLoadPicked = 0;
int currentLoadState = 0;
for(TourActivity currentAct : vehicleRoute.getTourActivities().getActivities()){
totalLoadPicked += getPickedLoad(currentAct);
currentLoadState += getCapDemand(currentAct);
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();
currentAct.setArrTime(arrivalTimeAtCurrAct);
currentAct.setEndTime(operationEndTime);
double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle);
double actCost = activityCost.getActivityCost(currentAct, arrivalTimeAtCurrAct, driver, vehicle);
vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost);
vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost);
totalOperationCost += transportCost;
totalOperationCost += actCost;
if(activityStatesSet){
ActivityState currentState = state(currentAct);
currentState.setEarliestOperationStart(operationStartTime);
currentState.setCurrentLoad(currentLoadState);
currentState.setCurrentCost(totalOperationCost);
}
prevAct = currentAct;
startAtPrevAct = operationEndTime;
}
End currentAct = vehicleRoute.getEnd();
double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle);
double transportTime = this.transportTime.getTransportTime(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle);
double arrivalTimeAtCurrAct = startAtPrevAct + transportTime;
currentAct.setArrTime(arrivalTimeAtCurrAct);
currentAct.setEndTime(arrivalTimeAtCurrAct);
totalOperationCost += transportCost;
routeStates.getRouteState(vehicleRoute).setCosts(totalOperationCost);
routeStates.getRouteState(vehicleRoute).setLoad(totalLoadPicked);
vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost);
vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getDriver());
vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getVehicle());
vehicleRoute.getVehicleRouteCostCalculator().finish();
return true;
}
private int getCapDemand(TourActivity currentAct) {
return currentAct.getCapacityDemand();
}
private double getPickedLoad(TourActivity currentAct) {
if(currentAct instanceof ServiceActivity){
return currentAct.getCapacityDemand();
}
// else if(currentAct instanceof Pickup){
// return currentAct.getCapacityDemand();
// }
return 0.0;
}
}

View file

@ -24,6 +24,6 @@ import basics.route.VehicleRoute;
interface VehicleRouteUpdater {
public boolean updateRoute(VehicleRoute vehicleRoute);
public void iterate(VehicleRoute vehicleRoute);
}

View file

@ -36,7 +36,8 @@ import org.apache.commons.configuration.XMLConfiguration;
import org.apache.log4j.Logger;
import util.RouteUtils;
import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractInsertionKey;
import algorithms.RuinStrategy.RuinListener;
import algorithms.VehicleRoutingAlgorithms.TypedMap.InsertionStrategyKey;
import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractKey;
import algorithms.VehicleRoutingAlgorithms.TypedMap.AcceptorKey;
import algorithms.VehicleRoutingAlgorithms.TypedMap.RuinStrategyKey;
@ -56,19 +57,21 @@ import basics.VehicleRoutingProblem.FleetSize;
import basics.VehicleRoutingProblemSolution;
import basics.algo.AlgorithmStartsListener;
import basics.algo.InsertionListener;
import basics.algo.IterationStartsListener;
import basics.algo.IterationWithoutImprovementBreaker;
import basics.algo.PrematureAlgorithmBreaker;
import basics.algo.SearchStrategy;
import basics.algo.SearchStrategy.DiscoveredSolution;
import basics.algo.SearchStrategyManager;
import basics.algo.SearchStrategyModule;
import basics.algo.SearchStrategyModuleListener;
import basics.algo.TimeBreaker;
import basics.algo.VariationCoefficientBreaker;
import basics.algo.SearchStrategy.DiscoveredSolution;
import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener;
import basics.algo.VehicleRoutingAlgorithmListeners.Priority;
import basics.io.AlgorithmConfig;
import basics.io.AlgorithmConfigXmlReader;
import basics.route.VehicleRoute;
@ -258,11 +261,11 @@ public class VehicleRoutingAlgorithms {
}
static class AbstractInsertionKey implements AbstractKey<AbstractInsertionStrategy>{
static class InsertionStrategyKey implements AbstractKey<InsertionStrategy>{
private ModKey modKey;
public AbstractInsertionKey(ModKey modKey) {
public InsertionStrategyKey(ModKey modKey) {
super();
this.modKey = modKey;
}
@ -284,7 +287,7 @@ public class VehicleRoutingAlgorithms {
return false;
if (getClass() != obj.getClass())
return false;
AbstractInsertionKey other = (AbstractInsertionKey) obj;
InsertionStrategyKey other = (InsertionStrategyKey) obj;
if (modKey == null) {
if (other.modKey != null)
return false;
@ -296,8 +299,8 @@ public class VehicleRoutingAlgorithms {
@Override
public Class<AbstractInsertionStrategy> getType() {
return AbstractInsertionStrategy.class;
public Class<InsertionStrategy> getType() {
return InsertionStrategy.class;
}
}
@ -445,9 +448,21 @@ public class VehicleRoutingAlgorithms {
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, new SolutionVerifier()));
RouteStates routeStates = new RouteStates();
routeStates.initialiseStateOfJobs(vrp.getJobs().values());
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, routeStates));
final StateManagerImpl routeStates = new StateManagerImpl();
IterationStartsListener resetStates = new IterationStartsListener() {
@Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
routeStates.clear();
}
};
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, resetStates));
// insertionListeners.add(new UdateCostsAtRouteLevel(routeStates,vrp.getTransportCosts(),vrp.getActivityCosts()));
// RouteStates routeStates = new RouteStates();
// routeStates.initialiseStateOfJobs(vrp.getJobs().values());
// algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, routeStates));
TypedMap definedClasses = new TypedMap();
@ -533,16 +548,14 @@ public class VehicleRoutingAlgorithms {
private static void registerInsertionListeners(TypedMap definedClasses, List<InsertionListener> insertionListeners) {
for(AbstractKey<?> key : definedClasses.keySet()){
if(key instanceof AbstractInsertionKey){
AbstractInsertionKey insertionKey = (AbstractInsertionKey) key;
AbstractInsertionStrategy insertionStrategy = definedClasses.get(insertionKey);
if(key instanceof InsertionStrategyKey){
InsertionStrategyKey insertionKey = (InsertionStrategyKey) key;
InsertionStrategy insertionStrategy = definedClasses.get(insertionKey);
for(InsertionListener l : insertionListeners){
// log.info("add insertionListener " + l + " to " + insertionStrategy);
insertionStrategy.addListener(l);
}
}
}
// log.warn("cannot register insertion listeners yet");
}
private static String getName(HierarchicalConfiguration strategyConfig) {
@ -557,7 +570,7 @@ public class VehicleRoutingAlgorithms {
metaAlgorithm.getAlgorithmListeners().addAll(algorithmListeners);
}
private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, RouteStates activityStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads) {
private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads) {
List<HierarchicalConfiguration> modConfigs = config.configurationsAt("construction.insertion");
if(modConfigs == null) return null;
if(modConfigs.isEmpty()) return null;
@ -568,15 +581,15 @@ public class VehicleRoutingAlgorithms {
String insertionId = modConfig.getString("[@id]");
if(insertionId == null) insertionId = "noId";
ModKey modKey = makeKey(insertionName,insertionId);
AbstractInsertionKey insertionStrategyKey = new AbstractInsertionKey(modKey);
AbstractInsertionStrategy insertionStrategy = definedClasses.get(insertionStrategyKey);
InsertionStrategyKey insertionStrategyKey = new InsertionStrategyKey(modKey);
InsertionStrategy insertionStrategy = definedClasses.get(insertionStrategyKey);
if(insertionStrategy == null){
List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
insertionStrategy = createInsertionStrategy(modConfig, vrp, vehicleFleetManager, activityStates, prioListeners, executorService, nuOfThreads);
insertionStrategy = createInsertionStrategy(modConfig, vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads);
algorithmListeners.addAll(prioListeners);
definedClasses.put(insertionStrategyKey,insertionStrategy);
}
final AbstractInsertionStrategy finalInsertionStrategy = insertionStrategy;
final InsertionStrategy finalInsertionStrategy = insertionStrategy;
return new AlgorithmStartsListener() {
@ -653,8 +666,8 @@ public class VehicleRoutingAlgorithms {
}
}
private static SearchStrategyModule buildModule(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager,
RouteStates activityStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads) {
private static SearchStrategyModule buildModule(HierarchicalConfiguration moduleConfig, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager,
final StateManagerImpl routeStates, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads) {
String moduleName = moduleConfig.getString("[@name]");
if(moduleName == null) throw new IllegalStateException("module(-name) is missing.");
String moduleId = moduleConfig.getString("[@id]");
@ -675,7 +688,7 @@ public class VehicleRoutingAlgorithms {
final RuinStrategy ruin;
ModKey ruinKey = makeKey(ruin_name,ruin_id);
if(ruin_name.equals("randomRuin")){
ruin = getRandomRuin(vrp, activityStates, definedClasses, ruinKey, shareToRuin);
ruin = getRandomRuin(vrp, routeStates, definedClasses, ruinKey, shareToRuin);
}
else if(ruin_name.equals("radialRuin")){
String ruin_distance = moduleConfig.getString("ruin.distance");
@ -688,7 +701,7 @@ public class VehicleRoutingAlgorithms {
else throw new IllegalStateException("does not know ruin.distance " + ruin_distance + ". either ommit ruin.distance then the "
+ "default is used or use 'euclidean'");
}
ruin = getRadialRuin(vrp, activityStates, definedClasses, ruinKey, shareToRuin, jobDistance);
ruin = getRadialRuin(vrp, routeStates, definedClasses, ruinKey, shareToRuin, jobDistance);
}
else throw new IllegalStateException("ruin[@name] " + ruin_name + " is not known. Use either randomRuin or radialRuin.");
@ -697,16 +710,16 @@ public class VehicleRoutingAlgorithms {
String insertionId = moduleConfig.getString("insertion[@id]");
if(insertionId == null) insertionId = "noId";
ModKey insertionKey = makeKey(insertionName,insertionId);
AbstractInsertionKey insertionStrategyKey = new AbstractInsertionKey(insertionKey);
AbstractInsertionStrategy insertion = definedClasses.get(insertionStrategyKey);
InsertionStrategyKey insertionStrategyKey = new InsertionStrategyKey(insertionKey);
InsertionStrategy insertion = definedClasses.get(insertionStrategyKey);
if(insertion == null){
List<HierarchicalConfiguration> insertionConfigs = moduleConfig.configurationsAt("insertion");
if(insertionConfigs.size() != 1) throw new IllegalStateException("this should be 1");
List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, activityStates, prioListeners, executorService, nuOfThreads);
insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads);
algorithmListeners.addAll(prioListeners);
}
final AbstractInsertionStrategy final_insertion = insertion;
final InsertionStrategy final_insertion = insertion;
SearchStrategyModule module = new SearchStrategyModule() {
private Logger logger = Logger.getLogger(SearchStrategyModule.class);
@ -714,7 +727,7 @@ public class VehicleRoutingAlgorithms {
@Override
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
Collection<Job> ruinedJobs = ruin.ruin(vrpSolution.getRoutes());
final_insertion.run(vrpSolution.getRoutes(), ruinedJobs, Double.MAX_VALUE);
final_insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobs);
double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes());
vrpSolution.setCost(totalCost);
return vrpSolution;
@ -734,7 +747,7 @@ public class VehicleRoutingAlgorithms {
public void addModuleListener(SearchStrategyModuleListener moduleListener) {
if(moduleListener instanceof InsertionListener){
InsertionListener iListener = (InsertionListener) moduleListener;
if(!final_insertion.getListener().contains(iListener)){
if(!final_insertion.getListeners().contains(iListener)){
logger.info("register moduleListener " + moduleListener);
final_insertion.addListener(iListener);
}
@ -746,41 +759,42 @@ public class VehicleRoutingAlgorithms {
return module;
}
if(moduleName.equals("gendreauPostOpt")){
if(moduleName.equals("gendreau")){
int iterations = moduleConfig.getInt("iterations");
double share = moduleConfig.getDouble("share");
String ruinName = moduleConfig.getString("ruin[@name]");
if(ruinName == null) throw new IllegalStateException("gendreauPostOpt.ruin[@name] is missing. set it to \"radialRuin\" or \"randomRuin\"");
if(ruinName == null) throw new IllegalStateException("gendreau.ruin[@name] is missing. set it to \"radialRuin\" or \"randomRuin\"");
String ruinId = moduleConfig.getString("ruin[@id]");
if(ruinId == null) ruinId = "noId";
ModKey ruinKey = makeKey(ruinName,ruinId);
RuinStrategyKey stratKey = new RuinStrategyKey(ruinKey);
RuinStrategy ruin = definedClasses.get(stratKey);
if(ruin == null){
ruin = RuinRadial.newInstance(vrp, 0.3, new JobDistanceAvgCosts(vrp.getTransportCosts()), new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts()));
ruin = new RuinRadial(vrp, 0.3, new JobDistanceAvgCosts(vrp.getTransportCosts()));
ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts()));
definedClasses.put(stratKey, ruin);
}
String insertionName = moduleConfig.getString("insertion[@name]");
if(insertionName == null) throw new IllegalStateException("gendreauPostOpt.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\"");
if(insertionName == null) throw new IllegalStateException("gendreau.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\"");
String insertionId = moduleConfig.getString("insertion[@id]");
if(insertionId == null) insertionId = "noId";
ModKey insertionKey = makeKey(insertionName,insertionId);
AbstractInsertionKey insertionStrategyKey = new AbstractInsertionKey(insertionKey);
AbstractInsertionStrategy insertion = definedClasses.get(insertionStrategyKey);
InsertionStrategyKey insertionStrategyKey = new InsertionStrategyKey(insertionKey);
InsertionStrategy insertion = definedClasses.get(insertionStrategyKey);
if(insertion == null){
List<HierarchicalConfiguration> insertionConfigs = moduleConfig.configurationsAt("insertion");
if(insertionConfigs.size() != 1) throw new IllegalStateException("this should be 1");
List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, activityStates, prioListeners, executorService, nuOfThreads);
insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads);
algorithmListeners.addAll(prioListeners);
}
GendreauPostOpt postOpt = new GendreauPostOpt(vrp, ruin, insertion);
postOpt.setShareOfJobsToRuin(share);
postOpt.setNuOfIterations(iterations);
postOpt.setFleetManager(vehicleFleetManager);
definedClasses.put(strategyModuleKey, postOpt);
return postOpt;
Gendreau gendreau = new Gendreau(vrp, ruin, insertion);
gendreau.setShareOfJobsToRuin(share);
gendreau.setNuOfIterations(iterations);
gendreau.setFleetManager(vehicleFleetManager);
definedClasses.put(strategyModuleKey, gendreau);
return gendreau;
}
throw new NullPointerException("no module found with moduleName=" + moduleName +
"\n\tcheck config whether the correct names are used" +
@ -791,30 +805,30 @@ public class VehicleRoutingAlgorithms {
"\n\tgendreauPostOpt");
}
private static RuinStrategy getRadialRuin(VehicleRoutingProblem vrp, RouteStates activityStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) {
private static RuinStrategy getRadialRuin(final VehicleRoutingProblem vrp, final StateManagerImpl routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) {
RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
RuinStrategy ruin = definedClasses.get(stratKey);
if(ruin == null){
ruin = RuinRadial.newInstance(vrp, shareToRuin, jobDistance, new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts()));
ruin = new RuinRadial(vrp, shareToRuin, jobDistance);
ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts()));
definedClasses.put(stratKey, ruin);
}
return ruin;
}
private static RuinStrategy getRandomRuin(VehicleRoutingProblem vrp,
RouteStates activityStates, TypedMap definedClasses,
ModKey modKey, double shareToRuin) {
private static RuinStrategy getRandomRuin(final VehicleRoutingProblem vrp, final StateManagerImpl routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin) {
RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
RuinStrategy ruin = definedClasses.get(stratKey);
if(ruin == null){
ruin = RuinRandom.newInstance(vrp, shareToRuin, new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts()));
ruin = new RuinRandom(vrp, shareToRuin);
ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts()));
definedClasses.put(stratKey, ruin);
}
return ruin;
}
private static AbstractInsertionStrategy createInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp,VehicleFleetManager vehicleFleetManager, RouteStates activityStates, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads) {
AbstractInsertionStrategy insertion = InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, activityStates, algorithmListeners, executorService, nuOfThreads);
private static InsertionStrategy createInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp,VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads) {
InsertionStrategy insertion = InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, routeStates, algorithmListeners, executorService, nuOfThreads);
return insertion;
}

View file

@ -21,7 +21,8 @@
package algorithms;
import basics.route.Vehicle;
import algorithms.RouteAlgorithm.VehicleSwitchedListener;
import basics.route.VehicleRoute;
class VehicleSwitched implements VehicleSwitchedListener{
@ -32,7 +33,7 @@ class VehicleSwitched implements VehicleSwitchedListener{
}
@Override
public void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle) {
public void vehicleSwitched(VehicleRoute vehicleRoute, Vehicle oldVehicle, Vehicle newVehicle) {
fleetManager.unlock(oldVehicle);
fleetManager.lock(newVehicle);
}

View file

@ -0,0 +1,11 @@
package algorithms;
import basics.algo.InsertionListener;
import basics.route.Vehicle;
import basics.route.VehicleRoute;
interface VehicleSwitchedListener extends InsertionListener{
public void vehicleSwitched(VehicleRoute vehicleRoute, Vehicle oldVehicle, Vehicle newVehicle);
}

View file

@ -22,10 +22,11 @@ package basics.algo;
import java.util.Collection;
import basics.Job;
import basics.route.VehicleRoute;
public interface InsertionStartsListener extends InsertionListener {
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2Recreate);
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
}

View file

@ -30,5 +30,5 @@ import basics.route.VehicleRoute;
public interface JobInsertedListener extends InsertionListener{
public void informJobInserted(int nOfJobsStill2Recreate, Job job2insert, VehicleRoute insertedIn);
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime);
}

View file

@ -274,7 +274,7 @@ public class VrpXMLReader{
if(distC != null) typeBuilder.setCostPerDistance(distC);
// if(start != null && end != null) typeBuilder.setTimeSchedule(new TimeSchedule(start, end));
VehicleTypeImpl type = typeBuilder.build();
types.put(type.typeId, type);
types.put(type.getTypeId(), type);
vrpBuilder.addVehicleType(type);
}

View file

@ -61,12 +61,15 @@ public final class End implements TourActivity {
this.locationId = locationId;
theoretical_earliestOperationStartTime = theoreticalStart;
theoretical_latestOperationStartTime = theoreticalEnd;
endTime = theoreticalEnd;
}
public End(End end) {
this.locationId = end.getLocationId();
theoretical_earliestOperationStartTime = end.getTheoreticalEarliestOperationStartTime();
theoretical_latestOperationStartTime = end.getTheoreticalLatestOperationStartTime();
arrTime = end.getArrTime();
endTime = end.getEndTime();
}
public double getTheoreticalEarliestOperationStartTime() {

View file

@ -26,6 +26,11 @@ public class PenaltyVehicleType implements VehicleType{
return type.getVehicleCostParams();
}
@Override
public double getMaxVelocity() {
return type.getMaxVelocity();
}
}

View file

@ -76,15 +76,9 @@ public class TourActivities {
}
private final ArrayList<TourActivity> tourActivities = new ArrayList<TourActivity>();
// private final LinkedList<TourActivity> tourActivities = new LinkedList<TourActivity>();
// private final TreeList tourActivities = new TreeList();
private final Set<Job> jobs = new HashSet<Job>();
private int load = 0;
private double cost = 0.0;
private ReverseActivityIterator backward;
private TourActivities(TourActivities tour2copy) {
@ -125,7 +119,7 @@ public class TourActivities {
}
/**
* Removes job AND belonging activity from tour.
* Removes job AND belonging activity from tour and returns true if job has been removed, otherwise false.
*
* @param job
* @return

View file

@ -158,6 +158,11 @@ public class VehicleRoute {
start.setEndTime(vehicleDepTime);
}
public double getDepartureTime(){
if(start == null) throw new IllegalStateException("cannot get departureTime without having a vehicle on this route. use setVehicle(vehicle,departureTime) instead.");
return start.getEndTime();
}
private void setStartAndEnd(Vehicle vehicle, double vehicleDepTime) {
if(!(vehicle instanceof NoVehicle)){
if(start == null && end == null){

View file

@ -8,6 +8,8 @@ public interface VehicleType {
public String getTypeId();
public int getCapacity();
public double getMaxVelocity();
public VehicleCostParams getVehicleCostParams();

View file

@ -35,6 +35,7 @@ public class VehicleTypeImpl implements VehicleType {
private String id;
private int capacity;
private double maxVelo = Double.MAX_VALUE;
/**
* default cost values for default vehicle type
*/
@ -48,6 +49,8 @@ public class VehicleTypeImpl implements VehicleType {
this.capacity = capacity;
}
public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds){ this.maxVelo = inMeterPerSeconds; return this; }
public VehicleTypeImpl.Builder setFixedCost(double fixedCost) { this.fixedCost = fixedCost; return this; }
public VehicleTypeImpl.Builder setCostPerDistance(double perDistance){ this.perDistance = perDistance; return this; }
@ -86,9 +89,13 @@ public class VehicleTypeImpl implements VehicleType {
return true;
}
public final String typeId;
public final int capacity;
public final VehicleTypeImpl.VehicleCostParams vehicleCostParams;
private final String typeId;
private final int capacity;
private final VehicleTypeImpl.VehicleCostParams vehicleCostParams;
private double maxVelocity;
public static VehicleTypeImpl newInstance(String typeId, int capacity, VehicleTypeImpl.VehicleCostParams para){
return new VehicleTypeImpl(typeId, capacity, para);
@ -97,6 +104,7 @@ public class VehicleTypeImpl implements VehicleType {
private VehicleTypeImpl(VehicleTypeImpl.Builder builder){
typeId = builder.id;
capacity = builder.capacity;
maxVelocity = builder.maxVelo;
vehicleCostParams = new VehicleCostParams(builder.fixedCost, builder.perTime, builder.perDistance);
}
@ -135,4 +143,9 @@ public class VehicleTypeImpl implements VehicleType {
public String toString() {
return "[typeId="+typeId+"][capacity="+capacity+"]" + vehicleCostParams;
}
@Override
public double getMaxVelocity() {
return maxVelocity;
}
}

View file

@ -10,7 +10,16 @@ import basics.route.Driver;
import basics.route.Vehicle;
import basics.route.VehicleTypeImpl.VehicleCostParams;
/**
* CostMatrix that allows pre-compiled time and distance-matrices to be considered as {@link VehicleRoutingRoutingCosts}
* in the {@link VehicleRoutingProblem}.
* <p>Note that you can also use it with distance matrix only (or time matrix). But ones
* you set a particular distance, this expects distance-entries for all relations. This counts also
* for a particular time. If the method getTransportCosts(...) is then invoked for a relation, where no distance can be found, an
* IllegalStateException will be thrown. Thus if you want to only use distances only, do not use addTransportTime(...).
* @author schroeder
*
*/
public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTransportCosts {
static class RelationKey {
@ -74,7 +83,12 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo
}
/**
* Builder that builds the matrix.
*
* @author schroeder
*
*/
public static class Builder {
private static Logger log = Logger.getLogger(Builder.class);
@ -84,6 +98,16 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo
private Map<RelationKey,Double> times = new HashMap<RelationKey, Double>();
private boolean distancesSet = false;
private boolean timesSet = false;
/**
* Creates a new builder returning the matrix-builder.
* <p>If you want to consider symmetric matrices, set isSymmetric to true.
* @param isSymmetric
* @return
*/
public static Builder newInstance(boolean isSymmetric){
return new Builder(isSymmetric);
}
@ -92,8 +116,16 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo
this.isSymmetric = isSymmetric;
}
/**
* Adds a transport-distance for a particular relation.
* @param from
* @param to
* @param distance
* @return
*/
public Builder addTransportDistance(String from, String to, double distance){
RelationKey key = RelationKey.newKey(from, to);
if(!distancesSet) distancesSet = true;
if(distances.containsKey(key)){
log.warn("distance from " + from + " to " + to + " already exists. This overrides distance.");
}
@ -101,8 +133,16 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo
return this;
}
/**
* Adds transport-time for a particular relation.
* @param from
* @param to
* @param time
* @return
*/
public Builder addTransportTime(String from, String to, double time){
RelationKey key = RelationKey.newKey(from, to);
if(!timesSet) timesSet = true;
if(times.containsKey(key)){
log.warn("transport-time from " + from + " to " + to + " already exists. This overrides distance.");
}
@ -110,6 +150,10 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo
return this;
}
/**
* Builds the matrix.
* @return
*/
public VehicleRoutingTransportCostsMatrix build(){
return new VehicleRoutingTransportCostsMatrix(this);
}
@ -121,10 +165,16 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo
private boolean isSymmetric;
private boolean timesSet;
private boolean distancesSet;
private VehicleRoutingTransportCostsMatrix(Builder builder){
this.isSymmetric = builder.isSymmetric;
distances.putAll(builder.distances);
times.putAll(builder.times);
timesSet = builder.timesSet;
distancesSet = builder.distancesSet;
}
@ -136,6 +186,7 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo
private double getTime(String fromId, String toId) {
if(fromId.equals(toId)) return 0.0;
if(!timesSet) return 0.0;
RelationKey key = RelationKey.newKey(fromId, toId);
if(!isSymmetric){
if(times.containsKey(key)) return times.get(key);
@ -153,6 +204,7 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo
private double getDistance(String fromId, String toId) {
if(fromId.equals(toId)) return 0.0;
if(!distancesSet) return 0.0;
RelationKey key = RelationKey.newKey(fromId, toId);
if(!isSymmetric){
if(distances.containsKey(key)) return distances.get(key);

View file

@ -166,14 +166,16 @@
<xs:group name="gendreau_group">
<xs:sequence>
<xs:element name="itertions" type="xs:integer"/>
<xs:element name="iterations" type="xs:integer"/>
<xs:element name="share" type="xs:double"/>
<xs:element name="ruin" type="ruinType"/>
<xs:element name="insertion" type="insertionType"/>
</xs:sequence>
</xs:group>
<xs:complexType name="ruinType">
<xs:sequence>
<xs:element name="share" minOccurs="1" maxOccurs="1">
<xs:element name="share" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:double">
<xs:minInclusive value="0.0"/>