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();