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