mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
add breaks
This commit is contained in:
parent
543d1c2ace
commit
4e83871984
16 changed files with 871 additions and 14 deletions
|
|
@ -0,0 +1,183 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (C) 2014 Stefan Schroeder
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
package jsprit.core.algorithm.recreate;
|
||||
|
||||
import jsprit.core.problem.JobActivityFactory;
|
||||
import jsprit.core.problem.Location;
|
||||
import jsprit.core.problem.constraint.*;
|
||||
import jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
|
||||
import jsprit.core.problem.cost.VehicleRoutingTransportCosts;
|
||||
import jsprit.core.problem.driver.Driver;
|
||||
import jsprit.core.problem.job.Break;
|
||||
import jsprit.core.problem.job.Job;
|
||||
import jsprit.core.problem.misc.JobInsertionContext;
|
||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import jsprit.core.problem.solution.route.activity.BreakActivity;
|
||||
import jsprit.core.problem.solution.route.activity.End;
|
||||
import jsprit.core.problem.solution.route.activity.Start;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
import jsprit.core.problem.vehicle.Vehicle;
|
||||
import jsprit.core.util.CalculationUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Calculator that calculates the best insertion position for a {@link jsprit.core.problem.job.Service}.
|
||||
*
|
||||
* @author schroeder
|
||||
*
|
||||
*/
|
||||
final class BreakInsertionCalculator implements JobInsertionCostsCalculator{
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(BreakInsertionCalculator.class);
|
||||
|
||||
private HardRouteConstraint hardRouteLevelConstraint;
|
||||
|
||||
private HardActivityConstraint hardActivityLevelConstraint;
|
||||
|
||||
private SoftRouteConstraint softRouteConstraint;
|
||||
|
||||
private SoftActivityConstraint softActivityConstraint;
|
||||
|
||||
private VehicleRoutingTransportCosts transportCosts;
|
||||
|
||||
private ActivityInsertionCostsCalculator additionalTransportCostsCalculator;
|
||||
|
||||
private JobActivityFactory activityFactory;
|
||||
|
||||
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
|
||||
|
||||
public BreakInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
|
||||
super();
|
||||
this.transportCosts = routingCosts;
|
||||
hardRouteLevelConstraint = constraintManager;
|
||||
hardActivityLevelConstraint = constraintManager;
|
||||
softActivityConstraint = constraintManager;
|
||||
softRouteConstraint = constraintManager;
|
||||
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
|
||||
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
|
||||
logger.debug("initialise " + this);
|
||||
}
|
||||
|
||||
public void setJobActivityFactory(JobActivityFactory jobActivityFactory){
|
||||
this.activityFactory = jobActivityFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[name=calculatesServiceInsertion]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the marginal cost of inserting job i locally. This is based on the
|
||||
* assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
|
||||
Break breakToInsert = (Break) jobToInsert;
|
||||
if(newVehicle.getBreak() == null || newVehicle.getBreak() != breakToInsert) return InsertionData.createEmptyInsertionData();
|
||||
|
||||
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
||||
int insertionIndex = InsertionData.NO_INDEX;
|
||||
|
||||
BreakActivity breakAct2Insert = (BreakActivity) activityFactory.createActivities(breakToInsert).get(0);
|
||||
insertionContext.getAssociatedActivities().add(breakAct2Insert);
|
||||
|
||||
boolean differentVehicles = false;
|
||||
if(!currentRoute.isEmpty()){
|
||||
differentVehicles = currentRoute.getVehicle() != newVehicle;
|
||||
}
|
||||
/*
|
||||
check hard constraints at route level
|
||||
*/
|
||||
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
|
||||
return InsertionData.createEmptyInsertionData();
|
||||
}
|
||||
|
||||
/*
|
||||
check soft constraints at route level
|
||||
*/
|
||||
double additionalICostsAtRouteLevel = softRouteConstraint.getCosts(insertionContext);
|
||||
|
||||
double bestCost = bestKnownCosts;
|
||||
additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext);
|
||||
|
||||
/*
|
||||
generate new start and end for new vehicle
|
||||
*/
|
||||
Start start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), Double.MAX_VALUE);
|
||||
start.setEndTime(newVehicleDepartureTime);
|
||||
End end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
|
||||
|
||||
Location bestLocation = null;
|
||||
|
||||
TourActivity prevAct = start;
|
||||
double prevActStartTime = newVehicleDepartureTime;
|
||||
int actIndex = 0;
|
||||
Iterator<TourActivity> activityIterator = currentRoute.getActivities().iterator();
|
||||
boolean tourEnd = false;
|
||||
while(!tourEnd){
|
||||
TourActivity nextAct;
|
||||
if(activityIterator.hasNext()) nextAct = activityIterator.next();
|
||||
else{
|
||||
nextAct = end;
|
||||
tourEnd = true;
|
||||
}
|
||||
boolean breakThis = true;
|
||||
List<Location> locations = Arrays.asList( prevAct.getLocation(), nextAct.getLocation());
|
||||
for(Location location : locations) {
|
||||
breakAct2Insert.setLocation(location);
|
||||
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, breakAct2Insert, nextAct, prevActStartTime);
|
||||
if (status.equals(ConstraintsStatus.FULFILLED)) {
|
||||
//from job2insert induced costs at activity level
|
||||
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, breakAct2Insert, nextAct, prevActStartTime);
|
||||
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, breakAct2Insert, prevActStartTime);
|
||||
if (additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts < bestCost) {
|
||||
bestCost = additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts;
|
||||
insertionIndex = actIndex;
|
||||
bestLocation = location;
|
||||
}
|
||||
breakThis = false;
|
||||
} else if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
|
||||
breakThis = false;
|
||||
}
|
||||
double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActStartTime, newDriver, newVehicle);
|
||||
prevActStartTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct);
|
||||
prevAct = nextAct;
|
||||
actIndex++;
|
||||
}
|
||||
if(breakThis) break;
|
||||
}
|
||||
if(insertionIndex == InsertionData.NO_INDEX) {
|
||||
return InsertionData.createEmptyInsertionData();
|
||||
}
|
||||
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
||||
breakAct2Insert.setLocation(bestLocation);
|
||||
insertionData.getEvents().add(new InsertBreak(currentRoute,newVehicle,breakAct2Insert,insertionIndex));
|
||||
insertionData.getEvents().add(new SwitchVehicle(currentRoute,newVehicle,newVehicleDepartureTime));
|
||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||
return insertionData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ class EventListeners {
|
|||
public EventListeners() {
|
||||
listeners.add(new InsertActivityListener());
|
||||
listeners.add(new SwitchVehicleListener());
|
||||
listeners.add(new InsertBreakListener());
|
||||
}
|
||||
|
||||
public void inform(Event event){
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package jsprit.core.algorithm.recreate;
|
||||
|
||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
import jsprit.core.problem.vehicle.Vehicle;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 19/05/15.
|
||||
*/
|
||||
class InsertBreak implements Event {
|
||||
|
||||
private VehicleRoute vehicleRoute;
|
||||
|
||||
private Vehicle newVehicle;
|
||||
|
||||
private TourActivity activity;
|
||||
|
||||
private int index;
|
||||
|
||||
public InsertBreak(VehicleRoute vehicleRoute, Vehicle newVehicle, TourActivity activity, int index) {
|
||||
this.vehicleRoute = vehicleRoute;
|
||||
this.newVehicle = newVehicle;
|
||||
this.activity = activity;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public Vehicle getNewVehicle() {
|
||||
return newVehicle;
|
||||
}
|
||||
|
||||
public VehicleRoute getVehicleRoute() {
|
||||
return vehicleRoute;
|
||||
}
|
||||
|
||||
public TourActivity getActivity() {
|
||||
return activity;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package jsprit.core.algorithm.recreate;
|
||||
|
||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 19/05/15.
|
||||
*/
|
||||
class InsertBreakListener implements EventListener {
|
||||
|
||||
@Override
|
||||
public void inform(Event event) {
|
||||
if(event instanceof InsertBreak){
|
||||
InsertBreak insertActivity = (InsertBreak) event;
|
||||
if(!insertActivity.getNewVehicle().isReturnToDepot()){
|
||||
if(insertActivity.getIndex()>=insertActivity.getVehicleRoute().getActivities().size()){
|
||||
insertActivity.getVehicleRoute().getEnd().setLocation(insertActivity.getActivity().getLocation());
|
||||
}
|
||||
}
|
||||
VehicleRoute vehicleRoute = ((InsertBreak) event).getVehicleRoute();
|
||||
if(!vehicleRoute.isEmpty()){
|
||||
if(vehicleRoute.getVehicle() != ((InsertBreak) event).getNewVehicle()){
|
||||
if(vehicleRoute.getVehicle().getBreak() != null){
|
||||
vehicleRoute.getTourActivities().removeJob(vehicleRoute.getVehicle().getBreak());
|
||||
}
|
||||
}
|
||||
}
|
||||
insertActivity.getVehicleRoute().getTourActivities().addActivity(insertActivity.getIndex(),((InsertBreak) event).getActivity());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -290,11 +290,15 @@ public class JobInsertionCostsCalculatorBuilder {
|
|||
ServiceInsertionCalculator serviceInsertion = new ServiceInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager);
|
||||
serviceInsertion.setJobActivityFactory(activityFactory);
|
||||
|
||||
BreakInsertionCalculator breakInsertionCalculator = new BreakInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager);
|
||||
breakInsertionCalculator.setJobActivityFactory(activityFactory);
|
||||
|
||||
JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
|
||||
switcher.put(Shipment.class, shipmentInsertion);
|
||||
switcher.put(Service.class, serviceInsertion);
|
||||
switcher.put(Pickup.class, serviceInsertion);
|
||||
switcher.put(Delivery.class, serviceInsertion);
|
||||
switcher.put(Break.class, breakInsertionCalculator);
|
||||
|
||||
return new CalculatorPlusListeners(switcher);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,10 +160,14 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
|||
}
|
||||
|
||||
private double scoreService(InsertionData best, Job job) {
|
||||
double maxDepotDistance = Math.max(
|
||||
getDistance(best.getSelectedVehicle().getStartLocation(), ((Service) job).getLocation()),
|
||||
getDistance(best.getSelectedVehicle().getEndLocation(), ((Service) job).getLocation())
|
||||
);
|
||||
Location location = ((Service) job).getLocation();
|
||||
double maxDepotDistance = 0;
|
||||
if(location != null) {
|
||||
maxDepotDistance = Math.max(
|
||||
getDistance(best.getSelectedVehicle().getStartLocation(), location),
|
||||
getDistance(best.getSelectedVehicle().getEndLocation(), location)
|
||||
);
|
||||
}
|
||||
return Math.max(tw_param * (((Service)job).getTimeWindow().getEnd() - ((Service)job).getTimeWindow().getStart()),minTimeWindowScore) +
|
||||
depotDistance_param * maxDepotDistance;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package jsprit.core.algorithm.ruin;
|
||||
|
||||
import jsprit.core.algorithm.ruin.listener.RuinListener;
|
||||
import jsprit.core.problem.job.Break;
|
||||
import jsprit.core.problem.job.Job;
|
||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 04/08/15.
|
||||
*/
|
||||
public class RuinBreaks implements RuinListener {
|
||||
|
||||
@Override
|
||||
public void ruinStarts(Collection<VehicleRoute> routes) {}
|
||||
|
||||
@Override
|
||||
public void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
||||
for(VehicleRoute r : routes){
|
||||
Break aBreak = r.getVehicle().getBreak();
|
||||
if(aBreak != null){
|
||||
r.getTourActivities().removeJob(aBreak);
|
||||
unassignedJobs.add(aBreak);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed(Job job, VehicleRoute fromRoute) {}
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import jsprit.core.problem.job.Job;
|
|||
import jsprit.core.problem.job.Service;
|
||||
import jsprit.core.problem.job.Shipment;
|
||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import jsprit.core.problem.solution.route.activity.BreakActivity;
|
||||
import jsprit.core.problem.solution.route.activity.DefaultShipmentActivityFactory;
|
||||
import jsprit.core.problem.solution.route.activity.DefaultTourActivityFactory;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
|
|
@ -117,7 +118,7 @@ public class VehicleRoutingProblem {
|
|||
acts.add(shipmentActivityFactory.createPickup((Shipment) job));
|
||||
acts.add(shipmentActivityFactory.createDelivery((Shipment) job));
|
||||
}
|
||||
return acts;
|
||||
return acts;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -138,7 +139,7 @@ public class VehicleRoutingProblem {
|
|||
|
||||
private final DefaultTourActivityFactory serviceActivityFactory = new DefaultTourActivityFactory();
|
||||
|
||||
private void incJobIndexCounter(){
|
||||
private void incJobIndexCounter(){
|
||||
jobIndexCounter++;
|
||||
}
|
||||
|
||||
|
|
@ -265,6 +266,16 @@ public class VehicleRoutingProblem {
|
|||
activityMap.put(job, jobActs);
|
||||
}
|
||||
|
||||
private void addBreaksToActivityMap(){
|
||||
for(Vehicle v : uniqueVehicles){
|
||||
if(v.getBreak() != null){
|
||||
AbstractActivity breakActivity = BreakActivity.newInstance(v.getBreak());
|
||||
breakActivity.setIndex(activityIndexCounter);
|
||||
incActivityIndexCounter();
|
||||
activityMap.put(v.getBreak(),Arrays.asList(breakActivity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an initial vehicle route.
|
||||
|
|
@ -402,10 +413,12 @@ public class VehicleRoutingProblem {
|
|||
if(transportCosts == null){
|
||||
transportCosts = new CrowFlyCosts(getLocations());
|
||||
}
|
||||
for(Job job : tentativeJobs.values())
|
||||
if (!jobsInInitialRoutes.contains(job.getId())) {
|
||||
addJobToFinalJobMapAndCreateActivities(job);
|
||||
}
|
||||
for(Job job : tentativeJobs.values()) {
|
||||
if (!jobsInInitialRoutes.contains(job.getId())) {
|
||||
addJobToFinalJobMapAndCreateActivities(job);
|
||||
}
|
||||
}
|
||||
addBreaksToActivityMap();
|
||||
return new VehicleRoutingProblem(this);
|
||||
}
|
||||
|
||||
|
|
|
|||
80
jsprit-core/src/main/java/jsprit/core/problem/job/Break.java
Normal file
80
jsprit-core/src/main/java/jsprit/core/problem/job/Break.java
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (C) 2014 Stefan Schroeder
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
package jsprit.core.problem.job;
|
||||
|
||||
|
||||
import jsprit.core.problem.Capacity;
|
||||
import jsprit.core.problem.Skills;
|
||||
|
||||
/**
|
||||
* Pickup extends Service and is intended to model a Service where smth is LOADED (i.e. picked up) to a transport unit.
|
||||
*
|
||||
* @author schroeder
|
||||
*
|
||||
*/
|
||||
public class Break extends Service {
|
||||
|
||||
public static class Builder extends Service.Builder {
|
||||
|
||||
/**
|
||||
* Returns a new instance of builder that builds a pickup.
|
||||
*
|
||||
* @param id the id of the pickup
|
||||
* @return the builder
|
||||
*/
|
||||
public static Builder newInstance(String id){
|
||||
return new Builder(id);
|
||||
}
|
||||
|
||||
private boolean variableLocation = true;
|
||||
|
||||
Builder(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds Pickup.
|
||||
*
|
||||
*<p>Pickup type is "pickup"
|
||||
*
|
||||
* @return pickup
|
||||
* @throws IllegalStateException if neither locationId nor coordinate has been set
|
||||
*/
|
||||
public Break build(){
|
||||
if(location != null){
|
||||
variableLocation = false;
|
||||
}
|
||||
this.setType("break");
|
||||
super.capacity = Capacity.Builder.newInstance().build();
|
||||
super.skills = Skills.Builder.newInstance().build();
|
||||
return new Break(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean variableLocation = true;
|
||||
|
||||
Break(Builder builder) {
|
||||
super(builder);
|
||||
this.variableLocation = builder.variableLocation;
|
||||
}
|
||||
|
||||
public boolean hasVariableLocation(){
|
||||
return variableLocation;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (C) 2014 Stefan Schroeder
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
package jsprit.core.problem.solution.route.activity;
|
||||
|
||||
import jsprit.core.problem.AbstractActivity;
|
||||
import jsprit.core.problem.Capacity;
|
||||
import jsprit.core.problem.Location;
|
||||
import jsprit.core.problem.job.Break;
|
||||
import jsprit.core.problem.job.Service;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity.JobActivity;
|
||||
|
||||
public class BreakActivity extends AbstractActivity implements JobActivity{
|
||||
|
||||
public static int counter = 0;
|
||||
|
||||
public double arrTime;
|
||||
|
||||
public double endTime;
|
||||
|
||||
private Location location;
|
||||
|
||||
/**
|
||||
* @return the arrTime
|
||||
*/
|
||||
public double getArrTime() {
|
||||
return arrTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param arrTime the arrTime to set
|
||||
*/
|
||||
public void setArrTime(double arrTime) {
|
||||
this.arrTime = arrTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the endTime
|
||||
*/
|
||||
public double getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param endTime the endTime to set
|
||||
*/
|
||||
public void setEndTime(double endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public static BreakActivity copyOf(BreakActivity breakActivity){
|
||||
return new BreakActivity(breakActivity);
|
||||
}
|
||||
|
||||
public static BreakActivity newInstance(Break aBreak){
|
||||
return new BreakActivity(aBreak);
|
||||
}
|
||||
|
||||
private final Break aBreak;
|
||||
|
||||
protected BreakActivity(Break aBreak) {
|
||||
counter++;
|
||||
this.aBreak = aBreak;
|
||||
}
|
||||
|
||||
protected BreakActivity(BreakActivity breakActivity) {
|
||||
counter++;
|
||||
this.aBreak = (Break) breakActivity.getJob();
|
||||
this.arrTime = breakActivity.getArrTime();
|
||||
this.endTime = breakActivity.getEndTime();
|
||||
this.location = breakActivity.getLocation();
|
||||
setIndex(breakActivity.getIndex());
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((aBreak == null) ? 0 : aBreak.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
BreakActivity other = (BreakActivity) obj;
|
||||
if (aBreak == null) {
|
||||
if (other.aBreak != null)
|
||||
return false;
|
||||
} else if (!aBreak.equals(other.aBreak))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public double getTheoreticalEarliestOperationStartTime() {
|
||||
return aBreak.getTimeWindow().getStart();
|
||||
}
|
||||
|
||||
public double getTheoreticalLatestOperationStartTime() {
|
||||
return aBreak.getTimeWindow().getEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getOperationTime() {
|
||||
return aBreak.getServiceDuration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocationId() {
|
||||
return aBreak.getLocation().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(Location breakLocation){
|
||||
this.location = breakLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Service getJob() {
|
||||
return aBreak;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[type="+getName()+"][location=" + getLocation()
|
||||
+ "][size=" + getSize().toString()
|
||||
+ "][twStart=" + Activities.round(getTheoreticalEarliestOperationStartTime())
|
||||
+ "][twEnd=" + Activities.round(getTheoreticalLatestOperationStartTime()) + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return aBreak.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TourActivity duplicate() {
|
||||
return new BreakActivity(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Capacity getSize() {
|
||||
return aBreak.getSize();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import jsprit.core.problem.HasId;
|
|||
import jsprit.core.problem.HasIndex;
|
||||
import jsprit.core.problem.Location;
|
||||
import jsprit.core.problem.Skills;
|
||||
import jsprit.core.problem.job.Break;
|
||||
|
||||
/**
|
||||
* Basic interface for vehicle-data.
|
||||
|
|
@ -72,4 +73,6 @@ public interface Vehicle extends HasId, HasIndex {
|
|||
public abstract VehicleTypeKey getVehicleTypeIdentifier();
|
||||
|
||||
public abstract Skills getSkills();
|
||||
|
||||
public abstract Break getBreak();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package jsprit.core.problem.vehicle;
|
|||
import jsprit.core.problem.AbstractVehicle;
|
||||
import jsprit.core.problem.Location;
|
||||
import jsprit.core.problem.Skills;
|
||||
import jsprit.core.problem.job.Break;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
|
|
@ -91,7 +92,10 @@ public class VehicleImpl extends AbstractVehicle{
|
|||
public Skills getSkills() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Break getBreak() { return null; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder that builds the vehicle.
|
||||
|
|
@ -125,7 +129,9 @@ public class VehicleImpl extends AbstractVehicle{
|
|||
|
||||
private Location endLocation;
|
||||
|
||||
private Builder(String id) {
|
||||
private Break aBreak;
|
||||
|
||||
private Builder(String id) {
|
||||
super();
|
||||
this.id = id;
|
||||
}
|
||||
|
|
@ -245,7 +251,12 @@ public class VehicleImpl extends AbstractVehicle{
|
|||
this.skillBuilder.addAllSkills(skills.values());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public Builder setBreak(Break aBreak) {
|
||||
this.aBreak = aBreak;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns empty/noVehicle which is a vehicle having no capacity, no type and no reasonable id.
|
||||
|
|
@ -274,6 +285,8 @@ public class VehicleImpl extends AbstractVehicle{
|
|||
|
||||
private final Location startLocation;
|
||||
|
||||
private final Break aBreak;
|
||||
|
||||
private VehicleImpl(Builder builder){
|
||||
id = builder.id;
|
||||
type = builder.type;
|
||||
|
|
@ -283,6 +296,7 @@ public class VehicleImpl extends AbstractVehicle{
|
|||
skills = builder.skills;
|
||||
endLocation = builder.endLocation;
|
||||
startLocation = builder.startLocation;
|
||||
aBreak = builder.aBreak;
|
||||
setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(),startLocation.getId(),endLocation.getId(),earliestDeparture,latestArrival,skills));
|
||||
}
|
||||
|
||||
|
|
@ -341,7 +355,12 @@ public class VehicleImpl extends AbstractVehicle{
|
|||
return skills;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
@Override
|
||||
public Break getBreak() {
|
||||
return aBreak;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
package jsprit.core.algorithm.ruin;
|
||||
|
||||
import jsprit.core.problem.Location;
|
||||
import jsprit.core.problem.VehicleRoutingProblem;
|
||||
import jsprit.core.problem.job.Break;
|
||||
import jsprit.core.problem.job.Job;
|
||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import jsprit.core.problem.solution.route.activity.BreakActivity;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
import jsprit.core.problem.vehicle.VehicleImpl;
|
||||
import junit.framework.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 04/08/15.
|
||||
*/
|
||||
public class RuinBreakTest {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
Break aBreak = Break.Builder.newInstance("break").build();
|
||||
VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("loc"))
|
||||
.setBreak(aBreak).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addVehicle(v).build();
|
||||
VehicleRoute route = VehicleRoute.Builder.newInstance(v).setJobActivityFactory(vrp.getJobActivityFactory()).addService(aBreak).build();
|
||||
TourActivity tourActivity = route.getActivities().get(0);
|
||||
System.out.println(tourActivity);
|
||||
Assert.assertTrue(tourActivity instanceof BreakActivity);
|
||||
RuinBreaks ruinBreaks = new RuinBreaks();
|
||||
List<Job> unassigned = new ArrayList<Job>();
|
||||
ruinBreaks.ruinEnds(Arrays.asList(route),unassigned);
|
||||
Assert.assertEquals(1,unassigned.size());
|
||||
Assert.assertEquals(aBreak,unassigned.get(0));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (C) 2014 Stefan Schroeder
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
package jsprit.core.problem.solution.route.activity;
|
||||
|
||||
import jsprit.core.problem.Location;
|
||||
import jsprit.core.problem.job.Break;
|
||||
import jsprit.core.problem.job.Service;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
public class BreakActivityTest {
|
||||
|
||||
private Break service;
|
||||
|
||||
private BreakActivity serviceActivity;
|
||||
|
||||
@Before
|
||||
public void doBefore(){
|
||||
service = (Break) Break.Builder.newInstance("service")
|
||||
.setTimeWindow(TimeWindow.newInstance(1., 2.)).setServiceTime(3).build();
|
||||
serviceActivity = BreakActivity.newInstance(service);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCallingCapacity_itShouldReturnCorrectCapacity(){
|
||||
assertEquals(0,serviceActivity.getSize().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasVariableLocationShouldBeTrue(){
|
||||
Break aBreak = (Break) serviceActivity.getJob();
|
||||
assertTrue(aBreak.hasVariableLocation());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void whenStartIsIniWithEarliestStart_itShouldBeSetCorrectly(){
|
||||
assertEquals(1.,serviceActivity.getTheoreticalEarliestOperationStartTime(),0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenStartIsIniWithLatestStart_itShouldBeSetCorrectly(){
|
||||
assertEquals(2.,serviceActivity.getTheoreticalLatestOperationStartTime(),0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSettingArrTime_itShouldBeSetCorrectly(){
|
||||
serviceActivity.setArrTime(4.0);
|
||||
assertEquals(4.,serviceActivity.getArrTime(),0.01);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSettingEndTime_itShouldBeSetCorrectly(){
|
||||
serviceActivity.setEndTime(5.0);
|
||||
assertEquals(5.,serviceActivity.getEndTime(),0.01);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void whenCopyingStart_itShouldBeDoneCorrectly(){
|
||||
BreakActivity copy = (BreakActivity) serviceActivity.duplicate();
|
||||
assertEquals(1.,copy.getTheoreticalEarliestOperationStartTime(),0.01);
|
||||
assertEquals(2.,copy.getTheoreticalLatestOperationStartTime(),0.01);
|
||||
assertTrue(copy!=serviceActivity);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void whenTwoDeliveriesHaveTheSameUnderlyingJob_theyAreEqual(){
|
||||
Service s1 = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).build();
|
||||
Service s2 = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).build();
|
||||
|
||||
ServiceActivity d1 = ServiceActivity.newInstance(s1);
|
||||
ServiceActivity d2 = ServiceActivity.newInstance(s2);
|
||||
|
||||
assertTrue(d1.equals(d2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTwoDeliveriesHaveTheDifferentUnderlyingJob_theyAreNotEqual(){
|
||||
Service s1 = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).build();
|
||||
Service s2 = Service.Builder.newInstance("s1").setLocation(Location.newInstance("loc")).build();
|
||||
|
||||
ServiceActivity d1 = ServiceActivity.newInstance(s1);
|
||||
ServiceActivity d2 = ServiceActivity.newInstance(s2);
|
||||
|
||||
assertFalse(d1.equals(d2));
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@ package jsprit.core.problem.vehicle;
|
|||
|
||||
|
||||
import jsprit.core.problem.Location;
|
||||
import jsprit.core.problem.job.Break;
|
||||
import jsprit.core.problem.solution.route.activity.TimeWindow;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
|
@ -221,5 +223,20 @@ public class VehicleImplTest {
|
|||
assertFalse(v.getSkills().containsSkill("ScrewDriver"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddingDriverBreak_itShouldBeAddedCorrectly(){
|
||||
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build();
|
||||
Break aBreak = (Break) Break.Builder.newInstance("break").setTimeWindow(TimeWindow.newInstance(100, 200)).setServiceTime(30).build();
|
||||
Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("start"))
|
||||
.setType(type1).setEndLocation(Location.newInstance("start"))
|
||||
.setBreak(aBreak).build();
|
||||
assertNotNull(v.getBreak());
|
||||
assertEquals(100.,v.getBreak().getTimeWindow().getStart(),0.1);
|
||||
assertEquals(200.,v.getBreak().getTimeWindow().getEnd(),0.1);
|
||||
assertEquals(30.,v.getBreak().getServiceDuration(),0.1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
106
jsprit-examples/src/main/java/jsprit/examples/BreakExample.java
Normal file
106
jsprit-examples/src/main/java/jsprit/examples/BreakExample.java
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (C) 2014 Stefan Schroeder
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
package jsprit.examples;
|
||||
|
||||
import jsprit.analysis.toolbox.Plotter;
|
||||
import jsprit.core.algorithm.VehicleRoutingAlgorithm;
|
||||
import jsprit.core.algorithm.box.Jsprit;
|
||||
import jsprit.core.algorithm.ruin.RuinBreaks;
|
||||
import jsprit.core.problem.Location;
|
||||
import jsprit.core.problem.VehicleRoutingProblem;
|
||||
import jsprit.core.problem.job.Break;
|
||||
import jsprit.core.problem.job.Service;
|
||||
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||
import jsprit.core.problem.solution.route.activity.TimeWindow;
|
||||
import jsprit.core.problem.vehicle.VehicleImpl;
|
||||
import jsprit.core.problem.vehicle.VehicleImpl.Builder;
|
||||
import jsprit.core.problem.vehicle.VehicleType;
|
||||
import jsprit.core.problem.vehicle.VehicleTypeImpl;
|
||||
import jsprit.core.reporting.SolutionPrinter;
|
||||
import jsprit.core.util.Solutions;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
|
||||
public class BreakExample {
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
/*
|
||||
* get a vehicle type-builder and build a type with the typeId "vehicleType" and one capacity dimension, i.e. weight, and capacity dimension value of 2
|
||||
*/
|
||||
final int WEIGHT_INDEX = 0;
|
||||
VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(WEIGHT_INDEX, 4);
|
||||
VehicleType vehicleType = vehicleTypeBuilder.build();
|
||||
|
||||
/*
|
||||
* get a vehicle-builder and build a vehicle located at (10,10) with type "vehicleType"
|
||||
*/
|
||||
Builder vehicleBuilder = Builder.newInstance("vehicle");
|
||||
vehicleBuilder.setStartLocation(Location.newInstance(10, 10));
|
||||
Break myFirstBreak = (Break) Break.Builder.newInstance("myFirstBreak").setTimeWindow(TimeWindow.newInstance(30, 50)).setServiceTime(10).build();
|
||||
vehicleBuilder.setBreak(myFirstBreak);
|
||||
vehicleBuilder.setType(vehicleType);
|
||||
VehicleImpl vehicle = vehicleBuilder.build();
|
||||
|
||||
/*
|
||||
* build services at the required locations, each with a capacity-demand of 1.
|
||||
*/
|
||||
Service service1 = Service.Builder.newInstance("1").addSizeDimension(WEIGHT_INDEX, 1).setLocation(Location.newInstance(5, 7)).build();
|
||||
Service service2 = Service.Builder.newInstance("2").addSizeDimension(WEIGHT_INDEX, 1).setLocation(Location.newInstance(5, 13)).build();
|
||||
|
||||
Service service3 = Service.Builder.newInstance("3").addSizeDimension(WEIGHT_INDEX, 1).setLocation(Location.newInstance(15, 7)).build();
|
||||
Service service4 = Service.Builder.newInstance("4").addSizeDimension(WEIGHT_INDEX, 1).setLocation(Location.newInstance(15, 13)).build();
|
||||
|
||||
|
||||
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
|
||||
vrpBuilder.addVehicle(vehicle);
|
||||
vrpBuilder.addJob(service1).addJob(service2).addJob(service3).addJob(service4);
|
||||
vrpBuilder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE);
|
||||
VehicleRoutingProblem problem = vrpBuilder.build();
|
||||
|
||||
/*
|
||||
* get the algorithm out-of-the-box.
|
||||
*/
|
||||
VehicleRoutingAlgorithm algorithm = Jsprit.Builder.newInstance(problem)
|
||||
.setProperty(Jsprit.Strategy.CLUSTER_REGRET,"0.")
|
||||
.setProperty(Jsprit.Strategy.CLUSTER_BEST,"0.").buildAlgorithm();
|
||||
algorithm.addListener(new RuinBreaks());
|
||||
/*
|
||||
* and search a solution
|
||||
*/
|
||||
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
|
||||
|
||||
/*
|
||||
* get the best
|
||||
*/
|
||||
VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions);
|
||||
|
||||
SolutionPrinter.print(problem, bestSolution, SolutionPrinter.Print.VERBOSE);
|
||||
|
||||
/*
|
||||
* plot
|
||||
*/
|
||||
new Plotter(problem,bestSolution).plot("output/plot","breaks");
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue