1
0
Fork 0
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:
kandelirina 2018-05-01 13:34:59 +03:00 committed by kobyb
parent 5b0efb61e7
commit 8fa3c81983
9 changed files with 544 additions and 3 deletions

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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();
}
}