diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java
index c9117119..f83f3357 100644
--- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java
+++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/InsertionBuilder.java
@@ -167,7 +167,12 @@ public class InsertionBuilder {
}
}
else if(strategy.equals(Strategy.REGRET)){
- insertion = new RegretInsertion(costCalculator, vrp);
+ if (executor == null) {
+ insertion = new RegretInsertion(costCalculator, vrp);
+ }
+ else {
+ insertion = new RegretInsertionConcurrent(costCalculator,vrp,executor);
+ }
}
else throw new IllegalStateException("you should never get here");
for(InsertionListener l : iListeners) insertion.addListener(l);
diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java
index 640f86d1..44840401 100644
--- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java
+++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertion.java
@@ -20,8 +20,8 @@ package jsprit.core.algorithm.recreate;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service;
+import jsprit.core.problem.job.Shipment;
import jsprit.core.problem.solution.route.VehicleRoute;
-import jsprit.core.problem.vehicle.Vehicle;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -111,6 +111,8 @@ public class RegretInsertion extends AbstractInsertionStrategy {
private double depotDistance_param = + 0.1;
+ private double minTimeWindowScore = - 100000;
+
public DefaultScorer(VehicleRoutingProblem vrp) {
this.vrp = vrp;
}
@@ -121,24 +123,50 @@ public class RegretInsertion extends AbstractInsertionStrategy {
@Override
public double score(InsertionData best, Job job) {
-
- double avgDepotDistance = getAvgDistance(best.getSelectedVehicle(),job);
-
- return Math.max(tw_param * (((Service)job).getTimeWindow().getEnd() - ((Service)job).getTimeWindow().getStart()),-100000) +
- depotDistance_param * avgDepotDistance;
+ double score;
+ if(job instanceof Service){
+ score = scoreService(best, job);
+ }
+ else if(job instanceof Shipment){
+ score = scoreShipment(best,job);
+ }
+ else throw new IllegalStateException("not supported");
+ return score;
}
- private double getAvgDistance(Vehicle vehicle, Job job) {
- double distance = vrp.getTransportCosts().getTransportCost(vehicle.getStartLocationId(),((Service)job).getLocationId(),0.,null,vehicle);
- if(vehicle.isReturnToDepot() && !vehicle.getStartLocationId().equals(vehicle.getEndLocationId())){
- distance = (distance + vrp.getTransportCosts().getTransportCost(vehicle.getEndLocationId(),((Service)job).getLocationId(),0.,null,vehicle))/2.;
- }
- return distance;
+ private double scoreShipment(InsertionData best, Job job) {
+ Shipment shipment = (Shipment)job;
+ double maxDepotDistance_1 = Math.max(
+ getDistance(best.getSelectedVehicle().getStartLocationId(),shipment.getPickupLocationId()),
+ getDistance(best.getSelectedVehicle().getStartLocationId(),shipment.getDeliveryLocationId())
+ );
+ double maxDepotDistance_2 = Math.max(
+ getDistance(best.getSelectedVehicle().getEndLocationId(),shipment.getPickupLocationId()),
+ getDistance(best.getSelectedVehicle().getEndLocationId(),shipment.getDeliveryLocationId())
+ );
+ 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;
+ }
+
+ private double scoreService(InsertionData best, Job job) {
+ double maxDepotDistance = Math.max(
+ getDistance(best.getSelectedVehicle().getStartLocationId(), ((Service) job).getLocationId()),
+ getDistance(best.getSelectedVehicle().getEndLocationId(), ((Service) job).getLocationId())
+ );
+ return Math.max(tw_param * (((Service)job).getTimeWindow().getEnd() - ((Service)job).getTimeWindow().getStart()),minTimeWindowScore) +
+ depotDistance_param * maxDepotDistance;
+ }
+
+
+ private double getDistance(String loc1, String loc2) {
+ return vrp.getTransportCosts().getTransportCost(loc1,loc2,0.,null,null);
}
@Override
public String toString() {
- return "[name=timeWindowScorer][scoringParam="+tw_param+"]";
+ return "[name=defaultScorer][twParam="+tw_param+"][depotDistanceParam=" + depotDistance_param + "]";
}
}
diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java
new file mode 100644
index 00000000..eeffe4fe
--- /dev/null
+++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * 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
Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference
+* between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction.
+* The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this
+* customer immediatedly. If difference is not that high, it might not impact solution if this customer is inserted later.
+*
+* @author stefan schroeder
+*
+*/
+public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
+
+
+ private static Logger logger = LogManager.getLogger(RegretInsertionConcurrent.class);
+
+ private ScoringFunction scoringFunction;
+
+ private final JobInsertionCostsCalculator insertionCostsCalculator;
+
+ private final ExecutorCompletionService By default, the this.TimeWindowScorer is used.
+ *
+ * @param scoringFunction to score
+ */
+ public void setScoringFunction(ScoringFunction scoringFunction) {
+ this.scoringFunction = scoringFunction;
+ }
+
+ public RegretInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, ExecutorService executorService) {
+ super(vehicleRoutingProblem);
+ this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
+ this.insertionCostsCalculator = jobInsertionCalculator;
+ this.vrp = vehicleRoutingProblem;
+ completionService = new ExecutorCompletionService Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
+ *
+ */
+ @Override
+ public Collection