diff --git a/jsprit-core/src/main/java/jsprit/core/problem/Skills.java b/jsprit-core/src/main/java/jsprit/core/problem/Skills.java index 5a5cf00e..402171b9 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/Skills.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/Skills.java @@ -81,7 +81,20 @@ public class Skills { return skills.contains(skill.toLowerCase()); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Skills skills1 = (Skills) o; + if (skills != null ? !skills.equals(skills1.skills) : skills1.skills != null) return false; + return true; + } + + @Override + public int hashCode() { + return skills != null ? skills.hashCode() : 0; + } } 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 328e2a29..c8c20b8f 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java @@ -417,7 +417,7 @@ public class VehicleRoutingProblem { Set vehicleTypeKeys = new HashSet(); List uniqueVehicles = new ArrayList(); for(Vehicle v : this.uniqueVehicles){ - VehicleTypeKey key = new VehicleTypeKey(v.getType().getTypeId(),v.getStartLocationId(),v.getEndLocationId(),v.getEarliestDeparture(),v.getLatestArrival()); + VehicleTypeKey key = new VehicleTypeKey(v.getType().getTypeId(),v.getStartLocationId(),v.getEndLocationId(),v.getEarliestDeparture(),v.getLatestArrival(), v.getSkills()); if(!vehicleTypeKeys.contains(key)){ uniqueVehicles.add(v); vehicleTypeKeys.add(key); @@ -439,7 +439,8 @@ public class VehicleRoutingProblem { VehicleImpl penVehicle = VehicleImpl.Builder.newInstance(vehicleId).setEarliestStart(v.getEarliestDeparture()) .setLatestArrival(v.getLatestArrival()).setStartLocationCoordinate(v.getStartLocationCoordinate()).setStartLocationId(v.getStartLocationId()) .setEndLocationId(v.getEndLocationId()).setEndLocationCoordinate(v.getEndLocationCoordinate()) - .setReturnToDepot(v.isReturnToDepot()).setType(penType).build(); + .addSkills(v.getSkills()) + .setReturnToDepot(v.isReturnToDepot()).setType(penType).build(); addVehicle(penVehicle); } } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java index 6daa900d..71b166f7 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/InfiniteVehicles.java @@ -44,7 +44,7 @@ class InfiniteVehicles implements VehicleFleetManager{ private void extractTypes(Collection vehicles) { for(Vehicle v : vehicles){ - VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocationId(),v.getEndLocationId(), v.getEarliestDeparture(), v.getLatestArrival()); + VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocationId(),v.getEndLocationId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills()); types.put(typeKey,v); sortedTypes.add(typeKey); @@ -81,7 +81,7 @@ class InfiniteVehicles implements VehicleFleetManager{ @Override public Collection getAvailableVehicles(Vehicle withoutThisType) { Collection vehicles = new ArrayList(); - VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType.getType().getTypeId(), withoutThisType.getStartLocationId(), withoutThisType.getEndLocationId(), withoutThisType.getEarliestDeparture(), withoutThisType.getLatestArrival()); + VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType.getType().getTypeId(), withoutThisType.getStartLocationId(), withoutThisType.getEndLocationId(), withoutThisType.getEarliestDeparture(), withoutThisType.getLatestArrival(), withoutThisType.getSkills()); for(VehicleTypeKey key : types.keySet()){ if(!key.equals(thisKey)){ vehicles.add(types.get(key)); diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java index f9a4255e..996a7632 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleFleetManagerImpl.java @@ -122,11 +122,11 @@ class VehicleFleetManagerImpl implements VehicleFleetManager { } String typeId = v.getType().getTypeId(); if(v.getType() instanceof PenaltyVehicleType){ - VehicleTypeKey typeKey = new VehicleTypeKey(typeId, v.getStartLocationId(), v.getEndLocationId(), v.getEarliestDeparture(), v.getLatestArrival()); + VehicleTypeKey typeKey = new VehicleTypeKey(typeId, v.getStartLocationId(), v.getEndLocationId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills()); penaltyVehicles.put(typeKey, v); } else{ - VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocationId(), v.getEndLocationId(), v.getEarliestDeparture(), v.getLatestArrival()); + VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocationId(), v.getEndLocationId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills()); if(!typeMapOfAvailableVehicles.containsKey(typeKey)){ typeMapOfAvailableVehicles.put(typeKey, new TypeContainer()); } @@ -137,7 +137,7 @@ class VehicleFleetManagerImpl implements VehicleFleetManager { private void removeVehicle(Vehicle v){ //it might be better to introduce a class PenaltyVehicle if(!(v.getType() instanceof PenaltyVehicleType)){ - VehicleTypeKey key = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocationId(), v.getEndLocationId(), v.getEarliestDeparture(), v.getLatestArrival()); + VehicleTypeKey key = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocationId(), v.getEndLocationId(), v.getEarliestDeparture(), v.getLatestArrival(), v.getSkills()); if(typeMapOfAvailableVehicles.containsKey(key)){ typeMapOfAvailableVehicles.get(key).remove(v); } @@ -170,7 +170,7 @@ class VehicleFleetManagerImpl implements VehicleFleetManager { @Override public Collection getAvailableVehicles(Vehicle withoutThisType) { List vehicles = new ArrayList(); - VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType.getType().getTypeId(), withoutThisType.getStartLocationId(), withoutThisType.getEndLocationId(), withoutThisType.getEarliestDeparture(), withoutThisType.getLatestArrival()); + VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType.getType().getTypeId(), withoutThisType.getStartLocationId(), withoutThisType.getEndLocationId(), withoutThisType.getEarliestDeparture(), withoutThisType.getLatestArrival(), withoutThisType.getSkills()); for(VehicleTypeKey key : typeMapOfAvailableVehicles.keySet()){ if(key.equals(thisKey)) continue; if(!typeMapOfAvailableVehicles.get(key).isEmpty()){ 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 7f2f106c..947ea632 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 @@ -244,8 +244,12 @@ public class VehicleImpl extends AbstractVehicle{ * @return vehicle builder */ public static Builder newInstance(String vehicleId){ return new Builder(vehicleId); } - - } + + public Builder addSkills(Skills skills) { + this.skillBuilder.addAllSkills(skills.values()); + return this; + } + } /** * Returns empty/noVehicle which is a vehicle having no capacity, no type and no reasonable id. @@ -294,8 +298,8 @@ public class VehicleImpl extends AbstractVehicle{ startLocationCoord = builder.startLocationCoord; endLocationId = builder.endLocationId; endLocationCoord = builder.endLocationCoord; - setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(),startLocationId,endLocationId,earliestDeparture,latestArrival)); skills = builder.skills; + setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(),startLocationId,endLocationId,earliestDeparture,latestArrival,skills)); } /** diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeKey.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeKey.java index 57eaa9b5..ce050058 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeKey.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/VehicleTypeKey.java @@ -19,6 +19,7 @@ package jsprit.core.problem.vehicle; import jsprit.core.problem.AbstractVehicle; +import jsprit.core.problem.Skills; /** * Key to identify similar vehicles @@ -35,67 +36,51 @@ public class VehicleTypeKey extends AbstractVehicle.AbstractTypeKey{ public final String endLocationId; public final double earliestStart; public final double latestEnd; + public final Skills skills; - public VehicleTypeKey(String typeId, String startLocationId, String endLocationId, double earliestStart, double latestEnd) { + public VehicleTypeKey(String typeId, String startLocationId, String endLocationId, double earliestStart, double latestEnd, Skills skills) { super(); this.type = typeId; this.startLocationId = startLocationId; this.endLocationId = endLocationId; this.earliestStart = earliestStart; this.latestEnd = latestEnd; + this.skills = skills; } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - long temp; - temp = Double.doubleToLongBits(earliestStart); - result = prime * result + (int) (temp ^ (temp >>> 32)); - result = prime * result - + ((endLocationId == null) ? 0 : endLocationId.hashCode()); - temp = Double.doubleToLongBits(latestEnd); - result = prime * result + (int) (temp ^ (temp >>> 32)); - result = prime * result - + ((startLocationId == null) ? 0 : startLocationId.hashCode()); - result = prime * result + ((type == null) ? 0 : type.hashCode()); - return result; - } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof VehicleTypeKey)) return false; - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - VehicleTypeKey other = (VehicleTypeKey) obj; - if (Double.doubleToLongBits(earliestStart) != Double - .doubleToLongBits(other.earliestStart)) - return false; - if (endLocationId == null) { - if (other.endLocationId != null) - return false; - } else if (!endLocationId.equals(other.endLocationId)) - return false; - if (Double.doubleToLongBits(latestEnd) != Double - .doubleToLongBits(other.latestEnd)) - return false; - if (startLocationId == null) { - if (other.startLocationId != null) - return false; - } else if (!startLocationId.equals(other.startLocationId)) - return false; - if (type == null) { - if (other.type != null) - return false; - } else if (!type.equals(other.type)) - return false; - return true; - } + VehicleTypeKey that = (VehicleTypeKey) o; - @Override + if (Double.compare(that.earliestStart, earliestStart) != 0) return false; + if (Double.compare(that.latestEnd, latestEnd) != 0) return false; + if (!endLocationId.equals(that.endLocationId)) return false; + if (!skills.equals(that.skills)) return false; + if (!startLocationId.equals(that.startLocationId)) return false; + if (!type.equals(that.type)) return false; + + return true; + } + + @Override + public int hashCode() { + int result; + long temp; + result = type.hashCode(); + result = 31 * result + startLocationId.hashCode(); + result = 31 * result + endLocationId.hashCode(); + temp = Double.doubleToLongBits(earliestStart); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(latestEnd); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + result = 31 * result + skills.hashCode(); + return result; + } + + @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(type).append("_").append(startLocationId).append("_").append(endLocationId) 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 1d4d238f..2a721305 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 @@ -19,7 +19,10 @@ package jsprit.core.algorithm.recreate; import jsprit.core.algorithm.ExampleActivityCostFunction; import jsprit.core.algorithm.state.StateManager; import jsprit.core.algorithm.state.UpdateVariableCosts; -import jsprit.core.problem.*; +import jsprit.core.problem.AbstractActivity; +import jsprit.core.problem.AbstractVehicle; +import jsprit.core.problem.JobActivityFactory; +import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.constraint.ConstraintManager; import jsprit.core.problem.cost.AbstractForwardVehicleRoutingTransportCosts; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; @@ -33,6 +36,7 @@ import jsprit.core.problem.solution.route.activity.TimeWindow; import jsprit.core.problem.vehicle.Vehicle; import jsprit.core.problem.vehicle.VehicleImpl; import jsprit.core.problem.vehicle.VehicleType; +import jsprit.core.problem.vehicle.VehicleTypeImpl; import jsprit.core.util.CostFactory; import org.junit.Before; import org.junit.Test; @@ -44,7 +48,6 @@ import java.util.List; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; @@ -76,11 +79,8 @@ public class TestCalculatesServiceInsertionOnRouteLevel { costs = mock(VehicleRoutingTransportCosts.class); - vehicle = mock(AbstractVehicle.class); - VehicleType type = mock(VehicleType.class); - - when(type.getCapacityDimensions()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 1000).build()); + VehicleType type = VehicleTypeImpl.Builder.newInstance("t").addCapacityDimension(0,1000).build(); vehicle = VehicleImpl.Builder.newInstance("v1").setType(type).setStartLocationId("0,0").setLatestArrival(100.).build(); newVehicle = VehicleImpl.Builder.newInstance("v2").setType(type).setStartLocationId("0,0").setLatestArrival(100.).build(); driver = DriverImpl.noDriver(); diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/state/SolomonSkills_IT.java b/jsprit-core/src/test/java/jsprit/core/algorithm/state/SolomonSkills_IT.java new file mode 100644 index 00000000..9ca77534 --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/state/SolomonSkills_IT.java @@ -0,0 +1,98 @@ +package jsprit.core.algorithm.state; + +import jsprit.core.algorithm.VehicleRoutingAlgorithm; +import jsprit.core.algorithm.VehicleRoutingAlgorithmBuilder; +import jsprit.core.algorithm.recreate.NoSolutionFoundException; +import jsprit.core.problem.Skills; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.constraint.ConstraintManager; +import jsprit.core.problem.io.VrpXMLReader; +import jsprit.core.problem.job.Job; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.problem.vehicle.VehicleType; +import jsprit.core.util.Solutions; +import org.junit.Test; + +import java.util.Collection; + +import static org.junit.Assert.*; + +/** + * to test skills with penalty vehicles + */ +public class SolomonSkills_IT { + + @Test + public void itShouldMakeCorrectAssignmentAccordingToSkills(){ + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + new VrpXMLReader(vrpBuilder).read("src/test/resources/solomon_c101.xml"); + VehicleRoutingProblem vrp = vrpBuilder.build(); + + //y >= 50 skill1 otherwise skill2 + //two vehicles: v1 - skill1 #5; v2 - skill2 #6 + Vehicle solomonVehicle = vrp.getVehicles().iterator().next(); + VehicleType newType = solomonVehicle.getType(); + VehicleRoutingProblem.Builder skillProblemBuilder = VehicleRoutingProblem.Builder.newInstance(); + for(int i=0;i<6;i++) { + VehicleImpl skill1Vehicle = VehicleImpl.Builder.newInstance("skill1_vehicle_"+i).addSkill("skill1") + .setStartLocationCoordinate(solomonVehicle.getStartLocationCoordinate()).setStartLocationId(solomonVehicle.getStartLocationId()) + .setEarliestStart(solomonVehicle.getEarliestDeparture()) + .setType(newType).build(); + VehicleImpl skill2Vehicle = VehicleImpl.Builder.newInstance("skill2_vehicle_"+i).addSkill("skill2") + .setStartLocationCoordinate(solomonVehicle.getStartLocationCoordinate()).setStartLocationId(solomonVehicle.getStartLocationId()) + .setEarliestStart(solomonVehicle.getEarliestDeparture()) + .setType(newType).build(); + skillProblemBuilder.addVehicle(skill1Vehicle).addVehicle(skill2Vehicle); + } + for(Job job : vrp.getJobs().values()){ + Service service = (Service) job; + Service.Builder skillServiceBuilder = Service.Builder.newInstance(service.getId()).setServiceTime(service.getServiceDuration()) + .setCoord(service.getCoord()).setLocationId(service.getLocationId()).setTimeWindow(service.getTimeWindow()) + .addSizeDimension(0,service.getSize().get(0)); + if(service.getCoord().getY()<50) skillServiceBuilder.addSkill("skill2"); + else skillServiceBuilder.addSkill("skill1"); + skillProblemBuilder.addJob(skillServiceBuilder.build()); + } + skillProblemBuilder.addPenaltyVehicles(3.); + skillProblemBuilder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE); + VehicleRoutingProblem skillProblem = skillProblemBuilder.build(); + + VehicleRoutingAlgorithmBuilder vraBuilder = new VehicleRoutingAlgorithmBuilder(skillProblem,"src/test/resources/algorithmConfig.xml"); + vraBuilder.addCoreConstraints(); + vraBuilder.addDefaultCostCalculators(); + + StateManager stateManager = new StateManager(skillProblem); + stateManager.updateSkillStates(); + + ConstraintManager constraintManager = new ConstraintManager(skillProblem,stateManager); + constraintManager.addSkillsConstraint(); + + VehicleRoutingAlgorithm vra = vraBuilder.build(); + vra.setNuOfIterations(500); + + try { + Collection solutions = vra.searchSolutions(); + VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions); + assertEquals(828.94, solution.getCost(), 0.01); + for(VehicleRoute route : solution.getRoutes()){ + Skills vehicleSkill = route.getVehicle().getSkills(); + for(Job job : route.getTourActivities().getJobs()){ + for(String skill : job.getRequiredSkills().values()){ + if(!vehicleSkill.containsSkill(skill)){ + assertFalse(true); + } + } + } + } + assertTrue(true); + } + catch (NoSolutionFoundException e){ + System.out.println(e.toString()); + assertFalse(true); + } + } +} diff --git a/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemTest.java b/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemTest.java index 2bd7c3ef..f80bf1f8 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/VehicleRoutingProblemTest.java @@ -94,8 +94,8 @@ public class VehicleRoutingProblemTest { public void whenBuildingWithFourVehiclesAndTwoTypes_vrpShouldContainTheCorrectNuOfTypes(){ VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - VehicleTypeImpl type1 = mock(VehicleTypeImpl.class); - VehicleTypeImpl type2 = mock(VehicleTypeImpl.class); + VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type1").build(); + VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("type2").build(); VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocationId("yo").setType(type1).build(); VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocationId("yo").setType(type1).build(); diff --git a/jsprit-core/src/test/java/jsprit/core/problem/constraint/VehicleDependentTimeWindowTest.java b/jsprit-core/src/test/java/jsprit/core/problem/constraint/VehicleDependentTimeWindowTest.java index d4627665..56831893 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/constraint/VehicleDependentTimeWindowTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/constraint/VehicleDependentTimeWindowTest.java @@ -22,7 +22,6 @@ import org.junit.Test; import java.util.*; import static org.junit.Assert.*; -import static org.mockito.Mockito.mock; /** * unit tests to test vehicle dependent time-windows @@ -52,22 +51,23 @@ public class VehicleDependentTimeWindowTest { routingCosts = CostFactory.createEuclideanCosts(); vrpBuilder.setRoutingCost(routingCosts); - vehicle = VehicleImpl.Builder.newInstance("v").setType(mock(VehicleType.class)).setStartLocationId("0,0") + VehicleType type = VehicleTypeImpl.Builder.newInstance("type").build(); + vehicle = VehicleImpl.Builder.newInstance("v").setType(type).setStartLocationId("0,0") .setEarliestStart(0.).setLatestArrival(100.).build(); - v2 = VehicleImpl.Builder.newInstance("v2").setType(mock(VehicleType.class)).setStartLocationId("0,0") + v2 = VehicleImpl.Builder.newInstance("v2").setType(type).setStartLocationId("0,0") .setEarliestStart(0.).setLatestArrival(60.).build(); - v3 = VehicleImpl.Builder.newInstance("v3").setType(mock(VehicleType.class)).setStartLocationId("0,0") + v3 = VehicleImpl.Builder.newInstance("v3").setType(type).setStartLocationId("0,0") .setEarliestStart(0.).setLatestArrival(50.).build(); - v4 = VehicleImpl.Builder.newInstance("v4").setType(mock(VehicleType.class)).setStartLocationId("0,0") + v4 = VehicleImpl.Builder.newInstance("v4").setType(type).setStartLocationId("0,0") .setEarliestStart(0.).setLatestArrival(10.).build(); - v5 = VehicleImpl.Builder.newInstance("v5").setType(mock(VehicleType.class)).setStartLocationId("0,0") + v5 = VehicleImpl.Builder.newInstance("v5").setType(type).setStartLocationId("0,0") .setEarliestStart(60.).setLatestArrival(100.).build(); - v6 = VehicleImpl.Builder.newInstance("v6").setType(mock(VehicleType.class)).setStartLocationId("0,0") + v6 = VehicleImpl.Builder.newInstance("v6").setType(type).setStartLocationId("0,0") .setEndLocationId("40,0").setEarliestStart(0.).setLatestArrival(40.).build(); vrpBuilder.addVehicle(vehicle).addVehicle(v2).addVehicle(v3).addVehicle(v4).addVehicle(v5).addVehicle(v6); diff --git a/jsprit-core/src/test/resources/solomon_c101.xml b/jsprit-core/src/test/resources/solomon_c101.xml new file mode 100644 index 00000000..a9ebce9e --- /dev/null +++ b/jsprit-core/src/test/resources/solomon_c101.xml @@ -0,0 +1,1441 @@ + + + + INFINITE + + + + solomonVehicle + solomonType + + 0 + + + + 0 + + + + 0.0 + 1236.0 + + true + + + + + solomonType + + 200 + + + 0.0 + 1.0 + + + + + + + 35 + + + 10 + + 90.0 + + + 283.0 + 344.0 + + + + + 36 + + + 10 + + 90.0 + + + 665.0 + 716.0 + + + + + 33 + + + 40 + + 90.0 + + + 87.0 + 158.0 + + + + + 34 + + + 20 + + 90.0 + + + 751.0 + 816.0 + + + + + 39 + + + 20 + + 90.0 + + + 567.0 + 624.0 + + + + + 37 + + + 20 + + 90.0 + + + 383.0 + 434.0 + + + + + 38 + + + 30 + + 90.0 + + + 479.0 + 522.0 + + + + + 43 + + + 10 + + 90.0 + + + 16.0 + 80.0 + + + + + 42 + + + 20 + + 90.0 + + + 68.0 + 149.0 + + + + + 41 + + + 10 + + 90.0 + + + 166.0 + 235.0 + + + + + 40 + + + 10 + + 90.0 + + + 264.0 + 321.0 + + + + + 22 + + + 20 + + 90.0 + + + 812.0 + 883.0 + + + + + 23 + + + 10 + + 90.0 + + + 732.0 + 777.0 + + + + + 24 + + + 10 + + 90.0 + + + 65.0 + 144.0 + + + + + 25 + + + 40 + + 90.0 + + + 169.0 + 224.0 + + + + + 26 + + + 10 + + 90.0 + + + 622.0 + 701.0 + + + + + 27 + + + 10 + + 90.0 + + + 261.0 + 316.0 + + + + + 28 + + + 20 + + 90.0 + + + 546.0 + 593.0 + + + + + 29 + + + 10 + + 90.0 + + + 358.0 + 405.0 + + + + + 3 + + + 10 + + 90.0 + + + 65.0 + 146.0 + + + + + 2 + + + 30 + + 90.0 + + + 825.0 + 870.0 + + + + + 1 + + + 10 + + 90.0 + + + 912.0 + 967.0 + + + + + 30 + + + 10 + + 90.0 + + + 449.0 + 504.0 + + + + + 7 + + + 20 + + 90.0 + + + 170.0 + 225.0 + + + + + 6 + + + 20 + + 90.0 + + + 621.0 + 702.0 + + + + + 5 + + + 10 + + 90.0 + + + 15.0 + 67.0 + + + + + 32 + + + 30 + + 90.0 + + + 31.0 + 100.0 + + + + + 4 + + + 10 + + 90.0 + + + 727.0 + 782.0 + + + + + 31 + + + 20 + + 90.0 + + + 200.0 + 237.0 + + + + + 9 + + + 10 + + 90.0 + + + 534.0 + 605.0 + + + + + 8 + + + 20 + + 90.0 + + + 255.0 + 324.0 + + + + + 19 + + + 10 + + 90.0 + + + 278.0 + 345.0 + + + + + 17 + + + 20 + + 90.0 + + + 99.0 + 148.0 + + + + + 18 + + + 20 + + 90.0 + + + 179.0 + 254.0 + + + + + 15 + + + 40 + + 90.0 + + + 384.0 + 429.0 + + + + + 16 + + + 40 + + 90.0 + + + 475.0 + 528.0 + + + + + 13 + + + 30 + + 90.0 + + + 30.0 + 92.0 + + + + + 14 + + + 10 + + 90.0 + + + 567.0 + 620.0 + + + + + 11 + + + 10 + + 90.0 + + + 448.0 + 505.0 + + + + + 12 + + + 20 + + 90.0 + + + 652.0 + 721.0 + + + + + 21 + + + 20 + + 90.0 + + + 914.0 + 965.0 + + + + + 20 + + + 10 + + 90.0 + + + 10.0 + 73.0 + + + + + 99 + + + 10 + + 90.0 + + + 743.0 + 820.0 + + + + + 100 + + + 20 + + 90.0 + + + 647.0 + 726.0 + + + + + 98 + + + 20 + + 90.0 + + + 30.0 + 84.0 + + + + + 97 + + + 30 + + 90.0 + + + 561.0 + 622.0 + + + + + 96 + + + 10 + + 90.0 + + + 95.0 + 156.0 + + + + + 95 + + + 30 + + 90.0 + + + 196.0 + 239.0 + + + + + 94 + + + 10 + + 90.0 + + + 285.0 + 336.0 + + + + + 93 + + + 40 + + 90.0 + + + 475.0 + 518.0 + + + + + 92 + + + 20 + + 90.0 + + + 368.0 + 441.0 + + + + + 91 + + + 10 + + 90.0 + + + 836.0 + 889.0 + + + + + 90 + + + 10 + + 90.0 + + + 20.0 + 84.0 + + + + + 10 + + + 10 + + 90.0 + + + 357.0 + 410.0 + + + + + 88 + + + 30 + + 90.0 + + + 645.0 + 708.0 + + + + + 89 + + + 10 + + 90.0 + + + 737.0 + 802.0 + + + + + 79 + + + 10 + + 90.0 + + + 668.0 + 731.0 + + + + + 78 + + + 20 + + 90.0 + + + 109.0 + 170.0 + + + + + 77 + + + 10 + + 90.0 + + + 574.0 + 643.0 + + + + + 82 + + + 20 + + 90.0 + + + 369.0 + 420.0 + + + + + 83 + + + 10 + + 90.0 + + + 265.0 + 338.0 + + + + + 80 + + + 10 + + 90.0 + + + 769.0 + 820.0 + + + + + 81 + + + 30 + + 90.0 + + + 47.0 + 124.0 + + + + + 86 + + + 10 + + 90.0 + + + 173.0 + 238.0 + + + + + 87 + + + 20 + + 90.0 + + + 85.0 + 144.0 + + + + + 84 + + + 20 + + 90.0 + + + 458.0 + 523.0 + + + + + 85 + + + 30 + + 90.0 + + + 555.0 + 612.0 + + + + + 67 + + + 10 + + 90.0 + + + 12.0 + 77.0 + + + + + 66 + + + 10 + + 90.0 + + + 826.0 + 875.0 + + + + + 69 + + + 10 + + 90.0 + + + 916.0 + 969.0 + + + + + 68 + + + 10 + + 90.0 + + + 734.0 + 777.0 + + + + + 70 + + + 30 + + 90.0 + + + 387.0 + 456.0 + + + + + 71 + + + 20 + + 90.0 + + + 293.0 + 360.0 + + + + + 72 + + + 10 + + 90.0 + + + 450.0 + 505.0 + + + + + 73 + + + 10 + + 90.0 + + + 478.0 + 551.0 + + + + + 74 + + + 50 + + 90.0 + + + 353.0 + 412.0 + + + + + 75 + + + 20 + + 90.0 + + + 997.0 + 1068.0 + + + + + 76 + + + 10 + + 90.0 + + + 203.0 + 260.0 + + + + + 59 + + + 10 + + 90.0 + + + 651.0 + 740.0 + + + + + 58 + + + 30 + + 90.0 + + + 471.0 + 534.0 + + + + + 57 + + + 40 + + 90.0 + + + 35.0 + 87.0 + + + + + 56 + + + 30 + + 90.0 + + + 385.0 + 436.0 + + + + + 55 + + + 10 + + 90.0 + + + 95.0 + 158.0 + + + + + 64 + + + 10 + + 90.0 + + + 632.0 + 693.0 + + + + + 65 + + + 10 + + 90.0 + + + 76.0 + 129.0 + + + + + 62 + + + 20 + + 90.0 + + + 262.0 + 317.0 + + + + + 63 + + + 50 + + 90.0 + + + 171.0 + 218.0 + + + + + 60 + + + 20 + + 90.0 + + + 562.0 + 629.0 + + + + + 61 + + + 10 + + 90.0 + + + 531.0 + 610.0 + + + + + 49 + + + 10 + + 90.0 + + + 1001.0 + 1066.0 + + + + + 48 + + + 10 + + 90.0 + + + 632.0 + 693.0 + + + + + 45 + + + 10 + + 90.0 + + + 541.0 + 600.0 + + + + + 44 + + + 10 + + 90.0 + + + 359.0 + 412.0 + + + + + 47 + + + 10 + + 90.0 + + + 1054.0 + 1127.0 + + + + + 46 + + + 30 + + 90.0 + + + 448.0 + 509.0 + + + + + 51 + + + 10 + + 90.0 + + + 725.0 + 786.0 + + + + + 52 + + + 10 + + 90.0 + + + 912.0 + 969.0 + + + + + 53 + + + 20 + + 90.0 + + + 286.0 + 347.0 + + + + + 54 + + + 40 + + 90.0 + + + 186.0 + 257.0 + + + + + 50 + + + 10 + + 90.0 + + + 815.0 + 880.0 + + + + + diff --git a/jsprit-examples/src/main/java/jsprit/examples/SolomonWithSkillsExample.java b/jsprit-examples/src/main/java/jsprit/examples/SolomonWithSkillsExample.java new file mode 100644 index 00000000..1b2f4af1 --- /dev/null +++ b/jsprit-examples/src/main/java/jsprit/examples/SolomonWithSkillsExample.java @@ -0,0 +1,87 @@ +package jsprit.examples; + + +import jsprit.analysis.toolbox.Plotter; +import jsprit.analysis.toolbox.SolutionPrinter; +import jsprit.core.algorithm.VehicleRoutingAlgorithm; +import jsprit.core.algorithm.VehicleRoutingAlgorithmBuilder; +import jsprit.core.algorithm.state.StateManager; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.constraint.ConstraintManager; +import jsprit.core.problem.job.Job; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleImpl; +import jsprit.core.problem.vehicle.VehicleType; +import jsprit.core.util.Solutions; +import jsprit.instance.reader.SolomonReader; + +import java.util.Collection; + +public class SolomonWithSkillsExample { + + public static void main(String[] args) { + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + new SolomonReader(vrpBuilder).read("input/C101_solomon.txt"); + VehicleRoutingProblem vrp = vrpBuilder.build(); + + //y >= 50 skill1 otherwise skill2 + //two vehicles: v1 - skill1 #5; v2 - skill2 #6 + Vehicle solomonVehicle = vrp.getVehicles().iterator().next(); + VehicleType newType = solomonVehicle.getType(); + VehicleRoutingProblem.Builder skillProblemBuilder = VehicleRoutingProblem.Builder.newInstance(); + for(int i=0;i<5;i++) { + VehicleImpl skill1Vehicle = VehicleImpl.Builder.newInstance("skill1_vehicle_"+i).addSkill("skill1") + .setStartLocationCoordinate(solomonVehicle.getStartLocationCoordinate()).setStartLocationId(solomonVehicle.getStartLocationId()) + .setEarliestStart(solomonVehicle.getEarliestDeparture()) + .setType(newType).build(); + VehicleImpl skill2Vehicle = VehicleImpl.Builder.newInstance("skill2_vehicle_"+i).addSkill("skill2") + .setStartLocationCoordinate(solomonVehicle.getStartLocationCoordinate()).setStartLocationId(solomonVehicle.getStartLocationId()) + .setEarliestStart(solomonVehicle.getEarliestDeparture()) + .setType(newType).build(); + skillProblemBuilder.addVehicle(skill1Vehicle).addVehicle(skill2Vehicle); + } + for(Job job : vrp.getJobs().values()){ + Service service = (Service) job; + Service.Builder skillServiceBuilder; + if(service.getCoord().getY()<50.){ + skillServiceBuilder = Service.Builder.newInstance(service.getId()+"_skill2").setServiceTime(service.getServiceDuration()) + .setCoord(service.getCoord()).setLocationId(service.getLocationId()).setTimeWindow(service.getTimeWindow()) + .addSizeDimension(0,service.getSize().get(0)); + skillServiceBuilder.addSkill("skill2"); + } + else { + skillServiceBuilder = Service.Builder.newInstance(service.getId()+"_skill1").setServiceTime(service.getServiceDuration()) + .setCoord(service.getCoord()).setLocationId(service.getLocationId()).setTimeWindow(service.getTimeWindow()) + .addSizeDimension(0,service.getSize().get(0)); + skillServiceBuilder.addSkill("skill1"); + } + skillProblemBuilder.addJob(skillServiceBuilder.build()); + } + skillProblemBuilder.addPenaltyVehicles(3.,100.); + skillProblemBuilder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE); + VehicleRoutingProblem skillProblem = skillProblemBuilder.build(); + + VehicleRoutingAlgorithmBuilder vraBuilder = new VehicleRoutingAlgorithmBuilder(skillProblem,"input/algorithmConfig_solomon.xml"); + vraBuilder.addCoreConstraints(); + vraBuilder.addDefaultCostCalculators(); + + StateManager stateManager = new StateManager(skillProblem); + stateManager.updateSkillStates(); + + ConstraintManager constraintManager = new ConstraintManager(skillProblem,stateManager); + constraintManager.addSkillsConstraint(); + + VehicleRoutingAlgorithm vra = vraBuilder.build(); +// vra.setNuOfIterations(500); + + + Collection solutions = vra.searchSolutions(); + VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions); + + SolutionPrinter.print(skillProblem, solution, SolutionPrinter.Print.VERBOSE); + + new Plotter(skillProblem,solution).plot("output/skill_solution","solomon_with_skills"); + } +}