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

optimize neighboorhood calculation

This commit is contained in:
oblonski 2016-07-06 13:41:15 +02:00
parent cb08d19397
commit a807024232
5 changed files with 320 additions and 55 deletions

View file

@ -13,7 +13,8 @@ public class JobNeighborhoodsFactory {
} }
public JobNeighborhoods createNeighborhoods(VehicleRoutingProblem vrp, JobDistance jobDistance, int capacity) { public JobNeighborhoods createNeighborhoods(VehicleRoutingProblem vrp, JobDistance jobDistance, int capacity) {
return new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, capacity); // return new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, capacity);
return new JobNeighborhoodsOptimized(vrp, jobDistance, capacity);
} }
} }

View file

@ -36,6 +36,7 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods {
@Override @Override
public Iterator<Job> getNearestNeighborsIterator(int nNeighbors, Job neighborTo) { public Iterator<Job> getNearestNeighborsIterator(int nNeighbors, Job neighborTo) {
TreeSet<ReferencedJob> tree = distanceNodeTree.get(neighborTo.getId()); TreeSet<ReferencedJob> tree = distanceNodeTree.get(neighborTo.getId());
if (tree == null) return new Iterator<Job>() { if (tree == null) return new Iterator<Job>() {
@ -73,10 +74,18 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods {
private void calculateDistancesFromJob2Job() { private void calculateDistancesFromJob2Job() {
logger.debug("preprocess distances between locations ..."); logger.debug("preprocess distances between locations ...");
//ToDo
/*
1 -> 2,3,4,5,6
2 -> 1,3,4,5,6
3
*/
StopWatch stopWatch = new StopWatch(); StopWatch stopWatch = new StopWatch();
stopWatch.start(); stopWatch.start();
int nuOfDistancesStored = 0; int nuOfDistancesStored = 0;
for (Job i : vrp.getJobs().values()) { for (Job i : vrp.getJobs().values()) {
// Collections.sort(list, );
TreeSet<ReferencedJob> treeSet = new TreeSet<ReferencedJob>( TreeSet<ReferencedJob> treeSet = new TreeSet<ReferencedJob>(
new Comparator<ReferencedJob>() { new Comparator<ReferencedJob>() {
@Override @Override

View file

@ -0,0 +1,135 @@
package com.graphhopper.jsprit.core.algorithm.ruin;
import com.graphhopper.jsprit.core.algorithm.ruin.distance.JobDistance;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.util.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* Created by schroeder on 07/01/15.
*/
class JobNeighborhoodsOptimized implements JobNeighborhoods {
static class ArrayIterator implements Iterator<Job> {
private final int noItems;
private final int[] itemArray;
private final Job[] jobs;
private int index = 0;
public ArrayIterator(int noItems, int[] itemArray, Job[] jobs) {
this.noItems = noItems;
this.itemArray = itemArray;
this.jobs = jobs;
}
@Override
public boolean hasNext() {
if(index < noItems && index < itemArray.length) {
return true;
}
return false;
}
@Override
public Job next() {
Job job = jobs[itemArray[index]];
index++;
return job;
}
}
private static Logger logger = LoggerFactory.getLogger(JobNeighborhoodsImpl.class);
private VehicleRoutingProblem vrp;
private int[][] neighbors;
private Job[] jobs;
private JobDistance jobDistance;
private int capacity;
private double maxDistance = 0.;
public JobNeighborhoodsOptimized(VehicleRoutingProblem vrp, JobDistance jobDistance, int capacity) {
super();
this.vrp = vrp;
this.jobDistance = jobDistance;
this.capacity = capacity;
neighbors = new int[vrp.getJobs().size()][capacity];
jobs = new Job[vrp.getJobs().size()+1];
logger.debug("initialize {}", this);
}
@Override
public Iterator<Job> getNearestNeighborsIterator(int nNeighbors, Job neighborTo) {
int[] neighbors = this.neighbors[neighborTo.getIndex()-1];
return new ArrayIterator(nNeighbors,neighbors,jobs);
}
@Override
public void initialise() {
logger.debug("calculates distances from EACH job to EACH job --> n^2={} calculations, but 'only' {} are cached.", Math.pow(vrp.getJobs().values().size(), 2), (vrp.getJobs().values().size() * capacity));
if (capacity == 0) return;
calculateDistancesFromJob2Job();
}
@Override
public double getMaxDistance() {
return maxDistance;
}
private void calculateDistancesFromJob2Job() {
logger.debug("pre-process distances between locations ...");
StopWatch stopWatch = new StopWatch();
stopWatch.start();
for (Job job_i : vrp.getJobs().values()) {
jobs[job_i.getIndex()] = job_i;
List<ReferencedJob> jobList = new ArrayList<ReferencedJob>(vrp.getJobs().size());
for (Job job_j : vrp.getJobs().values()) {
if (job_i == job_j) continue;
double distance = jobDistance.getDistance(job_i, job_j);
if (distance > maxDistance) maxDistance = distance;
ReferencedJob referencedJob = new ReferencedJob(job_j, distance);
jobList.add(referencedJob);
}
Collections.sort(jobList,getComparator());
int[] jobIndices = new int[capacity];
for(int index=0;index<capacity;index++){
jobIndices[index] = jobList.get(index).getJob().getIndex();
}
neighbors[job_i.getIndex()-1] = jobIndices;
}
stopWatch.stop();
logger.debug("pre-processing comp-time: {}", stopWatch);
}
private Comparator<ReferencedJob> getComparator(){
return new Comparator<ReferencedJob>() {
@Override
public int compare(ReferencedJob o1, ReferencedJob o2) {
if (o1.getDistance() < o2.getDistance()) {
return -1;
} else if (o1.getDistance() > o2.getDistance()){
return 1;
}
else return 0;
}
};
}
@Override
public String toString() {
return "[name=neighborhoodWithCapRestriction][capacity=" + capacity + "]";
}
}

View file

@ -0,0 +1,145 @@
/*******************************************************************************
* 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/>.
*
* Contributors:
* Stefan Schroeder - initial API and implementation
******************************************************************************/
package com.graphhopper.jsprit.core.algorithm.ruin;
import com.graphhopper.jsprit.core.algorithm.ruin.distance.EuclideanServiceDistance;
import com.graphhopper.jsprit.core.algorithm.ruin.distance.JobDistance;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.job.Service;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class JobNeighborhoodsOptimizedTest {
VehicleRoutingProblem vrp;
JobDistance jobDistance;
Service target;
Service s2;
Service s3;
Service s4;
Service s5;
Service s6;
Service s7;
@Before
public void doBefore() {
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
target = Service.Builder.newInstance("s1").addSizeDimension(0, 1).setLocation(Location.newInstance(0, 5)).build();
s2 = Service.Builder.newInstance("s2").addSizeDimension(0, 1).setLocation(Location.newInstance(0, 4)).build();
s3 = Service.Builder.newInstance("s3").addSizeDimension(0, 1).setLocation(Location.newInstance(0, 3)).build();
s4 = Service.Builder.newInstance("s4").addSizeDimension(0, 1).setLocation(Location.newInstance(0, 2)).build();
s5 = Service.Builder.newInstance("s5").addSizeDimension(0, 1).setLocation(Location.newInstance(0, 6)).build();
s6 = Service.Builder.newInstance("s6").addSizeDimension(0, 1).setLocation(Location.newInstance(0, 7)).build();
s7 = Service.Builder.newInstance("s7").addSizeDimension(0, 1).setLocation(Location.newInstance(0, 8)).build();
vrp = builder.addJob(target).addJob(s2).addJob(s3).addJob(s4).addJob(s5).addJob(s6).addJob(s7).build();
jobDistance = new EuclideanServiceDistance();
}
@Test
public void whenRequestingNeighborhoodOfTargetJob_nNeighborsShouldBeTwo() {
JobNeighborhoodsOptimized jn = new JobNeighborhoodsOptimized(vrp,jobDistance,2);
jn.initialise();
Iterator<Job> iter = jn.getNearestNeighborsIterator(2, target);
List<Service> services = new ArrayList<Service>();
while (iter.hasNext()) {
services.add((Service) iter.next());
}
assertEquals(2, services.size());
}
@Test
public void whenRequestingNeighborhoodOfTargetJob_s2ShouldBeNeighbor() {
JobNeighborhoodsOptimized jn = new JobNeighborhoodsOptimized(vrp,jobDistance,2);
jn.initialise();
Iterator<Job> iter = jn.getNearestNeighborsIterator(2, target);
List<Service> services = new ArrayList<Service>();
while (iter.hasNext()) {
services.add((Service) iter.next());
}
assertTrue(services.contains(s2));
}
@Test
public void whenRequestingNeighborhoodOfTargetJob_s4ShouldBeNeighbor() {
JobNeighborhoodsOptimized jn = new JobNeighborhoodsOptimized(vrp,jobDistance,2);
jn.initialise();
Iterator<Job> iter = jn.getNearestNeighborsIterator(2, target);
List<Service> services = new ArrayList<Service>();
while (iter.hasNext()) {
services.add((Service) iter.next());
}
assertTrue(services.contains(s5));
}
@Test
public void whenRequestingNeighborhoodOfTargetJob_sizeShouldBe4() {
JobNeighborhoodsOptimized jn = new JobNeighborhoodsOptimized(vrp,jobDistance,4);
jn.initialise();
Iterator<Job> iter = jn.getNearestNeighborsIterator(4, target);
List<Service> services = new ArrayList<Service>();
while (iter.hasNext()) {
services.add((Service) iter.next());
}
assertEquals(4, services.size());
}
@Test
public void whenRequestingNeighborhoodOfTargetJob_neighborsShouldBeCorrect() {
JobNeighborhoodsOptimized jn = new JobNeighborhoodsOptimized(vrp,jobDistance,4);
jn.initialise();
Iterator<Job> iter = jn.getNearestNeighborsIterator(4, s7);
List<Service> services = new ArrayList<Service>();
while (iter.hasNext()) {
services.add((Service) iter.next());
}
Assert.assertEquals(s6,services.get(0));
Assert.assertEquals(s5,services.get(1));
Assert.assertEquals(target,services.get(2));
Assert.assertEquals(s2,services.get(3));
}
@Test
public void whenRequestingMoreNeighborsThanExisting_itShouldReturnMaxNeighbors() {
JobNeighborhoodsOptimized jn = new JobNeighborhoodsOptimized(vrp,jobDistance,2);
jn.initialise();
Iterator<Job> iter = jn.getNearestNeighborsIterator(100, target);
List<Service> services = new ArrayList<Service>();
while (iter.hasNext()) {
services.add((Service) iter.next());
}
assertEquals(2, services.size());
}
}

View file

@ -2,7 +2,7 @@
<problem xmlns="http://www.w3schools.com" <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"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3schools.com vrp_xml_schema.xsd">
<problemType> <problemType>
<fleetSize>INFINITE</fleetSize> <fleetSize>FINITE</fleetSize>
</problemType> </problemType>
<vehicles> <vehicles>
<vehicle> <vehicle>
@ -20,6 +20,21 @@
</timeSchedule> </timeSchedule>
<returnToDepot>true</returnToDepot> <returnToDepot>true</returnToDepot>
</vehicle> </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> </vehicles>
<vehicleTypes> <vehicleTypes>
<type> <type>
@ -35,58 +50,18 @@
<wait>0.0</wait> <wait>0.0</wait>
</costs> </costs>
</type> </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>
<service>0.0</service>
<wait>0.0</wait>
</costs>
</type>
</vehicleTypes> </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> </problem>