|
| 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 | +} |
0 commit comments