From 2cd2f54b271aa93e09680c25c79a1c6ef8b46bc5 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Sat, 28 Jun 2014 23:22:32 +0200 Subject: [PATCH 01/19] added skills to jobs --- .../java/jsprit/core/problem/job/Service.java | 33 +++++++++++++++++++ .../jsprit/core/problem/job/Shipment.java | 20 +++++++++++ .../jsprit/core/problem/job/DeliveryTest.java | 18 ++++++++++ .../jsprit/core/problem/job/PickupTest.java | 18 ++++++++++ .../jsprit/core/problem/job/ServiceTest.java | 17 ++++++++++ .../jsprit/core/problem/job/ShipmentTest.java | 17 ++++++++++ 6 files changed, 123 insertions(+) diff --git a/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java b/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java index b8a21f8b..f4594ca5 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java @@ -16,6 +16,10 @@ ******************************************************************************/ package jsprit.core.problem.job; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + import jsprit.core.problem.Capacity; import jsprit.core.problem.solution.route.activity.TimeWindow; import jsprit.core.util.Coordinate; @@ -67,6 +71,8 @@ public class Service implements Job { protected Capacity capacity; + protected Set skills = new HashSet(); + /** * Constructs the builder. * @@ -179,6 +185,11 @@ public class Service implements Job { capacity = capacityBuilder.build(); return new Service(this); } + + public Builder addSkill(String string) { + skills.add(string.toLowerCase()); + return this; + } } @@ -196,6 +207,8 @@ public class Service implements Job { private final TimeWindow timeWindow; private final Capacity size; + + private final Set skills; Service(Builder builder){ id = builder.id; @@ -205,6 +218,7 @@ public class Service implements Job { timeWindow = builder.timeWindow; type = builder.type; size = builder.capacity; + skills = builder.skills; } @Override @@ -299,5 +313,24 @@ public class Service implements Job { public Capacity getSize() { return size; } + + /** + * Returns set of required skills. All skills are in lower case. + * + * @return + */ + public Set getRequiredSkills() { + return Collections.unmodifiableSet(skills); + } + + /** + * Returns true if this contains requiredSkill. Not case sensitive. + * + * @param requiredSkill + * @return + */ + public boolean requiresSkill(String requiredSkill){ + return skills.contains(requiredSkill.toLowerCase()); + } } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/job/Shipment.java b/jsprit-core/src/main/java/jsprit/core/problem/job/Shipment.java index 24617550..0c94f6e8 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/job/Shipment.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/job/Shipment.java @@ -1,5 +1,9 @@ package jsprit.core.problem.job; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + import jsprit.core.problem.Capacity; import jsprit.core.problem.solution.route.activity.TimeWindow; import jsprit.core.util.Coordinate; @@ -53,6 +57,8 @@ public class Shipment implements Job{ private Capacity capacity; + private Set skills = new HashSet(); + /** * Returns new instance of this builder. * @@ -230,6 +236,11 @@ public class Shipment implements Job{ return new Shipment(this); } + public Builder addSkill(String string) { + skills.add(string.toLowerCase()); + return this; + } + } @@ -252,6 +263,8 @@ public class Shipment implements Job{ private final TimeWindow pickupTimeWindow; private final Capacity capacity; + + private final Set skills; /** @@ -270,6 +283,7 @@ public class Shipment implements Job{ this.deliveryServiceTime = builder.deliveryServiceTime; this.deliveryTimeWindow = builder.deliveryTimeWindow; this.capacity = builder.capacity; + this.skills = builder.skills; } @Override @@ -386,5 +400,11 @@ public class Shipment implements Job{ return capacity; } + public Set getRequiredSkills() { + return Collections.unmodifiableSet(skills); + } + public boolean requiresSkill(String requiredSkill){ + return skills.contains(requiredSkill.toLowerCase()); + } } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/job/DeliveryTest.java b/jsprit-core/src/test/java/jsprit/core/problem/job/DeliveryTest.java index 2b714a5a..6855e992 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/job/DeliveryTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/job/DeliveryTest.java @@ -1,6 +1,7 @@ package jsprit.core.problem.job; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -38,6 +39,23 @@ public class DeliveryTest { assertEquals(1,one.getSize().getNuOfDimensions()); assertEquals(1,one.getSize().get(0)); } + + @Test + public void whenAddingSkills_theyShouldBeAddedCorrectly(){ + Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocationId("loc") + .addSkill("drill").addSkill("screwdriver").build(); + assertTrue(s.getRequiredSkills().contains("drill")); + assertTrue(s.requiresSkill("drill")); + assertTrue(s.requiresSkill("ScrewDriver")); + } + + @Test + public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ + Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocationId("loc") + .addSkill("DriLl").addSkill("screwDriver").build(); + assertTrue(s.getRequiredSkills().contains("drill")); + assertTrue(s.requiresSkill("drilL")); + } } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/job/PickupTest.java b/jsprit-core/src/test/java/jsprit/core/problem/job/PickupTest.java index 7d7cee9f..5987c4f1 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/job/PickupTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/job/PickupTest.java @@ -1,6 +1,7 @@ package jsprit.core.problem.job; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -38,6 +39,23 @@ public class PickupTest { assertEquals(1,one.getSize().getNuOfDimensions()); assertEquals(1,one.getSize().get(0)); } + + @Test + public void whenAddingSkills_theyShouldBeAddedCorrectly(){ + Pickup s = (Pickup) Pickup.Builder.newInstance("s").setLocationId("loc") + .addSkill("drill").addSkill("screwdriver").build(); + assertTrue(s.getRequiredSkills().contains("drill")); + assertTrue(s.requiresSkill("drill")); + assertTrue(s.requiresSkill("ScrewDriver")); + } + + @Test + public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ + Pickup s = (Pickup) Pickup.Builder.newInstance("s").setLocationId("loc") + .addSkill("DriLl").addSkill("screwDriver").build(); + assertTrue(s.getRequiredSkills().contains("drill")); + assertTrue(s.requiresSkill("drilL")); + } } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java b/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java index a556c7cc..b215408b 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java @@ -146,5 +146,22 @@ public class ServiceTest { assertEquals(1.0,s.getTimeWindow().getStart(),0.01); assertEquals(2.0,s.getTimeWindow().getEnd(),0.01); } + + @Test + public void whenAddingSkills_theyShouldBeAddedCorrectly(){ + Service s = Service.Builder.newInstance("s").setLocationId("loc") + .addSkill("drill").addSkill("screwdriver").build(); + assertTrue(s.getRequiredSkills().contains("drill")); + assertTrue(s.requiresSkill("drill")); + assertTrue(s.requiresSkill("ScrewDriver")); + } + + @Test + public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ + Service s = Service.Builder.newInstance("s").setLocationId("loc") + .addSkill("DriLl").addSkill("screwDriver").build(); + assertTrue(s.getRequiredSkills().contains("drill")); + assertTrue(s.requiresSkill("drilL")); + } } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/job/ShipmentTest.java b/jsprit-core/src/test/java/jsprit/core/problem/job/ShipmentTest.java index a314775e..5aa3d039 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/job/ShipmentTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/job/ShipmentTest.java @@ -231,4 +231,21 @@ public class ShipmentTest { assertEquals(1,one.getSize().getNuOfDimensions()); assertEquals(1,one.getSize().get(0)); } + + @Test + public void whenAddingSkills_theyShouldBeAddedCorrectly(){ + Shipment s = Shipment.Builder.newInstance("s").setPickupLocation("loc").setDeliveryLocation("delLoc") + .addSkill("drill").addSkill("screwdriver").build(); + assertTrue(s.getRequiredSkills().contains("drill")); + assertTrue(s.requiresSkill("drill")); + assertTrue(s.requiresSkill("ScrewDriver")); + } + + @Test + public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ + Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocationId("loc") + .addSkill("DriLl").addSkill("screwDriver").build(); + assertTrue(s.getRequiredSkills().contains("drill")); + assertTrue(s.requiresSkill("drilL")); + } } From d093e090ef02b1929462c857b609522353aa102f Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Sun, 29 Jun 2014 19:40:07 +0200 Subject: [PATCH 02/19] added skills to vehicle --- .../jsprit/core/problem/vehicle/Vehicle.java | 6 ++ .../core/problem/vehicle/VehicleImpl.java | 84 +++++++++++++++++-- .../core/problem/vehicle/VehicleImplTest.java | 28 +++++++ 3 files changed, 111 insertions(+), 7 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java index bb6b55a7..37c7a755 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java @@ -16,6 +16,8 @@ ******************************************************************************/ package jsprit.core.problem.vehicle; +import java.util.Set; + import jsprit.core.util.Coordinate; /** @@ -82,4 +84,8 @@ public interface Vehicle { * Returns the end-locationCoord of this vehicle. */ public abstract Coordinate getEndLocationCoordinate(); + + public abstract Set getSkills(); + + public abstract boolean hasSkill(String string); } 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 e1fe8aba..f2fff84f 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 @@ -16,6 +16,10 @@ ******************************************************************************/ package jsprit.core.problem.vehicle; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + import jsprit.core.util.Coordinate; import org.apache.log4j.Logger; @@ -74,6 +78,8 @@ public class VehicleImpl implements Vehicle { private VehicleType type = VehicleTypeImpl.Builder.newInstance("default").build(); + private Set skills = new HashSet(); + /** * Constructs the builder with the vehicleId. * @@ -227,6 +233,17 @@ public class VehicleImpl implements Vehicle { * @return vehicle builder */ public static Builder newInstance(String vehicleId){ return new Builder(vehicleId); } + + /** + * Adds skill and returns build. + * + * @param skill + * @return + */ + public Builder addSkill(String skill) { + this.skills.add(skill.toLowerCase()); + return this; + } } @@ -241,14 +258,18 @@ public class VehicleImpl implements Vehicle { return new NoVehicle(); } + public static VehicleImpl copyAndCreateVehicle(Vehicle vehicleToCopy){ + return new VehicleImpl(vehicleToCopy); + } +// + public static VehicleImpl copyAndCreateVehicleWithNewType(Vehicle vehicleToCopy, VehicleType newType){ + return new VehicleImpl(vehicleToCopy, newType); + } +// private final String id; private final VehicleType type; - private final String locationId; - - private final Coordinate coord; - private final double earliestDeparture; private final double latestArrival; @@ -262,12 +283,12 @@ public class VehicleImpl implements Vehicle { private final Coordinate startLocationCoord; private final String startLocationId; + + private final Set skills; private VehicleImpl(Builder builder){ id = builder.id; type = builder.type; - coord = builder.locationCoord; - locationId = builder.locationId; earliestDeparture = builder.earliestStart; latestArrival = builder.latestArrival; returnToDepot = builder.returnToDepot; @@ -275,6 +296,43 @@ public class VehicleImpl implements Vehicle { startLocationCoord = builder.startLocationCoord; endLocationId = builder.endLocationId; endLocationCoord = builder.endLocationCoord; + skills = builder.skills; + } + + /** + * Copy constructor. + * + * @param vehicle + */ + private VehicleImpl(Vehicle vehicle){ + id = vehicle.getId(); + type = vehicle.getType(); + startLocationId = vehicle.getStartLocationId(); + startLocationCoord = vehicle.getStartLocationCoordinate(); + endLocationId = vehicle.getEndLocationId(); + endLocationCoord = vehicle.getEndLocationCoordinate(); + earliestDeparture = vehicle.getEarliestDeparture(); + latestArrival = vehicle.getLatestArrival(); + returnToDepot = vehicle.isReturnToDepot(); + skills = vehicle.getSkills(); + } + + /** + * Copy constructor. + * + * @param vehicle + */ + private VehicleImpl(Vehicle vehicle, VehicleType newType){ + id = vehicle.getId(); + this.type = newType; + startLocationId = vehicle.getStartLocationId(); + startLocationCoord = vehicle.getStartLocationCoordinate(); + endLocationId = vehicle.getEndLocationId(); + endLocationCoord = vehicle.getEndLocationCoordinate(); + earliestDeparture = vehicle.getEarliestDeparture(); + latestArrival = vehicle.getLatestArrival(); + returnToDepot = vehicle.isReturnToDepot(); + skills = vehicle.getSkills(); } /** @@ -284,7 +342,9 @@ public class VehicleImpl implements Vehicle { */ @Override public String toString() { - return "[id="+id+"][type="+type+"][locationId="+locationId+"][coord=" + coord + "][isReturnToDepot=" + isReturnToDepot() + "]"; + return "[id="+id+"][type="+type+"][startLocationId="+startLocationId+"][startLocationCoord=" + startLocationCoord + "]" + + "[endLocationId="+endLocationId+"][endLocationCoord=" + endLocationCoord + "]" + + "[isReturnToDepot=" + isReturnToDepot() + "]"; } @Override @@ -368,6 +428,16 @@ public class VehicleImpl implements Vehicle { return true; } + @Override + public Set getSkills() { + return Collections.unmodifiableSet(skills); + } + + @Override + public boolean hasSkill(String skill) { + return skills.contains(skill.toLowerCase()); + } + diff --git a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java index 98c05fd3..3564c77a 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java @@ -187,5 +187,33 @@ public class VehicleImplTest { assertTrue(!v.equals(v2)); } + @Test + public void whenAddingSkills_theyShouldBeAddedCorrectly(){ + VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); + Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocationId("start").setType(type1).setEndLocationId("start") + .addSkill("drill").addSkill("screwdriver").build(); + assertTrue(v.getSkills().contains("drill")); + assertTrue(v.hasSkill("drill")); + assertTrue(v.hasSkill("screwdriver")); + } + + @Test + public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ + VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); + Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocationId("start").setType(type1).setEndLocationId("start") + .addSkill("drill").addSkill("screwdriver").build(); + assertTrue(v.getSkills().contains("drill")); + assertTrue(v.hasSkill("dRill")); + assertTrue(v.hasSkill("ScrewDriver")); + } + + @Test + public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly(){ + VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); + Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocationId("start").setType(type1).setEndLocationId("start") + .addSkill("drill").build(); + assertFalse(v.hasSkill("ScrewDriver")); + } + } From 415cb597fe971e126df0ddada6224e55d5b3ad20 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Sun, 29 Jun 2014 19:40:47 +0200 Subject: [PATCH 03/19] replaced penVehicle creation by copy constructor of vehicle --- .../jsprit/core/problem/VehicleRoutingProblem.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 edeaaacf..130c47b4 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/VehicleRoutingProblem.java @@ -353,12 +353,12 @@ public class VehicleRoutingProblem { .setCapacityDimensions(v.getType().getCapacityDimensions()) .build(); PenaltyVehicleType penType = new PenaltyVehicleType(t,penaltyFactor); - String vehicleId = v.getId(); -// String vehicleId = "penaltyVehicle_" + new VehicleTypeKey(v.getType().getTypeId(),v.getStartLocationId(),v.getEndLocationId(),v.getEarliestDeparture(),v.getLatestArrival()).toString(); - Vehicle 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(); + Vehicle penVehicle = VehicleImpl.copyAndCreateVehicleWithNewType(v, penType); +// String vehicleId = v.getId(); +// Vehicle 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(); addVehicle(penVehicle); } } From ed913010398163bcb9dd0ade827a5f64b68592f3 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Tue, 1 Jul 2014 23:07:46 +0200 Subject: [PATCH 04/19] added new method update(VehicleRoute) --- .../core/algorithm/state/StateManager.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java b/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java index a8a15e2f..9fb4444f 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java @@ -31,6 +31,7 @@ import jsprit.core.algorithm.recreate.listener.JobInsertedListener; import jsprit.core.algorithm.ruin.listener.RuinListener; import jsprit.core.algorithm.ruin.listener.RuinListeners; import jsprit.core.problem.Capacity; +import jsprit.core.problem.Skills; import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.cost.VehicleRoutingTransportCosts; import jsprit.core.problem.job.Job; @@ -66,10 +67,7 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart } public T getState(StateId id, Class type){ - if(states.containsKey(id)){ - T s = type.cast(states.get(id)); - return s; - } + if(states.containsKey(id)) return type.cast(states.get(id)); return null; } @@ -121,7 +119,7 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart defaultActivityStates_.put(StateFactory.PAST_MAXLOAD, Capacity.Builder.newInstance().build()); defaultRouteStates_.put(StateFactory.LOAD, Capacity.Builder.newInstance().build()); - + defaultRouteStates_.put(StateFactory.SKILLS, Skills.Builder.newInstance().build()); defaultRouteStates_.put(StateFactory.COSTS, 0.); defaultRouteStates_.put(StateFactory.DURATION, 0.); defaultRouteStates_.put(StateFactory.FUTURE_MAXLOAD, Capacity.Builder.newInstance().build()); @@ -300,7 +298,7 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart *

you can retrieve the duration of myRoute then by
* double totalRouteDuration = stateManager.getRouteState(myRoute, StateFactory.createStateId("route-duration"), Double.class); * - * @param act + * @param route * @param stateId * @param type * @param state @@ -353,7 +351,7 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart *

This reverseVisitor visits all activities in a route subsequently (starting from the end of the route) in two cases. First, if insertionStart (after ruinStrategies have removed activities from routes) * and, second, if a job has been inserted and thus if a route has changed. * - * @param reverseActivityVistor + * @param activityVistor */ void addActivityVisitor(ReverseActivityVisitor activityVistor){ revRouteActivityVisitor.addActivityVisitor(activityVistor); @@ -384,18 +382,20 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { // log.debug("insert " + job2insert + " in " + inRoute); insertionListeners.informJobInserted(job2insert, inRoute, additionalCosts, additionalTime); - for(RouteVisitor v : routeVisitors){ v.visit(inRoute); } - routeActivityVisitor.visit(inRoute); - revRouteActivityVisitor.visit(inRoute); + update(inRoute); } - @Override + public void update(VehicleRoute inRoute) { + for(RouteVisitor v : routeVisitors){ v.visit(inRoute); } + routeActivityVisitor.visit(inRoute); + revRouteActivityVisitor.visit(inRoute); + } + + @Override public void informInsertionStarts(Collection vehicleRoutes,Collection unassignedJobs) { insertionListeners.informInsertionStarts(vehicleRoutes, unassignedJobs); - for(VehicleRoute route : vehicleRoutes){ - for(RouteVisitor v : routeVisitors){ v.visit(route); } - routeActivityVisitor.visit(route); - revRouteActivityVisitor.visit(route); + for(VehicleRoute route : vehicleRoutes){ + update(route); } } From 22265c16d8c98409063a23203c9888bf1a4438dc Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Tue, 1 Jul 2014 23:08:47 +0200 Subject: [PATCH 05/19] created SkillUpdater --- .../core/algorithm/state/UpdateSkills.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateSkills.java diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateSkills.java b/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateSkills.java new file mode 100644 index 00000000..f49a3d92 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/state/UpdateSkills.java @@ -0,0 +1,43 @@ +package jsprit.core.algorithm.state; + +import jsprit.core.problem.Skills; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.solution.route.activity.ActivityVisitor; +import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.solution.route.state.StateFactory; + +/** + * Created by schroeder on 01.07.14. + */ +public class UpdateSkills implements StateUpdater, ActivityVisitor{ + + private Skills.Builder skillBuilder; + + private StateManager statesManager; + + private VehicleRoute route; + + public UpdateSkills(StateManager statesManager) { + this.statesManager = statesManager; + } + + @Override + public void begin(VehicleRoute route) { + this.route = route; + skillBuilder = Skills.Builder.newInstance(); + } + + @Override + public void visit(TourActivity activity) { + if(activity instanceof TourActivity.JobActivity){ + Skills skills = ((TourActivity.JobActivity) activity).getJob().getRequiredSkills(); + skillBuilder.addAllSkills(skills.values()); + } + } + + @Override + public void finish() { + Skills skills = skillBuilder.build(); + statesManager.putTypedInternalRouteState(route, StateFactory.SKILLS, Skills.class, skills); + } +} From e99392572d07276eaba90a88b959045f266c7948 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Tue, 1 Jul 2014 23:09:47 +0200 Subject: [PATCH 06/19] added .getSkills() to jobs --- .../java/jsprit/core/problem/job/Job.java | 8 +++++++ .../java/jsprit/core/problem/job/Service.java | 24 +++++++------------ .../jsprit/core/problem/job/Shipment.java | 20 +++++++--------- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/problem/job/Job.java b/jsprit-core/src/main/java/jsprit/core/problem/job/Job.java index 0d27c0b5..22419b05 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/job/Job.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/job/Job.java @@ -18,6 +18,7 @@ package jsprit.core.problem.job; import jsprit.core.problem.Capacity; +import jsprit.core.problem.Skills; /** * Basic interface for all jobs. @@ -40,5 +41,12 @@ public interface Job { * @return Capacity */ public Capacity getSize(); + + /** + * Returns required skills. + * + * @return + */ + public Skills getRequiredSkills(); } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java b/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java index f4594ca5..87ad0a78 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/job/Service.java @@ -21,6 +21,7 @@ import java.util.HashSet; import java.util.Set; import jsprit.core.problem.Capacity; +import jsprit.core.problem.Skills; import jsprit.core.problem.solution.route.activity.TimeWindow; import jsprit.core.util.Coordinate; @@ -71,7 +72,7 @@ public class Service implements Job { protected Capacity capacity; - protected Set skills = new HashSet(); + protected Skills.Builder skillBuilder = Skills.Builder.newInstance(); /** * Constructs the builder. @@ -187,7 +188,7 @@ public class Service implements Job { } public Builder addSkill(String string) { - skills.add(string.toLowerCase()); + skillBuilder.addSkill(string); return this; } @@ -208,7 +209,7 @@ public class Service implements Job { private final Capacity size; - private final Set skills; + private final Skills skills; Service(Builder builder){ id = builder.id; @@ -218,7 +219,7 @@ public class Service implements Job { timeWindow = builder.timeWindow; type = builder.type; size = builder.capacity; - skills = builder.skills; + skills = builder.skillBuilder.build(); } @Override @@ -319,18 +320,9 @@ public class Service implements Job { * * @return */ - public Set getRequiredSkills() { - return Collections.unmodifiableSet(skills); - } - - /** - * Returns true if this contains requiredSkill. Not case sensitive. - * - * @param requiredSkill - * @return - */ - public boolean requiresSkill(String requiredSkill){ - return skills.contains(requiredSkill.toLowerCase()); + public Skills getRequiredSkills() { + return skills; } + } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/job/Shipment.java b/jsprit-core/src/main/java/jsprit/core/problem/job/Shipment.java index 0c94f6e8..3f3bd3c3 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/job/Shipment.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/job/Shipment.java @@ -5,6 +5,7 @@ import java.util.HashSet; import java.util.Set; import jsprit.core.problem.Capacity; +import jsprit.core.problem.Skills; import jsprit.core.problem.solution.route.activity.TimeWindow; import jsprit.core.util.Coordinate; @@ -57,7 +58,7 @@ public class Shipment implements Job{ private Capacity capacity; - private Set skills = new HashSet(); + private Skills.Builder skillBuilder = Skills.Builder.newInstance(); /** * Returns new instance of this builder. @@ -236,8 +237,8 @@ public class Shipment implements Job{ return new Shipment(this); } - public Builder addSkill(String string) { - skills.add(string.toLowerCase()); + public Builder addSkill(String skill) { + skillBuilder.addSkill(skill); return this; } @@ -264,7 +265,7 @@ public class Shipment implements Job{ private final Capacity capacity; - private final Set skills; + private final Skills skills; /** @@ -283,7 +284,7 @@ public class Shipment implements Job{ this.deliveryServiceTime = builder.deliveryServiceTime; this.deliveryTimeWindow = builder.deliveryTimeWindow; this.capacity = builder.capacity; - this.skills = builder.skills; + this.skills = builder.skillBuilder.build(); } @Override @@ -400,11 +401,8 @@ public class Shipment implements Job{ return capacity; } - public Set getRequiredSkills() { - return Collections.unmodifiableSet(skills); - } - - public boolean requiresSkill(String requiredSkill){ - return skills.contains(requiredSkill.toLowerCase()); + public Skills getRequiredSkills() { + return skills; } + } From b12b305c7136792db285c506c50f2180c0f67646 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Tue, 1 Jul 2014 23:10:40 +0200 Subject: [PATCH 07/19] added new internal StateId SKILLS --- .../core/problem/solution/route/state/StateFactory.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java index 5b591e12..e5945cb7 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java @@ -27,9 +27,8 @@ import java.util.Map; public class StateFactory { - - - public interface StateId { + + public interface StateId { } @@ -77,6 +76,8 @@ public class StateFactory { } } + + public static final StateId SKILLS = new StateIdImpl("skills"); public final static StateId MAXLOAD = new StateIdImpl("maxload"); From 0392d9106db3d1515f000910ce3c18352afb2a81 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Tue, 1 Jul 2014 23:11:22 +0200 Subject: [PATCH 08/19] added skills --- .../jsprit/core/problem/vehicle/Vehicle.java | 9 ++- .../core/problem/vehicle/VehicleImpl.java | 25 +++----- .../state/UpdateRequiredSkillsTest.java | 62 +++++++++++++++++++ .../java/jsprit/core/problem/SkillsTest.java | 39 ++++++++++++ .../jsprit/core/problem/job/DeliveryTest.java | 18 ++++-- .../jsprit/core/problem/job/PickupTest.java | 19 ++++-- .../jsprit/core/problem/job/ServiceTest.java | 27 ++++---- .../jsprit/core/problem/job/ShipmentTest.java | 23 ++++--- .../core/problem/vehicle/VehicleImplTest.java | 14 ++--- 9 files changed, 182 insertions(+), 54 deletions(-) create mode 100644 jsprit-core/src/test/java/jsprit/core/algorithm/state/UpdateRequiredSkillsTest.java create mode 100644 jsprit-core/src/test/java/jsprit/core/problem/SkillsTest.java diff --git a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java index 37c7a755..c7c40a91 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/vehicle/Vehicle.java @@ -18,6 +18,7 @@ package jsprit.core.problem.vehicle; import java.util.Set; +import jsprit.core.problem.Skills; import jsprit.core.util.Coordinate; /** @@ -85,7 +86,11 @@ public interface Vehicle { */ public abstract Coordinate getEndLocationCoordinate(); - public abstract Set getSkills(); + /** + * Returns skills. + * + * @return + */ + public abstract Skills getSkills(); - public abstract boolean hasSkill(String string); } 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 f2fff84f..b2edec3e 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 @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; +import jsprit.core.problem.Skills; import jsprit.core.util.Coordinate; import org.apache.log4j.Logger; @@ -77,8 +78,8 @@ public class VehicleImpl implements Vehicle { private boolean returnToDepot = true; private VehicleType type = VehicleTypeImpl.Builder.newInstance("default").build(); - - private Set skills = new HashSet(); + + private Skills.Builder skillBuilder = Skills.Builder.newInstance(); /** * Constructs the builder with the vehicleId. @@ -235,13 +236,13 @@ public class VehicleImpl implements Vehicle { public static Builder newInstance(String vehicleId){ return new Builder(vehicleId); } /** - * Adds skill and returns build. + * Adds skill and returns builder. * * @param skill * @return */ public Builder addSkill(String skill) { - this.skills.add(skill.toLowerCase()); + skillBuilder.addSkill(skill); return this; } @@ -284,7 +285,7 @@ public class VehicleImpl implements Vehicle { private final String startLocationId; - private final Set skills; + private final Skills skills; private VehicleImpl(Builder builder){ id = builder.id; @@ -296,7 +297,7 @@ public class VehicleImpl implements Vehicle { startLocationCoord = builder.startLocationCoord; endLocationId = builder.endLocationId; endLocationCoord = builder.endLocationCoord; - skills = builder.skills; + skills = builder.skillBuilder.build(); } /** @@ -429,16 +430,8 @@ public class VehicleImpl implements Vehicle { } @Override - public Set getSkills() { - return Collections.unmodifiableSet(skills); + public Skills getSkills() { + return skills; } - @Override - public boolean hasSkill(String skill) { - return skills.contains(skill.toLowerCase()); - } - - - - } diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/state/UpdateRequiredSkillsTest.java b/jsprit-core/src/test/java/jsprit/core/algorithm/state/UpdateRequiredSkillsTest.java new file mode 100644 index 00000000..d018be5a --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/algorithm/state/UpdateRequiredSkillsTest.java @@ -0,0 +1,62 @@ +package jsprit.core.algorithm.state; + +import jsprit.core.problem.Skills; +import jsprit.core.problem.cost.VehicleRoutingTransportCosts; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.solution.route.state.StateFactory; +import jsprit.core.problem.vehicle.Vehicle; +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Created by schroeder on 01.07.14. + */ +public class UpdateRequiredSkillsTest { + + private VehicleRoute route; + + private StateManager stateManager; + + @Before + public void doBefore(){ + Vehicle vehicle = mock(Vehicle.class); + Service service = mock(Service.class); + Service service2 = mock(Service.class); + Service service3 = mock(Service.class); + when(service.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill1").build()); + when(service2.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill1").addSkill("skill2") + .addSkill("skill3").build()); + when(service3.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill4") + .addSkill("skill5").build()); + route = VehicleRoute.Builder.newInstance(vehicle).addService(service).addService(service2).addService(service3).build(); + stateManager = new StateManager(mock(VehicleRoutingTransportCosts.class)); + stateManager.addStateUpdater(new UpdateSkills(stateManager)); + } + + @Test + public void whenUpdatingRoute_skillsAtRouteLevelShouldContainAllSkills(){ + stateManager.update(route); + Skills skills = stateManager.getRouteState(route, StateFactory.SKILLS, Skills.class); + assertNotNull(skills); + Assert.assertEquals(5,skills.values().size()); + assertTrue(skills.containsSkill("skill1")); + assertTrue(skills.containsSkill("skill2")); + assertTrue(skills.containsSkill("skill3")); + assertTrue(skills.containsSkill("skill4")); + assertTrue(skills.containsSkill("skill5")); + } + + +} diff --git a/jsprit-core/src/test/java/jsprit/core/problem/SkillsTest.java b/jsprit-core/src/test/java/jsprit/core/problem/SkillsTest.java new file mode 100644 index 00000000..38628a8f --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/problem/SkillsTest.java @@ -0,0 +1,39 @@ +package jsprit.core.problem; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertTrue; + +/** + * Created by schroeder on 01.07.14. + */ +public class SkillsTest { + + @Test + public void whenSkillsAdded_theyShouldBeinSkillSet(){ + Skills skills = Skills.Builder.newInstance().addSkill("skill1").addSkill("skill2").build(); + assertTrue(skills.containsSkill("skill1")); + assertTrue(skills.containsSkill("skill2")); + } + + @Test + public void whenSkillsAddedCaseInsensitive_theyShouldBeinSkillSet(){ + Skills skills = Skills.Builder.newInstance().addSkill("skill1").addSkill("skill2").build(); + assertTrue(skills.containsSkill("skilL1")); + assertTrue(skills.containsSkill("skIll2")); + } + + @Test + public void whenSkillsAddedThroughAddAll_theyShouldBeinSkillSet(){ + Set skillSet = new HashSet(); + skillSet.add("skill1"); + skillSet.add("skill2"); + Skills skills = Skills.Builder.newInstance().addAllSkills(skillSet).build(); + assertTrue(skills.containsSkill("skill1")); + assertTrue(skills.containsSkill("skill2")); + } + +} diff --git a/jsprit-core/src/test/java/jsprit/core/problem/job/DeliveryTest.java b/jsprit-core/src/test/java/jsprit/core/problem/job/DeliveryTest.java index 6855e992..adb920d1 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/job/DeliveryTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/job/DeliveryTest.java @@ -1,6 +1,7 @@ package jsprit.core.problem.job; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -44,18 +45,25 @@ public class DeliveryTest { public void whenAddingSkills_theyShouldBeAddedCorrectly(){ Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocationId("loc") .addSkill("drill").addSkill("screwdriver").build(); - assertTrue(s.getRequiredSkills().contains("drill")); - assertTrue(s.requiresSkill("drill")); - assertTrue(s.requiresSkill("ScrewDriver")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver")); } @Test public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocationId("loc") .addSkill("DriLl").addSkill("screwDriver").build(); - assertTrue(s.getRequiredSkills().contains("drill")); - assertTrue(s.requiresSkill("drilL")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("drilL")); } + @Test + public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly(){ + Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocationId("loc") + .addSkill("screwDriver").build(); + assertFalse(s.getRequiredSkills().containsSkill("drill")); + assertFalse(s.getRequiredSkills().containsSkill("drilL")); + } + } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/job/PickupTest.java b/jsprit-core/src/test/java/jsprit/core/problem/job/PickupTest.java index 5987c4f1..ae76970c 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/job/PickupTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/job/PickupTest.java @@ -1,6 +1,7 @@ package jsprit.core.problem.job; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -44,18 +45,26 @@ public class PickupTest { public void whenAddingSkills_theyShouldBeAddedCorrectly(){ Pickup s = (Pickup) Pickup.Builder.newInstance("s").setLocationId("loc") .addSkill("drill").addSkill("screwdriver").build(); - assertTrue(s.getRequiredSkills().contains("drill")); - assertTrue(s.requiresSkill("drill")); - assertTrue(s.requiresSkill("ScrewDriver")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver")); } @Test public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ Pickup s = (Pickup) Pickup.Builder.newInstance("s").setLocationId("loc") .addSkill("DriLl").addSkill("screwDriver").build(); - assertTrue(s.getRequiredSkills().contains("drill")); - assertTrue(s.requiresSkill("drilL")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("drilL")); } + @Test + public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly(){ + Pickup s = (Pickup) Pickup.Builder.newInstance("s").setLocationId("loc") + .addSkill("screwDriver").build(); + assertFalse(s.getRequiredSkills().containsSkill("drill")); + assertFalse(s.getRequiredSkills().containsSkill("drilL")); + } + } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java b/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java index b215408b..2a71d9c3 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/job/ServiceTest.java @@ -16,12 +16,6 @@ ******************************************************************************/ package jsprit.core.problem.job; -import static org.junit.Assert.assertEquals; - -import static org.junit.Assert.assertNotNull; - -import static org.junit.Assert.assertTrue; - import java.util.HashSet; import java.util.Set; @@ -30,6 +24,9 @@ import jsprit.core.util.Coordinate; import org.junit.Test; +import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; + public class ServiceTest { @Test @@ -151,17 +148,25 @@ public class ServiceTest { public void whenAddingSkills_theyShouldBeAddedCorrectly(){ Service s = Service.Builder.newInstance("s").setLocationId("loc") .addSkill("drill").addSkill("screwdriver").build(); - assertTrue(s.getRequiredSkills().contains("drill")); - assertTrue(s.requiresSkill("drill")); - assertTrue(s.requiresSkill("ScrewDriver")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver")); } @Test public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ Service s = Service.Builder.newInstance("s").setLocationId("loc") .addSkill("DriLl").addSkill("screwDriver").build(); - assertTrue(s.getRequiredSkills().contains("drill")); - assertTrue(s.requiresSkill("drilL")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("drilL")); } + @Test + public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly(){ + Service s = Service.Builder.newInstance("s").setLocationId("loc") + .addSkill("screwDriver").build(); + assertFalse(s.getRequiredSkills().containsSkill("drill")); + assertFalse(s.getRequiredSkills().containsSkill("drilL")); + } + } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/job/ShipmentTest.java b/jsprit-core/src/test/java/jsprit/core/problem/job/ShipmentTest.java index 5aa3d039..79bda2a3 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/job/ShipmentTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/job/ShipmentTest.java @@ -1,13 +1,12 @@ package jsprit.core.problem.job; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import jsprit.core.problem.solution.route.activity.TimeWindow; import jsprit.core.util.Coordinate; import org.junit.Test; +import static org.junit.Assert.*; + public class ShipmentTest { @Test @@ -236,16 +235,24 @@ public class ShipmentTest { public void whenAddingSkills_theyShouldBeAddedCorrectly(){ Shipment s = Shipment.Builder.newInstance("s").setPickupLocation("loc").setDeliveryLocation("delLoc") .addSkill("drill").addSkill("screwdriver").build(); - assertTrue(s.getRequiredSkills().contains("drill")); - assertTrue(s.requiresSkill("drill")); - assertTrue(s.requiresSkill("ScrewDriver")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver")); } @Test public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocationId("loc") .addSkill("DriLl").addSkill("screwDriver").build(); - assertTrue(s.getRequiredSkills().contains("drill")); - assertTrue(s.requiresSkill("drilL")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("drilL")); } + + @Test + public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly(){ + Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocationId("loc") + .addSkill("screwDriver").build(); + assertFalse(s.getRequiredSkills().containsSkill("drill")); + assertFalse(s.getRequiredSkills().containsSkill("drilL")); + } } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java index 3564c77a..df3dfafd 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/vehicle/VehicleImplTest.java @@ -192,9 +192,9 @@ public class VehicleImplTest { VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocationId("start").setType(type1).setEndLocationId("start") .addSkill("drill").addSkill("screwdriver").build(); - assertTrue(v.getSkills().contains("drill")); - assertTrue(v.hasSkill("drill")); - assertTrue(v.hasSkill("screwdriver")); + assertTrue(v.getSkills().containsSkill("drill")); + assertTrue(v.getSkills().containsSkill("drill")); + assertTrue(v.getSkills().containsSkill("screwdriver")); } @Test @@ -202,9 +202,9 @@ public class VehicleImplTest { VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocationId("start").setType(type1).setEndLocationId("start") .addSkill("drill").addSkill("screwdriver").build(); - assertTrue(v.getSkills().contains("drill")); - assertTrue(v.hasSkill("dRill")); - assertTrue(v.hasSkill("ScrewDriver")); + assertTrue(v.getSkills().containsSkill("drill")); + assertTrue(v.getSkills().containsSkill("dRill")); + assertTrue(v.getSkills().containsSkill("ScrewDriver")); } @Test @@ -212,7 +212,7 @@ public class VehicleImplTest { VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocationId("start").setType(type1).setEndLocationId("start") .addSkill("drill").build(); - assertFalse(v.hasSkill("ScrewDriver")); + assertFalse(v.getSkills().containsSkill("ScrewDriver")); } From c5617602989f71d152b039d8c7d9ac9f7c16f826 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Tue, 1 Jul 2014 23:12:35 +0200 Subject: [PATCH 09/19] created new Skills obj --- .../main/java/jsprit/core/problem/Skills.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 jsprit-core/src/main/java/jsprit/core/problem/Skills.java diff --git a/jsprit-core/src/main/java/jsprit/core/problem/Skills.java b/jsprit-core/src/main/java/jsprit/core/problem/Skills.java new file mode 100644 index 00000000..63aacf8d --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/problem/Skills.java @@ -0,0 +1,76 @@ +package jsprit.core.problem; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Created by schroeder on 01.07.14. + */ +public class Skills { + + public static class Builder { + + /** + * Returns new instance of skill-builder. + * + * @return + */ + public static Builder newInstance(){ + return new Builder(); + } + + private Set skills = new HashSet(); + + /** + * Adds skill. Skill is transformed into lowerCase. + * + * @param skill + * @return + */ + public Builder addSkill(String skill){ + skills.add(skill.toLowerCase()); + return this; + } + + public Builder addAllSkills(Collection skills){ + for(String skill : skills) this.skills.add(skill); + return this; + } + + public Skills build(){ + return new Skills(this); + } + + } + + private Set skills = new HashSet(); + + private Skills(Builder builder){ + skills.addAll(builder.skills); + } + + /** + * Returns an unmodifiable set of skills. All skills are inLowerCase. + * + * @return + */ + public Set values(){ + return Collections.unmodifiableSet(skills); + } + + /** + * Not case sensitive. + * + * @param skill + * @return + */ + public boolean containsSkill(String skill){ + return skills.contains(skill.toLowerCase()); + } + + + + +} From c7c42b54a0e054674f165d0b437de8d1d37da6cc Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Tue, 1 Jul 2014 23:13:18 +0200 Subject: [PATCH 10/19] changed javadoc --- jsprit-core/src/main/java/jsprit/core/problem/Capacity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsprit-core/src/main/java/jsprit/core/problem/Capacity.java b/jsprit-core/src/main/java/jsprit/core/problem/Capacity.java index 6bdd2e35..f52fbdac 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/Capacity.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/Capacity.java @@ -53,7 +53,7 @@ public class Capacity { /** * Returns the inverted capacity, i.e. it multiplies all capacity dimensions with -1. * - * @param cap + * @param cap2invert * @return inverted capacity * @throws NullPointerException if one of the args is null */ From eca766cc5242bd6978a67b7b44a00aa4e4390ce0 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Tue, 1 Jul 2014 23:20:16 +0200 Subject: [PATCH 11/19] added skills to reservedIds --- .../jsprit/core/problem/solution/route/state/StateFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java index e5945cb7..33ac169e 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java @@ -100,7 +100,7 @@ public class StateFactory { public final static StateId PAST_MAXLOAD = new StateIdImpl("pastMaxload"); final static List reservedIds = Arrays.asList("maxload","load","costs","loadAtBeginning","loadAtEnd","duration","latestOST","earliestOST" - ,"futureMaxload","pastMaxload"); + ,"futureMaxload","pastMaxload","skills"); public static States createStates(){ From b48e2c404d99a3484a17214908043bf3f0fc2d97 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Wed, 2 Jul 2014 08:55:55 +0200 Subject: [PATCH 12/19] simplified if statement core.problem.solution.route.state.StateFactory --- .../core/problem/solution/route/state/StateFactory.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java index 33ac169e..0bd3234d 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/solution/route/state/StateFactory.java @@ -117,13 +117,11 @@ public class StateFactory { } public static boolean isReservedId(String stateId){ - if(reservedIds.contains(stateId)) return true; - return false; + return reservedIds.contains(stateId); } public static boolean isReservedId(StateId stateId){ - if(reservedIds.contains(stateId.toString())) return true; - return false; + return reservedIds.contains(stateId.toString()); } public static void throwReservedIdException(String name) { From 0637bdb4b6182e3b6146eedfdea8cc8b4aafe8f5 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Wed, 2 Jul 2014 23:43:35 +0200 Subject: [PATCH 13/19] added SkillConstraint --- .../problem/constraint/SkillConstraint.java | 36 ++++++ .../constraint/SkillConstraintTest.java | 107 ++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 jsprit-core/src/main/java/jsprit/core/problem/constraint/SkillConstraint.java create mode 100644 jsprit-core/src/test/java/jsprit/core/problem/constraint/SkillConstraintTest.java diff --git a/jsprit-core/src/main/java/jsprit/core/problem/constraint/SkillConstraint.java b/jsprit-core/src/main/java/jsprit/core/problem/constraint/SkillConstraint.java new file mode 100644 index 00000000..9459e350 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/problem/constraint/SkillConstraint.java @@ -0,0 +1,36 @@ +package jsprit.core.problem.constraint; + +import jsprit.core.problem.Skills; +import jsprit.core.problem.misc.JobInsertionContext; +import jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; +import jsprit.core.problem.solution.route.state.StateFactory; + +/** + * SkillConstraint that ensures that only vehicles with according skills can serve route and job to be inserted. + * + */ +public class SkillConstraint implements HardRouteStateLevelConstraint{ + + private RouteAndActivityStateGetter states; + + public SkillConstraint(RouteAndActivityStateGetter states) { + this.states = states; + } + + @Override + public boolean fulfilled(JobInsertionContext insertionContext) { + for(String skill : insertionContext.getJob().getRequiredSkills().values()){ + if(!insertionContext.getRoute().getVehicle().getSkills().containsSkill(skill)){ + return false; + } + } + Skills requiredSkillsForRoute = states.getRouteState(insertionContext.getRoute(), StateFactory.SKILLS, Skills.class); + for(String skill : requiredSkillsForRoute.values()){ + if(!insertionContext.getRoute().getVehicle().getSkills().containsSkill(skill)){ + return false; + } + } + return true; + } + +} diff --git a/jsprit-core/src/test/java/jsprit/core/problem/constraint/SkillConstraintTest.java b/jsprit-core/src/test/java/jsprit/core/problem/constraint/SkillConstraintTest.java new file mode 100644 index 00000000..8dd07676 --- /dev/null +++ b/jsprit-core/src/test/java/jsprit/core/problem/constraint/SkillConstraintTest.java @@ -0,0 +1,107 @@ +package jsprit.core.problem.constraint; + +import jsprit.core.algorithm.state.StateManager; +import jsprit.core.algorithm.state.UpdateSkills; +import jsprit.core.problem.Skills; +import jsprit.core.problem.cost.VehicleRoutingTransportCosts; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.misc.JobInsertionContext; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.vehicle.Vehicle; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +public class SkillConstraintTest { + + private HardRouteStateLevelConstraint skillConstraint; + + private StateManager stateManager; + + private VehicleRoute route; + + private Vehicle vehicle; + + @Before + public void doBefore(){ + vehicle = mock(Vehicle.class); + Service service = mock(Service.class); + Service service2 = mock(Service.class); + Service service3 = mock(Service.class); + when(service.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill1").build()); + when(service2.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill1").addSkill("skill2") + .addSkill("skill3").build()); + when(service3.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill4") + .addSkill("skill5").build()); + route = VehicleRoute.Builder.newInstance(vehicle).addService(service).addService(service2).addService(service3).build(); + stateManager = new StateManager(mock(VehicleRoutingTransportCosts.class)); + stateManager.addStateUpdater(new UpdateSkills(stateManager)); + stateManager.update(route); + skillConstraint = new SkillConstraint(stateManager); + } + + @Test + public void whenJobToBeInsertedRequiresSkillsThatVehicleDoesNotHave_itShouldReturnFalse(){ + Service s4 = mock(Service.class); + when(s4.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill5").build()); + when(vehicle.getSkills()).thenReturn(Skills.Builder.newInstance() + .addAllSkills(Arrays.asList("skill1","skill2","skill3","skill4")).build()); + JobInsertionContext insertionContext = new JobInsertionContext(route,s4,vehicle,route.getDriver(),0.); + assertFalse(skillConstraint.fulfilled(insertionContext)); + } + + @Test + public void whenJobToBeInsertedRequiresSkillsThatVehicleHave_itShouldReturnTrue(){ + Service s4 = mock(Service.class); + when(s4.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill4").build()); + when(vehicle.getSkills()).thenReturn(Skills.Builder.newInstance() + .addAllSkills(Arrays.asList("skill1","skill2","skill3","skill4","skill5")).build()); + JobInsertionContext insertionContext = new JobInsertionContext(route,s4,vehicle,route.getDriver(),0.); + assertTrue(skillConstraint.fulfilled(insertionContext)); + } + + @Test + public void whenRouteToBeOvertakenRequiresSkillsThatVehicleDoesNotHave_itShouldReturnFalse(){ + Service s4 = mock(Service.class); + when(s4.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill4").build()); + when(vehicle.getSkills()).thenReturn(Skills.Builder.newInstance() + .addAllSkills(Arrays.asList("skill1","skill2","skill6","skill4")).build()); + JobInsertionContext insertionContext = new JobInsertionContext(route,s4,vehicle,route.getDriver(),0.); + assertFalse(skillConstraint.fulfilled(insertionContext)); + } + + @Test + public void whenRouteToBeOvertakenRequiresSkillsThatVehicleDoesHave_itShouldReturnTrue(){ + Service s4 = mock(Service.class); + when(s4.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill4").build()); + when(vehicle.getSkills()).thenReturn(Skills.Builder.newInstance() + .addAllSkills(Arrays.asList("skill1","skill2","skill3","skill4","skill5")).build()); + JobInsertionContext insertionContext = new JobInsertionContext(route,s4,vehicle,route.getDriver(),0.); + assertTrue(skillConstraint.fulfilled(insertionContext)); + } + + @Test + public void whenNoSkillsAreRequired_itShouldReturnTrue(){ + Service s4 = mock(Service.class); + when(s4.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().build()); + when(vehicle.getSkills()).thenReturn(Skills.Builder.newInstance().build()); + JobInsertionContext insertionContext = new JobInsertionContext(VehicleRoute.emptyRoute(),s4,vehicle,route.getDriver(),0.); + assertTrue(skillConstraint.fulfilled(insertionContext)); + } + + @Test + public void whenSkillsIsRequiredWhichVehicleDoesNotHave_itShouldReturnFalse(){ + Service s4 = mock(Service.class); + when(s4.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill1").build()); + when(vehicle.getSkills()).thenReturn(Skills.Builder.newInstance().build()); + JobInsertionContext insertionContext = new JobInsertionContext(VehicleRoute.emptyRoute(),s4,vehicle,route.getDriver(),0.); + assertFalse(skillConstraint.fulfilled(insertionContext)); + } +} From 83e142faa5216b9b040e30d4c75bbf2f4c15eb19 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Wed, 2 Jul 2014 23:56:39 +0200 Subject: [PATCH 14/19] removed warnings and added .updateSkills --- .../core/algorithm/state/StateManager.java | 55 +++++++++++-------- .../problem/constraint/ConstraintManager.java | 11 +++- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java b/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java index 9fb4444f..a57bcc2b 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java @@ -57,8 +57,8 @@ import jsprit.core.problem.solution.route.state.StateFactory.StateId; * */ public class StateManager implements RouteAndActivityStateGetter, IterationStartsListener, RuinListener, InsertionStartsListener, JobInsertedListener, InsertionEndsListener { - - static class States_ { + + static class States_ { private Map states = new HashMap(); @@ -110,6 +110,8 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart private boolean updateLoad = false; private boolean updateTWs = false; + + private boolean updateSkills = false; private void addDefaultStates() { defaultActivityStates_.put(StateFactory.LOAD, Capacity.Builder.newInstance().build()); @@ -164,9 +166,9 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart * can add the default simply by coding
* addDefaultRouteState(StateFactory.createStateId("max_weight"), Integer.class, 0) * - * @param stateId - * @param type - * @param defaultState + * @param stateId id of state + * @param type type of memorized state + * @param defaultState actual state */ public void addDefaultRouteState(StateId stateId, Class type, T defaultState){ if(StateFactory.isReservedId(stateId)) StateFactory.throwReservedIdException(stateId.toString()); @@ -175,10 +177,10 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart /** * Generic method to add default activity state. - * - * @param stateId - * @param type - * @param defaultState + * + * @param stateId id of state + * @param type type of memorized state + * @param defaultState actual state */ public void addDefaultActivityState(StateId stateId, Class type, T defaultState){ if(StateFactory.isReservedId(stateId)) StateFactory.throwReservedIdException(stateId.toString()); @@ -211,11 +213,12 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart } /** - * - * @param act - * @param stateId - * @param type - * @return + * + * @param act tour activity + * @param stateId id of state + * @param type of actual state + * + * @return state */ private T getDefaultTypedActivityState(TourActivity act, StateId stateId,Class type) { if(defaultActivityStates_.containsKey(stateId)){ @@ -263,10 +266,10 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart *

you can retrieve the load at myActivity by
* Capacity load = stateManager.getActivityState(myActivity, StateFactory.createStateId("act-load"), Capacity.class); * - * @param act - * @param stateId - * @param type - * @param state + * @param act tour activity + * @param stateId stateId of state to be memorized + * @param type type of state + * @param state acutall state */ public void putTypedActivityState(TourActivity act, StateId stateId, Class type, T state){ if(StateFactory.isReservedId(stateId)) StateFactory.throwReservedIdException(stateId.toString()); @@ -298,10 +301,10 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart *

you can retrieve the duration of myRoute then by
* double totalRouteDuration = stateManager.getRouteState(myRoute, StateFactory.createStateId("route-duration"), Double.class); * - * @param route - * @param stateId - * @param type - * @param state + * @param route vehilcRoute that gets a state + * @param stateId id of state + * @param type of state + * @param state actual state */ public void putTypedRouteState(VehicleRoute route, StateId stateId, Class type, T state){ if(StateFactory.isReservedId(stateId)) StateFactory.throwReservedIdException(stateId.toString()); @@ -318,7 +321,7 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart *

The following rule pertain for activity/route visitors:These visitors visits all activities/route in a route subsequently in two cases. First, if insertionStart (after ruinStrategies have removed activities from routes) * and, second, if a job has been inserted and thus if a route has changed. * - * @param updater + * @param updater to be inserted here */ public void addStateUpdater(StateUpdater updater){ if(updater instanceof ActivityVisitor) addActivityVisitor((ActivityVisitor) updater); @@ -444,5 +447,11 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart } } + public void updateSkillStates(){ + if(!updateSkills){ + updateSkills=true; + addActivityVisitor(new UpdateSkills(this)); + } + } } 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 24a7b4e4..e323c8a5 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 @@ -38,7 +38,7 @@ import org.apache.log4j.Logger; */ public class ConstraintManager implements HardActivityStateLevelConstraint, HardRouteStateLevelConstraint, SoftActivityConstraint, SoftRouteConstraint{ - public static enum Priority { + public static enum Priority { CRITICAL, HIGH, LOW } @@ -59,6 +59,8 @@ public class ConstraintManager implements HardActivityStateLevelConstraint, Hard private boolean loadConstraintsSet = false; private boolean timeWindowConstraintsSet = false; + + private boolean skillconstraintSet = false; public ConstraintManager(VehicleRoutingProblem vrp, RouteAndActivityStateGetter stateManager) { this.vrp = vrp; @@ -113,6 +115,13 @@ public class ConstraintManager implements HardActivityStateLevelConstraint, Hard loadConstraintsSet=true; } } + + public void addSkillsConstraint() { + if (!skillconstraintSet){ + addConstraint(new SkillConstraint(stateManager)); + skillconstraintSet=true; + } + } // public void add From 34abc1b73710e8a6681850513c83e46932d89f3b Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Thu, 3 Jul 2014 10:02:35 +0200 Subject: [PATCH 15/19] bugfix #111 --- .../main/java/jsprit/analysis/toolbox/Plotter.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/jsprit-analysis/src/main/java/jsprit/analysis/toolbox/Plotter.java b/jsprit-analysis/src/main/java/jsprit/analysis/toolbox/Plotter.java index dc981409..a5ab00d3 100644 --- a/jsprit-analysis/src/main/java/jsprit/analysis/toolbox/Plotter.java +++ b/jsprit-analysis/src/main/java/jsprit/analysis/toolbox/Plotter.java @@ -128,7 +128,8 @@ public class Plotter { if(activity.equals(Activity.DELIVERY)) return DELIVERY_COLOR; if(activity.equals(Activity.SERVICE)) return SERVICE_COLOR; if(activity.equals(Activity.START)) return START_COLOR; - return END_COLOR; + if(activity.equals(Activity.END)) return END_COLOR; + throw new IllegalStateException("activity at "+dataItem.toString()+" cannot be assigned to a color"); } } @@ -219,7 +220,7 @@ public class Plotter { * Constructs Plotter with problem and routes to render individual routes. * * @param vrp - * @param solution + * @param routes */ public Plotter(VehicleRoutingProblem vrp, Collection routes) { super(); @@ -231,8 +232,8 @@ public class Plotter { /** * * @param show - * @return - * @deprecate always true + * @return plotter + * @deprecated always true */ @Deprecated public Plotter setShowFirstActivity(boolean show){ @@ -614,7 +615,9 @@ public class Plotter { if(!v.getStartLocationId().equals(v.getEndLocationId())){ Coordinate endCoord = v.getEndLocationCoordinate(); if(endCoord == null) throw new NoLocationFoundException(); - activities.add(endCoord.getX()*scalingFactor,endCoord.getY()*scalingFactor); + XYDataItem enditem = new XYDataItem(endCoord.getX()*scalingFactor,endCoord.getY()*scalingFactor); + markItem(enditem,Activity.END, null); + activities.add(enditem); } } for(Job job : vrp.getJobs().values()){ From ddb00ce1cedad69dbf23900f0eb12856f822461d Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Thu, 3 Jul 2014 10:04:05 +0200 Subject: [PATCH 16/19] activated skillConstraints --- .../algorithm/VehicleRoutingAlgorithm.java | 4 +-- .../VehicleRoutingAlgorithmBuilder.java | 28 ++++++++++--------- .../io/VehicleRoutingAlgorithms.java | 2 ++ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java b/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java index eec2300b..be6c1ac8 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithm.java @@ -112,7 +112,7 @@ public class VehicleRoutingAlgorithm { /** * Adds solution to the collection of initial solutions. * - * @param solution + * @param solution to the set of initialSolutions */ public void addInitialSolution(VehicleRoutingProblemSolution solution){ initialSolutions.add(solution); @@ -121,7 +121,7 @@ public class VehicleRoutingAlgorithm { /** * Sets premature termination. * - * @param prematureAlgorithmTermination + * @param prematureAlgorithmTermination that terminates the algorithm according to its termination criterion */ public void setPrematureAlgorithmTermination(PrematureAlgorithmTermination prematureAlgorithmTermination){ this.prematureAlgorithmTermination = prematureAlgorithmTermination; diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithmBuilder.java b/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithmBuilder.java index 3cec6751..e8179060 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithmBuilder.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/VehicleRoutingAlgorithmBuilder.java @@ -58,8 +58,8 @@ public class VehicleRoutingAlgorithmBuilder { /** * Constructs the builder with the problem and an algorithmConfigFile. Latter is to configure and specify the ruin-and-recreate meta-heuristic. * - * @param problem - * @param algorithmConfig + * @param problem to solve + * @param algorithmConfig config file of VehicleRoutingAlgorithm */ public VehicleRoutingAlgorithmBuilder(VehicleRoutingProblem problem, String algorithmConfig) { this.vrp=problem; @@ -69,9 +69,9 @@ public class VehicleRoutingAlgorithmBuilder { /** * Constructs the builder with the problem and an algorithmConfig. Latter is to configure and specify the ruin-and-recreate meta-heuristic. - * - * @param problem - * @param algorithmConfig + * + * @param problem to solve + * @param algorithmConfig config file of VehicleRoutingAlgorithm */ public VehicleRoutingAlgorithmBuilder(VehicleRoutingProblem problem, AlgorithmConfig algorithmConfig) { this.vrp=problem; @@ -85,7 +85,7 @@ public class VehicleRoutingAlgorithmBuilder { *

If objective function is not set, a default function is applied (which basically minimizes * fixed and variable transportation costs ({@link VariablePlusFixedSolutionCostCalculatorFactory}). * - * @param objectiveFunction + * @param objectiveFunction to be minimized * @see VariablePlusFixedSolutionCostCalculatorFactory */ public void setObjectiveFunction(SolutionCostCalculator objectiveFunction) { @@ -95,7 +95,7 @@ public class VehicleRoutingAlgorithmBuilder { /** * Sets stateManager to memorize states. * - * @param stateManager + * @param stateManager that memorizes your states * @see StateManager */ public void setStateManager(StateManager stateManager) { @@ -105,7 +105,7 @@ public class VehicleRoutingAlgorithmBuilder { /** * Adds core constraints. * - *

Thus, it adds vehicle-capacity and time-window constraints and their + *

Thus, it adds vehicle-capacity, time-window and skills constraints and their * required stateUpdater. * */ @@ -130,8 +130,8 @@ public class VehicleRoutingAlgorithmBuilder { /** * Sets state- and constraintManager. * - * @param stateManager - * @param constraintManager + * @param stateManager that memorizes your states + * @param constraintManager that manages your constraints * @see StateManager * @see ConstraintManager */ @@ -143,7 +143,7 @@ public class VehicleRoutingAlgorithmBuilder { /** * Sets nuOfThreads. * - * @param nuOfThreads + * @param nuOfThreads to be operated */ public void setNuOfThreads(int nuOfThreads){ this.nuOfThreads=nuOfThreads; @@ -154,7 +154,7 @@ public class VehicleRoutingAlgorithmBuilder { * *

If algorithmConfigFile is set, it reads the configuration. * - * @return + * @return the algorithm */ public VehicleRoutingAlgorithm build() { if(stateManager == null) stateManager = new StateManager(vrp.getTransportCosts()); @@ -167,8 +167,10 @@ public class VehicleRoutingAlgorithmBuilder { if(addCoreConstraints){ constraintManager.addLoadConstraint(); constraintManager.addTimeWindowConstraint(); - stateManager.updateLoadStates(); + constraintManager.addSkillsConstraint(); + stateManager.updateLoadStates(); stateManager.updateTimeWindowStates(); + stateManager.updateSkillStates(); } if(algorithmConfig==null){ algorithmConfig = new AlgorithmConfig(); diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/io/VehicleRoutingAlgorithms.java b/jsprit-core/src/main/java/jsprit/core/algorithm/io/VehicleRoutingAlgorithms.java index 59d2920e..d4eb5881 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/io/VehicleRoutingAlgorithms.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/io/VehicleRoutingAlgorithms.java @@ -489,6 +489,7 @@ public class VehicleRoutingAlgorithms { } stateManager.updateLoadStates(); stateManager.updateTimeWindowStates(); + stateManager.updateSkillStates(); stateManager.addStateUpdater(new UpdateEndLocationIfRouteIsOpen()); stateManager.addStateUpdater(new OpenRouteStateVerifier()); stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts())); @@ -501,6 +502,7 @@ public class VehicleRoutingAlgorithms { ConstraintManager constraintManager = new ConstraintManager(vrp,stateManager,vrp.getConstraints()); constraintManager.addTimeWindowConstraint(); constraintManager.addLoadConstraint(); + constraintManager.addSkillsConstraint(); return readAndCreateAlgorithm(vrp, config, nuOfThreads, null, stateManager, constraintManager, true); } From 8d04e907252227d3f8a6ca9aecb050846d8bd1fa Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Thu, 3 Jul 2014 10:04:53 +0200 Subject: [PATCH 17/19] activated skillContraints --- .../jsprit/core/algorithm/state/StateManager.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java b/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java index a57bcc2b..22f6cd0f 100644 --- a/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/state/StateManager.java @@ -343,10 +343,10 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart *

This visitor visits all activities in a route subsequently in two cases. First, if insertionStart (after ruinStrategies have removed activities from routes) * and, second, if a job has been inserted and thus if a route has changed. * - * @param activityVistor + * @param activityVisitor */ - void addActivityVisitor(ActivityVisitor activityVistor){ - routeActivityVisitor.addActivityVisitor(activityVistor); + void addActivityVisitor(ActivityVisitor activityVisitor){ + routeActivityVisitor.addActivityVisitor(activityVisitor); } /** @@ -354,10 +354,10 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart *

This reverseVisitor visits all activities in a route subsequently (starting from the end of the route) in two cases. First, if insertionStart (after ruinStrategies have removed activities from routes) * and, second, if a job has been inserted and thus if a route has changed. * - * @param activityVistor + * @param activityVisitor */ - void addActivityVisitor(ReverseActivityVisitor activityVistor){ - revRouteActivityVisitor.addActivityVisitor(activityVistor); + void addActivityVisitor(ReverseActivityVisitor activityVisitor){ + revRouteActivityVisitor.addActivityVisitor(activityVisitor); } void addRouteVisitor(RouteVisitor routeVisitor){ From b3cc891cc5b94a5ee2785bd2bab36b9a64314a30 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Thu, 3 Jul 2014 10:05:17 +0200 Subject: [PATCH 18/19] plot solution as well --- .../jsprit/examples/TransportOfDisabledPeople.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/jsprit-examples/src/main/java/jsprit/examples/TransportOfDisabledPeople.java b/jsprit-examples/src/main/java/jsprit/examples/TransportOfDisabledPeople.java index 65576ac1..df21df4b 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/TransportOfDisabledPeople.java +++ b/jsprit-examples/src/main/java/jsprit/examples/TransportOfDisabledPeople.java @@ -215,14 +215,12 @@ public class TransportOfDisabledPeople { problemPlotter.plotShipments(true); problemPlotter.setLabel(jsprit.analysis.toolbox.Plotter.Label.SIZE); problemPlotter.plot("output/transportOfDisabledPeopleExample_problem.png", "disabled people tp"); -// -// /* -// * plot problem with solution -// */ -// Plotter solutionPlotter = new Plotter(problem,Arrays.asList(Solutions.bestOf(solutions).getRoutes().iterator().next())); -// solutionPlotter.plotShipments(true); -// solutionPlotter.plot("output/enRoutePickupAndDeliveryWithMultipleLocationsExample_solution.png", "en-route pickup and delivery"); - + + Plotter solutionPlotter = new Plotter(problem,Solutions.bestOf(solutions)); + solutionPlotter.plotShipments(true); + solutionPlotter.setLabel(jsprit.analysis.toolbox.Plotter.Label.SIZE); + solutionPlotter.plot("output/transportOfDisabledPeopleExample_solution.png", "disabled people tp"); + new GraphStreamViewer(problem).labelWith(Label.ID).setRenderDelay(100).setRenderShipments(true).display(); new GraphStreamViewer(problem,Solutions.bestOf(solutions)).labelWith(Label.ACTIVITY).setRenderDelay(100).setRenderShipments(true).display(); From 501453490d61d1f1a9f1fb26296e4580e0ab5752 Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Thu, 3 Jul 2014 10:38:08 +0200 Subject: [PATCH 19/19] added skills --- .../problem/constraint/ConstraintManager.java | 2 +- ...nstraint.java => HardSkillConstraint.java} | 8 +- .../constraint/SkillConstraintTest.java | 24 +++- .../examples/SimpleExampleWithSkills.java | 121 ++++++++++++++++++ 4 files changed, 149 insertions(+), 6 deletions(-) rename jsprit-core/src/main/java/jsprit/core/problem/constraint/{SkillConstraint.java => HardSkillConstraint.java} (75%) create mode 100644 jsprit-examples/src/main/java/jsprit/examples/SimpleExampleWithSkills.java 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 e323c8a5..26d24c08 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 @@ -118,7 +118,7 @@ public class ConstraintManager implements HardActivityStateLevelConstraint, Hard public void addSkillsConstraint() { if (!skillconstraintSet){ - addConstraint(new SkillConstraint(stateManager)); + addConstraint(new HardSkillConstraint(stateManager)); skillconstraintSet=true; } } diff --git a/jsprit-core/src/main/java/jsprit/core/problem/constraint/SkillConstraint.java b/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardSkillConstraint.java similarity index 75% rename from jsprit-core/src/main/java/jsprit/core/problem/constraint/SkillConstraint.java rename to jsprit-core/src/main/java/jsprit/core/problem/constraint/HardSkillConstraint.java index 9459e350..ded358bf 100644 --- a/jsprit-core/src/main/java/jsprit/core/problem/constraint/SkillConstraint.java +++ b/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardSkillConstraint.java @@ -9,24 +9,24 @@ import jsprit.core.problem.solution.route.state.StateFactory; * SkillConstraint that ensures that only vehicles with according skills can serve route and job to be inserted. * */ -public class SkillConstraint implements HardRouteStateLevelConstraint{ +public class HardSkillConstraint implements HardRouteStateLevelConstraint{ private RouteAndActivityStateGetter states; - public SkillConstraint(RouteAndActivityStateGetter states) { + public HardSkillConstraint(RouteAndActivityStateGetter states) { this.states = states; } @Override public boolean fulfilled(JobInsertionContext insertionContext) { for(String skill : insertionContext.getJob().getRequiredSkills().values()){ - if(!insertionContext.getRoute().getVehicle().getSkills().containsSkill(skill)){ + if(!insertionContext.getNewVehicle().getSkills().containsSkill(skill)){ return false; } } Skills requiredSkillsForRoute = states.getRouteState(insertionContext.getRoute(), StateFactory.SKILLS, Skills.class); for(String skill : requiredSkillsForRoute.values()){ - if(!insertionContext.getRoute().getVehicle().getSkills().containsSkill(skill)){ + if(!insertionContext.getNewVehicle().getSkills().containsSkill(skill)){ return false; } } diff --git a/jsprit-core/src/test/java/jsprit/core/problem/constraint/SkillConstraintTest.java b/jsprit-core/src/test/java/jsprit/core/problem/constraint/SkillConstraintTest.java index 8dd07676..c19ba569 100644 --- a/jsprit-core/src/test/java/jsprit/core/problem/constraint/SkillConstraintTest.java +++ b/jsprit-core/src/test/java/jsprit/core/problem/constraint/SkillConstraintTest.java @@ -44,7 +44,7 @@ public class SkillConstraintTest { stateManager = new StateManager(mock(VehicleRoutingTransportCosts.class)); stateManager.addStateUpdater(new UpdateSkills(stateManager)); stateManager.update(route); - skillConstraint = new SkillConstraint(stateManager); + skillConstraint = new HardSkillConstraint(stateManager); } @Test @@ -57,6 +57,17 @@ public class SkillConstraintTest { assertFalse(skillConstraint.fulfilled(insertionContext)); } + @Test + public void whenJobToBeInsertedRequiresSkillsThatVehicle2DoesNotHave_itShouldReturnFalse(){ + Service s4 = mock(Service.class); + when(s4.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill5").build()); + Vehicle vehicle2 = mock(Vehicle.class); + when(vehicle2.getSkills()).thenReturn(Skills.Builder.newInstance() + .addAllSkills(Arrays.asList("skill1","skill2","skill3","skill4")).build()); + JobInsertionContext insertionContext = new JobInsertionContext(route,s4,vehicle2,route.getDriver(),0.); + assertFalse(skillConstraint.fulfilled(insertionContext)); + } + @Test public void whenJobToBeInsertedRequiresSkillsThatVehicleHave_itShouldReturnTrue(){ Service s4 = mock(Service.class); @@ -67,6 +78,17 @@ public class SkillConstraintTest { assertTrue(skillConstraint.fulfilled(insertionContext)); } + @Test + public void whenJobToBeInsertedRequiresSkillsThatVehicle2Have_itShouldReturnTrue(){ + Service s4 = mock(Service.class); + when(s4.getRequiredSkills()).thenReturn(Skills.Builder.newInstance().addSkill("skill4").build()); + Vehicle vehicle2 = mock(Vehicle.class); + when(vehicle2.getSkills()).thenReturn(Skills.Builder.newInstance() + .addAllSkills(Arrays.asList("skill1","skill2","skill3","skill4","skill5")).build()); + JobInsertionContext insertionContext = new JobInsertionContext(route,s4,vehicle2,route.getDriver(),0.); + assertTrue(skillConstraint.fulfilled(insertionContext)); + } + @Test public void whenRouteToBeOvertakenRequiresSkillsThatVehicleDoesNotHave_itShouldReturnFalse(){ Service s4 = mock(Service.class); diff --git a/jsprit-examples/src/main/java/jsprit/examples/SimpleExampleWithSkills.java b/jsprit-examples/src/main/java/jsprit/examples/SimpleExampleWithSkills.java new file mode 100644 index 00000000..cab74eb5 --- /dev/null +++ b/jsprit-examples/src/main/java/jsprit/examples/SimpleExampleWithSkills.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (C) 2013 Stefan Schroeder + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + ******************************************************************************/ +package jsprit.examples; + +import jsprit.analysis.toolbox.GraphStreamViewer; +import jsprit.analysis.toolbox.GraphStreamViewer.Label; +import jsprit.analysis.toolbox.SolutionPrinter; +import jsprit.analysis.toolbox.SolutionPrinter.Print; +import jsprit.core.algorithm.VehicleRoutingAlgorithm; +import jsprit.core.algorithm.box.SchrimpfFactory; +import jsprit.core.problem.VehicleRoutingProblem; +import jsprit.core.problem.io.VrpXMLWriter; +import jsprit.core.problem.job.Service; +import jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import jsprit.core.problem.vehicle.Vehicle; +import jsprit.core.problem.vehicle.VehicleImpl.Builder; +import jsprit.core.problem.vehicle.VehicleType; +import jsprit.core.problem.vehicle.VehicleTypeImpl; +import jsprit.core.util.Coordinate; +import jsprit.core.util.Solutions; + +import java.io.File; +import java.util.Collection; + + +public class SimpleExampleWithSkills { + + + + public static void main(String[] args) { + /* + * some preparation - create output folder + */ + File dir = new File("output"); + // if the directory does not exist, create it + if (!dir.exists()){ + System.out.println("creating directory ./output"); + boolean result = dir.mkdir(); + if(result) System.out.println("./output created"); + } + + /* + * 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, 2); + 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.setStartLocationCoordinate(Coordinate.newInstance(10, 10)); + vehicleBuilder.setType(vehicleType); + Vehicle vehicle = vehicleBuilder.build(); + + Builder vehicle2Builder = Builder.newInstance("vehicle2"); + vehicle2Builder.setStartLocationCoordinate(Coordinate.newInstance(1, 1)); + vehicle2Builder.setType(vehicleType); + vehicle2Builder.addSkill("drill"); + Vehicle vehicle2 = vehicle2Builder.build(); + + /* + * build services at the required locations, each with a capacity-demand of 1. + */ + Service service1 = Service.Builder.newInstance("1").addSizeDimension(WEIGHT_INDEX, 1).setCoord(Coordinate.newInstance(5, 7)).build(); + Service service2 = Service.Builder.newInstance("2").addSizeDimension(WEIGHT_INDEX, 1).setCoord(Coordinate.newInstance(5, 13)).build(); + + Service service3 = Service.Builder.newInstance("3").addSizeDimension(WEIGHT_INDEX, 1).setCoord(Coordinate.newInstance(15, 7)).build(); + + Service service4 = Service.Builder.newInstance("4").addSizeDimension(WEIGHT_INDEX, 1).addSkill("drill").setCoord(Coordinate.newInstance(15, 13)).build(); + + + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + vrpBuilder.addVehicle(vehicle).addVehicle(vehicle2); + vrpBuilder.addJob(service1).addJob(service2).addJob(service3).addJob(service4); + + VehicleRoutingProblem problem = vrpBuilder.build(); + + /* + * get the algorithm out-of-the-box. + */ + VehicleRoutingAlgorithm algorithm = new SchrimpfFactory().createAlgorithm(problem); + + /* + * and search a solution + */ + Collection solutions = algorithm.searchSolutions(); + + /* + * get the best + */ + VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions); + + new VrpXMLWriter(problem, solutions).write("output/problem-with-solution.xml"); + + SolutionPrinter.print(problem,bestSolution,Print.VERBOSE); + + /* + * plot + */ +// SolutionPlotter.plotSolutionAsPNG(problem, bestSolution, "output/solution.png", "solution"); + + new GraphStreamViewer(problem, bestSolution).labelWith(Label.ID).setRenderDelay(200).display(); + } + +}