Skip to content

Commit 2c5a16b

Browse files
committed
add new ruin strategy
1 parent 9998417 commit 2c5a16b

File tree

3 files changed

+265
-8
lines changed

3 files changed

+265
-8
lines changed

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java

+29-8
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ public enum Strategy {
8282
CLUSTER_BEST("cluster_best"),
8383
CLUSTER_REGRET("cluster_regret"),
8484
STRING_BEST("string_best"),
85-
STRING_REGRET("string_regret");
85+
STRING_REGRET("string_regret"),
86+
TIME_RELATED_REGRET("time_related_regret"),
87+
TIME_RELATED_BEST("time_related_best");
88+
8689

8790
String strategyName;
8891

@@ -189,6 +192,10 @@ private Properties createDefaultProperties() {
189192
Properties defaults = new Properties();
190193
defaults.put(Strategy.RADIAL_BEST.toString(), "0.");
191194
defaults.put(Strategy.RADIAL_REGRET.toString(), ".5");
195+
196+
defaults.put(Strategy.TIME_RELATED_BEST.toString(), "0.");
197+
defaults.put(Strategy.TIME_RELATED_REGRET.toString(), "0.");
198+
192199
defaults.put(Strategy.RANDOM_BEST.toString(), ".5");
193200
defaults.put(Strategy.RANDOM_REGRET.toString(), ".5");
194201

@@ -466,18 +473,18 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
466473

467474
RuinRadial radial = new RuinRadial(vrp, vrp.getJobs().size(), jobNeighborhoods);
468475
radial.setRandom(random);
469-
radial.setRuinShareFactory(new RuinShareFactoryImpl(
476+
RuinShareFactoryImpl radialRuinFactory = new RuinShareFactoryImpl(
470477
toInteger(properties.getProperty(Parameter.RADIAL_MIN_SHARE.toString())),
471478
toInteger(properties.getProperty(Parameter.RADIAL_MAX_SHARE.toString())),
472-
random)
473-
);
479+
random);
480+
radial.setRuinShareFactory(radialRuinFactory);
474481

475482
final RuinRandom random_for_regret = new RuinRandom(vrp, 0.5);
476483
random_for_regret.setRandom(random);
477484
random_for_regret.setRuinShareFactory(new RuinShareFactoryImpl(
478-
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MIN_SHARE.toString())),
479-
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MAX_SHARE.toString())),
480-
random)
485+
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MIN_SHARE.toString())),
486+
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MAX_SHARE.toString())),
487+
random)
481488
);
482489

483490
final RuinRandom random_for_best = new RuinRandom(vrp, 0.5);
@@ -521,12 +528,16 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
521528
stringRuin.setStringLength(lMin, lMax);
522529
stringRuin.setRandom(random);
523530

531+
final RuinTimeRelated ruinTimeRelated = new RuinTimeRelated(vrp);
532+
ruinTimeRelated.setRuinShareFactory(radialRuinFactory);
533+
ruinTimeRelated.setRandom(random);
534+
524535
AbstractInsertionStrategy regret;
525536
final ScoringFunction scorer;
526537

527538
boolean fastRegret = Boolean.parseBoolean(getProperty(Parameter.FAST_REGRET.toString()));
528539
if (es != null) {
529-
if(fastRegret){
540+
if (fastRegret) {
530541
RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionStrategyBuilder(vrp, vehicleFleetManager, stateManager, constraintManager)
531542
.setInsertionStrategy(InsertionStrategyBuilder.Strategy.REGRET)
532543
.setConcurrentMode(es, noThreads)
@@ -624,6 +635,12 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
624635
SearchStrategy radialBest = new SearchStrategy(Strategy.RADIAL_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
625636
radialBest.addModule(configureModule(new RuinAndRecreateModule(Strategy.RADIAL_BEST.toString(), best, radial)));
626637

638+
SearchStrategy timeRelatedRegret = new SearchStrategy(Strategy.TIME_RELATED_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction);
639+
timeRelatedRegret.addModule(configureModule(new RuinAndRecreateModule(Strategy.TIME_RELATED_REGRET.toString(), regret, ruinTimeRelated)));
640+
641+
SearchStrategy timeRelatedBest = new SearchStrategy(Strategy.TIME_RELATED_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
642+
timeRelatedBest.addModule(configureModule(new RuinAndRecreateModule(Strategy.TIME_RELATED_BEST.toString(), best, ruinTimeRelated)));
643+
627644
SearchStrategy randomBest = new SearchStrategy(Strategy.RANDOM_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
628645
randomBest.addModule(configureModule(new RuinAndRecreateModule(Strategy.RANDOM_BEST.toString(), best, random_for_best)));
629646

@@ -655,6 +672,10 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
655672
}
656673
prettyBuilder.withStrategy(radialRegret, toDouble(getProperty(Strategy.RADIAL_REGRET.toString())))
657674
.withStrategy(radialBest, toDouble(getProperty(Strategy.RADIAL_BEST.toString())))
675+
676+
.withStrategy(timeRelatedBest, toDouble(getProperty(Strategy.TIME_RELATED_BEST.toString())))
677+
.withStrategy(timeRelatedRegret, toDouble(getProperty(Strategy.TIME_RELATED_REGRET.toString())))
678+
658679
.withStrategy(randomBest, toDouble(getProperty(Strategy.RANDOM_BEST.toString())))
659680
.withStrategy(randomRegret, toDouble(getProperty(Strategy.RANDOM_REGRET.toString())))
660681
.withStrategy(worstBest, toDouble(getProperty(Strategy.WORST_BEST.toString())))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
/*
2+
* Licensed to GraphHopper GmbH under one or more contributor
3+
* license agreements. See the NOTICE file distributed with this work for
4+
* additional information regarding copyright ownership.
5+
*
6+
* GraphHopper GmbH licenses this file to you under the Apache License,
7+
* Version 2.0 (the "License"); you may not use this file except in
8+
* compliance with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package com.graphhopper.jsprit.core.algorithm.ruin;
19+
20+
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
21+
import com.graphhopper.jsprit.core.problem.job.Job;
22+
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
23+
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
24+
import com.graphhopper.jsprit.core.util.NoiseMaker;
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
27+
28+
import java.util.ArrayList;
29+
import java.util.Collection;
30+
import java.util.List;
31+
32+
33+
/**
34+
* @author stefan schroeder
35+
*/
36+
37+
public final class RuinTimeRelated extends AbstractRuinStrategy {
38+
39+
static class RelatednessToTourActivity {
40+
41+
final double time;
42+
43+
final TourActivity tourActivity;
44+
45+
final VehicleRoute route;
46+
47+
final double distance;
48+
49+
public RelatednessToTourActivity(double relatednessToTarget, double distance, TourActivity tourActivity, VehicleRoute route) {
50+
this.time = relatednessToTarget;
51+
this.distance = distance;
52+
this.tourActivity = tourActivity;
53+
this.route = route;
54+
}
55+
}
56+
57+
private static final Logger logger = LoggerFactory.getLogger(RuinTimeRelated.class);
58+
59+
private final VehicleRoutingProblem vrp;
60+
61+
private NoiseMaker noiseMaker = () -> 0;
62+
63+
public void setNoiseMaker(NoiseMaker noiseMaker) {
64+
this.noiseMaker = noiseMaker;
65+
}
66+
67+
public RuinTimeRelated(VehicleRoutingProblem vrp) {
68+
super(vrp);
69+
this.vrp = vrp;
70+
this.ruinShareFactory = () -> (int) Math.max(50, Math.round(vrp.getJobs().size() * 0.3));
71+
logger.debug("initialise {}", this);
72+
}
73+
74+
/**
75+
* Removes a fraction of jobs from vehicleRoutes.
76+
* <p>
77+
* <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined).
78+
*/
79+
@Override
80+
public Collection<Job> ruinRoutes(Collection<VehicleRoute> vehicleRoutes) {
81+
List<Job> unassignedJobs = new ArrayList<>();
82+
int totalActivities = 0;
83+
for (VehicleRoute route : vehicleRoutes) {
84+
totalActivities += route.getActivities().size();
85+
}
86+
if (totalActivities == 0) return unassignedJobs;
87+
int randomIndex = random.nextInt(totalActivities);
88+
int numActs = 0;
89+
TourActivity targetActivity = null;
90+
for (VehicleRoute route : vehicleRoutes) {
91+
if (numActs + route.getActivities().size() < randomIndex) {
92+
numActs += route.getActivities().size();
93+
} else {
94+
for (TourActivity activity : route.getActivities()) {
95+
if (numActs == randomIndex) {
96+
targetActivity = activity;
97+
break;
98+
}
99+
numActs++;
100+
}
101+
if (targetActivity != null) {
102+
break;
103+
}
104+
}
105+
}
106+
if (targetActivity == null) {
107+
return unassignedJobs;
108+
}
109+
List<RelatednessToTourActivity> neighborActivities = new ArrayList<>();
110+
long maxTime = 0;
111+
double maxDistance = 0;
112+
for (VehicleRoute route : vehicleRoutes) {
113+
for (TourActivity activity : route.getActivities()) {
114+
if (activity == targetActivity) continue;
115+
long absTime = Math.abs((long) targetActivity.getArrTime() - (long) activity.getArrTime());
116+
maxTime = Math.max(maxTime, absTime);
117+
double distance = Math.abs(vrp.getTransportCosts().getDistance(targetActivity.getLocation(), activity.getLocation(), 0, route.getVehicle()));
118+
maxDistance = Math.max(maxDistance, distance);
119+
neighborActivities.add(new RelatednessToTourActivity(absTime, distance, activity, route));
120+
}
121+
}
122+
final double maxT = maxTime;
123+
final double maxD = maxTime;
124+
final double timeI = 10;
125+
final double distanceI;
126+
double distanceInfluence = 1;
127+
if (random.nextDouble() < 0.5) {
128+
distanceI = 0;
129+
} else distanceI = distanceInfluence;
130+
neighborActivities.sort((o1, o2) -> {
131+
double rO1 = relatedness(o1, maxD, maxT, timeI, distanceI);
132+
double rO2 = relatedness(o2, maxD, maxT, timeI, distanceI);
133+
return Double.compare(rO1, rO2);
134+
});
135+
int toRemove = getRuinShareFactory().createNumberToBeRemoved();
136+
for (RelatednessToTourActivity neighborActivity : neighborActivities) {
137+
if (toRemove == 0) break;
138+
Job j = ((TourActivity.JobActivity) neighborActivity.tourActivity).getJob();
139+
if (removeJob(j, neighborActivity.route)) {
140+
unassignedJobs.add(j);
141+
toRemove--;
142+
}
143+
}
144+
return unassignedJobs;
145+
}
146+
147+
private double relatedness(RelatednessToTourActivity o1, double maxDistance, double maxTime, double timeI, double distanceI) {
148+
return timeI * o1.time / maxTime + distanceI * o1.distance / maxDistance;
149+
}
150+
151+
@Override
152+
public String toString() {
153+
return "[name=timeRelatedRuin]";
154+
}
155+
156+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Licensed to GraphHopper GmbH under one or more contributor
3+
* license agreements. See the NOTICE file distributed with this work for
4+
* additional information regarding copyright ownership.
5+
*
6+
* GraphHopper GmbH licenses this file to you under the Apache License,
7+
* Version 2.0 (the "License"); you may not use this file except in
8+
* compliance with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package com.graphhopper.jsprit.core.algorithm.ruin;
20+
21+
import com.graphhopper.jsprit.core.problem.Location;
22+
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
23+
import com.graphhopper.jsprit.core.problem.job.Job;
24+
import com.graphhopper.jsprit.core.problem.job.Service;
25+
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
26+
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
27+
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
28+
import com.graphhopper.jsprit.core.util.RandomNumberGeneration;
29+
import org.junit.Test;
30+
31+
import java.util.Arrays;
32+
import java.util.Collection;
33+
import java.util.Random;
34+
35+
/**
36+
* Created by schroeder on 06/03/15.
37+
*/
38+
public class RuinTimeRelatedTest {
39+
40+
@Test
41+
public void itShouldRuinTwoObviousClusters() {
42+
Service s0 = Service.Builder.newInstance("s0").setLocation(Location.newInstance(9, 0)).build();
43+
Service s1 = Service.Builder.newInstance("s1").setLocation(Location.newInstance(9, 1)).build();
44+
Service s2 = Service.Builder.newInstance("s2").setLocation(Location.newInstance(9, 10)).build();
45+
Service s3 = Service.Builder.newInstance("s3").setLocation(Location.newInstance(9, 9)).build();
46+
Service s4 = Service.Builder.newInstance("s4").setLocation(Location.newInstance(9, 16)).build();
47+
Service s5 = Service.Builder.newInstance("s5").setLocation(Location.newInstance(9, 17)).build();
48+
Service s6 = Service.Builder.newInstance("s6").setLocation(Location.newInstance(9, 15.5)).build();
49+
Service s7 = Service.Builder.newInstance("s7").setLocation(Location.newInstance(9, 30)).build();
50+
51+
VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0, 0)).build();
52+
53+
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2)
54+
.addJob(s6).addJob(s7).addJob(s0).addJob(s3).addJob(s4).addJob(s5).addVehicle(v).build();
55+
56+
VehicleRoute vr1 = VehicleRoute.Builder.newInstance(v).addService(s0).addService(s1).addService(s2).addService(s3).setJobActivityFactory(vrp.getJobActivityFactory()).build();
57+
long time = 0;
58+
for (TourActivity act : vr1.getActivities()) {
59+
time += 2;
60+
act.setArrTime(time);
61+
}
62+
VehicleRoute vr2 = VehicleRoute.Builder.newInstance(v)
63+
.addService(s6).addService(s7).addService(s4).addService(s5).setJobActivityFactory(vrp.getJobActivityFactory()).build();
64+
time = 0;
65+
for (TourActivity act : vr2.getActivities()) {
66+
time += 2;
67+
act.setArrTime(time);
68+
}
69+
70+
RuinTimeRelated ruin = new RuinTimeRelated(vrp);
71+
72+
Random r = RandomNumberGeneration.newInstance();
73+
ruin.setRandom(r);
74+
Collection<Job> ruined = ruin.ruinRoutes(Arrays.asList(vr1, vr2));
75+
76+
77+
}
78+
79+
80+
}

0 commit comments

Comments
 (0)