diff --git a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionWithTimeScheduling.java b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionWithTimeScheduling.java index f8ef9064..13ec9da2 100644 --- a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionWithTimeScheduling.java +++ b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionWithTimeScheduling.java @@ -27,8 +27,10 @@ import basics.route.Driver; import basics.route.Vehicle; import basics.route.VehicleRoute; + class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsCalculator{ + private static Logger log = Logger.getLogger(CalculatesServiceInsertionWithTimeScheduling.class); private JobInsertionCostsCalculator jic; @@ -67,9 +69,13 @@ class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsC for(int i=0;i earliestDeparture) vehicleDepartureTimes.add(neighborStartTime_earlier); +// if(neighborStartTime_earlier > earliestDeparture) { + vehicleDepartureTimes.add(neighborStartTime_earlier); +// } double neighborStartTime_later = currentStart + (i+1)*timeSlice; - if(neighborStartTime_later < latestEnd) vehicleDepartureTimes.add(neighborStartTime_later); +// if(neighborStartTime_later < latestEnd) { + vehicleDepartureTimes.add(neighborStartTime_later); +// } } InsertionData bestIData = null; diff --git a/jsprit-core/src/main/java/algorithms/RuinRadial.java b/jsprit-core/src/main/java/algorithms/RuinRadial.java index 2764eb0e..c950daf4 100644 --- a/jsprit-core/src/main/java/algorithms/RuinRadial.java +++ b/jsprit-core/src/main/java/algorithms/RuinRadial.java @@ -49,6 +49,194 @@ import basics.route.VehicleRoute; */ final class RuinRadial implements RuinStrategy { + static interface JobNeighborhoods { + + public Iterator getNearestNeighborsIterator(int nNeighbors, Job neighborTo); + + } + + static class NeighborhoodIterator implements Iterator{ + + private static Logger log = Logger.getLogger(NeighborhoodIterator.class); + + private Iterator jobIter; + + private int nJobs; + + private int jobCount = 0; + + public NeighborhoodIterator(Iterator jobIter, int nJobs) { + super(); + this.jobIter = jobIter; + this.nJobs = nJobs; + } + + @Override + public boolean hasNext() { + if(jobCount < nJobs){ + boolean hasNext = jobIter.hasNext(); + if(!hasNext) log.warn("more jobs are requested then iterator can iterate over. probably the number of neighbors memorized in JobNeighborhoods is too small"); + return hasNext; + } + return false; + } + + @Override + public Job next() { + ReferencedJob next = jobIter.next(); + jobCount++; + return next.getJob(); + } + + @Override + public void remove() { + jobIter.remove(); + } + + } + + static class JobNeighborhoodsImpl implements JobNeighborhoods { + + private static Logger logger = Logger.getLogger(JobNeighborhoodsImpl.class); + + private VehicleRoutingProblem vrp; + + private Map> distanceNodeTree = new HashMap>(); + + private JobDistance jobDistance; + + public JobNeighborhoodsImpl(VehicleRoutingProblem vrp, JobDistance jobDistance) { + super(); + this.vrp = vrp; + this.jobDistance = jobDistance; + logger.info("intialise " + this); + } + + public Iterator getNearestNeighborsIterator(int nNeighbors, Job neighborTo){ + TreeSet tree = distanceNodeTree.get(neighborTo.getId()); + Iterator descendingIterator = tree.iterator(); + return new NeighborhoodIterator(descendingIterator, nNeighbors); + } + + public void initialise(){ + logger.info("calculates and memorizes distances from EACH job to EACH job --> n^2 calculations"); + calculateDistancesFromJob2Job(); + } + + private void calculateDistancesFromJob2Job() { + logger.info("preprocess distances between locations ..."); + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + int nuOfDistancesStored = 0; + for (Job i : vrp.getJobs().values()) { + TreeSet treeSet = new TreeSet( + new Comparator() { + @Override + public int compare(ReferencedJob o1, ReferencedJob o2) { + if (o1.getDistance() <= o2.getDistance()) { + return -1; + } else { + return 1; + } + } + }); + distanceNodeTree.put(i.getId(), treeSet); + for (Job j : vrp.getJobs().values()) { + if(i==j) continue; + double distance = jobDistance.getDistance(i, j); + ReferencedJob refNode = new ReferencedJob(j, distance); + treeSet.add(refNode); + nuOfDistancesStored++; + } + + } + stopWatch.stop(); + logger.info("preprocessing comp-time: " + stopWatch + "; nuOfDistances stored: " + nuOfDistancesStored + "; estimated memory: " + + (distanceNodeTree.keySet().size()*64+nuOfDistancesStored*92) + " bytes"); + } + + } + + static class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods { + + private static Logger logger = Logger.getLogger(JobNeighborhoodsImpl.class); + + private VehicleRoutingProblem vrp; + + private Map> distanceNodeTree = new HashMap>(); + + private JobDistance jobDistance; + + private int capacity; + + public JobNeighborhoodsImplWithCapRestriction(VehicleRoutingProblem vrp, JobDistance jobDistance, int capacity) { + super(); + this.vrp = vrp; + this.jobDistance = jobDistance; + this.capacity = capacity; + logger.info("intialise " + this); + } + + public Iterator getNearestNeighborsIterator(int nNeighbors, Job neighborTo){ + TreeSet tree = distanceNodeTree.get(neighborTo.getId()); + Iterator descendingIterator = tree.iterator(); + return new NeighborhoodIterator(descendingIterator, nNeighbors); + } + + public void initialise(){ + logger.info("calculates distances from EACH job to EACH job --> n^2="+Math.pow(vrp.getJobs().values().size(), 2) + " calculations, but 'only' "+(vrp.getJobs().values().size()*capacity)+ " are cached."); + calculateDistancesFromJob2Job(); + } + + private void calculateDistancesFromJob2Job() { + logger.info("preprocess distances between locations ..."); + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + int nuOfDistancesStored = 0; + for (Job i : vrp.getJobs().values()) { + TreeSet treeSet = new TreeSet( + new Comparator() { + @Override + public int compare(ReferencedJob o1, ReferencedJob o2) { + if (o1.getDistance() <= o2.getDistance()) { + return -1; + } else { + return 1; + } + } + }); + distanceNodeTree.put(i.getId(), treeSet); + for (Job j : vrp.getJobs().values()) { + if(i==j) continue; + double distance = jobDistance.getDistance(i, j); + ReferencedJob refNode = new ReferencedJob(j, distance); + if(treeSet.size() < capacity){ + treeSet.add(refNode); + nuOfDistancesStored++; + } + else{ + if(treeSet.last().getDistance() > distance){ + treeSet.pollLast(); + treeSet.add(refNode); + } + } + } + assert treeSet.size() <= capacity : "treeSet.size() is bigger than specified capacity"; + + } + stopWatch.stop(); + logger.info("preprocessing comp-time: " + stopWatch + "; nuOfDistances stored: " + nuOfDistancesStored + "; estimated memory: " + + (distanceNodeTree.keySet().size()*64+nuOfDistancesStored*92) + " bytes"); + } + + @Override + public String toString() { + return "[name=neighborhoodWithCapRestriction][capacity="+capacity+"]"; + } + + } + + static class ReferencedJob { private Job job; private double distance; @@ -74,14 +262,12 @@ final class RuinRadial implements RuinStrategy { private double fractionOfAllNodes2beRuined; - private Map> distanceNodeTree = new HashMap>(); - private Random random = RandomNumberGeneration.getRandom(); - private JobDistance jobDistance; - private RuinListeners ruinListeners; + private JobNeighborhoods jobNeighborhoods; + public void setRandom(Random random) { this.random = random; } @@ -96,41 +282,46 @@ final class RuinRadial implements RuinStrategy { public RuinRadial(VehicleRoutingProblem vrp, double fraction2beRemoved, JobDistance jobDistance) { super(); this.vrp = vrp; - this.jobDistance = jobDistance; this.fractionOfAllNodes2beRuined = fraction2beRemoved; ruinListeners = new RuinListeners(); - calculateDistancesFromJob2Job(); + int nJobsToMemorize = (int) Math.ceil(vrp.getJobs().values().size()*fraction2beRemoved); + JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, nJobsToMemorize); + jobNeighborhoodsImpl.initialise(); + jobNeighborhoods = jobNeighborhoodsImpl; logger.info("intialise " + this); - } - - private void calculateDistancesFromJob2Job() { - logger.info("preprocess distances between locations ..."); - StopWatch stopWatch = new StopWatch(); - stopWatch.start(); - int nuOfDistancesStored = 0; - for (Job i : vrp.getJobs().values()) { - TreeSet treeSet = new TreeSet( - new Comparator() { - @Override - public int compare(ReferencedJob o1, ReferencedJob o2) { - if (o1.getDistance() <= o2.getDistance()) { - return 1; - } else { - return -1; - } - } - }); - distanceNodeTree.put(i.getId(), treeSet); - for (Job j : vrp.getJobs().values()) { - double distance = jobDistance.getDistance(i, j); - ReferencedJob refNode = new ReferencedJob(j, distance); - treeSet.add(refNode); - nuOfDistancesStored++; - } - } - stopWatch.stop(); - logger.info("preprocessing comp-time: " + stopWatch + "; nuOfDistances stored: " + nuOfDistancesStored + "; estimated memory: " + - (distanceNodeTree.keySet().size()*64+nuOfDistancesStored*92) + " bytes"); +//<<<<<<< HEAD +// } +// +// private void calculateDistancesFromJob2Job() { +// logger.info("preprocess distances between locations ..."); +// StopWatch stopWatch = new StopWatch(); +// stopWatch.start(); +// int nuOfDistancesStored = 0; +// for (Job i : vrp.getJobs().values()) { +// TreeSet treeSet = new TreeSet( +// new Comparator() { +// @Override +// public int compare(ReferencedJob o1, ReferencedJob o2) { +// if (o1.getDistance() <= o2.getDistance()) { +// return 1; +// } else { +// return -1; +// } +// } +// }); +// distanceNodeTree.put(i.getId(), treeSet); +// for (Job j : vrp.getJobs().values()) { +// double distance = jobDistance.getDistance(i, j); +// ReferencedJob refNode = new ReferencedJob(j, distance); +// treeSet.add(refNode); +// nuOfDistancesStored++; +// } +// } +// stopWatch.stop(); +// logger.info("preprocessing comp-time: " + stopWatch + "; nuOfDistances stored: " + nuOfDistancesStored + "; estimated memory: " + +// (distanceNodeTree.keySet().size()*64+nuOfDistancesStored*92) + " bytes"); +//======= +//>>>>>>> refs/heads/master } @Override @@ -145,11 +336,11 @@ final class RuinRadial implements RuinStrategy { @Override public Collection ruin(Collection vehicleRoutes) { if(vehicleRoutes.isEmpty()){ - return Collections.EMPTY_LIST; + return Collections.emptyList(); } int nOfJobs2BeRemoved = getNuOfJobs2BeRemoved(); if (nOfJobs2BeRemoved == 0) { - return Collections.EMPTY_LIST; + return Collections.emptyList(); } Job randomJob = pickRandomJob(); Collection unassignedJobs = ruin(vehicleRoutes,randomJob,nOfJobs2BeRemoved); @@ -162,27 +353,30 @@ final class RuinRadial implements RuinStrategy { public Collection ruin(Collection vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved){ ruinListeners.ruinStarts(vehicleRoutes); List unassignedJobs = new ArrayList(); - TreeSet tree = distanceNodeTree.get(targetJob.getId()); - Iterator descendingIterator = tree.descendingIterator(); - int counter = 0; - while (descendingIterator.hasNext() && counter < nOfJobs2BeRemoved) { - ReferencedJob refJob = descendingIterator.next(); - Job job = refJob.getJob(); + int nNeighbors = nOfJobs2BeRemoved - 1; + removeJob(targetJob,vehicleRoutes); + unassignedJobs.add(targetJob); + Iterator neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(nNeighbors, targetJob); + while(neighborhoodIterator.hasNext()){ + Job job = neighborhoodIterator.next(); + removeJob(job,vehicleRoutes); unassignedJobs.add(job); - counter++; - boolean removed = false; - for (VehicleRoute route : vehicleRoutes) { - removed = route.getTourActivities().removeJob(job);; - if (removed) { - ruinListeners.removed(job,route); - break; - } - } } ruinListeners.ruinEnds(vehicleRoutes, unassignedJobs); return unassignedJobs; } + private void removeJob(Job job, Collection vehicleRoutes) { + boolean removed = false; + for (VehicleRoute route : vehicleRoutes) { + removed = route.getTourActivities().removeJob(job);; + if (removed) { + ruinListeners.removed(job,route); + break; + } + } + } + private Job pickRandomJob() { int totNuOfJobs = vrp.getJobs().values().size(); int randomIndex = random.nextInt(totNuOfJobs); diff --git a/jsprit-core/src/test/java/algorithms/JobNeighborhoodsImplTest.java b/jsprit-core/src/test/java/algorithms/JobNeighborhoodsImplTest.java new file mode 100644 index 00000000..9ba678b6 --- /dev/null +++ b/jsprit-core/src/test/java/algorithms/JobNeighborhoodsImplTest.java @@ -0,0 +1,110 @@ +package algorithms; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import util.Coordinate; +import algorithms.RuinRadial.JobNeighborhoodsImpl; +import basics.Job; +import basics.Service; +import basics.VehicleRoutingProblem; + +public class JobNeighborhoodsImplTest { + + 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", 1).setCoord(Coordinate.newInstance(0, 5)).build(); + s2 = Service.Builder.newInstance("s2", 1).setCoord(Coordinate.newInstance(0, 4)).build(); + s3 = Service.Builder.newInstance("s3", 1).setCoord(Coordinate.newInstance(0, 3)).build(); + s4 = Service.Builder.newInstance("s4", 1).setCoord(Coordinate.newInstance(0, 2)).build(); + + s5 = Service.Builder.newInstance("s5", 1).setCoord(Coordinate.newInstance(0, 6)).build(); + s6 = Service.Builder.newInstance("s6", 1).setCoord(Coordinate.newInstance(0, 7)).build(); + s7 = Service.Builder.newInstance("s7", 1).setCoord(Coordinate.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(){ + JobNeighborhoodsImpl jn = new JobNeighborhoodsImpl(vrp, jobDistance); + 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(){ + JobNeighborhoodsImpl jn = new JobNeighborhoodsImpl(vrp, jobDistance); + 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(){ + JobNeighborhoodsImpl jn = new JobNeighborhoodsImpl(vrp, jobDistance); + 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(){ + JobNeighborhoodsImpl jn = new JobNeighborhoodsImpl(vrp, jobDistance); + 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 whenRequestingMoreNeighborsThanExisting_itShouldReturnMaxNeighbors(){ + JobNeighborhoodsImpl jn = new JobNeighborhoodsImpl(vrp, jobDistance); + jn.initialise(); + Iterator iter = jn.getNearestNeighborsIterator(100, target); + List services = new ArrayList(); + while(iter.hasNext()){ + services.add((Service) iter.next()); + } + assertEquals(6,services.size()); + } + +} diff --git a/jsprit-core/src/test/java/algorithms/JobNeighborhoodsWithCapRestrictionImplTest.java b/jsprit-core/src/test/java/algorithms/JobNeighborhoodsWithCapRestrictionImplTest.java new file mode 100644 index 00000000..8f4bbc28 --- /dev/null +++ b/jsprit-core/src/test/java/algorithms/JobNeighborhoodsWithCapRestrictionImplTest.java @@ -0,0 +1,111 @@ +package algorithms; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; + +import util.Coordinate; +import algorithms.RuinRadial.JobNeighborhoodsImpl; +import algorithms.RuinRadial.JobNeighborhoodsImplWithCapRestriction; +import basics.Job; +import basics.Service; +import basics.VehicleRoutingProblem; + +public class JobNeighborhoodsWithCapRestrictionImplTest { + + 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", 1).setCoord(Coordinate.newInstance(0, 5)).build(); + s2 = Service.Builder.newInstance("s2", 1).setCoord(Coordinate.newInstance(0, 4)).build(); + s3 = Service.Builder.newInstance("s3", 1).setCoord(Coordinate.newInstance(0, 3)).build(); + s4 = Service.Builder.newInstance("s4", 1).setCoord(Coordinate.newInstance(0, 2)).build(); + + s5 = Service.Builder.newInstance("s5", 1).setCoord(Coordinate.newInstance(0, 6)).build(); + s6 = Service.Builder.newInstance("s6", 1).setCoord(Coordinate.newInstance(0, 7)).build(); + s7 = Service.Builder.newInstance("s7", 1).setCoord(Coordinate.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(){ + JobNeighborhoodsImplWithCapRestriction jn = new JobNeighborhoodsImplWithCapRestriction(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(){ + JobNeighborhoodsImplWithCapRestriction jn = new JobNeighborhoodsImplWithCapRestriction(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(){ + JobNeighborhoodsImplWithCapRestriction jn = new JobNeighborhoodsImplWithCapRestriction(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(){ + JobNeighborhoodsImplWithCapRestriction jn = new JobNeighborhoodsImplWithCapRestriction(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 whenRequestingMoreNeighborsThanExisting_itShouldReturnMaxNeighbors(){ + JobNeighborhoodsImplWithCapRestriction jn = new JobNeighborhoodsImplWithCapRestriction(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-examples/src/main/java/examples/ConfigureAlgorithmInCodeInsteadOfPerXml.java b/jsprit-examples/src/main/java/examples/ConfigureAlgorithmInCodeInsteadOfPerXml.java new file mode 100644 index 00000000..96497237 --- /dev/null +++ b/jsprit-examples/src/main/java/examples/ConfigureAlgorithmInCodeInsteadOfPerXml.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (C) 2013 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 . + ******************************************************************************/ +package examples; + +import java.io.File; +import java.util.Collection; + +import org.apache.commons.configuration.XMLConfiguration; + +import util.Coordinate; +import util.Solutions; +import algorithms.VehicleRoutingAlgorithms; +import analysis.SolutionPlotter; +import analysis.SolutionPrinter; +import analysis.SolutionPrinter.Print; +import basics.Service; +import basics.VehicleRoutingAlgorithm; +import basics.VehicleRoutingProblem; +import basics.VehicleRoutingProblemSolution; +import basics.io.AlgorithmConfig; +import basics.io.VrpXMLWriter; +import basics.route.Vehicle; +import basics.route.VehicleImpl; +import basics.route.VehicleImpl.Builder; +import basics.route.VehicleType; +import basics.route.VehicleTypeImpl; + +public class ConfigureAlgorithmInCodeInsteadOfPerXml { + + 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 a capacity of 2 + */ + VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType", 2); + VehicleType vehicleType = vehicleTypeBuilder.build(); + + /* + * get a vehicle-builder and build a vehicle located at (10,10) with type "vehicleType" + */ + Builder vehicleBuilder = VehicleImpl.Builder.newInstance("vehicle"); + vehicleBuilder.setLocationCoord(Coordinate.newInstance(10, 10)); + vehicleBuilder.setType(vehicleType); + Vehicle vehicle = vehicleBuilder.build(); + + /* + * build services at the required locations, each with a capacity-demand of 1. + */ + Service service1 = Service.Builder.newInstance("1", 1).setCoord(Coordinate.newInstance(5, 7)).build(); + Service service2 = Service.Builder.newInstance("2", 1).setCoord(Coordinate.newInstance(5, 13)).build(); + + Service service3 = Service.Builder.newInstance("3", 1).setCoord(Coordinate.newInstance(15, 7)).build(); + Service service4 = Service.Builder.newInstance("4", 1).setCoord(Coordinate.newInstance(15, 13)).build(); + + + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + vrpBuilder.addVehicle(vehicle); + vrpBuilder.addService(service1).addService(service2).addService(service3).addService(service4); + + VehicleRoutingProblem problem = vrpBuilder.build(); + + /* + * get the algorithm out-of-the-box. + */ + AlgorithmConfig algorithmConfig = getAlgorithmConfig(); + VehicleRoutingAlgorithm algorithm = VehicleRoutingAlgorithms.createAlgorithm(problem,algorithmConfig); + + /* + * and search a solution + */ + Collection solutions = algorithm.searchSolutions(); + + /* + * get the best + */ + VehicleRoutingProblemSolution bestSolution = Solutions.getBest(solutions); + + new VrpXMLWriter(problem, solutions).write("output/problem-with-solution.xml"); + + SolutionPrinter.print(bestSolution,Print.VERBOSE); + + /* + * plot + */ + SolutionPlotter.plotSolutionAsPNG(problem, bestSolution, "output/solution.png", "solution"); + } + + private static AlgorithmConfig getAlgorithmConfig() { + AlgorithmConfig config = new AlgorithmConfig(); + XMLConfiguration xmlConfig = config.getXMLConfiguration(); + xmlConfig.setProperty("iterations", 2000); + xmlConfig.setProperty("construction.insertion[@name]","bestInsertion"); + + xmlConfig.setProperty("strategy.memory", 1); + String searchStrategy = "strategy.searchStrategies.searchStrategy"; + + xmlConfig.setProperty(searchStrategy + "(0).selector[@name]","selectBest"); + xmlConfig.setProperty(searchStrategy + "(0).acceptor[@name]","acceptNewRemoveWorst"); + xmlConfig.setProperty(searchStrategy + "(0).modules.module(0)[@name]","ruin_and_recreate"); + xmlConfig.setProperty(searchStrategy + "(0).modules.module(0).ruin[@name]","randomRuin"); + xmlConfig.setProperty(searchStrategy + "(0).modules.module(0).ruin.share","0.3"); + xmlConfig.setProperty(searchStrategy + "(0).modules.module(0).insertion[@name]","bestInsertion"); + xmlConfig.setProperty(searchStrategy + "(0).probability","0.5"); + + xmlConfig.setProperty(searchStrategy + "(1).selector[@name]","selectBest"); + xmlConfig.setProperty(searchStrategy + "(1).acceptor[@name]","acceptNewRemoveWorst"); + xmlConfig.setProperty(searchStrategy + "(1).modules.module(0)[@name]","ruin_and_recreate"); + xmlConfig.setProperty(searchStrategy + "(1).modules.module(0).ruin[@name]","radialRuin"); + xmlConfig.setProperty(searchStrategy + "(1).modules.module(0).ruin.share","0.15"); + xmlConfig.setProperty(searchStrategy + "(1).modules.module(0).insertion[@name]","bestInsertion"); + xmlConfig.setProperty(searchStrategy + "(1).probability","0.5"); + + return config; + } + +} diff --git a/pom.xml b/pom.xml index 3b3c5309..4d8a5078 100644 --- a/pom.xml +++ b/pom.xml @@ -34,8 +34,8 @@ - GNU General Public License, version 2 (GPL-2.0) - http://opensource.org/licenses/GPL-2.0 + GNU Lesser General Public Licence, version 3.0 + http://opensource.org/licenses/LGPL-3.0