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

add and test new ruin strategy: cluster ruin based on dbscan clusterer

This commit is contained in:
oblonski 2015-03-06 16:16:09 +01:00
parent 708400a34a
commit f4dc5e3b8d
8 changed files with 356 additions and 30 deletions

View file

@ -0,0 +1,185 @@
package jsprit.core.algorithm.ruin;
import jsprit.core.problem.Location;
import jsprit.core.problem.cost.VehicleRoutingTransportCosts;
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.solution.route.activity.TourActivity;
import jsprit.core.util.RandomNumberGeneration;
import jsprit.core.util.RandomUtils;
import org.apache.commons.math3.ml.clustering.Cluster;
import org.apache.commons.math3.ml.clustering.Clusterable;
import org.apache.commons.math3.ml.distance.DistanceMeasure;
import java.util.*;
/**
* Created by schroeder on 04/02/15.
*/
public class DBSCANClusterer {
private static class LocationWrapper implements Clusterable {
private static int objCounter = 0;
private final Job job;
private List<Location> locations;
private int id;
public LocationWrapper(Job job) {
this.locations = getLocations(job);
objCounter++;
this.job = job;
this.id = objCounter;
}
private List<Location> getLocations(Job job){
List<Location> locs = new ArrayList<Location>();
if(job instanceof Service) {
locs.add(((Service) job).getLocation());
}
else if(job instanceof Shipment){
locs.add(((Shipment) job).getPickupLocation());
locs.add(((Shipment) job).getDeliveryLocation());
}
return locs;
}
public List<Location> getLocations() {
return locations;
}
@Override
public double[] getPoint() {
return new double[]{ id };
}
public Job getJob() {
return job;
}
}
private static class MyDistance implements DistanceMeasure {
private Map<Integer,LocationWrapper> locations;
private VehicleRoutingTransportCosts costs;
public MyDistance(List<LocationWrapper> locations, VehicleRoutingTransportCosts costs) {
this.locations = new HashMap<Integer, LocationWrapper>();
for(LocationWrapper lw : locations){
this.locations.put((int)lw.getPoint()[0],lw);
}
this.costs = costs;
}
@Override
public double compute(double[] doubles, double[] doubles1) {
LocationWrapper l1 = locations.get((int)doubles[0]);
LocationWrapper l2 = locations.get((int)doubles1[0]);
int count = 0;
double sum = 0;
for(Location loc_1 : l1.getLocations()){
for(Location loc_2 : l2.getLocations()){
sum += costs.getTransportCost(loc_1,loc_2,0,null,null);
count++;
}
}
return sum / (double)count;
}
}
private VehicleRoutingTransportCosts costs;
private int minNoOfJobsInCluster = 1;
private int noDistanceSamples = 10;
private double epsFactor = 0.8;
private Double epsDistance;
public DBSCANClusterer(VehicleRoutingTransportCosts costs) {
this.costs = costs;
}
public void setMinPts(int pts){
this.minNoOfJobsInCluster = pts;
}
public void setEpsFactor(double epsFactor){
this.epsFactor = epsFactor;
}
public void setEpsDistance(double epsDistance){
this.epsDistance = epsDistance;
}
public List<List<Job>> getClusters(VehicleRoute route){
List<LocationWrapper> locations = new ArrayList<LocationWrapper>(route.getTourActivities().getJobs().size());
for(Job j : route.getTourActivities().getJobs()){
locations.add(new LocationWrapper(j));
}
List<Cluster<LocationWrapper>> clusterResults = getClusters(route, locations);
return makeList(clusterResults);
}
private List<Cluster<LocationWrapper>> getClusters(VehicleRoute route, List<LocationWrapper> locations) {
double sampledDistance;
if(epsDistance != null) sampledDistance = epsDistance;
else sampledDistance = Math.max(0, sample(costs, route));
org.apache.commons.math3.ml.clustering.DBSCANClusterer<LocationWrapper> clusterer = new org.apache.commons.math3.ml.clustering.DBSCANClusterer<LocationWrapper>(sampledDistance, minNoOfJobsInCluster, new MyDistance(locations,costs));
return clusterer.cluster(locations);
}
private List<List<Job>> makeList(List<Cluster<LocationWrapper>> clusterResults) {
List<List<Job>> l = new ArrayList<List<Job>>();
for(Cluster<LocationWrapper> c : clusterResults){
List<Job> l_ = getJobList(c);
l.add(l_);
}
return l;
}
private List<Job> getJobList(Cluster<LocationWrapper> c) {
List<Job> l_ = new ArrayList<Job>();
if(c == null) return l_;
for(LocationWrapper lw : c.getPoints()){
l_.add(lw.getJob());
}
return l_;
}
public List<Job> getRandomCluster(VehicleRoute route){
if(route.isEmpty()) return Collections.emptyList();
List<LocationWrapper> locations = new ArrayList<LocationWrapper>(route.getTourActivities().getJobs().size());
for(Job j : route.getTourActivities().getJobs()){
locations.add(new LocationWrapper(j));
}
List<Cluster<LocationWrapper>> clusterResults = getClusters(route,locations);
if(clusterResults.isEmpty()) return Collections.emptyList();
Cluster<LocationWrapper> randomCluster = RandomUtils.nextItem(clusterResults, RandomNumberGeneration.getRandom());
return getJobList(randomCluster);
}
private double sample(VehicleRoutingTransportCosts costs, VehicleRoute r) {
double min = Double.MAX_VALUE;
double sum = 0;
Random random = RandomNumberGeneration.getRandom();
for(int i=0;i<noDistanceSamples;i++){
TourActivity act1 = RandomUtils.nextItem(r.getActivities(), random);
TourActivity act2 = RandomUtils.nextItem(r.getActivities(), random);
double dist = costs.getTransportCost(act1.getLocation(), act2.getLocation(),
0., null, r.getVehicle());
if(dist < min) min = dist;
sum += dist;
}
double avg = sum / ((double)noDistanceSamples);
return (avg - min) * epsFactor;
}
}

View file

@ -0,0 +1,75 @@
package jsprit.core.algorithm.ruin;
import jsprit.core.problem.Location;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service;
import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.vehicle.VehicleImpl;
import jsprit.core.util.EuclideanCosts;
import junit.framework.Assert;
import org.junit.Test;
import java.util.List;
/**
* Created by schroeder on 06/03/15.
*/
public class DBSCANClustererTest {
@Test
public void itShouldReturnOneClusterOfSizeTwo(){
Service s1 = Service.Builder.newInstance("s1").setLocation(Location.newInstance(1,1)).build();
Service s2 = Service.Builder.newInstance("s2").setLocation(Location.newInstance(10,10)).build();
Service s3 = Service.Builder.newInstance("s3").setLocation(Location.newInstance(9,9)).build();
VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
VehicleRoute r = VehicleRoute.Builder.newInstance(v).addService(s1).addService(s2).addService(s3).build();
DBSCANClusterer c = new DBSCANClusterer(new EuclideanCosts());
c.setEpsDistance(3);
List<Job> cluster = c.getRandomCluster(r);
Assert.assertEquals(2,cluster.size());
}
@Test
public void itShouldReturnOneCluster(){
Service s1 = Service.Builder.newInstance("s1").setLocation(Location.newInstance(1,1)).build();
Service s2 = Service.Builder.newInstance("s2").setLocation(Location.newInstance(10,10)).build();
Service s3 = Service.Builder.newInstance("s3").setLocation(Location.newInstance(9,9)).build();
VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
VehicleRoute r = VehicleRoute.Builder.newInstance(v).addService(s1).addService(s2).addService(s3).build();
DBSCANClusterer c = new DBSCANClusterer(new EuclideanCosts());
c.setEpsDistance(3);
List<List<Job>> cluster = c.getClusters(r);
Assert.assertEquals(1,cluster.size());
}
@Test
public void itShouldReturnTwoClusters(){
Service s0 = Service.Builder.newInstance("s0").setLocation(Location.newInstance(9,0)).build();
Service s1 = Service.Builder.newInstance("s1").setLocation(Location.newInstance(9,1)).build();
Service s2 = Service.Builder.newInstance("s2").setLocation(Location.newInstance(9,10)).build();
Service s3 = Service.Builder.newInstance("s3").setLocation(Location.newInstance(9,9)).build();
Service s4 = Service.Builder.newInstance("s4").setLocation(Location.newInstance(9,16)).build();
Service s5 = Service.Builder.newInstance("s5").setLocation(Location.newInstance(9,17)).build();
VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
VehicleRoute r = VehicleRoute.Builder.newInstance(v).addService(s1).addService(s2).addService(s3)
.addService(s0).addService(s4).addService(s5).build();
DBSCANClusterer c = new DBSCANClusterer(new EuclideanCosts());
c.setMinPts(1);
c.setEpsDistance(2);
List<List<Job>> cluster = c.getClusters(r);
for(List<Job> l : cluster) {
System.out.println("--");
for (Job j : l) System.out.println(j);
}
Assert.assertEquals(3,cluster.size());
}
}

View file

@ -0,0 +1,48 @@
package jsprit.core.algorithm.ruin;
import jsprit.core.algorithm.ruin.distance.AvgServiceAndShipmentDistance;
import jsprit.core.problem.Location;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service;
import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.vehicle.VehicleImpl;
import junit.framework.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
/**
* Created by schroeder on 06/03/15.
*/
public class RuinClustersTest {
@Test
public void itShouldRuinTwoObviousClusters(){
Service s0 = Service.Builder.newInstance("s0").setLocation(Location.newInstance(9, 0)).build();
Service s1 = Service.Builder.newInstance("s1").setLocation(Location.newInstance(9, 1)).build();
Service s2 = Service.Builder.newInstance("s2").setLocation(Location.newInstance(9,10)).build();
Service s3 = Service.Builder.newInstance("s3").setLocation(Location.newInstance(9,9)).build();
Service s4 = Service.Builder.newInstance("s4").setLocation(Location.newInstance(9,16)).build();
Service s5 = Service.Builder.newInstance("s5").setLocation(Location.newInstance(9,17)).build();
Service s6 = Service.Builder.newInstance("s6").setLocation(Location.newInstance(9,15.5)).build();
Service s7 = Service.Builder.newInstance("s7").setLocation(Location.newInstance(9,30)).build();
VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2)
.addJob(s6).addJob(s7).addJob(s0).addJob(s3).addJob(s4).addJob(s5).addVehicle(v).build();
VehicleRoute vr1 = VehicleRoute.Builder.newInstance(v).addService(s0).addService(s1).addService(s2).addService(s3).setJobActivityFactory(vrp.getJobActivityFactory()).build();
VehicleRoute vr2 = VehicleRoute.Builder.newInstance(v)
.addService(s6).addService(s7).addService(s4).addService(s5).setJobActivityFactory(vrp.getJobActivityFactory()).build();
JobNeighborhoods n = new JobNeighborhoodsFactory().createNeighborhoods(vrp,new AvgServiceAndShipmentDistance(vrp.getTransportCosts()));
n.initialise();
RuinClusters rc = new RuinClusters(vrp,5,n);
Collection<Job> ruined = rc.ruinRoutes(Arrays.asList(vr1,vr2));
Assert.assertEquals(5,ruined.size());
}
}