mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
RandomInsertionAdded (#46)
* RandomInsertionAdded * fix * oops * wrong algorithm name * add breaks too * test added * containAlll * if
This commit is contained in:
parent
5b0efb61e7
commit
8fa3c81983
9 changed files with 544 additions and 3 deletions
|
|
@ -35,7 +35,7 @@ public class InsertionBuilder {
|
|||
|
||||
|
||||
public enum Strategy {
|
||||
REGRET, BEST
|
||||
REGRET, BEST, RANDOM
|
||||
}
|
||||
|
||||
private VehicleRoutingProblem vrp;
|
||||
|
|
@ -200,6 +200,8 @@ public class InsertionBuilder {
|
|||
}
|
||||
|
||||
}
|
||||
} else if (strategy.equals(Strategy.RANDOM)) {
|
||||
insertion = new RandomInsertion(costCalculator, vrp);
|
||||
} else throw new IllegalStateException("you should never get here");
|
||||
for (InsertionListener l : iListeners) insertion.addListener(l);
|
||||
return insertion;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
package com.graphhopper.jsprit.core.algorithm.recreate;
|
||||
|
||||
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
|
||||
import com.graphhopper.jsprit.core.problem.job.Break;
|
||||
import com.graphhopper.jsprit.core.problem.job.Job;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class RandomInsertion extends AbstractInsertionStrategy {
|
||||
private static Logger logger = LoggerFactory.getLogger(BestInsertion.class);
|
||||
|
||||
private JobInsertionCostsCalculator bestInsertionCostCalculator;
|
||||
final Map<String, Integer> jobCanBeServedByDriversCount = new HashMap<>();
|
||||
|
||||
public RandomInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) {
|
||||
super(vehicleRoutingProblem);
|
||||
bestInsertionCostCalculator = jobInsertionCalculator;
|
||||
|
||||
initJobsCanBeServedByNumDrivers();
|
||||
logger.debug("initialise {}", this);
|
||||
}
|
||||
|
||||
void initJobsCanBeServedByNumDrivers() {
|
||||
for (Job job : vrp.getJobs().values()) {
|
||||
int count = 0;
|
||||
for (Vehicle vehicle : vrp.getVehicles())
|
||||
if (vehicle.getSkills().values().containsAll(job.getRequiredSkills().values()))
|
||||
count++;
|
||||
|
||||
jobCanBeServedByDriversCount.put(job.getId(), count);
|
||||
}
|
||||
|
||||
for (Vehicle vehicle : vrp.getVehicles()) {
|
||||
final Break aBreak = vehicle.getBreak();
|
||||
if (aBreak != null)
|
||||
jobCanBeServedByDriversCount.put(aBreak.getId(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[name=randomInsertion]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||
List<Job> badJobs = new ArrayList<>(unassignedJobs.size());
|
||||
List<Job> unassignedJobList = new ArrayList<>(unassignedJobs);
|
||||
Collections.shuffle(unassignedJobList, random);
|
||||
|
||||
final double p = random.nextDouble();
|
||||
if (p < .25)
|
||||
Collections.sort(unassignedJobList, new AccordingToPriorities());
|
||||
else if (p < .5)
|
||||
Collections.sort(unassignedJobList, new Comparator<Job>() {
|
||||
@Override
|
||||
public int compare(Job o1, Job o2) {return jobCanBeServedByDriversCount.get(o1.getId()) - jobCanBeServedByDriversCount.get(o2.getId());}
|
||||
});
|
||||
|
||||
for (Job unassignedJob : unassignedJobList) {
|
||||
List<VehicleRoute> routes = new ArrayList<>(vehicleRoutes);
|
||||
final VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
||||
routes.add(newRoute);
|
||||
Collections.shuffle(routes, random);
|
||||
|
||||
InsertionData empty = new InsertionData.NoInsertionFound();
|
||||
double bestInsertionCost = Double.MAX_VALUE;
|
||||
boolean inserted = false;
|
||||
for (VehicleRoute vehicleRoute : routes) {
|
||||
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||
if (iData instanceof InsertionData.NoInsertionFound) {
|
||||
empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames());
|
||||
continue;
|
||||
}
|
||||
|
||||
inserted = true;
|
||||
final boolean isNewRoute = vehicleRoute.getActivities().size() == 0;
|
||||
if (isNewRoute) {
|
||||
updateNewRouteInsertionData(iData);
|
||||
vehicleRoutes.add(vehicleRoute);
|
||||
}
|
||||
|
||||
final boolean vehicleSwitched = !vehicleRoute.getVehicle().getId().equals(iData.getSelectedVehicle().getId());
|
||||
insertJob(unassignedJob, iData, vehicleRoute);
|
||||
if (vehicleSwitched)
|
||||
insertBreak(bestInsertionCostCalculator, badJobs, vehicleRoute, iData);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!inserted) {
|
||||
markUnassigned(unassignedJob, empty.getFailedConstraintNames());
|
||||
badJobs.add(unassignedJob);
|
||||
}
|
||||
}
|
||||
return badJobs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
package com.graphhopper.jsprit.core.algorithm.recreate;
|
||||
|
||||
import com.graphhopper.jsprit.core.problem.Location;
|
||||
import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem;
|
||||
import com.graphhopper.jsprit.core.problem.job.Break;
|
||||
import com.graphhopper.jsprit.core.problem.job.Delivery;
|
||||
import com.graphhopper.jsprit.core.problem.job.Service;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class RandomInsertionTest {
|
||||
|
||||
@Test
|
||||
public void initJobsCanBeServedByNumDrivers1() {
|
||||
final HashSet<String> first = new HashSet<>(); first.add("C");
|
||||
final HashSet<String> second = new HashSet<>(); second.add("A");second.add("B");
|
||||
final VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE)
|
||||
.addVehicle(getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, first, false, 1, 1, false))
|
||||
.addVehicle(getVehicle("v2", Location.newInstance(0, 14), 0, 100, 20, second, false, 1, 1, false))
|
||||
.addJob(getService(Location.newInstance(0, 5), 0, 20, new HashSet<String>(), 1))
|
||||
.addJob(getService(Location.newInstance(0, 6), 0, 20, new HashSet<String>(), 1));
|
||||
|
||||
final RandomInsertion randomInsertion = new RandomInsertion(null, builder.build());
|
||||
final Map<String, Integer> jobCanBeServedByDriversCount = randomInsertion.jobCanBeServedByDriversCount;
|
||||
|
||||
for (int numCanServe : jobCanBeServedByDriversCount.values())
|
||||
assertEquals(numCanServe, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initBreaksCanBeServedByOneDriver() {
|
||||
final HashSet<String> first = new HashSet<>(); first.add("C");
|
||||
final HashSet<String> second = new HashSet<>(); second.add("A");second.add("B");
|
||||
final VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE)
|
||||
.addVehicle(getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, first, false, 1, 1, true))
|
||||
.addVehicle(getVehicle("v2", Location.newInstance(0, 14), 0, 100, 20, second, false, 1, 1, true))
|
||||
.addJob(getService(Location.newInstance(0, 5), 0, 20, new HashSet<String>(), 1))
|
||||
.addJob(getService(Location.newInstance(0, 6), 0, 20, new HashSet<String>(), 1));
|
||||
|
||||
final RandomInsertion randomInsertion = new RandomInsertion(null, builder.build());
|
||||
final Map<String, Integer> jobCanBeServedByDriversCount = randomInsertion.jobCanBeServedByDriversCount;
|
||||
|
||||
int numBreaks = 0;
|
||||
for (Map.Entry<String, Integer> entry : jobCanBeServedByDriversCount.entrySet()) {
|
||||
if (entry.getKey().contains("break_")) {
|
||||
++numBreaks;
|
||||
assertEquals((int) entry.getValue(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(numBreaks, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initJobsCanBeServedByNumDrivers2() {
|
||||
final HashSet<String> first = new HashSet<>(); first.add("C");
|
||||
final HashSet<String> second = new HashSet<>(); second.add("A");second.add("B");
|
||||
final VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE)
|
||||
.addVehicle(getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, first, false, 1, 1, false))
|
||||
.addVehicle(getVehicle("v2", Location.newInstance(0, 14), 0, 100, 20, second, false, 1, 1, false))
|
||||
.addJob(getService(Location.newInstance(0, 5), 0, 20, first, 1))
|
||||
.addJob(getService(Location.newInstance(0, 6), 0, 20, second, 1));
|
||||
|
||||
final RandomInsertion randomInsertion = new RandomInsertion(null, builder.build());
|
||||
final Map<String, Integer> jobCanBeServedByDriversCount = randomInsertion.jobCanBeServedByDriversCount;
|
||||
|
||||
for (int numCanServe : jobCanBeServedByDriversCount.values())
|
||||
assertEquals(numCanServe, 1);
|
||||
}
|
||||
|
||||
private static Service getService(Location location, int start, int end, Set<String> requiredSkills, int priority) {
|
||||
return Delivery.Builder.newInstance("service_" + UUID.randomUUID().toString().substring(0,5))
|
||||
.setLocation(location)
|
||||
.setServiceTime(1)
|
||||
.addTimeWindow(new TimeWindow(start, end))
|
||||
.addSizeDimension(0, 1)
|
||||
.addAllRequiredSkills(requiredSkills)
|
||||
.setPriority(priority)
|
||||
.setName(UUID.randomUUID().toString()).build();
|
||||
|
||||
}
|
||||
|
||||
private static Vehicle getVehicle(String id, Location location, int start, int end, int capacity, Set<String> skills, boolean returnToDepot, int fixedCost, int costPerDistance, boolean aBreak) {
|
||||
final VehicleImpl.Builder builder = VehicleImpl.Builder.newInstance(id)
|
||||
.setStartLocation(location).setLatestArrival(end).setEarliestStart(start).setType(
|
||||
VehicleTypeImpl.Builder.newInstance(UUID.randomUUID().toString()).setFixedCost(fixedCost).setCostPerDistance(costPerDistance).addCapacityDimension(0, capacity).build()
|
||||
)
|
||||
.addAllSkills(skills).setReturnToDepot(returnToDepot);
|
||||
|
||||
if (aBreak)
|
||||
builder.setBreak(Break.Builder.newInstance("break_" + id).build());
|
||||
return builder.build();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
package com.graphhopper.jsprit.examples;
|
||||
|
||||
import com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer;
|
||||
import com.graphhopper.jsprit.core.algorithm.VariablePlusFixedSolutionCostCalculatorFactory;
|
||||
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
|
||||
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
|
||||
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.VehicleRoutingTransportCosts;
|
||||
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
||||
import com.graphhopper.jsprit.core.problem.job.Delivery;
|
||||
import com.graphhopper.jsprit.core.problem.job.Service;
|
||||
import com.graphhopper.jsprit.core.problem.job.Shipment;
|
||||
import com.graphhopper.jsprit.core.problem.solution.SolutionCostCalculator;
|
||||
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
|
||||
import com.graphhopper.jsprit.core.reporting.SolutionPrinter;
|
||||
import com.graphhopper.jsprit.core.util.Solutions;
|
||||
import com.graphhopper.jsprit.io.algorithm.VehicleRoutingAlgorithms;
|
||||
import com.graphhopper.jsprit.io.problem.VrpXMLWriter;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class SkillsWithPriorities {
|
||||
public static void main(String[] args) {
|
||||
final HashSet<String> first = new HashSet<>(); first.add("C");
|
||||
final HashSet<String> second = new HashSet<>(); second.add("A");second.add("B");
|
||||
final VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE)
|
||||
.addVehicle(getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, first, false, 1, 1))
|
||||
.addVehicle(getVehicle("v2", Location.newInstance(0, 14), 0, 100, 20, second, false, 1, 1))
|
||||
.addJob(getService(Location.newInstance(0, 5), 0, 20, new HashSet<String>(), 1))
|
||||
.addJob(getService(Location.newInstance(0, 6), 0, 20, new HashSet<String>(), 1))
|
||||
.addJob(getShipment(Location.newInstance(10, 10), Location.newInstance(10, 12), 10, 20, 10, 50, first, 10));
|
||||
|
||||
builder.setRoutingCost(getTransportCosts());
|
||||
VehicleRoutingProblem vrp = builder.build();
|
||||
StateManager stateManager = new StateManager(vrp);
|
||||
final SolutionCostCalculator calculator = new VariablePlusFixedSolutionCostCalculatorFactory(stateManager).createCalculator();
|
||||
SolutionCostCalculator solutionCostCalculator = new SolutionCostCalculator() {
|
||||
@Override
|
||||
public double getCosts(VehicleRoutingProblemSolution solution) {
|
||||
return calculator.getCosts(solution) + solution.getUnassignedJobs().size() * 10;
|
||||
}
|
||||
};
|
||||
final VehicleRoutingAlgorithm algorithm = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, 1,"jsprit-examples/input/algorithmConfig.xml", stateManager, new ConstraintManager(vrp, stateManager), solutionCostCalculator);
|
||||
|
||||
Collection<VehicleRoutingProblemSolution> solutions = algorithm.searchSolutions();
|
||||
|
||||
VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions);
|
||||
|
||||
new VrpXMLWriter(vrp, solutions).write("output/problem-with-solution.xml");
|
||||
|
||||
SolutionPrinter.print(vrp, bestSolution, SolutionPrinter.Print.VERBOSE);
|
||||
new GraphStreamViewer(vrp, bestSolution).labelWith(GraphStreamViewer.Label.ID).setRenderDelay(200).display();
|
||||
}
|
||||
|
||||
private static VehicleRoutingTransportCosts getTransportCosts() {
|
||||
return new VehicleRoutingTransportCosts() {
|
||||
@Override
|
||||
public double getBackwardTransportCost(Location from, Location to, double arrivalTime, Driver driver, Vehicle vehicle) { return getDistance(from, to, arrivalTime, vehicle); }
|
||||
|
||||
@Override
|
||||
public double getBackwardTransportTime(Location from, Location to, double arrivalTime, Driver driver, Vehicle vehicle) { return getDistance(from, to, arrivalTime, vehicle); }
|
||||
|
||||
@Override
|
||||
public double getTransportCost(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { return getDistance(from, to, departureTime, vehicle); }
|
||||
|
||||
@Override
|
||||
public double getTransportTime(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { return getDistance(from, to, departureTime, vehicle); }
|
||||
|
||||
@Override
|
||||
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
|
||||
return Math.abs(from.getCoordinate().getX() - to.getCoordinate().getX()) + Math.abs(from.getCoordinate().getY() - to.getCoordinate().getY());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Vehicle getVehicle(String id, Location location, int start, int end, int capacity, Set<String> skills, boolean returnToDepot, int fixedCost, int costPerDistance) {
|
||||
return VehicleImpl.Builder.newInstance(id)
|
||||
.setStartLocation(location).setLatestArrival(end).setEarliestStart(start).setType(
|
||||
VehicleTypeImpl.Builder.newInstance(UUID.randomUUID().toString()).setFixedCost(fixedCost).setCostPerDistance(costPerDistance).addCapacityDimension(0, capacity).build()
|
||||
)
|
||||
.addAllSkills(skills).setReturnToDepot(returnToDepot).build();
|
||||
|
||||
}
|
||||
|
||||
private static Service getService(Location location, int start, int end, Set<String> requiredSkills, int priority) {
|
||||
return Delivery.Builder.newInstance("service_" + UUID.randomUUID().toString().substring(0,5))
|
||||
.setLocation(location)
|
||||
.setServiceTime(1)
|
||||
.addTimeWindow(new TimeWindow(start, end))
|
||||
.addSizeDimension(0, 1)
|
||||
.addAllRequiredSkills(requiredSkills)
|
||||
.setPriority(priority)
|
||||
.setName(UUID.randomUUID().toString()).build();
|
||||
|
||||
}
|
||||
|
||||
public static Shipment getShipment(Location pickupLocation, Location dropoffLocation, int pickupStart, int pickupEnd, int dropoffStart, int dropoffEnd, Set<String> skills, int priority) {
|
||||
return Shipment.Builder.newInstance("shipment_" + UUID.randomUUID().toString().substring(0,5))
|
||||
.setPickupLocation(pickupLocation).setDeliveryLocation(dropoffLocation)
|
||||
.setDeliveryServiceTime(1).setPickupServiceTime(1)
|
||||
.addSizeDimension(0, 1)
|
||||
.setPickupTimeWindow(new TimeWindow(pickupStart, pickupEnd))
|
||||
.setDeliveryTimeWindow(new TimeWindow(dropoffStart, dropoffEnd))
|
||||
.addAllRequiredSkills(skills)
|
||||
.setPriority(priority)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@ class InsertionFactory {
|
|||
|
||||
if (config.containsKey("[@name]")) {
|
||||
String insertionName = config.getString("[@name]");
|
||||
if (!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion")) {
|
||||
if (!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion") && !insertionName.equals("randomInsertion")) {
|
||||
throw new IllegalStateException(insertionName + " is not supported. use either \"bestInsertion\" or \"regretInsertion\"");
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +104,8 @@ class InsertionFactory {
|
|||
if (fastRegret != null) {
|
||||
iBuilder.setFastRegret(Boolean.parseBoolean(fastRegret));
|
||||
}
|
||||
} else if (insertionName.equals("randomInsertion")) {
|
||||
iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.RANDOM);
|
||||
}
|
||||
return iBuilder.build();
|
||||
} else throw new IllegalStateException("cannot create insertionStrategy, since it has no name.");
|
||||
|
|
|
|||
|
|
@ -886,7 +886,7 @@ public class VehicleRoutingAlgorithms {
|
|||
|
||||
String insertionName = moduleConfig.getString("insertion[@name]");
|
||||
if (insertionName == null)
|
||||
throw new IllegalStateException("module.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\"");
|
||||
throw new IllegalStateException("module.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\" or \"randomInsertion\"");
|
||||
String insertionId = moduleConfig.getString("insertion[@id]");
|
||||
if (insertionId == null) insertionId = "noId";
|
||||
ModKey insertionKey = makeKey(insertionName, insertionId);
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@
|
|||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="bestInsertion"/>
|
||||
<xs:enumeration value="regretInsertion"/>
|
||||
<xs:enumeration value="randomInsertion"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
package com.graphhopper.jsprit.io.algorithm;
|
||||
|
||||
import com.graphhopper.jsprit.core.algorithm.VariablePlusFixedSolutionCostCalculatorFactory;
|
||||
import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm;
|
||||
import com.graphhopper.jsprit.core.algorithm.state.StateManager;
|
||||
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.VehicleRoutingTransportCosts;
|
||||
import com.graphhopper.jsprit.core.problem.driver.Driver;
|
||||
import com.graphhopper.jsprit.core.problem.job.Delivery;
|
||||
import com.graphhopper.jsprit.core.problem.job.Service;
|
||||
import com.graphhopper.jsprit.core.problem.job.Shipment;
|
||||
import com.graphhopper.jsprit.core.problem.solution.SolutionCostCalculator;
|
||||
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl;
|
||||
import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl;
|
||||
import com.graphhopper.jsprit.core.util.Solutions;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SkillsTest {
|
||||
@Test
|
||||
public void skillsAdded() {
|
||||
final HashSet<String> first = new HashSet<>(); first.add("C");
|
||||
final HashSet<String> second = new HashSet<>(); second.add("A");second.add("B");
|
||||
final VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE)
|
||||
.addVehicle(getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, first, false, 1, 1))
|
||||
.addVehicle(getVehicle("v2", Location.newInstance(0, 14), 0, 100, 20, second, false, 1, 1))
|
||||
.addJob(getService(Location.newInstance(0, 5), 0, 20, new HashSet<String>(), 1))
|
||||
.addJob(getService(Location.newInstance(0, 6), 0, 20, new HashSet<String>(), 1))
|
||||
.addJob(getShipment(Location.newInstance(10, 10), Location.newInstance(10, 12), 10, 20, 10, 50, first, 10));
|
||||
|
||||
builder.setRoutingCost(getTransportCosts());
|
||||
VehicleRoutingProblem vrp = builder.build();
|
||||
|
||||
VehicleRoutingProblemSolution bestSolution = getVehicleRoutingProblemSolution(vrp, "com/graphhopper/jsprit/io/algorithm/algorithmConfig.xml");
|
||||
assertEquals(bestSolution.getRoutes().size(), 1);
|
||||
assertFalse(bestSolution.getUnassignedJobs().isEmpty());
|
||||
|
||||
bestSolution = getVehicleRoutingProblemSolution(vrp, "com/graphhopper/jsprit/io/algorithm/configWithRandomInsert.xml");
|
||||
assertEquals(bestSolution.getRoutes().size(), 2);
|
||||
assertTrue(bestSolution.getUnassignedJobs().isEmpty());
|
||||
}
|
||||
|
||||
private VehicleRoutingProblemSolution getVehicleRoutingProblemSolution(VehicleRoutingProblem vrp, String config) {
|
||||
StateManager stateManager = new StateManager(vrp);
|
||||
final SolutionCostCalculator calculator = new VariablePlusFixedSolutionCostCalculatorFactory(stateManager).createCalculator();
|
||||
SolutionCostCalculator solutionCostCalculator = new SolutionCostCalculator() {
|
||||
@Override
|
||||
public double getCosts(VehicleRoutingProblemSolution solution) {
|
||||
return calculator.getCosts(solution) + solution.getUnassignedJobs().size() * 100;
|
||||
}
|
||||
};
|
||||
final VehicleRoutingAlgorithm algorithm = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, 1, config, stateManager, new ConstraintManager(vrp, stateManager), solutionCostCalculator);
|
||||
return Solutions.bestOf(algorithm.searchSolutions());
|
||||
}
|
||||
|
||||
|
||||
private static VehicleRoutingTransportCosts getTransportCosts() {
|
||||
return new VehicleRoutingTransportCosts() {
|
||||
@Override
|
||||
public double getBackwardTransportCost(Location from, Location to, double arrivalTime, Driver driver, Vehicle vehicle) { return getDistance(from, to, arrivalTime, vehicle); }
|
||||
|
||||
@Override
|
||||
public double getBackwardTransportTime(Location from, Location to, double arrivalTime, Driver driver, Vehicle vehicle) { return getDistance(from, to, arrivalTime, vehicle); }
|
||||
|
||||
@Override
|
||||
public double getTransportCost(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { return getDistance(from, to, departureTime, vehicle); }
|
||||
|
||||
@Override
|
||||
public double getTransportTime(Location from, Location to, double departureTime, Driver driver, Vehicle vehicle) { return getDistance(from, to, departureTime, vehicle); }
|
||||
|
||||
@Override
|
||||
public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) {
|
||||
return Math.abs(from.getCoordinate().getX() - to.getCoordinate().getX()) + Math.abs(from.getCoordinate().getY() - to.getCoordinate().getY());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Vehicle getVehicle(String id, Location location, int start, int end, int capacity, Set<String> skills, boolean returnToDepot, int fixedCost, int costPerDistance) {
|
||||
return VehicleImpl.Builder.newInstance(id)
|
||||
.setStartLocation(location).setLatestArrival(end).setEarliestStart(start).setType(
|
||||
VehicleTypeImpl.Builder.newInstance(UUID.randomUUID().toString()).setFixedCost(fixedCost).setCostPerDistance(costPerDistance).addCapacityDimension(0, capacity).build()
|
||||
)
|
||||
.addAllSkills(skills).setReturnToDepot(returnToDepot).build();
|
||||
|
||||
}
|
||||
|
||||
private static Service getService(Location location, int start, int end, Set<String> requiredSkills, int priority) {
|
||||
return Delivery.Builder.newInstance("service_" + UUID.randomUUID().toString().substring(0,5))
|
||||
.setLocation(location)
|
||||
.setServiceTime(1)
|
||||
.addTimeWindow(new TimeWindow(start, end))
|
||||
.addSizeDimension(0, 1)
|
||||
.addAllRequiredSkills(requiredSkills)
|
||||
.setPriority(priority)
|
||||
.setName(UUID.randomUUID().toString()).build();
|
||||
|
||||
}
|
||||
|
||||
private static Shipment getShipment(Location pickupLocation, Location dropoffLocation, int pickupStart, int pickupEnd, int dropoffStart, int dropoffEnd, Set<String> skills, int priority) {
|
||||
return Shipment.Builder.newInstance("shipment_" + UUID.randomUUID().toString().substring(0,5))
|
||||
.setPickupLocation(pickupLocation).setDeliveryLocation(dropoffLocation)
|
||||
.setDeliveryServiceTime(1).setPickupServiceTime(1)
|
||||
.addSizeDimension(0, 1)
|
||||
.setPickupTimeWindow(new TimeWindow(pickupStart, pickupEnd))
|
||||
.setDeliveryTimeWindow(new TimeWindow(dropoffStart, dropoffEnd))
|
||||
.addAllRequiredSkills(skills)
|
||||
.setPriority(priority)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<algorithm xmlns="http://www.w3schools.com"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.w3schools.com algorithm_schema.xsd">
|
||||
|
||||
<iterations>2000</iterations>
|
||||
|
||||
<construction>
|
||||
<insertion name="regretInsertion">
|
||||
|
||||
</insertion>
|
||||
</construction>
|
||||
|
||||
<strategy>
|
||||
<memory>1</memory>
|
||||
<searchStrategies>
|
||||
<searchStrategy name="randomRR">
|
||||
<selector name="selectBest"/>
|
||||
<acceptor name="schrimpfAcceptance">
|
||||
<alpha>0.2</alpha>
|
||||
<warmup>20</warmup>
|
||||
</acceptor>
|
||||
<modules>
|
||||
<module name="ruin_and_recreate">
|
||||
<ruin name="randomRuin">
|
||||
<share>0.9</share>
|
||||
</ruin>
|
||||
<insertion name="randomInsertion"/>
|
||||
</module>
|
||||
|
||||
</modules>
|
||||
<probability>0.1</probability>
|
||||
</searchStrategy>
|
||||
|
||||
<searchStrategy name="radialRR">
|
||||
<selector name="selectBest"/>
|
||||
<acceptor name="schrimpfAcceptance"/>
|
||||
|
||||
<modules>
|
||||
<module name="ruin_and_recreate">
|
||||
<ruin id="1" name="radialRuin">
|
||||
<share>0.3</share>
|
||||
</ruin>
|
||||
<insertion name="regretInsertion"/>
|
||||
</module>
|
||||
|
||||
</modules>
|
||||
<probability>0.4</probability>
|
||||
</searchStrategy>
|
||||
|
||||
<searchStrategy name="smallRadialRR">
|
||||
<selector name="selectBest"/>
|
||||
<acceptor name="schrimpfAcceptance"/>
|
||||
<modules>
|
||||
<module name="ruin_and_recreate">
|
||||
<ruin id="2" name="radialRuin">
|
||||
<share>0.05</share>
|
||||
</ruin>
|
||||
<insertion name="regretInsertion"/>
|
||||
</module>
|
||||
|
||||
</modules>
|
||||
<probability>0.2</probability>
|
||||
</searchStrategy>
|
||||
|
||||
</searchStrategies>
|
||||
</strategy>
|
||||
</algorithm>
|
||||
Loading…
Add table
Add a link
Reference in a new issue