From 7cc8cf18386bd1493b2f9598ee0eee9b4195bbd0 Mon Sep 17 00:00:00 2001 From: kandelirina Date: Fri, 17 Aug 2018 10:01:59 +0300 Subject: [PATCH] include driver can serve task count (#59) * include driver can serve task count * . * remove back * can serve fix --- .../algorithm/recreate/RandomInsertion.java | 50 +++++-- .../recreate/RandomInsertionTest.java | 136 +++++++++++++++--- 2 files changed, 157 insertions(+), 29 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RandomInsertion.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RandomInsertion.java index c002edef..7fa1db6c 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RandomInsertion.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RandomInsertion.java @@ -3,7 +3,10 @@ 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.job.Service; +import com.graphhopper.jsprit.core.problem.job.Shipment; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; +import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow; import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,9 +30,10 @@ public class RandomInsertion extends AbstractInsertionStrategy { void initJobsCanBeServedByNumDrivers() { for (Job job : vrp.getJobs().values()) { int count = 0; - for (Vehicle vehicle : vrp.getVehicles()) - if (vehicle.getSkills().values().containsAll(job.getRequiredSkills().values())) + for (Vehicle vehicle : vrp.getVehicles()) { + if (cabBeServedByVehicle(job, vehicle)) count++; + } jobCanBeServedByDriversCount.put(job.getId(), count); } @@ -52,14 +56,7 @@ public class RandomInsertion extends AbstractInsertionStrategy { List 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() { - @Override - public int compare(Job o1, Job o2) {return jobCanBeServedByDriversCount.get(o1.getId()) - jobCanBeServedByDriversCount.get(o2.getId());} - }); + sortJobs(unassignedJobList); for (Job unassignedJob : unassignedJobList) { List routes = new ArrayList<>(vehicleRoutes); @@ -99,4 +96,37 @@ public class RandomInsertion extends AbstractInsertionStrategy { return badJobs; } + void sortJobs(List unassignedJobList) { + final double p = random.nextDouble(); + if (p < .25) + Collections.sort(unassignedJobList, new AccordingToPriorities()); + else if (p < .75) + Collections.sort(unassignedJobList, new Comparator() { + @Override + public int compare(Job o1, Job o2) {return jobCanBeServedByDriversCount.get(o1.getId()) - jobCanBeServedByDriversCount.get(o2.getId());} + }); + } + + protected static boolean inTimeWindow(Job job, double earliestDeparture, double latestArrival) { + if (job instanceof Service) { + return inTimeWindow(((Service) job).getTimeWindows(), earliestDeparture, latestArrival); + } else if (job instanceof Shipment) { + Shipment shipment = (Shipment) job; + return inTimeWindow(shipment.getDeliveryTimeWindows(), earliestDeparture, latestArrival) && inTimeWindow(shipment.getPickupTimeWindows(), earliestDeparture, latestArrival); + } + return true; + } + + private static boolean cabBeServedByVehicle(Job job, Vehicle vehicle) { + return inTimeWindow(job, vehicle.getEarliestDeparture(), vehicle.getLatestArrival()) && vehicle.getSkills().values().containsAll(job.getRequiredSkills().values()) && vehicle.isTaskPermited(job.getId()); + } + + private static boolean inTimeWindow(Collection timeWindows, double earliestDeparture, double latestArrival) { + for (TimeWindow timeWindow : timeWindows) { + if (timeWindow.getStart() < latestArrival && timeWindow.getEnd() > earliestDeparture) + return true; + } + return false; + } + } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/RandomInsertionTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/RandomInsertionTest.java index 8afe4e9e..21a88755 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/RandomInsertionTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/RandomInsertionTest.java @@ -2,21 +2,16 @@ 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.job.*; 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 java.util.*; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; public class RandomInsertionTest { @@ -25,8 +20,8 @@ public class RandomInsertionTest { final HashSet first = new HashSet<>(); first.add("C"); final HashSet 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)) + .addVehicle(getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, first, false, 1, 1, false, null)) + .addVehicle(getVehicle("v2", Location.newInstance(0, 14), 0, 100, 20, second, false, 1, 1, false, null)) .addJob(getService(Location.newInstance(0, 5), 0, 20, new HashSet(), 1)) .addJob(getService(Location.newInstance(0, 6), 0, 20, new HashSet(), 1)); @@ -34,7 +29,7 @@ public class RandomInsertionTest { final Map jobCanBeServedByDriversCount = randomInsertion.jobCanBeServedByDriversCount; for (int numCanServe : jobCanBeServedByDriversCount.values()) - assertEquals(numCanServe, 2); + assertEquals(2, numCanServe); } @Test @@ -42,8 +37,8 @@ public class RandomInsertionTest { final HashSet first = new HashSet<>(); first.add("C"); final HashSet 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)) + .addVehicle(getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, first, false, 1, 1, true, null)) + .addVehicle(getVehicle("v2", Location.newInstance(0, 14), 0, 100, 20, second, false, 1, 1, true, null)) .addJob(getService(Location.newInstance(0, 5), 0, 20, new HashSet(), 1)) .addJob(getService(Location.newInstance(0, 6), 0, 20, new HashSet(), 1)); @@ -58,7 +53,7 @@ public class RandomInsertionTest { } } - assertEquals(numBreaks, 2); + assertEquals(2, numBreaks); } @Test @@ -66,8 +61,8 @@ public class RandomInsertionTest { final HashSet first = new HashSet<>(); first.add("C"); final HashSet 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)) + .addVehicle(getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, first, false, 1, 1, false, null)) + .addVehicle(getVehicle("v2", Location.newInstance(0, 14), 0, 100, 20, second, false, 1, 1, false, null)) .addJob(getService(Location.newInstance(0, 5), 0, 20, first, 1)) .addJob(getService(Location.newInstance(0, 6), 0, 20, second, 1)); @@ -75,7 +70,28 @@ public class RandomInsertionTest { final Map jobCanBeServedByDriversCount = randomInsertion.jobCanBeServedByDriversCount; for (int numCanServe : jobCanBeServedByDriversCount.values()) - assertEquals(numCanServe, 1); + assertEquals(1, numCanServe); + } + + @Test + public void initJobsCanBeServedByNumDrivers3() { + final Service service1 = getService(Location.newInstance(0, 5), 0, 20, new HashSet(), 1); + final Service service2 = getService(Location.newInstance(0, 6), 0, 20, new HashSet(), 1); + final Vehicle v1 = getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, new HashSet(), false, 1, 1, false, service1.getId()); + final Vehicle v2 = getVehicle("v2", Location.newInstance(0, 14), 0, 100, 20, new HashSet(), false, 1, 1, false, service2.getId()); + + + final VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE) + .addVehicle(v1) + .addVehicle(v2) + .addJob(service1) + .addJob(service2); + + final RandomInsertion randomInsertion = new RandomInsertion(null, builder.build()); + final Map jobCanBeServedByDriversCount = randomInsertion.jobCanBeServedByDriversCount; + + for (int numCanServe : jobCanBeServedByDriversCount.values()) + assertEquals(1, numCanServe); } private static Service getService(Location location, int start, int end, Set requiredSkills, int priority) { @@ -87,20 +103,102 @@ public class RandomInsertionTest { .addAllRequiredSkills(requiredSkills) .setPriority(priority) .setName(UUID.randomUUID().toString()).build(); - } - private static Vehicle getVehicle(String id, Location location, int start, int end, int capacity, Set skills, boolean returnToDepot, int fixedCost, int costPerDistance, boolean aBreak) { + private static Vehicle getVehicle(String id, Location location, int start, int end, int capacity, Set skills, boolean returnToDepot, int fixedCost, int costPerDistance, boolean aBreak, String excludeTask) { 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 (excludeTask != null) + builder.addExcludedTask(excludeTask); if (aBreak) builder.setBreak(Break.Builder.newInstance("break_" + id).build()); return builder.build(); } + @Test + public void inTimeWindowShipment() { + assertTrue(RandomInsertion.inTimeWindow(getShipment(50, 100, 120, 200), 75, 170)); + assertTrue(RandomInsertion.inTimeWindow(getShipment(50, 100, 120, 200), 0, 170)); + assertTrue(RandomInsertion.inTimeWindow(getShipment(50, 100, 120, 200), 75, 150)); + assertTrue(RandomInsertion.inTimeWindow(getShipment(50, 100, 120, 200), 90, 250)); + + assertFalse(RandomInsertion.inTimeWindow(getShipment(50, 100, 120, 200), 90, 110)); + assertFalse(RandomInsertion.inTimeWindow(getShipment(50, 100, 120, 200), 110, 250)); + } + + @Test + public void inTimeWindowService() { + assertTrue(RandomInsertion.inTimeWindow(getService(50, 100), 75, 170)); + assertTrue(RandomInsertion.inTimeWindow(getService(50, 100), 0, 75)); + assertTrue(RandomInsertion.inTimeWindow(getService(50, 100), 50, 100)); + + assertFalse(RandomInsertion.inTimeWindow(getService(50, 100), 110, 250)); + assertFalse(RandomInsertion.inTimeWindow(getService(50, 100), 0, 25)); + } + + @Test + public void sortTest() { + final HashSet skillsService1 = new HashSet<>(); + skillsService1.add("a"); skillsService1.add("b"); + final HashSet skillsService2 = new HashSet<>(); + skillsService2.add("c"); skillsService2.add("b"); + final HashSet skillsDriver1 = new HashSet<>(); + skillsDriver1.add("a"); skillsDriver1.add("b"); + final HashSet skillsDriver2 = new HashSet<>(); + skillsDriver2.add("c"); skillsDriver2.add("b"); + final HashSet skillsDriver3 = new HashSet<>(); + skillsDriver3.add("c"); skillsDriver3.add("b"); skillsDriver3.add("a"); + final Service service1 = getService(Location.newInstance(0, 5), 0, 20, skillsService1, 1); + final Service service2 = getService(Location.newInstance(0, 6), 0, 20, skillsService2, 1); + final Vehicle v1 = getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, skillsDriver1, false, 1, 1, false, service2.getId()); + final Vehicle v2 = getVehicle("v2", Location.newInstance(0, 14), 0, 100, 20, skillsDriver2, false, 1, 1, false, service1.getId()); + final Vehicle v3 = getVehicle("v3", Location.newInstance(0, 14), 0, 100, 20, skillsDriver3, false, 1, 1, false, service2.getId()); + + + final VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE) + .addVehicle(v1) + .addVehicle(v2) + .addVehicle(v3) + .addJob(service1) + .addJob(service2); + final RandomInsertion randomInsertion = new RandomInsertion(null, builder.build()); + + randomInsertion.random = new Random() { + @Override + public double nextDouble() { + return 0.5; + } + }; + + final List unassigned = new ArrayList<>(); + unassigned.add(service1); unassigned.add(service2); + Collections.shuffle(unassigned); + randomInsertion.sortJobs(unassigned); + assertEquals(1, (int) randomInsertion.jobCanBeServedByDriversCount.get(service2.getId())); + assertEquals(2, (int) randomInsertion.jobCanBeServedByDriversCount.get(service1.getId())); + assertEquals(service2, unassigned.get(0)); + assertEquals(service1, unassigned.get(1)); + } + + private Shipment getShipment(int pStart, int pEnd, int dStart, int dEnd) { + return Shipment.Builder.newInstance(UUID.randomUUID().toString()) + .setPickupLocation(Location.newInstance(UUID.randomUUID().toString())) + .setDeliveryLocation(Location.newInstance(UUID.randomUUID().toString())) + .setPickupTimeWindow(new TimeWindow(pStart, pEnd)) + .setDeliveryTimeWindow(new TimeWindow(dStart, dEnd)) + .build(); + } + + private Service getService(int start, int end) { + return Service.Builder.newInstance(UUID.randomUUID().toString()) + .setLocation(Location.newInstance(UUID.randomUUID().toString())) + .setTimeWindow(new TimeWindow(start, end)) + .build(); + } + }