mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
add and test new ruin strategy: RuinWorst
This commit is contained in:
parent
a93d88a0c1
commit
1488502f65
3 changed files with 375 additions and 0 deletions
|
|
@ -0,0 +1,165 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
package jsprit.core.algorithm.ruin;
|
||||
|
||||
import jsprit.core.problem.VehicleRoutingProblem;
|
||||
import jsprit.core.problem.driver.DriverImpl;
|
||||
import jsprit.core.problem.job.Job;
|
||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
import jsprit.core.problem.vehicle.Vehicle;
|
||||
import jsprit.core.util.NoiseMaker;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* Ruin strategy that ruins current solution randomly. I.e.
|
||||
* customer are removed randomly from current solution.
|
||||
*
|
||||
* @author stefan schroeder
|
||||
*
|
||||
*/
|
||||
|
||||
public final class RuinWorst extends AbstractRuinStrategy {
|
||||
|
||||
private Logger logger = LogManager.getLogger(RuinWorst.class);
|
||||
|
||||
private VehicleRoutingProblem vrp;
|
||||
|
||||
private NoiseMaker noiseMaker = new NoiseMaker(){
|
||||
|
||||
@Override
|
||||
public double makeNoise() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
public void setNoiseMaker(NoiseMaker noiseMaker) {
|
||||
this.noiseMaker = noiseMaker;
|
||||
}
|
||||
|
||||
public RuinWorst(VehicleRoutingProblem vrp, final int initialNumberJobsToRemove) {
|
||||
super();
|
||||
this.vrp = vrp;
|
||||
setRuinShareFactory(new RuinShareFactory() {
|
||||
@Override
|
||||
public int createNumberToBeRemoved() {
|
||||
return initialNumberJobsToRemove;
|
||||
}
|
||||
});
|
||||
logger.info("initialise " + this);
|
||||
logger.info("done");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a fraction of jobs from vehicleRoutes.
|
||||
*
|
||||
* <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<Job>();
|
||||
int nOfJobs2BeRemoved = getRuinShareFactory().createNumberToBeRemoved();
|
||||
ruin(vehicleRoutes, nOfJobs2BeRemoved, unassignedJobs);
|
||||
return unassignedJobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes nOfJobs2BeRemoved from vehicleRoutes, including targetJob.
|
||||
*/
|
||||
@Override
|
||||
public Collection<Job> ruinRoutes(Collection<VehicleRoute> vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved) {
|
||||
throw new UnsupportedOperationException("ruinRoutes not supported");
|
||||
}
|
||||
|
||||
private void ruin(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2BeRemoved, List<Job> unassignedJobs) {
|
||||
LinkedList<Job> availableJobs = new LinkedList<Job>(vrp.getJobs().values());
|
||||
int toRemove = nOfJobs2BeRemoved;
|
||||
while(toRemove > 0){
|
||||
Job worst = getWorst(vehicleRoutes);
|
||||
if(worst == null) break;
|
||||
removeJob(worst,vehicleRoutes);
|
||||
availableJobs.remove(worst);
|
||||
unassignedJobs.add(worst);
|
||||
toRemove--;
|
||||
}
|
||||
}
|
||||
|
||||
private Job getWorst(Collection<VehicleRoute> copied) {
|
||||
Job worst = null;
|
||||
double bestSavings = Double.MIN_VALUE;
|
||||
|
||||
for(VehicleRoute route : copied) {
|
||||
if(route.isEmpty()) continue;
|
||||
Map<Job,Double> savingsMap = new HashMap<Job,Double>();
|
||||
TourActivity actBefore = route.getStart();
|
||||
TourActivity actToEval = null;
|
||||
for (TourActivity act : route.getActivities()) {
|
||||
if (actToEval == null) {
|
||||
actToEval = act;
|
||||
continue;
|
||||
}
|
||||
double savings = savings(route, actBefore, actToEval, act);
|
||||
Job job = ((TourActivity.JobActivity) actToEval).getJob();
|
||||
if(!savingsMap.containsKey(job)){
|
||||
savingsMap.put(job,savings);
|
||||
}
|
||||
else {
|
||||
double s = savingsMap.get(job);
|
||||
savingsMap.put(job,s+savings);
|
||||
}
|
||||
actBefore = actToEval;
|
||||
actToEval = act;
|
||||
}
|
||||
double savings = savings(route, actBefore, actToEval, route.getEnd());
|
||||
Job job = ((TourActivity.JobActivity) actToEval).getJob();
|
||||
if(!savingsMap.containsKey(job)){
|
||||
savingsMap.put(job,savings);
|
||||
}
|
||||
else {
|
||||
double s = savingsMap.get(job);
|
||||
savingsMap.put(job,s+savings);
|
||||
}
|
||||
//getCounts best
|
||||
for(Job j : savingsMap.keySet()){
|
||||
if(savingsMap.get(j) > bestSavings){
|
||||
bestSavings = savingsMap.get(j);
|
||||
worst = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
return worst;
|
||||
}
|
||||
|
||||
private double savings(VehicleRoute route, TourActivity actBefore, TourActivity actToEval, TourActivity act) {
|
||||
double savings = c(actBefore, actToEval, route.getVehicle()) + c(actToEval, act, route.getVehicle()) - c(actBefore, act, route.getVehicle());
|
||||
return Math.max(0,savings + noiseMaker.makeNoise());
|
||||
}
|
||||
|
||||
private double c(TourActivity from, TourActivity to, Vehicle vehicle) {
|
||||
return vrp.getTransportCosts().getTransportCost(from.getLocation(),to.getLocation(),from.getEndTime(), DriverImpl.noDriver(), vehicle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[name=worstRuin]";
|
||||
}
|
||||
|
||||
}
|
||||
10
jsprit-core/src/main/java/jsprit/core/util/NoiseMaker.java
Normal file
10
jsprit-core/src/main/java/jsprit/core/util/NoiseMaker.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package jsprit.core.util;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 16/01/15.
|
||||
*/
|
||||
public interface NoiseMaker {
|
||||
|
||||
public double makeNoise();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,200 @@
|
|||
package jsprit.core.algorithm.ruin;
|
||||
|
||||
import jsprit.core.problem.Location;
|
||||
import jsprit.core.problem.VehicleRoutingProblem;
|
||||
import jsprit.core.problem.job.Job;
|
||||
import jsprit.core.problem.job.Service;
|
||||
import jsprit.core.problem.job.Shipment;
|
||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import jsprit.core.problem.vehicle.VehicleImpl;
|
||||
import jsprit.core.util.Coordinate;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Created by schroeder on 30/01/15.
|
||||
*/
|
||||
public class RuinWorstTest {
|
||||
|
||||
@Test
|
||||
public void itShouldRemoveCorrectNumber(){
|
||||
Service s1 = Service.Builder.newInstance("s1")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(1, 1)).build()).build();
|
||||
Service s2 = Service.Builder.newInstance("s2")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(3, 1)).build()).build();
|
||||
Service s3 = Service.Builder.newInstance("s3")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 10)).build()).build();
|
||||
VehicleImpl v = VehicleImpl.Builder.newInstance("v")
|
||||
.setStartLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(0, 0)).build()).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addJob(s3).addVehicle(v).build();
|
||||
RuinWorst worst = new RuinWorst(vrp,1);
|
||||
|
||||
VehicleRoute route = VehicleRoute.Builder.newInstance(v).addService(s1).addService(s2).addService(s3).setJobActivityFactory(vrp.getJobActivityFactory()).build();
|
||||
Collection<Job> unassigned = worst.ruinRoutes(Arrays.asList(route));
|
||||
assertEquals(1,unassigned.size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itShouldRemoveWorst(){
|
||||
Service s1 = Service.Builder.newInstance("s1")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(1, 1)).build()).build();
|
||||
Service s2 = Service.Builder.newInstance("s2")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(3, 1)).build()).build();
|
||||
Service s3 = Service.Builder.newInstance("s3")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 10)).build()).build();
|
||||
VehicleImpl v = VehicleImpl.Builder.newInstance("v")
|
||||
.setStartLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(0, 0)).build()).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addJob(s3).addVehicle(v).build();
|
||||
RuinWorst worst = new RuinWorst(vrp,1);
|
||||
|
||||
VehicleRoute route = VehicleRoute.Builder.newInstance(v).addService(s1).addService(s2).addService(s3).setJobActivityFactory(vrp.getJobActivityFactory()).build();
|
||||
Collection<Job> unassigned = worst.ruinRoutes(Arrays.asList(route));
|
||||
assertEquals(s3,unassigned.iterator().next());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itShouldRemoveWorstTwo(){
|
||||
Service s1 = Service.Builder.newInstance("s1")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(1, 1)).build()).build();
|
||||
Service s2 = Service.Builder.newInstance("s2")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(3, 1)).build()).build();
|
||||
Service s3 = Service.Builder.newInstance("s3")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 10)).build()).build();
|
||||
VehicleImpl v = VehicleImpl.Builder.newInstance("v")
|
||||
.setStartLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(0, 0)).build()).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().addJob(s1).addJob(s2).addJob(s3).addVehicle(v).build();
|
||||
RuinWorst worst = new RuinWorst(vrp,1);
|
||||
worst.setRuinShareFactory(new RuinShareFactory() {
|
||||
@Override
|
||||
public int createNumberToBeRemoved() {
|
||||
return 2;
|
||||
}
|
||||
});
|
||||
|
||||
VehicleRoute route = VehicleRoute.Builder.newInstance(v).addService(s1).addService(s2).addService(s3).setJobActivityFactory(vrp.getJobActivityFactory()).build();
|
||||
Collection<Job> unassigned = worst.ruinRoutes(Arrays.asList(route));
|
||||
|
||||
assertTrue(unassigned.size() == 2);
|
||||
assertTrue(unassigned.contains(s2));
|
||||
assertTrue(unassigned.contains(s3));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itShouldRemoveShipment(){
|
||||
Service s1 = Service.Builder.newInstance("s1")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(1, 1)).build()).build();
|
||||
Service s2 = Service.Builder.newInstance("s2")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(3, 1)).build()).build();
|
||||
Service s3 = Service.Builder.newInstance("s3")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 10)).build()).build();
|
||||
Shipment shipment = Shipment.Builder.newInstance("ship1")
|
||||
.setPickupLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(2, 2)).build())
|
||||
.setDeliveryLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(9, 9)).build()).build();
|
||||
VehicleImpl v = VehicleImpl.Builder.newInstance("v")
|
||||
.setStartLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(0, 0)).build()).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(shipment).addJob(s1).addJob(s2).addJob(s3).addVehicle(v).build();
|
||||
RuinWorst worst = new RuinWorst(vrp,1);
|
||||
worst.setRuinShareFactory(new RuinShareFactory() {
|
||||
@Override
|
||||
public int createNumberToBeRemoved() {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
VehicleRoute route = VehicleRoute.Builder.newInstance(v)
|
||||
.addPickup(shipment).addService(s1).addService(s2).addService(s3).addDelivery(shipment)
|
||||
.setJobActivityFactory(vrp.getJobActivityFactory()).build();
|
||||
Collection<Job> unassigned = worst.ruinRoutes(Arrays.asList(route));
|
||||
|
||||
assertTrue(unassigned.size() == 1);
|
||||
assertTrue(unassigned.contains(shipment));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itShouldRemoveShipmentFromSecondRoute(){
|
||||
Service s1 = Service.Builder.newInstance("s1")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(1, 1)).build()).build();
|
||||
Service s2 = Service.Builder.newInstance("s2")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(3, 1)).build()).build();
|
||||
Service s3 = Service.Builder.newInstance("s3")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 10)).build()).build();
|
||||
Shipment shipment = Shipment.Builder.newInstance("ship1")
|
||||
.setPickupLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(3, 1)).build())
|
||||
.setDeliveryLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 10.1)).build()).build();
|
||||
VehicleImpl v = VehicleImpl.Builder.newInstance("v")
|
||||
.setStartLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(0, 0)).build()).build();
|
||||
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2")
|
||||
.setStartLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(0, 0)).build()).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(shipment).addJob(s1).addJob(s2).addJob(s3).addVehicle(v).addVehicle(v2).build();
|
||||
RuinWorst worst = new RuinWorst(vrp,1);
|
||||
worst.setRuinShareFactory(new RuinShareFactory() {
|
||||
@Override
|
||||
public int createNumberToBeRemoved() {
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
|
||||
VehicleRoute route1 = VehicleRoute.Builder.newInstance(v)
|
||||
.addService(s1).addService(s2).addService(s3)
|
||||
.setJobActivityFactory(vrp.getJobActivityFactory()).build();
|
||||
VehicleRoute route2 = VehicleRoute.Builder.newInstance(v2)
|
||||
.addPickup(shipment).addDelivery(shipment).build();
|
||||
Collection<Job> unassigned = worst.ruinRoutes(Arrays.asList(route1,route2));
|
||||
|
||||
assertTrue(unassigned.size() == 1);
|
||||
assertTrue(unassigned.contains(shipment));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itShouldRemoveServiceAndShipmentFromSecondRoute(){
|
||||
Service s1 = Service.Builder.newInstance("s1")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(1, 1)).build()).build();
|
||||
Service s2 = Service.Builder.newInstance("s2")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(3, 1)).build()).build();
|
||||
Service s3 = Service.Builder.newInstance("s3")
|
||||
.setLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 10)).build()).build();
|
||||
Shipment shipment = Shipment.Builder.newInstance("ship1")
|
||||
.setPickupLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(3, 1)).build())
|
||||
.setDeliveryLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 10.1)).build()).build();
|
||||
VehicleImpl v = VehicleImpl.Builder.newInstance("v")
|
||||
.setStartLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(0, 0)).build()).build();
|
||||
VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2")
|
||||
.setStartLocation(Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(0, 0)).build()).build();
|
||||
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance()
|
||||
.addJob(shipment).addJob(s1).addJob(s2).addJob(s3).addVehicle(v).addVehicle(v2).build();
|
||||
RuinWorst worst = new RuinWorst(vrp,1);
|
||||
worst.setRuinShareFactory(new RuinShareFactory() {
|
||||
@Override
|
||||
public int createNumberToBeRemoved() {
|
||||
return 2;
|
||||
}
|
||||
});
|
||||
|
||||
VehicleRoute route1 = VehicleRoute.Builder.newInstance(v)
|
||||
.addService(s1).addService(s2).addService(s3)
|
||||
.setJobActivityFactory(vrp.getJobActivityFactory()).build();
|
||||
VehicleRoute route2 = VehicleRoute.Builder.newInstance(v2)
|
||||
.addPickup(shipment).addDelivery(shipment).build();
|
||||
Collection<Job> unassigned = worst.ruinRoutes(Arrays.asList(route1,route2));
|
||||
|
||||
assertTrue(unassigned.size() == 2);
|
||||
assertTrue(unassigned.contains(shipment));
|
||||
assertTrue(unassigned.contains(s3));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue