diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AuxilliaryCostCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AuxilliaryCostCalculator.java index 2ff04582..0010f9f5 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AuxilliaryCostCalculator.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AuxilliaryCostCalculator.java @@ -22,6 +22,7 @@ import java.util.List; import jsprit.core.problem.cost.VehicleRoutingActivityCosts; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; import jsprit.core.problem.driver.Driver; +import jsprit.core.problem.solution.route.activity.End; import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.vehicle.Vehicle; @@ -33,10 +34,10 @@ final class AuxilliaryCostCalculator { private final VehicleRoutingActivityCosts activityCosts; - public AuxilliaryCostCalculator(final VehicleRoutingTransportCosts routingCosts, final VehicleRoutingActivityCosts costFunction) { + public AuxilliaryCostCalculator(final VehicleRoutingTransportCosts routingCosts, final VehicleRoutingActivityCosts actCosts) { super(); this.routingCosts = routingCosts; - this.activityCosts = costFunction; + this.activityCosts = actCosts; } /** @@ -59,6 +60,11 @@ final class AuxilliaryCostCalculator { double departureTimePrevAct = depTime; while(actIter.hasNext()){ TourActivity act = actIter.next(); + if(act instanceof End){ + if(!vehicle.isReturnToDepot()){ + return cost; + } + } double transportCost = routingCosts.getTransportCost(prevAct.getLocationId(), act.getLocationId(), departureTimePrevAct, driver, vehicle); double transportTime = routingCosts.getTransportTime(prevAct.getLocationId(), act.getLocationId(), departureTimePrevAct, driver, vehicle); cost += transportCost; @@ -72,37 +78,5 @@ final class AuxilliaryCostCalculator { return cost; } - public double costOfPath(String startLocationId, final double startTime, final List path, String endLocationId, final Driver driver, final Vehicle vehicle){ - if(path.isEmpty()){ - return 0.0; - } - double cost = 0.0; -// Iterator actIter = path.iterator(); - String prevActLocation = startLocationId; -// TourActivity prevAct = actIter.next(); - double startCost = 0.0; - cost += startCost; - double departureTimePrevAct = startTime; - for(TourActivity act : path){ -// TourActivity act = actIter.next(); - double transportCost = routingCosts.getTransportCost(prevActLocation, act.getLocationId(), departureTimePrevAct, driver, vehicle); - double transportTime = routingCosts.getTransportTime(prevActLocation, act.getLocationId(), departureTimePrevAct, driver, vehicle); - cost += transportCost; - double actStartTime = departureTimePrevAct + transportTime; - double earliestOperationStartTime = Math.max(actStartTime, act.getTheoreticalEarliestOperationStartTime()); - double actEndTime = earliestOperationStartTime + act.getOperationTime(); - departureTimePrevAct = actEndTime; - cost += activityCosts.getActivityCost(act, actStartTime, driver, vehicle); - prevActLocation = act.getLocationId(); - } - - /* - *!!! ENDLOCATION - => Start u. End können primitiv sein. - - */ - - return cost; - } } diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/Inserter.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/Inserter.java index 9ea0f15f..61422bb3 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/Inserter.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/Inserter.java @@ -72,7 +72,6 @@ class Inserter { } private void setEndLocation(VehicleRoute route, Service service) { - route.getEnd().setCoordinate(service.getCoord()); route.getEnd().setLocationId(service.getLocationId()); } @@ -106,7 +105,6 @@ class Inserter { } private void setEndLocation(VehicleRoute route, Shipment shipment) { - route.getEnd().setCoordinate(shipment.getDeliveryCoord()); route.getEnd().setLocationId(shipment.getDeliveryLocation()); } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java b/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java index 8a2bf8fd..99af56b5 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java @@ -25,9 +25,7 @@ import java.util.Map; import jsprit.core.problem.cost.VehicleRoutingActivityCosts; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; import jsprit.core.problem.driver.Driver; -import jsprit.core.problem.job.Delivery; import jsprit.core.problem.job.Job; -import jsprit.core.problem.job.Pickup; import jsprit.core.problem.job.Service; import jsprit.core.problem.job.Shipment; import jsprit.core.problem.solution.route.activity.TourActivity; @@ -64,9 +62,11 @@ public class VehicleRoutingProblem { * *

DELIVERIES_FIRST corresponds to the vehicle routing problem with back hauls, i.e. before a vehicle is not entirely unloaded, no pickup can be made. * + * @deprecated define constraint directly - since constraints are too diverse to put them in an enum * @author stefan * */ + @Deprecated public enum Constraint { DELIVERIES_FIRST } @@ -186,12 +186,6 @@ public class VehicleRoutingProblem { }; } - - public void addProblemConstraint(Constraint constraint){ - if(!problemConstraints.contains(constraint)) problemConstraints.add(constraint); - } - - /** * Sets routing costs. * @@ -218,39 +212,6 @@ public class VehicleRoutingProblem { return this; } - /** - * Sets the fleetComposition. - * - *

FleetComposition is either FleetComposition.HETEROGENEOUS or FleetComposition.HOMOGENEOUS - * - * @deprecated has no effect - * @param fleetComposition - * @return - */ - @Deprecated - public Builder setFleetComposition(FleetComposition fleetComposition){ - this.fleetComposition = fleetComposition; - return this; - } - - /** - * Adds a service to jobList. - * - *

If jobList already contains service, a warning message is printed, and the existing job will be overwritten. - * - * @deprecated use addJob(...) instead - * @param service - * @return - */ - @Deprecated - public Builder addService(Service service){ - coordinates.put(service.getLocationId(), service.getCoord()); - if(jobs.containsKey(service.getId())){ logger.warn("service " + service + " already in job list. overrides existing job."); } - jobs.put(service.getId(),service); - services.add(service); - return this; - } - /** * Adds a job which is either a service or a shipment. * @@ -297,30 +258,6 @@ public class VehicleRoutingProblem { return this; } - /** - * Adds a vehicleType. - * - * @deprecated use add vehicle instead - * @param type - * @return builder - */ - @Deprecated - public Builder addVehicleType(VehicleType type){ - vehicleTypes.add(type); - return this; - } - - /** - * Sets the neighborhood. - * - * @param neighborhood - * @return - */ - public Builder setNeighborhood(Neighborhood neighborhood){ - this.neighborhood = neighborhood; - return this; - } - /** * Sets the activityCostFunction that considers also activities on a vehicle-route. * @@ -391,8 +328,15 @@ public class VehicleRoutingProblem { return Collections.unmodifiableCollection(vehicles); } - public void addConstraint(jsprit.core.problem.constraint.Constraint constraint){ + /** + * Adds constraint to problem. + * + * @param constraint + * @return + */ + public Builder addConstraint(jsprit.core.problem.constraint.Constraint constraint){ constraints.add(constraint); + return this; } /** @@ -407,6 +351,75 @@ public class VehicleRoutingProblem { public Collection getAddedJobs(){ return Collections.unmodifiableCollection(jobs.values()); } + + /** + * Sets the fleetComposition. + * + *

FleetComposition is either FleetComposition.HETEROGENEOUS or FleetComposition.HOMOGENEOUS + * + * @deprecated has no effect + * @param fleetComposition + * @return + */ + @Deprecated + public Builder setFleetComposition(FleetComposition fleetComposition){ + this.fleetComposition = fleetComposition; + return this; + } + + /** + * Adds a service to jobList. + * + *

If jobList already contains service, a warning message is printed, and the existing job will be overwritten. + * + * @deprecated use addJob(...) instead + * @param service + * @return + */ + @Deprecated + public Builder addService(Service service){ + coordinates.put(service.getLocationId(), service.getCoord()); + if(jobs.containsKey(service.getId())){ logger.warn("service " + service + " already in job list. overrides existing job."); } + jobs.put(service.getId(),service); + services.add(service); + return this; + } + + /** + * Adds a vehicleType. + * + * @deprecated use add vehicle instead + * @param type + * @return builder + */ + @Deprecated + public Builder addVehicleType(VehicleType type){ + vehicleTypes.add(type); + return this; + } + + /** + * Sets the neighborhood. + * + * @deprecated use HardRoute- or ActivityLevelConstraint instead + * @param neighborhood + * @return + */ + @Deprecated + public Builder setNeighborhood(Neighborhood neighborhood){ + this.neighborhood = neighborhood; + return this; + } + + /** + * + * @deprecated use .addConstraint(new ServiceDeliveriesFirstConstraint()) + * @param constraint + */ + @Deprecated + public void addProblemConstraint(Constraint constraint){ + if(!problemConstraints.contains(constraint)) problemConstraints.add(constraint); + } } /** @@ -485,13 +498,6 @@ public class VehicleRoutingProblem { "transportCost="+transportCosts+"][activityCosts="+activityCosts+"]"; } - /** - * @return the neighborhood - */ - public Neighborhood getNeighborhood() { - return neighborhood; - } - /** * Returns fleet-composition. * @@ -521,15 +527,6 @@ public class VehicleRoutingProblem { return Collections.unmodifiableMap(jobs); } - /** - * Returns unmodifiable collection of problem-constraints. - * - * @return - */ - public Collection getProblemConstraints(){ - return Collections.unmodifiableCollection(problemConstraints); - } - /** * Returns the entire, unmodifiable collection of types. * @@ -568,9 +565,34 @@ public class VehicleRoutingProblem { return activityCosts; } + /** + * Returns an unmodifiable collection of constraints. + * + * @return + */ public Collection getConstraints(){ return Collections.unmodifiableCollection(constraints); } + + /** + * @deprecated see builder.setNeighborhood(...). addConstraint(...) instead. + * @return the neighborhood + */ + @Deprecated + public Neighborhood getNeighborhood() { + return neighborhood; + } + + /** + * Returns unmodifiable collection of problem-constraints. + * + * @deprecated use .getConstraints() and builder.add + * @return + */ + @Deprecated + public Collection getProblemConstraints(){ + return Collections.unmodifiableCollection(problemConstraints); + } } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/constraint/ConstraintManager.java b/jsprit-core/src/main/java/jsprit/core/problem/constraint/ConstraintManager.java index 0ed08625..d476c696 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/constraint/ConstraintManager.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/constraint/ConstraintManager.java @@ -1,8 +1,9 @@ package jsprit.core.problem.constraint; +import java.util.ArrayList; import java.util.Collection; - -import org.apache.log4j.Logger; +import java.util.Collections; +import java.util.List; import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem.Constraint; @@ -10,6 +11,8 @@ import jsprit.core.problem.misc.JobInsertionContext; import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; +import org.apache.log4j.Logger; + public class ConstraintManager implements HardActivityStateLevelConstraint, HardRouteStateLevelConstraint{ public static enum Priority { @@ -96,4 +99,11 @@ public class ConstraintManager implements HardActivityStateLevelConstraint, Hard return actLevelConstraintManager.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime); } + public Collection getConstraints(){ + List constraints = new ArrayList(); + constraints.addAll(actLevelConstraintManager.getAllConstraints()); + constraints.addAll(routeLevelConstraintManager.getConstraints()); + return Collections.unmodifiableCollection(constraints); + } + } \ No newline at end of file diff --git a/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardActivityLevelConstraintManager.java b/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardActivityLevelConstraintManager.java index 1cad4e3f..84e619ca 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardActivityLevelConstraintManager.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardActivityLevelConstraintManager.java @@ -2,6 +2,8 @@ package jsprit.core.problem.constraint; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.List; import jsprit.core.problem.constraint.ConstraintManager.Priority; import jsprit.core.problem.misc.JobInsertionContext; @@ -28,6 +30,20 @@ class HardActivityLevelConstraintManager implements HardActivityStateLevelConstr } } + Collection getCriticalConstraints(){ return Collections.unmodifiableCollection(criticalConstraints); } + + Collection getHighPrioConstraints(){ return Collections.unmodifiableCollection(highPrioConstraints); } + + Collection getLowPrioConstraints(){ return Collections.unmodifiableCollection(lowPrioConstraints); } + + Collection getAllConstraints(){ + List c = new ArrayList(); + c.addAll(criticalConstraints); + c.addAll(highPrioConstraints); + c.addAll(lowPrioConstraints); + return Collections.unmodifiableCollection(c); + } + @Override public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { ConstraintsStatus notFulfilled = null; diff --git a/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardRouteLevelConstraintManager.java b/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardRouteLevelConstraintManager.java index 8aa485a6..7ce307c7 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardRouteLevelConstraintManager.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardRouteLevelConstraintManager.java @@ -2,6 +2,7 @@ package jsprit.core.problem.constraint; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import jsprit.core.problem.misc.JobInsertionContext; @@ -13,6 +14,8 @@ class HardRouteLevelConstraintManager implements HardRouteStateLevelConstraint { public void addConstraint(HardRouteStateLevelConstraint constraint){ hardConstraints.add(constraint); } + + Collection getConstraints(){ return Collections.unmodifiableCollection(hardConstraints); } @Override public boolean fulfilled(JobInsertionContext insertionContext) { diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/End.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/End.java index beacc9ad..69079d2f 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/End.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/End.java @@ -35,11 +35,11 @@ public final class End implements TourActivity { private Coordinate coordinate; - public Coordinate getCoordinate() { + Coordinate getCoordinate() { return coordinate; } - public void setCoordinate(Coordinate coordinate) { + void setCoordinate(Coordinate coordinate) { this.coordinate = coordinate; } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/Start.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/Start.java index 13067feb..5ae08844 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/Start.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/activity/Start.java @@ -65,11 +65,11 @@ public final class Start implements TourActivity { - public Coordinate getCoordinate() { + Coordinate getCoordinate() { return coordinate; } - public void setCoordinate(Coordinate coordinate) { + void setCoordinate(Coordinate coordinate) { this.coordinate = coordinate; } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java index 3be48623..9778d633 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleImpl.java @@ -45,6 +45,14 @@ public class VehicleImpl implements Vehicle { } + /** + * builds the vehicle. + * + *

by default, it returns to the depot. + * + * @author stefan + * + */ public static class Builder { static Logger log = Logger.getLogger(Builder.class); private String id; diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestAuxilliaryCostCalculator.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestAuxilliaryCostCalculator.java new file mode 100644 index 00000000..f0bb4d5c --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestAuxilliaryCostCalculator.java @@ -0,0 +1,103 @@ +package jsprit.core.algorithm.recreate; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; + +import jsprit.core.problem.cost.VehicleRoutingActivityCosts; +import jsprit.core.problem.cost.VehicleRoutingTransportCosts; +import jsprit.core.problem.solution.route.activity.End; +import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.vehicle.Vehicle; + +import org.junit.Before; +import org.junit.Test; + +public class TestAuxilliaryCostCalculator { + + private VehicleRoutingTransportCosts routingCosts; + + private VehicleRoutingActivityCosts actCosts; + + private Vehicle vehicle; + + @Before + public void doBefore(){ + vehicle = mock(Vehicle.class); + + routingCosts = mock(VehicleRoutingTransportCosts.class); + actCosts = mock(VehicleRoutingActivityCosts.class); + + when(routingCosts.getTransportCost("i", "j", 0.0, null, vehicle)).thenReturn(2.0); + when(routingCosts.getTransportTime("i", "j", 0.0, null, vehicle)).thenReturn(0.0); + when(routingCosts.getTransportCost("i", "k", 0.0, null, vehicle)).thenReturn(3.0); + when(routingCosts.getTransportTime("i", "k", 0.0, null, vehicle)).thenReturn(0.0); + when(routingCosts.getTransportCost("k", "j", 0.0, null, vehicle)).thenReturn(3.0); + when(routingCosts.getTransportTime("k", "j", 0.0, null, vehicle)).thenReturn(0.0); + } + + @Test + public void whenRouteIsClosed_itCalculatesCostUpToEnd_v1(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocationId()).thenReturn("i"); + TourActivity nextAct = mock(TourActivity.class); + when(nextAct.getLocationId()).thenReturn("j"); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocationId()).thenReturn("k"); + + when(vehicle.isReturnToDepot()).thenReturn(true); + + AuxilliaryCostCalculator aCalc = new AuxilliaryCostCalculator(routingCosts, actCosts); + double costs = aCalc.costOfPath(Arrays.asList(prevAct,newAct,nextAct), 0.0, null, vehicle); + assertEquals(6.0,costs,0.01); + } + + @Test + public void whenRouteIsClosed_itCalculatesCostUpToEnd_v2(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocationId()).thenReturn("i"); + End nextAct = End.newInstance("j", 0.0, 0.0); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocationId()).thenReturn("k"); + + when(vehicle.isReturnToDepot()).thenReturn(true); + + AuxilliaryCostCalculator aCalc = new AuxilliaryCostCalculator(routingCosts, actCosts); + double costs = aCalc.costOfPath(Arrays.asList(prevAct,newAct,nextAct), 0.0, null, vehicle); + assertEquals(6.0,costs,0.01); + } + + @Test + public void whenRouteIsOpen_itCalculatesCostUpToEnd_v1(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocationId()).thenReturn("i"); + TourActivity nextAct = mock(TourActivity.class); + when(nextAct.getLocationId()).thenReturn("j"); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocationId()).thenReturn("k"); + + when(vehicle.isReturnToDepot()).thenReturn(false); + + AuxilliaryCostCalculator aCalc = new AuxilliaryCostCalculator(routingCosts, actCosts); + double costs = aCalc.costOfPath(Arrays.asList(prevAct,newAct,nextAct), 0.0, null, vehicle); + assertEquals(6.0,costs,0.01); + } + + @Test + public void whenRouteIsOpen_itCalculatesCostUpToEnd_v2(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocationId()).thenReturn("i"); + End nextAct = End.newInstance("j", 0.0, 0.0); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocationId()).thenReturn("k"); + + when(vehicle.isReturnToDepot()).thenReturn(false); + + AuxilliaryCostCalculator aCalc = new AuxilliaryCostCalculator(routingCosts, actCosts); + double costs = aCalc.costOfPath(Arrays.asList(prevAct,newAct,nextAct), 0.0, null, vehicle); + assertEquals(3.0,costs,0.01); + } + +} diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java index c634b076..72e9f6c0 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java @@ -267,9 +267,6 @@ public class TestCalculatesServiceInsertion { assertEquals(2, iData.getDeliveryInsertionIndex()); } - @Test - public void whenInsertingAndRouteIsOpen(){ - assertTrue(false); - } + } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertionOnRouteLevel.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertionOnRouteLevel.java index 0c621a74..141ed220 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertionOnRouteLevel.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertionOnRouteLevel.java @@ -83,12 +83,14 @@ public class TestCalculatesServiceInsertionOnRouteLevel { when(vehicle.getLocationId()).thenReturn("0,0"); when(vehicle.getEarliestDeparture()).thenReturn(0.0); when(vehicle.getLatestArrival()).thenReturn(100.0); + when(vehicle.isReturnToDepot()).thenReturn(true); newVehicle = mock(Vehicle.class); when(newVehicle.getCapacity()).thenReturn(1000); when(newVehicle.getLocationId()).thenReturn("0,0"); when(newVehicle.getEarliestDeparture()).thenReturn(0.0); when(newVehicle.getLatestArrival()).thenReturn(100.0); + when(newVehicle.isReturnToDepot()).thenReturn(true); driver = DriverImpl.noDriver(); @@ -240,10 +242,5 @@ public class TestCalculatesServiceInsertionOnRouteLevel { assertEquals(2, iData.getDeliveryInsertionIndex()); } - @Test - public void whenInsertingAndRouteIsOpen(){ - assertTrue(false); - } - } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestInserter.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestInserter.java index 20e28113..a9887a1b 100644 --- a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestInserter.java +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestInserter.java @@ -1,7 +1,122 @@ package jsprit.core.algorithm.recreate; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import jsprit.core.algorithm.recreate.listener.InsertionListeners; +import jsprit.core.problem.driver.Driver; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.job.Shipment; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.vehicle.Vehicle; + +import org.junit.Test; + public class TestInserter { + @Test + public void whenInsertingServiceAndRouteIsClosed_itInsertsCorrectly(){ + Service service = mock(Service.class); + Vehicle vehicle = mock(Vehicle.class); + when(vehicle.getLocationId()).thenReturn("vehLoc"); + when(vehicle.isReturnToDepot()).thenReturn(true); + when(vehicle.getId()).thenReturn("vehId"); + + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, mock(Driver.class)).addService(service).build(); + //start - pick(shipment) - del(shipment) - end + Service serviceToInsert = mock(Service.class); + when(serviceToInsert.getLocationId()).thenReturn("delLoc"); + + InsertionData iData = mock(InsertionData.class); + when(iData.getDeliveryInsertionIndex()).thenReturn(1); + when(iData.getSelectedVehicle()).thenReturn(vehicle); + + Inserter inserter = new Inserter(mock(InsertionListeners.class)); + inserter.insertJob(serviceToInsert, iData, route); + + assertEquals(2,route.getTourActivities().getActivities().size()); + assertEquals(route.getTourActivities().getActivities().get(1).getLocationId(),serviceToInsert.getLocationId()); + assertEquals(route.getEnd().getLocationId(),vehicle.getLocationId()); + } + + @Test + public void whenInsertingServiceAndRouteIsOpen_itInsertsCorrectlyAndSwitchesEndLocation(){ + Service service = mock(Service.class); + Vehicle vehicle = mock(Vehicle.class); + when(vehicle.getLocationId()).thenReturn("vehLoc"); + when(vehicle.isReturnToDepot()).thenReturn(false); + when(vehicle.getId()).thenReturn("vehId"); + + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, mock(Driver.class)).addService(service).build(); + Service serviceToInsert = mock(Service.class); + when(serviceToInsert.getLocationId()).thenReturn("delLoc"); + + InsertionData iData = mock(InsertionData.class); + when(iData.getDeliveryInsertionIndex()).thenReturn(1); + when(iData.getSelectedVehicle()).thenReturn(vehicle); + + Inserter inserter = new Inserter(mock(InsertionListeners.class)); + inserter.insertJob(serviceToInsert, iData, route); + + assertEquals(2,route.getTourActivities().getActivities().size()); + assertEquals(route.getTourActivities().getActivities().get(1).getLocationId(),serviceToInsert.getLocationId()); + assertEquals(route.getEnd().getLocationId(),serviceToInsert.getLocationId()); + } + + + @Test + public void whenInsertingShipmentAndRouteIsClosed_itInsertsCorrectly(){ + Shipment shipment = mock(Shipment.class); + Vehicle vehicle = mock(Vehicle.class); + when(vehicle.getLocationId()).thenReturn("vehLoc"); + when(vehicle.isReturnToDepot()).thenReturn(true); + when(vehicle.getId()).thenReturn("vehId"); + + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, mock(Driver.class)).addPickup(shipment).addDelivery(shipment).build(); + //start - pick(shipment) - del(shipment) - end + Shipment shipmentToInsert = mock(Shipment.class); + when(shipmentToInsert.getDeliveryLocation()).thenReturn("delLoc"); + when(shipmentToInsert.getPickupLocation()).thenReturn("pickLoc"); + InsertionData iData = mock(InsertionData.class); + when(iData.getPickupInsertionIndex()).thenReturn(2); + when(iData.getDeliveryInsertionIndex()).thenReturn(2); + when(iData.getSelectedVehicle()).thenReturn(vehicle); + + Inserter inserter = new Inserter(mock(InsertionListeners.class)); + inserter.insertJob(shipmentToInsert, iData, route); + + assertEquals(4,route.getTourActivities().getActivities().size()); + assertEquals(route.getTourActivities().getActivities().get(2).getLocationId(),shipmentToInsert.getPickupLocation()); + assertEquals(route.getTourActivities().getActivities().get(3).getLocationId(),shipmentToInsert.getDeliveryLocation()); + assertEquals(route.getEnd().getLocationId(),vehicle.getLocationId()); + } + + @Test + public void whenInsertingShipmentAndRouteIsOpen_itInsertsCorrectlyAndSwitchesEndLocation(){ + Shipment shipment = mock(Shipment.class); + Vehicle vehicle = mock(Vehicle.class); + when(vehicle.getLocationId()).thenReturn("vehLoc"); + when(vehicle.isReturnToDepot()).thenReturn(false); + when(vehicle.getId()).thenReturn("vehId"); + + VehicleRoute route = VehicleRoute.Builder.newInstance(vehicle, mock(Driver.class)).addPickup(shipment).addDelivery(shipment).build(); + //start - pick(shipment) - del(shipment) - end + Shipment shipmentToInsert = mock(Shipment.class); + when(shipmentToInsert.getDeliveryLocation()).thenReturn("delLoc"); + when(shipmentToInsert.getPickupLocation()).thenReturn("pickLoc"); + InsertionData iData = mock(InsertionData.class); + when(iData.getPickupInsertionIndex()).thenReturn(2); + when(iData.getDeliveryInsertionIndex()).thenReturn(2); + when(iData.getSelectedVehicle()).thenReturn(vehicle); + + Inserter inserter = new Inserter(mock(InsertionListeners.class)); + inserter.insertJob(shipmentToInsert, iData, route); + + assertEquals(4,route.getTourActivities().getActivities().size()); + assertEquals(route.getTourActivities().getActivities().get(2).getLocationId(),shipmentToInsert.getPickupLocation()); + assertEquals(route.getTourActivities().getActivities().get(3).getLocationId(),shipmentToInsert.getDeliveryLocation()); + assertEquals(route.getEnd().getLocationId(),shipmentToInsert.getDeliveryLocation()); + } } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java new file mode 100644 index 00000000..b391adfa --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java @@ -0,0 +1,113 @@ +package jsprit.core.algorithm.recreate; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import jsprit.core.algorithm.recreate.ActivityInsertionCostsCalculator.ActivityInsertionCosts; +import jsprit.core.problem.cost.VehicleRoutingActivityCosts; +import jsprit.core.problem.cost.VehicleRoutingTransportCosts; +import jsprit.core.problem.misc.JobInsertionContext; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.solution.route.activity.End; +import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.vehicle.Vehicle; + +import org.junit.Before; +import org.junit.Test; + +public class TestLocalActivityInsertionCostsCalculator { + + VehicleRoutingTransportCosts tpCosts; + + VehicleRoutingActivityCosts actCosts; + + LocalActivityInsertionCostsCalculator calc; + + Vehicle vehicle; + + VehicleRoute route; + + JobInsertionContext jic; + + @Before + public void doBefore(){ + + vehicle = mock(Vehicle.class); + route = mock(VehicleRoute.class); + when(route.isEmpty()).thenReturn(false); + when(route.getVehicle()).thenReturn(vehicle); + + jic = mock(JobInsertionContext.class); + when(jic.getRoute()).thenReturn(route); + when(jic.getNewVehicle()).thenReturn(vehicle); + + tpCosts = mock(VehicleRoutingTransportCosts.class); + when(tpCosts.getTransportCost("i", "j", 0.0, null, vehicle)).thenReturn(2.0); + when(tpCosts.getTransportTime("i", "j", 0.0, null, vehicle)).thenReturn(0.0); + when(tpCosts.getTransportCost("i", "k", 0.0, null, vehicle)).thenReturn(3.0); + when(tpCosts.getTransportTime("i", "k", 0.0, null, vehicle)).thenReturn(0.0); + when(tpCosts.getTransportCost("k", "j", 0.0, null, vehicle)).thenReturn(3.0); + when(tpCosts.getTransportTime("k", "j", 0.0, null, vehicle)).thenReturn(0.0); + + actCosts = mock(VehicleRoutingActivityCosts.class); + calc = new LocalActivityInsertionCostsCalculator(tpCosts, actCosts); + } + + @Test + public void whenInsertingActBetweenTwoRouteActs_itCalcsMarginalTpCosts(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocationId()).thenReturn("i"); + TourActivity nextAct = mock(TourActivity.class); + when(nextAct.getLocationId()).thenReturn("j"); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocationId()).thenReturn("k"); + + when(vehicle.isReturnToDepot()).thenReturn(true); + + ActivityInsertionCosts costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); + assertEquals(4.0,costs.getAdditionalCosts(),0.01); + } + + @Test + public void whenInsertingActBetweenLastActAndEnd_itCalcsMarginalTpCosts(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocationId()).thenReturn("i"); + End nextAct = End.newInstance("j", 0.0, 0.0); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocationId()).thenReturn("k"); + + when(vehicle.isReturnToDepot()).thenReturn(true); + + ActivityInsertionCosts costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); + assertEquals(4.0,costs.getAdditionalCosts(),0.01); + } + + @Test + public void whenInsertingActBetweenTwoRouteActsAndRouteIsOpen_itCalcsMarginalTpCosts(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocationId()).thenReturn("i"); + TourActivity nextAct = mock(TourActivity.class); + when(nextAct.getLocationId()).thenReturn("j"); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocationId()).thenReturn("k"); + + when(vehicle.isReturnToDepot()).thenReturn(false); + + ActivityInsertionCosts costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); + assertEquals(4.0,costs.getAdditionalCosts(),0.01); + } + + @Test + public void whenInsertingActBetweenLastActAndEndAndRouteIsOpen_itCalculatesTpCostsFromPrevToNewAct(){ + TourActivity prevAct = mock(TourActivity.class); + when(prevAct.getLocationId()).thenReturn("i"); + End nextAct = End.newInstance("j", 0.0, 0.0); + TourActivity newAct = mock(TourActivity.class); + when(newAct.getLocationId()).thenReturn("k"); + + when(vehicle.isReturnToDepot()).thenReturn(false); + + ActivityInsertionCosts costs = calc.getCosts(jic, prevAct, nextAct, newAct, 0.0); + assertEquals(3.0,costs.getAdditionalCosts(),0.01); + } +} diff --git a/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemBuilderTest.java b/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemBuilderTest.java index 71467722..05465ca9 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemBuilderTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemBuilderTest.java @@ -17,8 +17,9 @@ package jsprit.core.problem; import static org.junit.Assert.assertEquals; -import jsprit.core.problem.VehicleRoutingProblem; +import static org.mockito.Mockito.mock; import jsprit.core.problem.VehicleRoutingProblem.FleetSize; +import jsprit.core.problem.constraint.Constraint; import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Shipment; import jsprit.core.problem.vehicle.Vehicle; @@ -82,5 +83,15 @@ public class VehicleRoutingProblemBuilderTest { assertEquals(s2,vrp.getJobs().get("s2")); } + @Test + public void whenConstraintsAdded_theyShouldAppearInConstraintCollection(){ + Constraint c1 = mock(Constraint.class); + Constraint c2 = mock(Constraint.class); + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + builder.addConstraint(c1).addConstraint(c2); + VehicleRoutingProblem problem = builder.build(); + assertEquals(2,problem.getConstraints().size()); + } + } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/constraint/TestConstraintManager.java b/jsprit-core/src/test/java/jsprit/core/problem/constraint/TestConstraintManager.java new file mode 100644 index 00000000..58c55f22 --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/problem/constraint/TestConstraintManager.java @@ -0,0 +1,34 @@ +package jsprit.core.problem.constraint; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; + +import java.util.ArrayList; +import java.util.List; + +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; + +import org.junit.Test; + +public class TestConstraintManager { + + @Test + public void whenGettingConstraintsViaConstructor_theyShouldBeResolvedCorrectly(){ + List constraints = new ArrayList(); + constraints.add(new ServiceDeliveriesFirstConstraint()); + constraints.add(mock(HardRouteStateLevelConstraint.class)); + ConstraintManager cManager = new ConstraintManager(mock(VehicleRoutingProblem.class),mock(RouteAndActivityStateGetter.class),constraints); + assertEquals(2,cManager.getConstraints().size()); + } + + @Test + public void whenGettingConstraintsViaConstructorAndAtLeastOneConstraintCannotBeResolved_itShouldOnlyAddTheKnownConstraints(){ + List constraints = new ArrayList(); + constraints.add(new ServiceDeliveriesFirstConstraint()); + constraints.add(mock(Constraint.class)); + ConstraintManager cManager = new ConstraintManager(mock(VehicleRoutingProblem.class),mock(RouteAndActivityStateGetter.class),constraints); + assertEquals(1,cManager.getConstraints().size()); + } + +} diff --git a/jsprit-core/src/test/java/jsprit/core/problem/solution/route/VehicleRouteBuilderTest.java b/jsprit-core/src/test/java/jsprit/core/problem/solution/route/VehicleRouteBuilderTest.java index 5d998aaa..3a584e17 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/solution/route/VehicleRouteBuilderTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/solution/route/VehicleRouteBuilderTest.java @@ -1,8 +1,8 @@ package jsprit.core.problem.solution.route; -import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import jsprit.core.problem.driver.Driver; import jsprit.core.problem.job.Shipment; import jsprit.core.problem.vehicle.Vehicle; @@ -60,18 +60,73 @@ public class VehicleRouteBuilderTest { } @Test - public void whenBuildingOpenRoute(){ - assertTrue(false); + public void whenBuildingClosedRoute_routeEndShouldHaveLocationOfVehicle(){ + Shipment s = mock(Shipment.class); + Shipment s2 = mock(Shipment.class); + Vehicle vehicle = mock(Vehicle.class); + when(vehicle.isReturnToDepot()).thenReturn(true); + when(vehicle.getLocationId()).thenReturn("vehLoc"); + VehicleRoute.Builder builder = VehicleRoute.Builder.newInstance(vehicle, mock(Driver.class)); + builder.addPickup(s); + builder.addPickup(s2); + builder.addDelivery(s); + builder.addDelivery(s2); + VehicleRoute route = builder.build(); + assertEquals(route.getEnd().getLocationId(), vehicle.getLocationId()); + } + + @Test + public void whenBuildingOpenRoute_routeEndShouldHaveLocationOfLastActivity(){ + Shipment s = mock(Shipment.class); + Shipment s2 = mock(Shipment.class); + when(s2.getDeliveryLocation()).thenReturn("delLoc"); + Vehicle vehicle = mock(Vehicle.class); + when(vehicle.isReturnToDepot()).thenReturn(false); + when(vehicle.getLocationId()).thenReturn("vehLoc"); + VehicleRoute.Builder builder = VehicleRoute.Builder.newInstance(vehicle, mock(Driver.class)); + builder.addPickup(s); + builder.addPickup(s2); + builder.addDelivery(s); + builder.addDelivery(s2); + VehicleRoute route = builder.build(); + assertEquals(route.getEnd().getLocationId(), s2.getDeliveryLocation()); } @Test public void whenSettingDepartureTime(){ - assertTrue(false); + Shipment s = mock(Shipment.class); + Shipment s2 = mock(Shipment.class); + when(s2.getDeliveryLocation()).thenReturn("delLoc"); + Vehicle vehicle = mock(Vehicle.class); + when(vehicle.isReturnToDepot()).thenReturn(false); + when(vehicle.getLocationId()).thenReturn("vehLoc"); + VehicleRoute.Builder builder = VehicleRoute.Builder.newInstance(vehicle, mock(Driver.class)); + builder.addPickup(s); + builder.addPickup(s2); + builder.addDelivery(s); + builder.addDelivery(s2); + builder.setDepartureTime(100); + VehicleRoute route = builder.build(); + assertEquals(100.0,route.getDepartureTime(),0.01); + assertEquals(100.0,route.getStart().getEndTime(),0.01); } @Test public void whenSettingEndTime(){ - assertTrue(false); + Shipment s = mock(Shipment.class); + Shipment s2 = mock(Shipment.class); + when(s2.getDeliveryLocation()).thenReturn("delLoc"); + Vehicle vehicle = mock(Vehicle.class); + when(vehicle.isReturnToDepot()).thenReturn(false); + when(vehicle.getLocationId()).thenReturn("vehLoc"); + VehicleRoute.Builder builder = VehicleRoute.Builder.newInstance(vehicle, mock(Driver.class)); + builder.addPickup(s); + builder.addPickup(s2); + builder.addDelivery(s); + builder.addDelivery(s2); + builder.setRouteEndArrivalTime(100.0); + VehicleRoute route = builder.build(); + assertEquals(100.0,route.getEnd().getArrTime(),0.01); } } diff --git a/jsprit-examples/input/bicycle_messenger_demand.txt b/jsprit-examples/input/bicycle_messenger_demand.txt deleted file mode 100644 index 42890e1b..00000000 --- a/jsprit-examples/input/bicycle_messenger_demand.txt +++ /dev/null @@ -1,31 +0,0 @@ -item id pickup_x pickup_y deliver_x deliver_y -envelope 1 13745 55419 13883 55756 -envelope 2 8406 53246 13937 55854 -envelope 3 15738 57396 35996 79499 -envelope 4 12045 60418 19349 57118 -envelope 5 13750 56416 35733 78403 -envelope 6 13190 57068 11860 59749 -envelope 7 15021 55768 14098 57379 -envelope 8 11513 58543 11501 59683 -envelope 9 12013 64155 14120 59301 -envelope 10 15006 57578 35511 78426 -envelope 11 11450 58819 11916 58338 -envelope 12 13728 56304 35524 79013 -envelope 13 15104 60923 17937 57066 -envelope 14 11373 58388 13983 53804 -envelope 15 18575 55186 18718 54381 -envelope 16 11639 50071 17363 58375 -envelope 17 11273 53410 10860 60441 -envelope 18 13766 59041 13963 57769 -envelope 19 16138 55801 16183 56024 -envelope 20 13728 56146 14301 61694 -envelope 21 12848 57059 13586 59734 -envelope 22 13645 56488 13955 55859 -envelope 23 12896 56838 13937 55908 -envelope 24 13341 58150 35709 78924 -envelope 25 13483 57303 13614 57820 -envelope 26 12741 63478 15230 59838 -envelope 27 14676 51691 16501 48361 -envelope 28 13748 54933 14120 56110 -envelope 29 17875 59565 20453 61903 -envelope 30 9772 56424 6404 55601 \ No newline at end of file diff --git a/jsprit-examples/input/bicycle_messenger_supply.txt b/jsprit-examples/input/bicycle_messenger_supply.txt deleted file mode 100644 index f25f8b66..00000000 --- a/jsprit-examples/input/bicycle_messenger_supply.txt +++ /dev/null @@ -1,6 +0,0 @@ -type id x y -messenger A 13750 57578 -messenger B 15104 53410 -messenger C 13728 55801 -messenger D 12741 63478 -messenger E 14676 18575 \ No newline at end of file diff --git a/jsprit-examples/input/pickups_and_deliveries_solomon_r101_open.xml b/jsprit-examples/input/pickups_and_deliveries_solomon_r101_open.xml new file mode 100644 index 00000000..758cfab0 --- /dev/null +++ b/jsprit-examples/input/pickups_and_deliveries_solomon_r101_open.xml @@ -0,0 +1,1236 @@ + + + + INFINITE + HOMOGENEOUS + + + + solomonVehicle + solomonType + + 0 + + + + 0.0 + 230.0 + + false + + + + + solomonType + 200 + + 100.0 + 1.0 + + + + + + + [x=63.0][y=65.0] + + 8 + 10.0 + + + 143.0 + 153.0 + + + + + [x=2.0][y=60.0] + + 5 + 10.0 + + + 41.0 + 51.0 + + + + + [x=53.0][y=52.0] + + 11 + 10.0 + + + 37.0 + 47.0 + + + + + [x=65.0][y=55.0] + + 14 + 10.0 + + + 117.0 + 127.0 + + + + + [x=60.0][y=12.0] + + 31 + 10.0 + + + 44.0 + 54.0 + + + + + [x=20.0][y=20.0] + + 8 + 10.0 + + + 134.0 + 144.0 + + + + + [x=5.0][y=5.0] + + 16 + 10.0 + + + 83.0 + 93.0 + + + + + [x=23.0][y=3.0] + + 7 + 10.0 + + + 132.0 + 142.0 + + + + + [x=24.0][y=12.0] + + 5 + 10.0 + + + 31.0 + 41.0 + + + + + [x=42.0][y=7.0] + + 5 + 10.0 + + + 97.0 + 107.0 + + + + + [x=40.0][y=25.0] + + 9 + 10.0 + + + 85.0 + 95.0 + + + + + [x=45.0][y=10.0] + + 18 + 10.0 + + + 97.0 + 107.0 + + + + + [x=55.0][y=5.0] + + 29 + 10.0 + + + 68.0 + 78.0 + + + + + [x=65.0][y=35.0] + + 3 + 10.0 + + + 153.0 + 163.0 + + + + + [x=65.0][y=20.0] + + 6 + 10.0 + + + 172.0 + 182.0 + + + + + [x=45.0][y=30.0] + + 17 + 10.0 + + + 132.0 + 142.0 + + + + + [x=35.0][y=40.0] + + 16 + 10.0 + + + 37.0 + 47.0 + + + + + [x=41.0][y=37.0] + + 16 + 10.0 + + + 39.0 + 49.0 + + + + + [x=64.0][y=42.0] + + 9 + 10.0 + + + 63.0 + 73.0 + + + + + [x=55.0][y=45.0] + + 13 + 10.0 + + + 116.0 + 126.0 + + + + + [x=35.0][y=17.0] + + 7 + 10.0 + + + 50.0 + 60.0 + + + + + [x=41.0][y=49.0] + + 10 + 10.0 + + + 161.0 + 171.0 + + + + + [x=40.0][y=60.0] + + 21 + 10.0 + + + 71.0 + 81.0 + + + + + [x=20.0][y=50.0] + + 5 + 10.0 + + + 81.0 + 91.0 + + + + + [x=25.0][y=30.0] + + 3 + 10.0 + + + 99.0 + 109.0 + + + + + [x=15.0][y=30.0] + + 26 + 10.0 + + + 34.0 + 44.0 + + + + + [x=35.0][y=69.0] + + 23 + 10.0 + + + 141.0 + 151.0 + + + + + [x=55.0][y=20.0] + + 19 + 10.0 + + + 149.0 + 159.0 + + + + + [x=31.0][y=52.0] + + 27 + 10.0 + + + 50.0 + 60.0 + + + + + [x=55.0][y=60.0] + + 16 + 10.0 + + + 97.0 + 107.0 + + + + + [x=10.0][y=43.0] + + 9 + 10.0 + + + 95.0 + 105.0 + + + + + [x=15.0][y=60.0] + + 17 + 10.0 + + + 76.0 + 86.0 + + + + + [x=5.0][y=30.0] + + 2 + 10.0 + + + 157.0 + 167.0 + + + + + [x=20.0][y=40.0] + + 12 + 10.0 + + + 87.0 + 97.0 + + + + + [x=30.0][y=5.0] + + 8 + 10.0 + + + 61.0 + 71.0 + + + + + [x=10.0][y=20.0] + + 19 + 10.0 + + + 75.0 + 85.0 + + + + + [x=30.0][y=25.0] + + 23 + 10.0 + + + 159.0 + 169.0 + + + + + [x=15.0][y=10.0] + + 20 + 10.0 + + + 32.0 + 42.0 + + + + + [x=20.0][y=65.0] + + 12 + 10.0 + + + 67.0 + 77.0 + + + + + [x=50.0][y=35.0] + + 19 + 10.0 + + + 63.0 + 73.0 + + + + + [x=45.0][y=20.0] + + 11 + 10.0 + + + 62.0 + 72.0 + + + + + [x=45.0][y=65.0] + + 9 + 10.0 + + + 126.0 + 136.0 + + + + + [x=20.0][y=26.0] + + 9 + 10.0 + + + 83.0 + 93.0 + + + + + [x=18.0][y=18.0] + + 17 + 10.0 + + + 185.0 + 195.0 + + + + + [x=19.0][y=21.0] + + 10 + 10.0 + + + 58.0 + 68.0 + + + + + [x=25.0][y=21.0] + + 12 + 10.0 + + + 133.0 + 143.0 + + + + + [x=22.0][y=27.0] + + 11 + 10.0 + + + 135.0 + 145.0 + + + + + [x=25.0][y=24.0] + + 20 + 10.0 + + + 39.0 + 49.0 + + + + + [x=26.0][y=27.0] + + 27 + 10.0 + + + 100.0 + 110.0 + + + + + [x=18.0][y=24.0] + + 22 + 10.0 + + + 188.0 + 198.0 + + + + + [x=22.0][y=22.0] + + 2 + 10.0 + + + 18.0 + 28.0 + + + + + [x=15.0][y=19.0] + + 1 + 10.0 + + + 160.0 + 170.0 + + + + + [x=31.0][y=67.0] + + 3 + 10.0 + + + 95.0 + 105.0 + + + + + [x=30.0][y=60.0] + + 16 + 10.0 + + + 124.0 + 134.0 + + + + + [x=26.0][y=52.0] + + 9 + 10.0 + + + 74.0 + 84.0 + + + + + [x=26.0][y=35.0] + + 15 + 10.0 + + + 176.0 + 186.0 + + + + + [x=57.0][y=48.0] + + 23 + 10.0 + + + 92.0 + 102.0 + + + + + [x=61.0][y=52.0] + + 3 + 10.0 + + + 96.0 + 106.0 + + + + + [x=53.0][y=43.0] + + 14 + 10.0 + + + 179.0 + 189.0 + + + + + [x=15.0][y=47.0] + + 16 + 10.0 + + + 55.0 + 65.0 + + + + + [x=14.0][y=37.0] + + 11 + 10.0 + + + 44.0 + 54.0 + + + + + [x=56.0][y=37.0] + + 6 + 10.0 + + + 182.0 + 192.0 + + + + + [x=55.0][y=54.0] + + 26 + 10.0 + + + 94.0 + 104.0 + + + + + [x=4.0][y=18.0] + + 35 + 10.0 + + + 94.0 + 104.0 + + + + + [x=28.0][y=18.0] + + 26 + 10.0 + + + 93.0 + 103.0 + + + + + [x=11.0][y=31.0] + + 7 + 10.0 + + + 101.0 + 111.0 + + + + + [x=16.0][y=22.0] + + 41 + 10.0 + + + 91.0 + 101.0 + + + + + [x=67.0][y=5.0] + + 25 + 10.0 + + + 83.0 + 93.0 + + + + + [x=49.0][y=73.0] + + 25 + 10.0 + + + 127.0 + 137.0 + + + + + [x=37.0][y=47.0] + + 6 + 10.0 + + + 50.0 + 60.0 + + + + + [x=56.0][y=39.0] + + 36 + 10.0 + + + 142.0 + 152.0 + + + + + [x=37.0][y=56.0] + + 5 + 10.0 + + + 182.0 + 192.0 + + + + + [x=57.0][y=68.0] + + 15 + 10.0 + + + 77.0 + 87.0 + + + + + [x=47.0][y=16.0] + + 25 + 10.0 + + + 35.0 + 45.0 + + + + + [x=44.0][y=17.0] + + 9 + 10.0 + + + 78.0 + 88.0 + + + + + [x=46.0][y=13.0] + + 8 + 10.0 + + + 149.0 + 159.0 + + + + + [x=49.0][y=11.0] + + 18 + 10.0 + + + 69.0 + 79.0 + + + + + [x=49.0][y=42.0] + + 13 + 10.0 + + + 73.0 + 83.0 + + + + + [x=21.0][y=24.0] + + 28 + 10.0 + + + 18.0 + 28.0 + + + + + [x=36.0][y=26.0] + + 18 + 10.0 + + + 200.0 + 210.0 + + + + + [x=32.0][y=12.0] + + 7 + 10.0 + + + 101.0 + 111.0 + + + + + [x=53.0][y=12.0] + + 6 + 10.0 + + + 130.0 + 140.0 + + + + + [x=63.0][y=23.0] + + 2 + 10.0 + + + 136.0 + 146.0 + + + + + [x=15.0][y=77.0] + + 9 + 10.0 + + + 73.0 + 83.0 + + + + + [x=62.0][y=77.0] + + 20 + 10.0 + + + 51.0 + 61.0 + + + + + [x=24.0][y=58.0] + + 19 + 10.0 + + + 58.0 + 68.0 + + + + + [x=27.0][y=69.0] + + 10 + 10.0 + + + 34.0 + 44.0 + + + + + [x=17.0][y=34.0] + + 3 + 10.0 + + + 162.0 + 172.0 + + + + + [x=12.0][y=24.0] + + 13 + 10.0 + + + 76.0 + 86.0 + + + + + [x=6.0][y=68.0] + + 30 + 10.0 + + + 108.0 + 118.0 + + + + + [x=13.0][y=52.0] + + 36 + 10.0 + + + 165.0 + 175.0 + + + + + [x=6.0][y=38.0] + + 16 + 10.0 + + + 32.0 + 42.0 + + + + + [x=11.0][y=14.0] + + 18 + 10.0 + + + 69.0 + 79.0 + + + + + [x=8.0][y=56.0] + + 27 + 10.0 + + + 51.0 + 61.0 + + + + + [x=2.0][y=48.0] + + 1 + 10.0 + + + 117.0 + 127.0 + + + + + [x=49.0][y=58.0] + + 10 + 10.0 + + + 88.0 + 98.0 + + + + + [x=27.0][y=43.0] + + 9 + 10.0 + + + 52.0 + 62.0 + + + + + [x=37.0][y=31.0] + + 14 + 10.0 + + + 95.0 + 105.0 + + + + + [x=57.0][y=29.0] + + 18 + 10.0 + + + 140.0 + 150.0 + + + + + [x=47.0][y=47.0] + + 13 + 10.0 + + + 124.0 + 134.0 + + + + + diff --git a/jsprit-examples/src/main/java/jsprit/examples/BicycleMessenger.java b/jsprit-examples/src/main/java/jsprit/examples/BicycleMessenger.java index ccfd8780..c997c7d4 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/BicycleMessenger.java +++ b/jsprit-examples/src/main/java/jsprit/examples/BicycleMessenger.java @@ -4,9 +4,7 @@ import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -19,8 +17,10 @@ import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem.Builder; import jsprit.core.problem.VehicleRoutingProblem.FleetSize; import jsprit.core.problem.constraint.HardActivityStateLevelConstraint; +import jsprit.core.problem.constraint.HardRouteStateLevelConstraint; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; import jsprit.core.problem.driver.DriverImpl; +import jsprit.core.problem.io.VrpXMLWriter; import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Shipment; import jsprit.core.problem.misc.JobInsertionContext; @@ -39,42 +39,22 @@ public class BicycleMessenger { static class ThreeTimesLessThanDirectRouteConstraint implements HardActivityStateLevelConstraint { - private VehicleRoutingTransportCosts vrpCosts; + private VehicleRoutingTransportCosts routingCosts; //jobId map direct-distance by nearestMessenger private Map bestMessengers = new HashMap(); - public ThreeTimesLessThanDirectRouteConstraint(VehicleRoutingTransportCosts vrpCosts, Collection envelopes, Collection messengers) { - super(); - this.vrpCosts = vrpCosts; - determineNearestMessenger(envelopes,messengers); - } - - private void determineNearestMessenger(Collection envelopes,Collection messengers) { - for(Job envelope : envelopes){ - double minDirect = Double.MAX_VALUE; - for(Vehicle m : messengers){ - double direct = getDirectRouteDistance(envelope,m); - if(direct < minDirect){ - minDirect = direct; - } - } - bestMessengers.put(envelope.getId(), minDirect); - } - } - - private double getDirectRouteDistance(Job job, Vehicle v) { - Shipment envelope = (Shipment) job; - double direct = vrpCosts.getTransportTime(v.getLocationId(), envelope.getPickupLocation(), 0.0, DriverImpl.noDriver(), v) + - vrpCosts.getTransportTime(envelope.getPickupLocation(), envelope.getDeliveryLocation(), 0.0, DriverImpl.noDriver(), v); - return direct; + public ThreeTimesLessThanDirectRouteConstraint(Map nearestMessengers, VehicleRoutingTransportCosts routingCosts) { + this.bestMessengers = nearestMessengers; + this.routingCosts = routingCosts; } @Override public ConstraintsStatus fulfilled(JobInsertionContext iFacts,TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { if(newAct instanceof DeliverShipment){ - double deliveryTime = prevActDepTime + vrpCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); - if(deliveryTime > 3 * bestMessengers.get(((DeliverShipment) newAct).getJob().getId())){ + double deliveryTime = prevActDepTime + routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevActDepTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); + double directTimeOfNearestMessenger = bestMessengers.get(((DeliverShipment) newAct).getJob().getId()); + if(deliveryTime > 3 * directTimeOfNearestMessenger){ return ConstraintsStatus.NOT_FULFILLED_BREAK; } } @@ -83,21 +63,52 @@ public class BicycleMessenger { } + static class IgnoreMessengerThatCanNeverMeetTimeRequirements implements HardRouteStateLevelConstraint { + + private Map bestMessengers = new HashMap(); + + private VehicleRoutingTransportCosts routingCosts; + + public IgnoreMessengerThatCanNeverMeetTimeRequirements(Map bestMessengers,VehicleRoutingTransportCosts routingCosts) { + super(); + this.bestMessengers = bestMessengers; + this.routingCosts = routingCosts; + } + + @Override + public boolean fulfilled(JobInsertionContext insertionContext) { + double timeOfDirectRoute = getTimeOfDirectRoute(insertionContext.getJob(), insertionContext.getNewVehicle(), routingCosts); + double timeOfNearestMessenger = bestMessengers.get(insertionContext.getJob().getId()); + if(timeOfDirectRoute > 3 * timeOfNearestMessenger){ + return false; + } + return true; + } + + } + /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException { + VehicleRoutingProblem.Builder problemBuilder = VehicleRoutingProblem.Builder.newInstance(); readEnvelopes(problemBuilder); readMessengers(problemBuilder); + + VehicleRoutingTransportCosts routingCosts = new CrowFlyCosts(problemBuilder.getLocations()); + Map nearestMessengers = getNearestMessengers(routingCosts, problemBuilder.getAddedJobs(), problemBuilder.getAddedVehicles()); + problemBuilder.setFleetSize(FleetSize.FINITE); -// problemBuilder.addConstraint(new ThreeTimesLessThanDirectRouteConstraint(new CrowFlyCosts(problemBuilder.getLocations()),problemBuilder.getAddedJobs(),problemBuilder.getAddedVehicles())); + problemBuilder.addConstraint(new ThreeTimesLessThanDirectRouteConstraint(nearestMessengers, routingCosts)); + problemBuilder.addConstraint(new IgnoreMessengerThatCanNeverMeetTimeRequirements(nearestMessengers, routingCosts)); + VehicleRoutingProblem bicycleMessengerProblem = problemBuilder.build(); - VehicleRoutingAlgorithm algorithm = VehicleRoutingAlgorithms.readAndCreateAlgorithm(bicycleMessengerProblem, 5,"input/algorithmConfig_open.xml"); -// algorithm.setPrematureAlgorithmTermination(new IterationWithoutImprovementTermination(200)); + VehicleRoutingAlgorithm algorithm = VehicleRoutingAlgorithms.readAndCreateAlgorithm(bicycleMessengerProblem,"input/algorithmConfig_open.xml"); + algorithm.setPrematureAlgorithmTermination(new IterationWithoutImprovementTermination(200)); Collection solutions = algorithm.searchSolutions(); SolutionPrinter.print(Solutions.bestOf(solutions)); @@ -113,9 +124,33 @@ public class BicycleMessenger { // plotter1.setBoundingBox(10000, 47500, 20000, 67500); plotter1.plot("output/bicycleMessengerSolution.png", "bicycleMessenger"); + new VrpXMLWriter(bicycleMessengerProblem, solutions).write("output/bicycleMessenger.xml"); + } + static Map getNearestMessengers(VehicleRoutingTransportCosts routingCosts, Collection envelopes, Collection messengers) { + Map nearestMessengers = new HashMap(); + for(Job envelope : envelopes){ + double minDirect = Double.MAX_VALUE; + for(Vehicle m : messengers){ + double direct = getTimeOfDirectRoute(envelope, m, routingCosts); + if(direct < minDirect){ + minDirect = direct; + } + } + nearestMessengers.put(envelope.getId(), minDirect); + } + return nearestMessengers; + } + + static double getTimeOfDirectRoute(Job job, Vehicle v, VehicleRoutingTransportCosts routingCosts) { + Shipment envelope = (Shipment) job; + double direct = routingCosts.getTransportTime(v.getLocationId(), envelope.getPickupLocation(), 0.0, DriverImpl.noDriver(), v) + + routingCosts.getTransportTime(envelope.getPickupLocation(), envelope.getDeliveryLocation(), 0.0, DriverImpl.noDriver(), v); + return direct; + } + private static void readEnvelopes(Builder problemBuilder) throws IOException { BufferedReader reader = new BufferedReader(new FileReader(new File("input/bicycle_messenger_demand.txt"))); String line = null; @@ -134,7 +169,7 @@ public class BicycleMessenger { BufferedReader reader = new BufferedReader(new FileReader(new File("input/bicycle_messenger_supply.txt"))); String line = null; boolean firstLine = true; - VehicleType messengerType = VehicleTypeImpl.Builder.newInstance("messengerType", Integer.MAX_VALUE).setCostPerDistance(1).build(); + VehicleType messengerType = VehicleTypeImpl.Builder.newInstance("messengerType", 15).setCostPerDistance(1).build(); while((line = reader.readLine()) != null){ if(firstLine) { firstLine = false; continue; } String[] tokens = line.split("\\s+"); diff --git a/jsprit-examples/src/main/java/jsprit/examples/SolomonOpenExample.java b/jsprit-examples/src/main/java/jsprit/examples/SolomonOpenExample.java index 6cba5e5c..ae2be7ca 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/SolomonOpenExample.java +++ b/jsprit-examples/src/main/java/jsprit/examples/SolomonOpenExample.java @@ -27,7 +27,6 @@ import jsprit.core.algorithm.selector.SelectBest; import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.io.VrpXMLReader; import jsprit.core.problem.solution.VehicleRoutingProblemSolution; -import jsprit.instance.reader.SolomonReader; public class SolomonOpenExample { diff --git a/jsprit-examples/src/main/java/jsprit/examples/VRPWithBackhaulsExample.java b/jsprit-examples/src/main/java/jsprit/examples/VRPWithBackhaulsExample.java index 5105b27e..defe942d 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/VRPWithBackhaulsExample.java +++ b/jsprit-examples/src/main/java/jsprit/examples/VRPWithBackhaulsExample.java @@ -28,6 +28,7 @@ import jsprit.core.algorithm.io.VehicleRoutingAlgorithms; import jsprit.core.algorithm.selector.SelectBest; import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem.Constraint; +import jsprit.core.problem.constraint.ServiceDeliveriesFirstConstraint; import jsprit.core.problem.io.VrpXMLReader; import jsprit.core.problem.solution.VehicleRoutingProblemSolution; @@ -62,7 +63,8 @@ public class VRPWithBackhaulsExample { /* * Finally, the problem can be built. By default, transportCosts are crowFlyDistances (as usually used for vrp-instances). */ - vrpBuilder.addProblemConstraint(Constraint.DELIVERIES_FIRST); +// vrpBuilder.addProblemConstraint(Constraint.DELIVERIES_FIRST); + vrpBuilder.addConstraint(new ServiceDeliveriesFirstConstraint()); VehicleRoutingProblem vrp = vrpBuilder.build(); diff --git a/jsprit-examples/src/main/java/jsprit/examples/VRPWithBackhaulsExample2.java b/jsprit-examples/src/main/java/jsprit/examples/VRPWithBackhaulsExample2.java index 8e611a48..10840db6 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/VRPWithBackhaulsExample2.java +++ b/jsprit-examples/src/main/java/jsprit/examples/VRPWithBackhaulsExample2.java @@ -28,6 +28,7 @@ import jsprit.core.algorithm.io.VehicleRoutingAlgorithms; import jsprit.core.algorithm.selector.SelectBest; import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem.Constraint; +import jsprit.core.problem.constraint.ServiceDeliveriesFirstConstraint; import jsprit.core.problem.io.VrpXMLReader; import jsprit.core.problem.solution.VehicleRoutingProblemSolution; @@ -62,7 +63,7 @@ public class VRPWithBackhaulsExample2 { /* * add the backhaul constraint to the problem */ - vrpBuilder.addProblemConstraint(Constraint.DELIVERIES_FIRST); + vrpBuilder.addConstraint(new ServiceDeliveriesFirstConstraint()); /* * Finally, the problem can be built. By default, transportCosts are crowFlyDistances (as usually used for vrp-instances).