1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

incorporate priorities into search - #242

This commit is contained in:
oblonski 2016-05-24 22:14:03 +02:00
parent 6cf2ac2d56
commit af2e9b0a32
12 changed files with 288 additions and 74 deletions

View file

@ -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;
}
};

View file

@ -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<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
List<Job> unassignedJobList = new ArrayList<Job>(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<Job> unassignedJobList) {
if(random.nextDouble() < 0.5){
Collections.sort(unassignedJobList, new Comparator<Job>() {
@Override
public int compare(Job o1, Job o2) {
return o1.getPriority() - o2.getPriority();
}
});
}
}
}

View file

@ -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<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
Collections.shuffle(unassignedJobList, random);
sometimesSortPriorities(unassignedJobList);
List<Batch> 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<Job> unassignedJobList) {
if(random.nextDouble() < 0.5){
Collections.sort(unassignedJobList, new Comparator<Job>() {
@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;

View file

@ -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 + "]";
}
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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.
* <p>
* Default is 2 = medium.
*
* @return priority
*/
public int getPriority();
}

View file

@ -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<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();
SolutionPrinter.print(vrp, Solutions.bestOf(solutions), SolutionPrinter.Print.VERBOSE);

View file

@ -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<Job> jobs = new ArrayList<Job>();
jobs.add(s2);
jobs.add(s3);
jobs.add(s4);
jobs.add(s);
Collections.sort(jobs, new Comparator<Job>() {
@Override
public int compare(Job o1, Job o2) {
return o1.getPriority() - o2.getPriority();
}
});
for(Job j : jobs){
System.out.println(j.getId());
}
}
}

View file

@ -2,7 +2,7 @@
<problem xmlns="http://www.w3schools.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3schools.com vrp_xml_schema.xsd">
<problemType>
<fleetSize>FINITE</fleetSize>
<fleetSize>INFINITE</fleetSize>
</problemType>
<vehicles>
<vehicle>
@ -20,21 +20,6 @@
</timeSchedule>
<returnToDepot>true</returnToDepot>
</vehicle>
<vehicle>
<id>v2</id>
<typeId>vehType2</typeId>
<startLocation>
<id>loc</id>
</startLocation>
<endLocation>
<id>loc</id>
</endLocation>
<timeSchedule>
<start>0.0</start>
<end>1.7976931348623157E308</end>
</timeSchedule>
<returnToDepot>true</returnToDepot>
</vehicle>
</vehicles>
<vehicleTypes>
<type>
@ -48,16 +33,58 @@
<time>0.0</time>
</costs>
</type>
<type>
<id>vehType2</id>
<capacity-dimensions>
<dimension index="0">200</dimension>
</capacity-dimensions>
<costs>
<fixed>0.0</fixed>
<distance>1.0</distance>
<time>0.0</time>
</costs>
</type>
</vehicleTypes>
<services>
<service id="1" type="service">
<location>
<id>loc</id>
</location>
<capacity-dimensions>
<dimension index="0">1</dimension>
</capacity-dimensions>
<duration>2.0</duration>
<timeWindows>
<timeWindow>
<start>0.0</start>
<end>1.7976931348623157E308</end>
</timeWindow>
</timeWindows>
</service>
<service id="2" type="service">
<location>
<id>loc2</id>
</location>
<capacity-dimensions>
<dimension index="0">1</dimension>
</capacity-dimensions>
<duration>4.0</duration>
<timeWindows>
<timeWindow>
<start>0.0</start>
<end>1.7976931348623157E308</end>
</timeWindow>
</timeWindows>
</service>
</services>
<solutions>
<solution>
<cost>10.0</cost>
<routes>
<route>
<driverId>noDriver</driverId>
<vehicleId>v1</vehicleId>
<start>0.0</start>
<act type="service">
<serviceId>1</serviceId>
<arrTime>0.0</arrTime>
<endTime>0.0</endTime>
</act>
<end>0.0</end>
</route>
</routes>
<unassignedJobs>
<job id="2"/>
</unassignedJobs>
</solution>
</solutions>
</problem>

View file

@ -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 <http://www.gnu.org/licenses/>.
******************************************************************************/
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<VehicleRoutingProblemSolution> 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();
}
}