From 6cf2ac2d5679cde50d62e47ee676ac1b212d631b Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 24 May 2016 21:03:14 +0200 Subject: [PATCH 1/3] model and test priorities - #242 --- .../jsprit/core/problem/job/Service.java | 33 ++++++++++++++- .../jsprit/core/problem/job/Shipment.java | 31 +++++++++++++- .../jsprit/core/problem/job/DeliveryTest.java | 29 +++++++++---- .../jsprit/core/problem/job/PickupTest.java | 29 +++++++++---- .../jsprit/core/problem/job/ServiceTest.java | 36 ++++++++++++++++ .../jsprit/core/problem/job/ShipmentTest.java | 42 +++++++++++++++++++ 6 files changed, 184 insertions(+), 16 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java index 50805639..88d7bb33 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java @@ -39,7 +39,6 @@ import java.util.Collection; */ public class Service extends AbstractJob { - /** * Builder that builds a service. * @@ -48,6 +47,8 @@ public class Service extends AbstractJob { public static class Builder { + + /** * Returns a new instance of builder that builds a service. * @@ -86,6 +87,8 @@ public class Service extends AbstractJob { private boolean twAdded = false; + private int priority = 2; + Builder(String id){ this.id = id; timeWindows = new TimeWindowsImpl(); @@ -206,6 +209,20 @@ public class Service extends AbstractJob { } return this; } + + /** + * Set priority to service. Only 1 = high priority, 2 = medium and 3 = low are allowed. + *

+ * Default is 2 = medium. + * + * @param priority + * @return builder + */ + public Builder setPriority(int priority) { + if(priority < 1 || priority > 3) throw new IllegalStateException("incorrect priority. only 1 = high, 2 = medium and 3 = low is allowed"); + this.priority = priority; + return this; + } } private final String id; @@ -226,6 +243,8 @@ public class Service extends AbstractJob { private final TimeWindows timeWindowManager; + private final int priority; + Service(Builder builder) { id = builder.id; serviceTime = builder.serviceTime; @@ -236,6 +255,7 @@ public class Service extends AbstractJob { name = builder.name; location = builder.location; timeWindowManager = builder.timeWindows; + priority = builder.priority; } public Collection getTimeWindows(){ @@ -338,4 +358,15 @@ public class Service extends AbstractJob { return name; } + /** + * Get priority of service. Only 1 = high priority, 2 = medium and 3 = low are allowed. + *

+ * Default is 2 = medium. + * + * @return priority + */ + public int getPriority() { + return priority; + } + } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java index 51b37cc7..6e862af9 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java @@ -46,6 +46,7 @@ public class Shipment extends AbstractJob { + /** * Builder that builds the shipment. * @@ -85,6 +86,8 @@ public class Shipment extends AbstractJob { private TimeWindowsImpl pickupTimeWindows; + private int priority = 2; + /** * Returns new instance of this builder. * @@ -263,6 +266,20 @@ public class Shipment extends AbstractJob { public Builder addPickupTimeWindow(double earliest, double latest) { return addPickupTimeWindow(TimeWindow.newInstance(earliest, latest)); } + + /** + * Set priority to shipment. Only 1 = high priority, 2 = medium and 3 = low are allowed. + *

+ * Default is 2 = medium. + * + * @param priority + * @return builder + */ + public Builder setPriority(int priority) { + if(priority < 1 || priority > 3) throw new IllegalStateException("incorrect priority. only 1 = high, 2 = medium and 3 = low is allowed"); + this.priority = priority; + return this; + } } private final String id; @@ -289,6 +306,8 @@ public class Shipment extends AbstractJob { private final TimeWindowsImpl pickupTimeWindows; + private final int priority; + Shipment(Builder builder) { this.id = builder.id; this.pickupServiceTime = builder.pickupServiceTime; @@ -302,6 +321,7 @@ public class Shipment extends AbstractJob { this.deliveryLocation_ = builder.deliveryLocation_; this.deliveryTimeWindows = builder.deliveryTimeWindows; this.pickupTimeWindows = builder.pickupTimeWindows; + this.priority = builder.priority; } @Override @@ -409,5 +429,14 @@ public class Shipment extends AbstractJob { return name; } - + /** + * Get priority of shipment. Only 1 = high priority, 2 = medium and 3 = low are allowed. + *

+ * Default is 2 = medium. + * + * @return priority + */ + public int getPriority() { + return priority; + } } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/DeliveryTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/DeliveryTest.java index 1628235e..304ee13c 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/DeliveryTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/DeliveryTest.java @@ -17,6 +17,7 @@ package com.graphhopper.jsprit.core.problem.job; import com.graphhopper.jsprit.core.problem.Location; +import org.junit.Assert; import org.junit.Test; import static org.junit.Assert.*; @@ -30,7 +31,7 @@ public class DeliveryTest { @Test public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() { - Delivery one = (Delivery) Delivery.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) + Delivery one = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) .addSizeDimension(0, 2) .addSizeDimension(1, 4) .build(); @@ -42,7 +43,7 @@ public class DeliveryTest { @Test public void whenPickupIsBuiltWithoutSpecifyingCapacity_itShouldHvCapWithOneDimAndDimValOfZero() { - Delivery one = (Delivery) Delivery.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) + Delivery one = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) .build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(0, one.getSize().get(0)); @@ -50,7 +51,7 @@ public class DeliveryTest { @Test public void whenPickupIsBuiltWithConstructorWhereSizeIsSpecified_capacityShouldBeSetCorrectly() { - Delivery one = (Delivery) Delivery.Builder.newInstance("s").addSizeDimension(0, 1).setLocation(Location.newInstance("foofoo")) + Delivery one = Delivery.Builder.newInstance("s").addSizeDimension(0, 1).setLocation(Location.newInstance("foofoo")) .build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(1, one.getSize().get(0)); @@ -58,7 +59,7 @@ public class DeliveryTest { @Test public void whenAddingSkills_theyShouldBeAddedCorrectly() { - Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) .addRequiredSkill("drill").addRequiredSkill("screwdriver").build(); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver")); @@ -66,7 +67,7 @@ public class DeliveryTest { @Test public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly() { - Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) .addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build(); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("drilL")); @@ -74,7 +75,7 @@ public class DeliveryTest { @Test public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() { - Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) .addRequiredSkill("screwDriver").build(); assertFalse(s.getRequiredSkills().containsSkill("drill")); assertFalse(s.getRequiredSkills().containsSkill("drilL")); @@ -82,10 +83,24 @@ public class DeliveryTest { @Test public void nameShouldBeAssigned() { - Delivery s = (Delivery) Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) .setName("name").build(); assertEquals("name", s.getName()); } + @Test + public void whenSettingPriorities_itShouldBeSetCorrectly(){ + Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .setPriority(3).build(); + Assert.assertEquals(3, s.getPriority()); + } + + @Test + public void whenNotSettingPriorities_defaultShouldBe(){ + Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .build(); + Assert.assertEquals(2, s.getPriority()); + } + } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/PickupTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/PickupTest.java index 97211973..9482722f 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/PickupTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/PickupTest.java @@ -17,6 +17,7 @@ package com.graphhopper.jsprit.core.problem.job; import com.graphhopper.jsprit.core.problem.Location; +import org.junit.Assert; import org.junit.Test; import static org.junit.Assert.*; @@ -30,7 +31,7 @@ public class PickupTest { @Test public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() { - Pickup one = (Pickup) Pickup.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) + Pickup one = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) .addSizeDimension(0, 2) .addSizeDimension(1, 4) .build(); @@ -42,7 +43,7 @@ public class PickupTest { @Test public void whenPickupIsBuiltWithoutSpecifyingCapacity_itShouldHvCapWithOneDimAndDimValOfZero() { - Pickup one = (Pickup) Pickup.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) + Pickup one = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) .build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(0, one.getSize().get(0)); @@ -50,7 +51,7 @@ public class PickupTest { @Test public void whenPickupIsBuiltWithConstructorWhereSizeIsSpecified_capacityShouldBeSetCorrectly() { - Pickup one = (Pickup) Pickup.Builder.newInstance("s").addSizeDimension(0, 1).setLocation(Location.newInstance("foofoo")) + Pickup one = Pickup.Builder.newInstance("s").addSizeDimension(0, 1).setLocation(Location.newInstance("foofoo")) .build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(1, one.getSize().get(0)); @@ -58,7 +59,7 @@ public class PickupTest { @Test public void whenAddingSkills_theyShouldBeAddedCorrectly() { - Pickup s = (Pickup) Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) .addRequiredSkill("drill").addRequiredSkill("screwdriver").build(); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("drill")); @@ -67,7 +68,7 @@ public class PickupTest { @Test public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly() { - Pickup s = (Pickup) Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) .addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build(); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("drilL")); @@ -75,7 +76,7 @@ public class PickupTest { @Test public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() { - Pickup s = (Pickup) Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) .addRequiredSkill("screwDriver").build(); assertFalse(s.getRequiredSkills().containsSkill("drill")); assertFalse(s.getRequiredSkills().containsSkill("drilL")); @@ -83,10 +84,24 @@ public class PickupTest { @Test public void nameShouldBeAssigned() { - Pickup s = (Pickup) Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) .setName("name").build(); assertEquals("name", s.getName()); } + @Test + public void whenSettingPriorities_itShouldBeSetCorrectly(){ + Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .setPriority(3).build(); + Assert.assertEquals(3, s.getPriority()); + } + + @Test + public void whenNotSettingPriorities_defaultShouldBe(){ + Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .build(); + Assert.assertEquals(2, s.getPriority()); + } + } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java index da5ac763..8ed72c02 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java @@ -18,6 +18,7 @@ package com.graphhopper.jsprit.core.problem.job; import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow; +import org.junit.Assert; import org.junit.Test; import java.util.HashSet; @@ -234,4 +235,39 @@ public class ServiceTest { .setName("name").build(); } + @Test + public void whenSettingPriorities_itShouldBeSetCorrectly(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .setPriority(1).build(); + Assert.assertEquals(1, s.getPriority()); + } + + @Test + public void whenSettingPriorities_itShouldBeSetCorrectly2(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .setPriority(3).build(); + Assert.assertEquals(3, s.getPriority()); + } + + @Test + public void whenNotSettingPriorities_defaultShouldBe2(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .build(); + Assert.assertEquals(2, s.getPriority()); + } + + @Test(expected = IllegalStateException.class) + public void whenSettingIncorrectPriorities_itShouldThrowException(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .setPriority(30).build(); + + } + + @Test(expected = IllegalStateException.class) + public void whenSettingIncorrectPriorities_itShouldThrowException2(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .setPriority(0).build(); + + } + } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java index 205c6e7b..814f271f 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java @@ -20,6 +20,7 @@ import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow; import com.graphhopper.jsprit.core.util.Coordinate; import com.graphhopper.jsprit.core.util.TestUtils; +import org.junit.Assert; import org.junit.Test; import static org.hamcrest.core.Is.is; @@ -382,4 +383,45 @@ public class ShipmentTest { assertEquals("del", s.getDeliveryLocation().getId()); assertEquals("del", s.getDeliveryLocation().getId()); } + + @Test + public void whenSettingPriorities_itShouldBeSetCorrectly(){ + Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) + .setDeliveryLocation(Location.newInstance("loc")) + .setPriority(1).build(); + Assert.assertEquals(1, s.getPriority()); + } + + @Test + public void whenSettingPriorities_itShouldBeSetCorrectly2(){ + Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) + .setDeliveryLocation(Location.newInstance("loc")) + .setPriority(3).build(); + Assert.assertEquals(3, s.getPriority()); + } + + @Test + public void whenNotSettingPriorities_defaultShouldBe2(){ + Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) + .setDeliveryLocation(Location.newInstance("loc")) + .build(); + Assert.assertEquals(2, s.getPriority()); + } + + @Test(expected = IllegalStateException.class) + public void whenSettingIncorrectPriorities_itShouldThrowException(){ + Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) + .setDeliveryLocation(Location.newInstance("loc")) + .setPriority(30).build(); + + } + + @Test(expected = IllegalStateException.class) + public void whenSettingIncorrectPriorities_itShouldThrowException2(){ + Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) + .setDeliveryLocation(Location.newInstance("loc")) + .setPriority(0).build(); + + } + } From af2e9b0a32bcc2683e995fd34d9019b3561f8680 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 24 May 2016 22:14:03 +0200 Subject: [PATCH 2/3] incorporate priorities into search - #242 --- .../jsprit/core/algorithm/box/Jsprit.java | 12 +- .../algorithm/recreate/BestInsertion.java | 17 ++- .../recreate/BestInsertionConcurrent.java | 17 ++- .../algorithm/recreate/DefaultScorer.java | 16 +-- .../recreate/InsertionDataUpdater.java | 13 +- .../algorithm/recreate/RegretInsertion.java | 13 +- .../core/algorithm/recreate/Scorer.java | 24 ++++ .../jsprit/core/problem/job/Job.java | 10 ++ ...CostsHigherThanTimesAndFiniteFleet_IT.java | 3 +- .../algorithm/recreate/TestComparator.java | 44 +++++++ .../test/resources/infiniteWriterV2Test.xml | 81 ++++++++----- .../examples/SimpleExampleWithPriorities.java | 112 ++++++++++++++++++ 12 files changed, 288 insertions(+), 74 deletions(-) create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java create mode 100644 jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestComparator.java create mode 100644 jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/SimpleExampleWithPriorities.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 1b20a9da..2fc20cf0 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -14,6 +14,7 @@ import com.graphhopper.jsprit.core.algorithm.selector.SelectBest; import com.graphhopper.jsprit.core.algorithm.state.StateManager; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager; +import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.solution.SolutionCostCalculator; import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; @@ -568,8 +569,7 @@ public class Jsprit { } private DefaultScorer getRegretScorer(VehicleRoutingProblem vrp) { - DefaultScorer scorer; - scorer = new DefaultScorer(vrp); + DefaultScorer scorer = new DefaultScorer(vrp); scorer.setTimeWindowParam(Double.valueOf(properties.getProperty(Parameter.REGRET_TIME_WINDOW_SCORER.toString()))); scorer.setDepotDistanceParam(Double.valueOf(properties.getProperty(Parameter.REGRET_DISTANCE_SCORER.toString()))); return scorer; @@ -638,14 +638,16 @@ public class Jsprit { if (!hasBreak) { //break defined and required but not assigned penalty if (route.getEnd().getArrTime() > route.getVehicle().getBreak().getTimeWindow().getEnd()) { - costs += maxCosts * 2 + route.getVehicle().getBreak().getServiceDuration() * route.getVehicle().getType().getVehicleCostParams().perServiceTimeUnit; + costs += maxCosts * 1 + route.getVehicle().getBreak().getServiceDuration() * route.getVehicle().getType().getVehicleCostParams().perServiceTimeUnit; } else { - costs -= maxCosts * 2; +// costs -= maxCosts * 2; } } } } - costs += solution.getUnassignedJobs().size() * maxCosts * 2; + for(Job j : solution.getUnassignedJobs()){ + costs += maxCosts * (4 - j.getPriority()); + } return costs; } }; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java index 17c7d56a..d26a17f3 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java @@ -23,10 +23,7 @@ import com.graphhopper.jsprit.core.util.NoiseMaker; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; /** @@ -65,6 +62,7 @@ public final class BestInsertion extends AbstractInsertionStrategy { List badJobs = new ArrayList(unassignedJobs.size()); List unassignedJobList = new ArrayList(unassignedJobs); Collections.shuffle(unassignedJobList, random); + sometimesSortPriorities(unassignedJobList); for (Job unassignedJob : unassignedJobList) { Insertion bestInsertion = null; double bestInsertionCost = Double.MAX_VALUE; @@ -93,4 +91,15 @@ public final class BestInsertion extends AbstractInsertionStrategy { return badJobs; } + private void sometimesSortPriorities(List unassignedJobList) { + if(random.nextDouble() < 0.5){ + Collections.sort(unassignedJobList, new Comparator() { + @Override + public int compare(Job o1, Job o2) { + return o1.getPriority() - o2.getPriority(); + } + }); + } + } + } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java index f9c298d8..76450c73 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java @@ -26,10 +26,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; import java.util.concurrent.*; @@ -101,6 +98,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy { List badJobs = new ArrayList(unassignedJobs.size()); List unassignedJobList = new ArrayList(unassignedJobs); Collections.shuffle(unassignedJobList, random); + sometimesSortPriorities(unassignedJobList); List batches = distributeRoutes(vehicleRoutes, nuOfBatches); for (final Job unassignedJob : unassignedJobList) { Insertion bestInsertion = null; @@ -143,6 +141,17 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy { return badJobs; } + private void sometimesSortPriorities(List unassignedJobList) { + if(random.nextDouble() < 0.5){ + Collections.sort(unassignedJobList, new Comparator() { + @Override + public int compare(Job o1, Job o2) { + return o1.getPriority() - o2.getPriority(); + } + }); + } + } + private Insertion getBestInsertion(Batch batch, Job unassignedJob) { Insertion bestInsertion = null; double bestInsertionCost = Double.MAX_VALUE; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DefaultScorer.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DefaultScorer.java index 19994ff5..2f88caf9 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DefaultScorer.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DefaultScorer.java @@ -13,9 +13,9 @@ public class DefaultScorer implements ScoringFunction { private VehicleRoutingProblem vrp; - private double tw_param = -0.5; + private double timeWindowParam = -0.5; - private double depotDistance_param = +0.1; + private double depotDistanceParam = +0.1; private double minTimeWindowScore = -100000; @@ -24,11 +24,11 @@ public class DefaultScorer implements ScoringFunction { } public void setTimeWindowParam(double tw_param) { - this.tw_param = tw_param; + this.timeWindowParam = tw_param; } public void setDepotDistanceParam(double depotDistance_param) { - this.depotDistance_param = depotDistance_param; + this.depotDistanceParam = depotDistance_param; } @Override @@ -55,7 +55,7 @@ public class DefaultScorer implements ScoringFunction { double maxDepotDistance = Math.max(maxDepotDistance_1, maxDepotDistance_2); double minTimeToOperate = Math.min(shipment.getPickupTimeWindow().getEnd() - shipment.getPickupTimeWindow().getStart(), shipment.getDeliveryTimeWindow().getEnd() - shipment.getDeliveryTimeWindow().getStart()); - return Math.max(tw_param * minTimeToOperate, minTimeWindowScore) + depotDistance_param * maxDepotDistance; + return Math.max(timeWindowParam * minTimeToOperate, minTimeWindowScore) + depotDistanceParam * maxDepotDistance; } private double scoreService(InsertionData best, Job job) { @@ -67,8 +67,8 @@ public class DefaultScorer implements ScoringFunction { getDistance(best.getSelectedVehicle().getEndLocation(), location) ); } - return Math.max(tw_param * (((Service) job).getTimeWindow().getEnd() - ((Service) job).getTimeWindow().getStart()), minTimeWindowScore) + - depotDistance_param * maxDepotDistance; + return Math.max(timeWindowParam * (((Service) job).getTimeWindow().getEnd() - ((Service) job).getTimeWindow().getStart()), minTimeWindowScore) + + depotDistanceParam * maxDepotDistance; } @@ -78,6 +78,6 @@ public class DefaultScorer implements ScoringFunction { @Override public String toString() { - return "[name=defaultScorer][twParam=" + tw_param + "][depotDistanceParam=" + depotDistance_param + "]"; + return "[name=defaultScorer][twParam=" + timeWindowParam + "][depotDistanceParam=" + depotDistanceParam + "]"; } } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java index 7e9df6f2..3b3eb476 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java @@ -140,18 +140,7 @@ class InsertionDataUpdater { } static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) { - if (best == null) { - throw new IllegalStateException("cannot insert job " + unassignedJob.getId()); - } - double score; - if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob - //if only one vehicle, I want the job to be inserted with min iCosts - //if there are more vehicles, I want this job to be prioritized since there are no alternatives - score = Integer.MAX_VALUE - best.getInsertionCost() + scoringFunction.score(best, unassignedJob); - } else { - score = (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); - } - return score; + return Scorer.score(unassignedJob,best,secondBest,scoringFunction); } } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java index 9c65b7a5..2bb93b4e 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java @@ -204,18 +204,7 @@ public class RegretInsertion extends AbstractInsertionStrategy { static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) { - if (best == null) { - throw new IllegalStateException("cannot insert job " + unassignedJob.getId()); - } - double score; - if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob - //if only one vehicle, I want the job to be inserted with min iCosts - //if there are more vehicles, I want this job to be prioritized since there are no alternatives - score = Integer.MAX_VALUE - best.getInsertionCost() + scoringFunction.score(best, unassignedJob); - } else { - score = (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); - } - return score; + return Scorer.score(unassignedJob,best,secondBest,scoringFunction); } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java new file mode 100644 index 00000000..44cf1927 --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java @@ -0,0 +1,24 @@ +package com.graphhopper.jsprit.core.algorithm.recreate; + +import com.graphhopper.jsprit.core.problem.job.Job; + +/** + * Created by schroeder on 24/05/16. + */ +class Scorer { + + static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction){ + if (best == null) { + throw new IllegalStateException("cannot insert job " + unassignedJob.getId()); + } + double score; + if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob + //if only one vehicle, I want the job to be inserted with min iCosts + //if there are more vehicles, I want this job to be prioritized since there are no alternatives + score = (4 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); + } else { + score = (4 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); + } + return score; + } +} diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Job.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Job.java index fd9d9517..e1a4920d 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Job.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Job.java @@ -51,4 +51,14 @@ public interface Job extends HasId, HasIndex { * @return name */ public String getName(); + + /** + * Get priority of job. Only 1 = high priority, 2 = medium and 3 = low are allowed. + *

+ * Default is 2 = medium. + * + * @return priority + */ + public int getPriority(); + } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/RefuseCollectionWithCostsHigherThanTimesAndFiniteFleet_IT.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/RefuseCollectionWithCostsHigherThanTimesAndFiniteFleet_IT.java index b67d1c20..4421f674 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/RefuseCollectionWithCostsHigherThanTimesAndFiniteFleet_IT.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/RefuseCollectionWithCostsHigherThanTimesAndFiniteFleet_IT.java @@ -18,7 +18,6 @@ package com.graphhopper.jsprit.core.algorithm; import com.graphhopper.jsprit.core.IntegrationTest; import com.graphhopper.jsprit.core.algorithm.box.GreedySchrimpfFactory; -import com.graphhopper.jsprit.core.algorithm.termination.IterationWithoutImprovementTermination; import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; import com.graphhopper.jsprit.core.problem.job.Service; @@ -143,7 +142,7 @@ public class RefuseCollectionWithCostsHigherThanTimesAndFiniteFleet_IT { vrpBuilder.setRoutingCost(matrixBuilder.build()); VehicleRoutingProblem vrp = vrpBuilder.build(); VehicleRoutingAlgorithm vra = new GreedySchrimpfFactory().createAlgorithm(vrp); - vra.setPrematureAlgorithmTermination(new IterationWithoutImprovementTermination(100)); +// vra.setPrematureAlgorithmTermination(new IterationWithoutImprovementTermination(100)); Collection solutions = vra.searchSolutions(); SolutionPrinter.print(vrp, Solutions.bestOf(solutions), SolutionPrinter.Print.VERBOSE); diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestComparator.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestComparator.java new file mode 100644 index 00000000..7e042b7f --- /dev/null +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestComparator.java @@ -0,0 +1,44 @@ +package com.graphhopper.jsprit.core.algorithm.recreate; + +import com.graphhopper.jsprit.core.problem.Location; +import com.graphhopper.jsprit.core.problem.job.Job; +import com.graphhopper.jsprit.core.problem.job.Service; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * Created by schroeder on 24/05/16. + */ +public class TestComparator { + + @Test + public void test(){ + Service s = Service.Builder.newInstance("1").setLocation(Location.newInstance("loc")) + .setPriority(1).build(); + Service s2 = Service.Builder.newInstance("2").setLocation(Location.newInstance("loc")) + .setPriority(2).build(); + Service s3 = Service.Builder.newInstance("3").setLocation(Location.newInstance("loc")) + .setPriority(3).build(); + Service s4 = Service.Builder.newInstance("4").setLocation(Location.newInstance("loc")) + .setPriority(1).build(); + List jobs = new ArrayList(); + jobs.add(s2); + jobs.add(s3); + jobs.add(s4); + jobs.add(s); + Collections.sort(jobs, new Comparator() { + @Override + public int compare(Job o1, Job o2) { + return o1.getPriority() - o2.getPriority(); + } + }); + + for(Job j : jobs){ + System.out.println(j.getId()); + } + } +} diff --git a/jsprit-core/src/test/resources/infiniteWriterV2Test.xml b/jsprit-core/src/test/resources/infiniteWriterV2Test.xml index c7c40d9f..2d9058ab 100644 --- a/jsprit-core/src/test/resources/infiniteWriterV2Test.xml +++ b/jsprit-core/src/test/resources/infiniteWriterV2Test.xml @@ -2,7 +2,7 @@ - FINITE + INFINITE @@ -20,21 +20,6 @@ true - - v2 - vehType2 - - loc - - - loc - - - 0.0 - 1.7976931348623157E308 - - true - @@ -48,16 +33,58 @@ - - vehType2 - - 200 - - - 0.0 - 1.0 - - - + + + + loc + + + 1 + + 2.0 + + + 0.0 + 1.7976931348623157E308 + + + + + + loc2 + + + 1 + + 4.0 + + + 0.0 + 1.7976931348623157E308 + + + + + + + 10.0 + + + noDriver + v1 + 0.0 + + 1 + 0.0 + 0.0 + + 0.0 + + + + + + + diff --git a/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/SimpleExampleWithPriorities.java b/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/SimpleExampleWithPriorities.java new file mode 100644 index 00000000..04368a63 --- /dev/null +++ b/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/SimpleExampleWithPriorities.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (C) 2014 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 com.graphhopper.jsprit.examples; + +import com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer; +import com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer.Label; +import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; +import com.graphhopper.jsprit.core.algorithm.box.Jsprit; +import com.graphhopper.jsprit.core.problem.Location; +import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.io.VrpXMLWriter; +import com.graphhopper.jsprit.core.problem.job.Service; +import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl.Builder; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleType; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl; +import com.graphhopper.jsprit.core.reporting.SolutionPrinter; +import com.graphhopper.jsprit.core.util.Solutions; + +import java.io.File; +import java.util.Collection; + + +public class SimpleExampleWithPriorities { + + + 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.setStartLocation(Location.newInstance(10, 10)); + vehicleBuilder.setType(vehicleType); + VehicleImpl vehicle = vehicleBuilder.build(); + + /* + * build services at the required locations, each with a capacity-demand of 1. + */ + Service service1 = Service.Builder.newInstance("1").setPriority(1).addSizeDimension(WEIGHT_INDEX, 1).setLocation(Location.newInstance(5, 7)).build(); + Service service2 = Service.Builder.newInstance("2").addSizeDimension(WEIGHT_INDEX, 1).setLocation(Location.newInstance(5, 13)).build(); + + Service service3 = Service.Builder.newInstance("3").addSizeDimension(WEIGHT_INDEX, 1).setLocation(Location.newInstance(15, 7)).build(); + Service service4 = Service.Builder.newInstance("4").setPriority(1).addSizeDimension(WEIGHT_INDEX, 1).setLocation(Location.newInstance(15, 13)).build(); + + + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + vrpBuilder.addVehicle(vehicle); + vrpBuilder.addJob(service1).addJob(service2).addJob(service3).addJob(service4).setFleetSize(VehicleRoutingProblem.FleetSize.FINITE); + + VehicleRoutingProblem problem = vrpBuilder.build(); + + /* + * get the algorithm out-of-the-box. + */ + VehicleRoutingAlgorithm algorithm = Jsprit.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, SolutionPrinter.Print.VERBOSE); + + /* + * plot + */ +// SolutionPlotter.plotSolutionAsPNG(problem, bestSolution, "output/solution.png", "solution"); + + new GraphStreamViewer(problem, bestSolution).labelWith(Label.ID).setRenderDelay(200).display(); + } + +} From d241647f34e35e59bd223c781a9d637d5010ae80 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 25 May 2016 10:05:14 +0200 Subject: [PATCH 3/3] align default cost func --- .../com/graphhopper/jsprit/core/algorithm/box/Jsprit.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 2fc20cf0..fce66c3d 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -638,15 +638,13 @@ public class Jsprit { if (!hasBreak) { //break defined and required but not assigned penalty if (route.getEnd().getArrTime() > route.getVehicle().getBreak().getTimeWindow().getEnd()) { - costs += maxCosts * 1 + route.getVehicle().getBreak().getServiceDuration() * route.getVehicle().getType().getVehicleCostParams().perServiceTimeUnit; - } else { -// costs -= maxCosts * 2; + costs += 4 * (maxCosts * 2 + route.getVehicle().getBreak().getServiceDuration() * route.getVehicle().getType().getVehicleCostParams().perServiceTimeUnit); } } } } for(Job j : solution.getUnassignedJobs()){ - costs += maxCosts * (4 - j.getPriority()); + costs += maxCosts * 2 * (4 - j.getPriority()); } return costs; }