Skip to content

Commit

Permalink
add new ruin strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
oblonski committed May 5, 2023
1 parent 9998417 commit 2c5a16b
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ public enum Strategy {
CLUSTER_BEST("cluster_best"),
CLUSTER_REGRET("cluster_regret"),
STRING_BEST("string_best"),
STRING_REGRET("string_regret");
STRING_REGRET("string_regret"),
TIME_RELATED_REGRET("time_related_regret"),
TIME_RELATED_BEST("time_related_best");


String strategyName;

Expand Down Expand Up @@ -189,6 +192,10 @@ private Properties createDefaultProperties() {
Properties defaults = new Properties();
defaults.put(Strategy.RADIAL_BEST.toString(), "0.");
defaults.put(Strategy.RADIAL_REGRET.toString(), ".5");

defaults.put(Strategy.TIME_RELATED_BEST.toString(), "0.");
defaults.put(Strategy.TIME_RELATED_REGRET.toString(), "0.");

defaults.put(Strategy.RANDOM_BEST.toString(), ".5");
defaults.put(Strategy.RANDOM_REGRET.toString(), ".5");

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

RuinRadial radial = new RuinRadial(vrp, vrp.getJobs().size(), jobNeighborhoods);
radial.setRandom(random);
radial.setRuinShareFactory(new RuinShareFactoryImpl(
RuinShareFactoryImpl radialRuinFactory = new RuinShareFactoryImpl(
toInteger(properties.getProperty(Parameter.RADIAL_MIN_SHARE.toString())),
toInteger(properties.getProperty(Parameter.RADIAL_MAX_SHARE.toString())),
random)
);
random);
radial.setRuinShareFactory(radialRuinFactory);

final RuinRandom random_for_regret = new RuinRandom(vrp, 0.5);
random_for_regret.setRandom(random);
random_for_regret.setRuinShareFactory(new RuinShareFactoryImpl(
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MIN_SHARE.toString())),
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MAX_SHARE.toString())),
random)
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MIN_SHARE.toString())),
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MAX_SHARE.toString())),
random)
);

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

final RuinTimeRelated ruinTimeRelated = new RuinTimeRelated(vrp);
ruinTimeRelated.setRuinShareFactory(radialRuinFactory);
ruinTimeRelated.setRandom(random);

AbstractInsertionStrategy regret;
final ScoringFunction scorer;

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

SearchStrategy timeRelatedRegret = new SearchStrategy(Strategy.TIME_RELATED_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction);
timeRelatedRegret.addModule(configureModule(new RuinAndRecreateModule(Strategy.TIME_RELATED_REGRET.toString(), regret, ruinTimeRelated)));

SearchStrategy timeRelatedBest = new SearchStrategy(Strategy.TIME_RELATED_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
timeRelatedBest.addModule(configureModule(new RuinAndRecreateModule(Strategy.TIME_RELATED_BEST.toString(), best, ruinTimeRelated)));

SearchStrategy randomBest = new SearchStrategy(Strategy.RANDOM_BEST.toString(), new SelectBest(), acceptor, objectiveFunction);
randomBest.addModule(configureModule(new RuinAndRecreateModule(Strategy.RANDOM_BEST.toString(), best, random_for_best)));

Expand Down Expand Up @@ -655,6 +672,10 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
}
prettyBuilder.withStrategy(radialRegret, toDouble(getProperty(Strategy.RADIAL_REGRET.toString())))
.withStrategy(radialBest, toDouble(getProperty(Strategy.RADIAL_BEST.toString())))

.withStrategy(timeRelatedBest, toDouble(getProperty(Strategy.TIME_RELATED_BEST.toString())))
.withStrategy(timeRelatedRegret, toDouble(getProperty(Strategy.TIME_RELATED_REGRET.toString())))

.withStrategy(randomBest, toDouble(getProperty(Strategy.RANDOM_BEST.toString())))
.withStrategy(randomRegret, toDouble(getProperty(Strategy.RANDOM_REGRET.toString())))
.withStrategy(worstBest, toDouble(getProperty(Strategy.WORST_BEST.toString())))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* 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.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.NoiseMaker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;


/**
* @author stefan schroeder
*/

public final class RuinTimeRelated extends AbstractRuinStrategy {

static class RelatednessToTourActivity {

final double time;

final TourActivity tourActivity;

final VehicleRoute route;

final double distance;

public RelatednessToTourActivity(double relatednessToTarget, double distance, TourActivity tourActivity, VehicleRoute route) {
this.time = relatednessToTarget;
this.distance = distance;
this.tourActivity = tourActivity;
this.route = route;
}
}

private static final Logger logger = LoggerFactory.getLogger(RuinTimeRelated.class);

private final VehicleRoutingProblem vrp;

private NoiseMaker noiseMaker = () -> 0;

public void setNoiseMaker(NoiseMaker noiseMaker) {
this.noiseMaker = noiseMaker;
}

public RuinTimeRelated(VehicleRoutingProblem vrp) {
super(vrp);
this.vrp = vrp;
this.ruinShareFactory = () -> (int) Math.max(50, Math.round(vrp.getJobs().size() * 0.3));
logger.debug("initialise {}", this);
}

/**
* Removes a fraction of jobs from vehicleRoutes.
* <p>
* <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined).
*/
@Override
public Collection<Job> ruinRoutes(Collection<VehicleRoute> vehicleRoutes) {
List<Job> unassignedJobs = new ArrayList<>();
int totalActivities = 0;
for (VehicleRoute route : vehicleRoutes) {
totalActivities += route.getActivities().size();
}
if (totalActivities == 0) return unassignedJobs;
int randomIndex = random.nextInt(totalActivities);
int numActs = 0;
TourActivity targetActivity = null;
for (VehicleRoute route : vehicleRoutes) {
if (numActs + route.getActivities().size() < randomIndex) {
numActs += route.getActivities().size();
} else {
for (TourActivity activity : route.getActivities()) {
if (numActs == randomIndex) {
targetActivity = activity;
break;
}
numActs++;
}
if (targetActivity != null) {
break;
}
}
}
if (targetActivity == null) {
return unassignedJobs;
}
List<RelatednessToTourActivity> neighborActivities = new ArrayList<>();
long maxTime = 0;
double maxDistance = 0;
for (VehicleRoute route : vehicleRoutes) {
for (TourActivity activity : route.getActivities()) {
if (activity == targetActivity) continue;
long absTime = Math.abs((long) targetActivity.getArrTime() - (long) activity.getArrTime());
maxTime = Math.max(maxTime, absTime);
double distance = Math.abs(vrp.getTransportCosts().getDistance(targetActivity.getLocation(), activity.getLocation(), 0, route.getVehicle()));
maxDistance = Math.max(maxDistance, distance);
neighborActivities.add(new RelatednessToTourActivity(absTime, distance, activity, route));
}
}
final double maxT = maxTime;
final double maxD = maxTime;
final double timeI = 10;
final double distanceI;
double distanceInfluence = 1;
if (random.nextDouble() < 0.5) {
distanceI = 0;
} else distanceI = distanceInfluence;
neighborActivities.sort((o1, o2) -> {
double rO1 = relatedness(o1, maxD, maxT, timeI, distanceI);
double rO2 = relatedness(o2, maxD, maxT, timeI, distanceI);
return Double.compare(rO1, rO2);
});
int toRemove = getRuinShareFactory().createNumberToBeRemoved();
for (RelatednessToTourActivity neighborActivity : neighborActivities) {
if (toRemove == 0) break;
Job j = ((TourActivity.JobActivity) neighborActivity.tourActivity).getJob();
if (removeJob(j, neighborActivity.route)) {
unassignedJobs.add(j);
toRemove--;
}
}
return unassignedJobs;
}

private double relatedness(RelatednessToTourActivity o1, double maxDistance, double maxTime, double timeI, double distanceI) {
return timeI * o1.time / maxTime + distanceI * o1.distance / maxDistance;
}

@Override
public String toString() {
return "[name=timeRelatedRuin]";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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.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 com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
import com.graphhopper.jsprit.core.util.RandomNumberGeneration;
import org.junit.Test;

import java.util.Arrays;
import java.util.Collection;
import java.util.Random;

/**
* Created by schroeder on 06/03/15.
*/
public class RuinTimeRelatedTest {

@Test
public void itShouldRuinTwoObviousClusters() {
Service s0 = Service.Builder.newInstance("s0").setLocation(Location.newInstance(9, 0)).build();
Service s1 = Service.Builder.newInstance("s1").setLocation(Location.newInstance(9, 1)).build();
Service s2 = Service.Builder.newInstance("s2").setLocation(Location.newInstance(9, 10)).build();
Service s3 = Service.Builder.newInstance("s3").setLocation(Location.newInstance(9, 9)).build();
Service s4 = Service.Builder.newInstance("s4").setLocation(Location.newInstance(9, 16)).build();
Service s5 = Service.Builder.newInstance("s5").setLocation(Location.newInstance(9, 17)).build();
Service s6 = Service.Builder.newInstance("s6").setLocation(Location.newInstance(9, 15.5)).build();
Service s7 = Service.Builder.newInstance("s7").setLocation(Location.newInstance(9, 30)).build();

VehicleImpl v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0, 0)).build();

VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2)
.addJob(s6).addJob(s7).addJob(s0).addJob(s3).addJob(s4).addJob(s5).addVehicle(v).build();

VehicleRoute vr1 = VehicleRoute.Builder.newInstance(v).addService(s0).addService(s1).addService(s2).addService(s3).setJobActivityFactory(vrp.getJobActivityFactory()).build();
long time = 0;
for (TourActivity act : vr1.getActivities()) {
time += 2;
act.setArrTime(time);
}
VehicleRoute vr2 = VehicleRoute.Builder.newInstance(v)
.addService(s6).addService(s7).addService(s4).addService(s5).setJobActivityFactory(vrp.getJobActivityFactory()).build();
time = 0;
for (TourActivity act : vr2.getActivities()) {
time += 2;
act.setArrTime(time);
}

RuinTimeRelated ruin = new RuinTimeRelated(vrp);

Random r = RandomNumberGeneration.newInstance();
ruin.setRandom(r);
Collection<Job> ruined = ruin.ruinRoutes(Arrays.asList(vr1, vr2));


}


}

0 comments on commit 2c5a16b

Please sign in to comment.