diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsFactory.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsFactory.java index 9ac38a43..de57363c 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsFactory.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsFactory.java @@ -13,7 +13,8 @@ public class JobNeighborhoodsFactory { } 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); } } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsImplWithCapRestriction.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsImplWithCapRestriction.java index bb3f9f2f..031b7034 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsImplWithCapRestriction.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsImplWithCapRestriction.java @@ -36,6 +36,7 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods { @Override public Iterator getNearestNeighborsIterator(int nNeighbors, Job neighborTo) { + TreeSet tree = distanceNodeTree.get(neighborTo.getId()); if (tree == null) return new Iterator() { @@ -73,10 +74,18 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods { private void calculateDistancesFromJob2Job() { 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.start(); int nuOfDistancesStored = 0; for (Job i : vrp.getJobs().values()) { + // Collections.sort(list, ); TreeSet treeSet = new TreeSet( new Comparator() { @Override diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsOptimized.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsOptimized.java new file mode 100644 index 00000000..2e3aed65 --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsOptimized.java @@ -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 { + + 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 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 jobList = new ArrayList(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 getComparator(){ + return new Comparator() { + @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 + "]"; + } + +} diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsOptimizedTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsOptimizedTest.java new file mode 100644 index 00000000..fa217795 --- /dev/null +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/ruin/JobNeighborhoodsOptimizedTest.java @@ -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 . + * + * 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 iter = jn.getNearestNeighborsIterator(2, target); + List services = new ArrayList(); + 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 iter = jn.getNearestNeighborsIterator(2, target); + List services = new ArrayList(); + 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 iter = jn.getNearestNeighborsIterator(2, target); + List services = new ArrayList(); + 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 iter = jn.getNearestNeighborsIterator(4, target); + List services = new ArrayList(); + 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 iter = jn.getNearestNeighborsIterator(4, s7); + List services = new ArrayList(); + 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 iter = jn.getNearestNeighborsIterator(100, target); + List services = new ArrayList(); + while (iter.hasNext()) { + services.add((Service) iter.next()); + } + assertEquals(2, services.size()); + } + +} diff --git a/jsprit-core/src/test/resources/infiniteWriterV2Test.xml b/jsprit-core/src/test/resources/infiniteWriterV2Test.xml index c7b5a449..b34bf776 100644 --- a/jsprit-core/src/test/resources/infiniteWriterV2Test.xml +++ b/jsprit-core/src/test/resources/infiniteWriterV2Test.xml @@ -2,7 +2,7 @@ - INFINITE + FINITE @@ -20,6 +20,21 @@ true + + v2 + vehType2 + + loc + + + loc + + + 0.0 + 1.7976931348623157E308 + + true + @@ -35,58 +50,18 @@ 0.0 + + vehType2 + + 200 + + + 0.0 + 1.0 + + 0.0 + 0.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 - - - - - - -