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 9fcf07c8..27db5d8e 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);
@@ -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 56d03540..6b81a846 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
@@ -461,6 +461,7 @@ public class VehicleRoutingAlgorithms {
}
stateManager.updateLoadStates();
stateManager.updateTimeWindowStates();
+ stateManager.updateSkillStates();
stateManager.addStateUpdater(new UpdateEndLocationIfRouteIsOpen());
stateManager.addStateUpdater(new OpenRouteStateVerifier());
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts()));
@@ -473,6 +474,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);
}
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);
+ }
+}
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 680351e1..5022ed9b 100644
--- a/jsprit-core/src/main/java/jsprit/core/problem/Capacity.java
+++ b/jsprit-core/src/main/java/jsprit/core/problem/Capacity.java
@@ -71,7 +71,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
*/
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());
+ }
+
+
+
+
+}
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 e0cecff4..daecb75e 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 java.util.List;
*/
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 HardSkillConstraint(stateManager));
+ skillconstraintSet=true;
+ }
+ }
// public void add
diff --git a/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardSkillConstraint.java b/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardSkillConstraint.java
new file mode 100644
index 00000000..ded358bf
--- /dev/null
+++ b/jsprit-core/src/main/java/jsprit/core/problem/constraint/HardSkillConstraint.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 HardSkillConstraint implements HardRouteStateLevelConstraint{
+
+ private RouteAndActivityStateGetter states;
+
+ public HardSkillConstraint(RouteAndActivityStateGetter states) {
+ this.states = states;
+ }
+
+ @Override
+ public boolean fulfilled(JobInsertionContext insertionContext) {
+ for(String skill : insertionContext.getJob().getRequiredSkills().values()){
+ 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.getNewVehicle().getSkills().containsSkill(skill)){
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
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/constraint/SkillConstraintTest.java b/jsprit-core/src/test/java/jsprit/core/problem/constraint/SkillConstraintTest.java
new file mode 100644
index 00000000..c19ba569
--- /dev/null
+++ b/jsprit-core/src/test/java/jsprit/core/problem/constraint/SkillConstraintTest.java
@@ -0,0 +1,129 @@
+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 HardSkillConstraint(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 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);
+ 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 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);
+ 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));
+ }
+}
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 1900f2f0..8741cc23 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
@@ -19,6 +19,8 @@
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;
@@ -56,6 +58,30 @@ 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().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().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 5f13a377..d338c2fd 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
@@ -19,6 +19,8 @@
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;
@@ -56,6 +58,31 @@ 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().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().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 a556c7cc..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
@@ -146,5 +143,30 @@ 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().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().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 6b215cc5..bb7df6ea 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
@@ -18,14 +18,13 @@
******************************************************************************/
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
@@ -249,4 +248,29 @@ 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().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().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 413ccaf2..0b799f16 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
@@ -205,5 +205,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().containsSkill("drill"));
+ assertTrue(v.getSkills().containsSkill("drill"));
+ assertTrue(v.getSkills().containsSkill("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().containsSkill("drill"));
+ assertTrue(v.getSkills().containsSkill("dRill"));
+ assertTrue(v.getSkills().containsSkill("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.getSkills().containsSkill("ScrewDriver"));
+ }
+
}
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();
+ }
+
+}
diff --git a/jsprit-examples/src/main/java/jsprit/examples/TransportOfDisabledPeople.java b/jsprit-examples/src/main/java/jsprit/examples/TransportOfDisabledPeople.java
index 687f4c2f..e36da1a0 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();