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

refine string removal

This commit is contained in:
oblonski 2017-01-18 19:43:52 +01:00
parent 142c3beff6
commit 25fe083809
No known key found for this signature in database
GPG key ID: 179DE487285680D1
8 changed files with 960 additions and 264 deletions

View file

@ -82,7 +82,9 @@ public class Jsprit {
WORST_BEST("worst_best"), WORST_BEST("worst_best"),
WORST_REGRET("worst_regret"), WORST_REGRET("worst_regret"),
CLUSTER_BEST("cluster_best"), CLUSTER_BEST("cluster_best"),
CLUSTER_REGRET("cluster_regret"); CLUSTER_REGRET("cluster_regret"),
STRING_BEST("string_best"),
STRING_REGRET("string_regret");
String strategyName; String strategyName;
@ -178,6 +180,10 @@ public class Jsprit {
defaults.put(Strategy.RADIAL_REGRET.toString(), ".5"); defaults.put(Strategy.RADIAL_REGRET.toString(), ".5");
defaults.put(Strategy.RANDOM_BEST.toString(), ".5"); defaults.put(Strategy.RANDOM_BEST.toString(), ".5");
defaults.put(Strategy.RANDOM_REGRET.toString(), ".5"); defaults.put(Strategy.RANDOM_REGRET.toString(), ".5");
defaults.put(Strategy.STRING_BEST.toString(), ".5");
defaults.put(Strategy.STRING_REGRET.toString(), ".5");
defaults.put(Strategy.WORST_BEST.toString(), "0."); defaults.put(Strategy.WORST_BEST.toString(), "0.");
defaults.put(Strategy.WORST_REGRET.toString(), "1."); defaults.put(Strategy.WORST_REGRET.toString(), "1.");
defaults.put(Strategy.CLUSTER_BEST.toString(), "0."); defaults.put(Strategy.CLUSTER_BEST.toString(), "0.");
@ -472,6 +478,9 @@ public class Jsprit {
random) random)
); );
final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods);
stringRuin.setRandom(random);
AbstractInsertionStrategy regret; AbstractInsertionStrategy regret;
final ScoringFunction scorer; final ScoringFunction scorer;
@ -592,6 +601,11 @@ public class Jsprit {
final SearchStrategy clusters_best = new SearchStrategy(Strategy.CLUSTER_BEST.toString(), new SelectBest(), acceptor, objectiveFunction); final SearchStrategy clusters_best = new SearchStrategy(Strategy.CLUSTER_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
clusters_best.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_BEST.toString(), best, clusters)); clusters_best.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_BEST.toString(), best, clusters));
SearchStrategy stringRegret = new SearchStrategy(Strategy.STRING_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction);
stringRegret.addModule(new RuinAndRecreateModule(Strategy.STRING_REGRET.toString(), regret, stringRuin));
SearchStrategy stringBest = new SearchStrategy(Strategy.STRING_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
stringBest.addModule(new RuinAndRecreateModule(Strategy.STRING_BEST.toString(), best, stringRuin));
PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fm, stateManager, constraintManager); PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fm, stateManager, constraintManager);
prettyBuilder.setRandom(random); prettyBuilder.setRandom(random);
@ -605,7 +619,10 @@ public class Jsprit {
.withStrategy(worst_best, toDouble(getProperty(Strategy.WORST_BEST.toString()))) .withStrategy(worst_best, toDouble(getProperty(Strategy.WORST_BEST.toString())))
.withStrategy(worst_regret, toDouble(getProperty(Strategy.WORST_REGRET.toString()))) .withStrategy(worst_regret, toDouble(getProperty(Strategy.WORST_REGRET.toString())))
.withStrategy(clusters_regret, toDouble(getProperty(Strategy.CLUSTER_REGRET.toString()))) .withStrategy(clusters_regret, toDouble(getProperty(Strategy.CLUSTER_REGRET.toString())))
.withStrategy(clusters_best, toDouble(getProperty(Strategy.CLUSTER_BEST.toString()))); .withStrategy(clusters_best, toDouble(getProperty(Strategy.CLUSTER_BEST.toString())))
.withStrategy(stringBest, toDouble(getProperty(Strategy.STRING_BEST.toString())))
.withStrategy(stringRegret, toDouble(getProperty(Strategy.STRING_REGRET.toString())));
if (getProperty(Parameter.CONSTRUCTION.toString()).equals(Construction.BEST_INSERTION.toString())) { if (getProperty(Parameter.CONSTRUCTION.toString()).equals(Construction.BEST_INSERTION.toString())) {
prettyBuilder.constructInitialSolutionWith(best, objectiveFunction); prettyBuilder.constructInitialSolutionWith(best, objectiveFunction);
} else { } else {

View file

@ -0,0 +1,231 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.ruin;
import com.graphhopper.jsprit.core.algorithm.ruin.distance.JobDistance;
import com.graphhopper.jsprit.core.problem.AbstractActivity;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.job.Job;
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.util.RandomUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* RuinStrategy that ruins the neighborhood of a randomly selected job. The size and the structure of the neighborhood is defined by
* the share of jobs to be removed and the distance between jobs (where distance not necessarily mean Euclidean distance but an arbitrary
* measure).
*
* @author stefan
*/
public final class RuinString extends AbstractRuinStrategy {
private Logger logger = LoggerFactory.getLogger(RuinString.class);
private VehicleRoutingProblem vrp;
private JobNeighborhoods jobNeighborhoods;
private int Kmin = 1;
private int Kmax = 6;
private int Lmin = 1;
private int Lmax = 40;
/**
* Constructs RuinRadial.
*
* @param vrp
* @param jobDistance i.e. a measure to define the distance between two jobs and whether they are located close or distant to eachother
* @param Kmin
* @param Kmax
* @param Lmin
* @param Lmax
*/
public RuinString(VehicleRoutingProblem vrp, JobDistance jobDistance, int Kmin, int Kmax, int Lmin, int Lmax) {
super(vrp);
this.vrp = vrp;
JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, Kmax * Lmax);
jobNeighborhoodsImpl.initialise();
jobNeighborhoods = jobNeighborhoodsImpl;
this.Kmin = Kmin;
this.Kmax = Kmax;
this.Lmin = Lmin;
this.Lmax = Lmax;
logger.debug("initialise {}", this);
}
public RuinString(VehicleRoutingProblem vrp, JobDistance jobDistance) {
super(vrp);
this.vrp = vrp;
JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, Kmax * Lmax);
jobNeighborhoodsImpl.initialise();
jobNeighborhoods = jobNeighborhoodsImpl;
logger.debug("initialise {}", this);
}
public RuinString(VehicleRoutingProblem vrp, JobNeighborhoods jobNeighborhoods) {
super(vrp);
this.vrp = vrp;
this.jobNeighborhoods = jobNeighborhoods;
logger.debug("initialise {}", this);
}
@Override
public String toString() {
return "[name=splitRuin]";
}
/**
* Ruins the collection of vehicleRoutes, i.e. removes a share of jobs. First, it selects a job randomly. Second, it identifies its neighborhood. And finally, it removes
* the neighborhood plus the randomly selected job from the number of vehicleRoutes. All removed jobs are then returned as a collection.
*/
@Override
public Collection<Job> ruinRoutes(Collection<VehicleRoute> vehicleRoutes) {
if (vehicleRoutes.isEmpty() || vrp.getJobs().isEmpty()) {
return Collections.emptyList();
}
int noStrings = Kmin + random.nextInt((Kmax - Kmin));
noStrings = Math.min(noStrings, vehicleRoutes.size());
Set<Job> unassignedJobs = new HashSet<>();
Set<VehicleRoute> ruinedRoutes = new HashSet<>();
Job prevJob = RandomUtils.nextJob(vrp.getJobs().values(), random);
Iterator<Job> neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(Kmax * Lmax, prevJob);
while (neighborhoodIterator.hasNext() && ruinedRoutes.size() <= noStrings) {
if (!unassignedJobs.contains(prevJob)) {
VehicleRoute route = getRouteOf(prevJob, vehicleRoutes);
if (route != null && !ruinedRoutes.contains(route)) {
if (random.nextDouble() < .5) {
ruinRouteWithStringRuin(route, prevJob, unassignedJobs);
} else {
ruinRouteWithSplitStringRuin(route, prevJob, unassignedJobs);
}
ruinedRoutes.add(route);
}
}
prevJob = neighborhoodIterator.next();
}
return unassignedJobs;
}
private VehicleRoute getRouteOf(Job job, Collection<VehicleRoute> vehicleRoutes) {
for (VehicleRoute route : vehicleRoutes) {
if (route.getTourActivities().servesJob(job)) return route;
}
return null;
}
private void ruinRouteWithSplitStringRuin(VehicleRoute seedRoute, Job prevJob, Set<Job> unassignedJobs) {
int noActivities = seedRoute.getActivities().size();
int stringLength = Lmin + random.nextInt(Lmax - Lmin);
stringLength = Math.min(stringLength, seedRoute.getActivities().size());
int preservedSubstringLength = StringUtil.determineSubstringLength(stringLength, noActivities, random);
List<AbstractActivity> acts = vrp.getActivities(prevJob);
AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random);
int seedIndex = 0;
int index = 0;
for (TourActivity act : seedRoute.getActivities()) {
if (act.getIndex() == randomSeedAct.getIndex()) {
seedIndex = index;
break;
}
index++;
}
int totalStringLength = stringLength + preservedSubstringLength;
List<Integer> stringBounds = StringUtil.getLowerBoundsOfAllStrings(totalStringLength, seedIndex, noActivities);
if (stringBounds.isEmpty()) return;
int lowerBound = RandomUtils.nextItem(stringBounds, random);
List<Job> jobs2Remove = new ArrayList<>();
int startIndexOfPreservedSubstring = random.nextInt(stringLength);
int position = 0;
int noStringsInPreservedSubstring = 0;
boolean isPreservedSubstring = false;
for (int i = lowerBound; i < (lowerBound + totalStringLength); i++) {
if (position == startIndexOfPreservedSubstring) {
isPreservedSubstring = true;
}
if (noStringsInPreservedSubstring >= preservedSubstringLength) {
isPreservedSubstring = false;
}
if (!isPreservedSubstring) {
TourActivity act = seedRoute.getActivities().get(i);
if (act instanceof TourActivity.JobActivity) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (vrp.getJobs().containsKey(job.getId())) {
jobs2Remove.add(job);
}
}
} else noStringsInPreservedSubstring++;
position++;
}
for (Job job : jobs2Remove) {
removeJob(job, seedRoute);
unassignedJobs.add(job);
}
}
private void ruinRouteWithStringRuin(VehicleRoute seedRoute, Job prevJob, Set<Job> unassignedJobs) {
int stringLength = Lmin + random.nextInt(Lmax - Lmin);
stringLength = Math.min(stringLength, seedRoute.getActivities().size());
List<AbstractActivity> acts = vrp.getActivities(prevJob);
AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random);
int seedIndex = 0;
int noActivities = seedRoute.getActivities().size();
int index = 0;
for (TourActivity act : seedRoute.getActivities()) {
if (act.getIndex() == randomSeedAct.getIndex()) {
seedIndex = index;
break;
}
index++;
}
List<Integer> stringBounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
if (stringBounds.isEmpty()) return;
int lowerBound = RandomUtils.nextItem(stringBounds, random);
List<Job> jobs2Remove = new ArrayList<>();
for (int i = lowerBound; i < (lowerBound + stringLength); i++) {
TourActivity act = seedRoute.getActivities().get(i);
if (act instanceof TourActivity.JobActivity) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (vrp.getJobs().containsKey(job.getId())) {
jobs2Remove.add(job);
}
}
}
for (Job job : jobs2Remove) {
removeJob(job, seedRoute);
unassignedJobs.add(job);
}
}
}

View file

@ -0,0 +1,52 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.ruin;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Created by schroeder on 13/01/17.
*/
class StringUtil {
static List<Integer> getLowerBoundsOfAllStrings(int length, int seedIndex, int routeLength) {
List<Integer> lowerBounds = new ArrayList<>();
for (int i = 1; i <= length; i++) {
int lower = seedIndex - (length - i);
int upper = seedIndex + (i - 1);
if (lower >= 0 && upper < routeLength) {
lowerBounds.add(lower);
}
}
return lowerBounds;
}
static int determineSubstringLength(int baseLength, int routeLength, Random random) {
if (baseLength == routeLength) return 0;
int substringLength = 1;
while (baseLength + substringLength < routeLength) {
if (random.nextDouble() < 0.01) {
return substringLength;
} else substringLength++;
}
return substringLength;
}
}

View file

@ -0,0 +1,87 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.core.algorithm.ruin;
import org.junit.Assert;
import org.junit.Test;
import java.util.List;
/**
* Created by schroeder on 13/01/17.
*/
public class StringUtilTest {
@Test
public void test() {
int stringLength = 4;
int seedIndex = 4;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(4, bounds.size());
Assert.assertEquals(1, (int) bounds.get(0));
Assert.assertEquals(2, (int) bounds.get(1));
Assert.assertEquals(3, (int) bounds.get(2));
Assert.assertEquals(4, (int) bounds.get(3));
}
@Test
public void test2() {
int stringLength = 4;
int seedIndex = 2;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(3, bounds.size());
Assert.assertEquals(0, (int) bounds.get(0));
Assert.assertEquals(1, (int) bounds.get(1));
Assert.assertEquals(2, (int) bounds.get(2));
}
@Test
public void test3() {
int stringLength = 4;
int seedIndex = 0;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(1, bounds.size());
Assert.assertEquals(0, (int) bounds.get(0));
}
@Test
public void test4() {
int stringLength = 4;
int seedIndex = 9;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(1, bounds.size());
Assert.assertEquals(6, (int) bounds.get(0));
}
@Test
public void test5() {
int stringLength = 4;
int seedIndex = 8;
int noActivities = 10;
List<Integer> bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities);
Assert.assertEquals(2, bounds.size());
Assert.assertEquals(5, (int) bounds.get(0));
Assert.assertEquals(6, (int) bounds.get(1));
}
}

View file

@ -0,0 +1,56 @@
2 4 50 4
0 2000
1 37 52 0 7 1 4 1 2 4 8
2 49 49 0 30 1 4 1 2 4 8
3 52 64 0 16 1 4 1 2 4 8
4 20 26 0 9 1 4 1 2 4 8
5 40 30 0 21 1 4 1 2 4 8
6 21 47 0 15 1 4 1 2 4 8
7 17 63 0 19 1 4 1 2 4 8
8 31 62 0 23 1 4 1 2 4 8
9 52 33 0 11 1 4 1 2 4 8
10 51 21 0 5 1 4 1 2 4 8
11 42 41 0 19 1 4 1 2 4 8
12 31 32 0 29 1 4 1 2 4 8
13 5 25 0 23 1 4 1 2 4 8
14 12 42 0 21 1 4 1 2 4 8
15 36 16 0 10 1 4 1 2 4 8
16 52 41 0 15 1 4 1 2 4 8
17 27 23 0 3 1 4 1 2 4 8
18 17 33 0 41 1 4 1 2 4 8
19 13 13 0 9 1 4 1 2 4 8
20 57 58 0 28 1 4 1 2 4 8
21 62 42 0 8 1 4 1 2 4 8
22 42 57 0 8 1 4 1 2 4 8
23 16 57 0 16 1 4 1 2 4 8
24 8 52 0 10 1 4 1 2 4 8
25 7 38 0 28 1 4 1 2 4 8
26 27 68 0 7 1 4 1 2 4 8
27 30 48 0 15 1 4 1 2 4 8
28 43 67 0 14 1 4 1 2 4 8
29 58 48 0 6 1 4 1 2 4 8
30 58 27 0 19 1 4 1 2 4 8
31 37 69 0 11 1 4 1 2 4 8
32 38 46 0 12 1 4 1 2 4 8
33 46 10 0 23 1 4 1 2 4 8
34 61 33 0 26 1 4 1 2 4 8
35 62 63 0 17 1 4 1 2 4 8
36 63 69 0 6 1 4 1 2 4 8
37 32 22 0 9 1 4 1 2 4 8
38 45 35 0 15 1 4 1 2 4 8
39 59 15 0 14 1 4 1 2 4 8
40 5 6 0 7 1 4 1 2 4 8
41 10 17 0 27 1 4 1 2 4 8
42 21 10 0 13 1 4 1 2 4 8
43 5 64 0 11 1 4 1 2 4 8
44 30 15 0 16 1 4 1 2 4 8
45 39 10 0 10 1 4 1 2 4 8
46 32 39 0 5 1 4 1 2 4 8
47 25 32 0 25 1 4 1 2 4 8
48 25 55 0 17 1 4 1 2 4 8
49 48 28 0 18 1 4 1 2 4 8
50 56 37 0 10 1 4 1 2 4 8
51 20 20 0 0 0 0
52 30 40 0 0 0 0
53 50 30 0 0 0 0
54 60 50 0 0 0 0

View file

@ -20,7 +20,6 @@ package com.graphhopper.jsprit.examples;
import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsRecorder; import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsRecorder;
import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsViewer;
import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder; import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder;
import com.graphhopper.jsprit.core.algorithm.SearchStrategy; import com.graphhopper.jsprit.core.algorithm.SearchStrategy;
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
@ -116,17 +115,18 @@ public class BuildAlgorithmFromScratch {
final VehicleRoutingProblem vrp = vrpBuilder.build(); final VehicleRoutingProblem vrp = vrpBuilder.build();
VehicleRoutingAlgorithm vra = createAlgorithm(vrp); VehicleRoutingAlgorithm vra = createAlgorithm(vrp);
vra.setMaxIterations(100); vra.setMaxIterations(2000);
AlgorithmEventsRecorder eventsRecorder = new AlgorithmEventsRecorder(vrp, "output/events.dgs.gz"); AlgorithmEventsRecorder eventsRecorder = new AlgorithmEventsRecorder(vrp, "output/events.dgs.gz");
eventsRecorder.setRecordingRange(90, 100); eventsRecorder.setRecordingRange(90, 100);
vra.addListener(eventsRecorder); vra.addListener(eventsRecorder);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE); SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE);
AlgorithmEventsViewer viewer = new AlgorithmEventsViewer();
viewer.setRuinDelay(3); // AlgorithmEventsViewer viewer = new AlgorithmEventsViewer();
viewer.setRecreationDelay(1); // viewer.setRuinDelay(3);
viewer.display("output/events.dgs.gz"); // viewer.setRecreationDelay(1);
// viewer.display("output/events.dgs.gz");
} }
@ -146,10 +146,11 @@ public class BuildAlgorithmFromScratch {
//regret insertion //regret insertion
InsertionBuilder iBuilder = new InsertionBuilder(vrp, fleetManager, stateManager, constraintManager); InsertionBuilder iBuilder = new InsertionBuilder(vrp, fleetManager, stateManager, constraintManager);
iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET); iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET);
iBuilder.setFastRegret(true);
RegretInsertionFast regret = (RegretInsertionFast) iBuilder.build(); RegretInsertionFast regret = (RegretInsertionFast) iBuilder.build();
DefaultScorer scoringFunction = new DefaultScorer(vrp); DefaultScorer scoringFunction = new DefaultScorer(vrp);
scoringFunction.setDepotDistanceParam(0.2); scoringFunction.setDepotDistanceParam(0.0);
scoringFunction.setTimeWindowParam(-.2); scoringFunction.setTimeWindowParam(0.0);
regret.setScoringFunction(scoringFunction); regret.setScoringFunction(scoringFunction);
/* /*

View file

@ -0,0 +1,252 @@
/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.jsprit.examples;
import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsRecorder;
import com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer;
import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder;
import com.graphhopper.jsprit.core.algorithm.SearchStrategy;
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
import com.graphhopper.jsprit.core.algorithm.acceptor.SchrimpfAcceptance;
import com.graphhopper.jsprit.core.algorithm.box.Jsprit;
import com.graphhopper.jsprit.core.algorithm.listener.IterationStartsListener;
import com.graphhopper.jsprit.core.algorithm.module.RuinAndRecreateModule;
import com.graphhopper.jsprit.core.algorithm.recreate.*;
import com.graphhopper.jsprit.core.algorithm.ruin.RadialRuinStrategyFactory;
import com.graphhopper.jsprit.core.algorithm.ruin.RandomRuinStrategyFactory;
import com.graphhopper.jsprit.core.algorithm.ruin.RuinStrategy;
import com.graphhopper.jsprit.core.algorithm.ruin.RuinString;
import com.graphhopper.jsprit.core.algorithm.ruin.distance.AvgServiceAndShipmentDistance;
import com.graphhopper.jsprit.core.algorithm.selector.SelectBest;
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
import com.graphhopper.jsprit.core.analysis.SolutionAnalyser;
import com.graphhopper.jsprit.core.problem.Location;
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
import com.graphhopper.jsprit.core.problem.cost.TransportDistance;
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;
import com.graphhopper.jsprit.core.problem.vehicle.FiniteFleetManagerFactory;
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager;
import com.graphhopper.jsprit.core.reporting.SolutionPrinter;
import com.graphhopper.jsprit.core.util.Solutions;
import com.graphhopper.jsprit.instance.reader.CordeauReader;
import com.graphhopper.jsprit.util.Examples;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class BuildAlgorithmFromScratch2 {
public static class MyBestStrategy extends AbstractInsertionStrategy {
private JobInsertionCostsCalculatorLight insertionCalculator;
public MyBestStrategy(VehicleRoutingProblem vrp, VehicleFleetManager fleetManager, StateManager stateManager, ConstraintManager constraintManager) {
super(vrp);
insertionCalculator = JobInsertionCostsCalculatorLightFactory.createStandardCalculator(vrp, fleetManager, stateManager, constraintManager);
}
@Override
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
List<Job> badJobs = new ArrayList<Job>();
List<Job> unassigned = new ArrayList<Job>(unassignedJobs);
Collections.shuffle(unassigned, random);
for (Job j : unassigned) {
InsertionData bestInsertionData = InsertionData.createEmptyInsertionData();
VehicleRoute bestRoute = null;
//look for inserting unassigned job into existing route
for (VehicleRoute r : vehicleRoutes) {
InsertionData insertionData = insertionCalculator.getInsertionData(j, r, bestInsertionData.getInsertionCost());
if (insertionData instanceof InsertionData.NoInsertionFound) continue;
if (insertionData.getInsertionCost() < bestInsertionData.getInsertionCost()) {
bestInsertionData = insertionData;
bestRoute = r;
}
}
//try whole new route
VehicleRoute empty = VehicleRoute.emptyRoute();
InsertionData insertionData = insertionCalculator.getInsertionData(j, empty, bestInsertionData.getInsertionCost());
if (!(insertionData instanceof InsertionData.NoInsertionFound)) {
if (insertionData.getInsertionCost() < bestInsertionData.getInsertionCost()) {
vehicleRoutes.add(empty);
insertJob(j, insertionData, empty);
}
} else {
if (bestRoute != null) insertJob(j, bestInsertionData, bestRoute);
else badJobs.add(j);
}
}
return badJobs;
}
}
public static void main(String[] args) {
Examples.createOutputFolder();
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
new CordeauReader(vrpBuilder).read("input/p11");
final VehicleRoutingProblem vrp = vrpBuilder.build();
// VehicleRoutingAlgorithm vra = createAlgorithm(vrp);
VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setProperty(Jsprit.Parameter.FAST_REGRET, "true")
.setProperty(Jsprit.Parameter.THREADS, "4")
.setProperty(Jsprit.Parameter.REGRET_DISTANCE_SCORER, "0.0001")
.setProperty(Jsprit.Strategy.STRING_BEST, "0.2")
.setProperty(Jsprit.Strategy.STRING_REGRET, "0.2")
.buildAlgorithm();
vra.setMaxIterations(15000);
AlgorithmEventsRecorder eventsRecorder = new AlgorithmEventsRecorder(vrp, "output/events.dgs.gz");
eventsRecorder.setRecordingRange(40, 100);
// vra.addListener(eventsRecorder);
VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE);
new GraphStreamViewer(vrp, solution).display();
// AlgorithmEventsViewer viewer = new AlgorithmEventsViewer();
// viewer.setRuinDelay(6);
// viewer.setRecreationDelay(1);
// viewer.display("output/events.dgs.gz");
}
public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp) {
VehicleFleetManager fleetManager = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
StateManager stateManager = new StateManager(vrp);
ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
/*
* insertion strategies
*/
//my custom best insertion
MyBestStrategy best = new MyBestStrategy(vrp, fleetManager, stateManager, constraintManager);
//regret insertion
InsertionBuilder iBuilder = new InsertionBuilder(vrp, fleetManager, stateManager, constraintManager);
iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET);
iBuilder.setFastRegret(true);
RegretInsertionFast regret = (RegretInsertionFast) iBuilder.build();
DefaultScorer scoringFunction = new DefaultScorer(vrp);
scoringFunction.setDepotDistanceParam(0.00001);
scoringFunction.setTimeWindowParam(0);
regret.setScoringFunction(scoringFunction);
/*
* ruin strategies
*/
RuinStrategy randomRuin = new RandomRuinStrategyFactory(0.5).createStrategy(vrp);
RuinStrategy radialRuin = new RadialRuinStrategyFactory(0.3, new AvgServiceAndShipmentDistance(vrp.getTransportCosts())).createStrategy(vrp);
/*
* objective function
*/
RuinStrategy stringRuin = new RuinString(vrp, new AvgServiceAndShipmentDistance(vrp.getTransportCosts()));
SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp);
final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1, 0.15);
IterationStartsListener schrimpfThreshold = new IterationStartsListener() {
@Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
if (i == 1) {
double initialThreshold = Solutions.bestOf(solutions).getCost() * 0.03;
schrimpfAcceptance.setInitialThreshold(initialThreshold);
}
}
};
SearchStrategy firstStrategy = new SearchStrategy("firstStrategy", new SelectBest(), schrimpfAcceptance, objectiveFunction);
firstStrategy.addModule(new RuinAndRecreateModule("randRuinRegretIns", regret, stringRuin));
// SearchStrategy secondStrategy = new SearchStrategy("secondStrategy", new SelectBest(), new GreedyAcceptance(1), objectiveFunction);
// secondStrategy.addModule(new RuinAndRecreateModule("radRuinRegretIns", regret, radialRuin));
// SearchStrategy thirdStrategy = new SearchStrategy("thirdStrategy", new SelectBest(), new GreedyAcceptance(1), objectiveFunction);
// secondStrategy.addModule(new RuinAndRecreateModule("radRuinBestIns", regret, radialRuin));
PrettyAlgorithmBuilder prettyAlgorithmBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fleetManager, stateManager, constraintManager);
final VehicleRoutingAlgorithm vra = prettyAlgorithmBuilder
.withStrategy(firstStrategy, 0.5)
// .withStrategy(secondStrategy, 0.5).withStrategy(thirdStrategy, 0.2)
.addCoreStateAndConstraintStuff()
.constructInitialSolutionWith(regret, objectiveFunction)
.build();
//if you want to switch on/off strategies or adapt their weight within the search, you can do the following
//e.g. from iteration 50 on, switch off first strategy
//switch on again at iteration 90 with slightly higher weight
// IterationStartsListener strategyAdaptor = new IterationStartsListener() {
// @Override
// public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
// if (i == 50) {
// vra.getSearchStrategyManager().informStrategyWeightChanged("firstStrategy", 0.0);
// System.out.println("switched off firstStrategy");
// }
// if (i == 90) {
// vra.getSearchStrategyManager().informStrategyWeightChanged("firstStrategy", 0.7);
// System.out.println("switched on firstStrategy again with higher weight");
// }
// }
// };
// vra.addListener(strategyAdaptor);
vra.addListener(schrimpfThreshold);
vra.addListener(schrimpfAcceptance);
return vra;
}
private static SolutionCostCalculator getObjectiveFunction(final VehicleRoutingProblem vrp) {
return new SolutionCostCalculator() {
@Override
public double getCosts(VehicleRoutingProblemSolution solution) {
SolutionAnalyser analyser = new SolutionAnalyser(vrp, solution, new TransportDistance() {
@Override
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
return vrp.getTransportCosts().getTransportCost(from, to, 0., null, null);
}
});
return analyser.getVariableTransportCosts() + solution.getUnassignedJobs().size() * 500.;
}
};
}
}