mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
infiniteWithBreaks (#77)
* infiniteWithBreaks * originalJobActivityFactory * if contains return * ctor for us * jobCanBeServedByDriversCount for infinite vrp * test fix * tests * bound * run tests * fix
This commit is contained in:
parent
ca72c6f05f
commit
b6d7640f5a
9 changed files with 168 additions and 32 deletions
|
|
@ -1,7 +1,6 @@
|
|||
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;
|
||||
|
|
@ -17,7 +16,15 @@ public class RandomInsertion extends AbstractInsertionStrategy {
|
|||
private static Logger logger = LoggerFactory.getLogger(BestInsertion.class);
|
||||
|
||||
private JobInsertionCostsCalculator bestInsertionCostCalculator;
|
||||
final Map<String, Integer> jobCanBeServedByDriversCount = new HashMap<>();
|
||||
final Map<String, Integer> jobCanBeServedByDriversCount = new HashMap<String, Integer>() {
|
||||
@Override
|
||||
public Integer get(Object key) {
|
||||
if (!super.containsKey(key)) {
|
||||
return 1;
|
||||
}
|
||||
return super.get(key);
|
||||
}
|
||||
};
|
||||
|
||||
public RandomInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) {
|
||||
super(vehicleRoutingProblem);
|
||||
|
|
@ -37,12 +44,6 @@ public class RandomInsertion extends AbstractInsertionStrategy {
|
|||
|
||||
jobCanBeServedByDriversCount.put(job.getId(), count);
|
||||
}
|
||||
|
||||
for (Vehicle vehicle : vrp.getVehicles()) {
|
||||
final Break aBreak = vehicle.getBreak();
|
||||
if (aBreak != null)
|
||||
jobCanBeServedByDriversCount.put(aBreak.getId(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart
|
|||
|
||||
private Map<String, StateId> createdStateIds = new HashMap<String, StateId>();
|
||||
|
||||
private int nuActivities;
|
||||
protected int nuActivities;
|
||||
|
||||
private int nuVehicleTypeKeys;
|
||||
|
||||
|
|
@ -130,26 +130,31 @@ public class StateManager implements RouteAndActivityStateGetter, IterationStart
|
|||
* @param vehicleRoutingProblem the corresponding VehicleRoutingProblem
|
||||
*/
|
||||
public StateManager(VehicleRoutingProblem vehicleRoutingProblem) {
|
||||
this(vehicleRoutingProblem, Math.max(10, vehicleRoutingProblem.getNuActivities() + 1));
|
||||
}
|
||||
|
||||
public StateManager(VehicleRoutingProblem vehicleRoutingProblem, int nuActivities) {
|
||||
stateIndexCounter = initialNoStates;
|
||||
int initialStateArrayLength = 30;
|
||||
this.vrp = vehicleRoutingProblem;
|
||||
nuActivities = Math.max(10, vrp.getNuActivities() + 1);
|
||||
this.nuActivities = Math.max(10, nuActivities);
|
||||
nuVehicleTypeKeys = Math.max(3, getNuVehicleTypes(vrp) + 2);
|
||||
activityStates = new Object[nuActivities][initialStateArrayLength];
|
||||
vehicleDependentActivityStates = new Object[nuActivities][nuVehicleTypeKeys][initialStateArrayLength];
|
||||
activityStates = new Object[this.nuActivities][initialStateArrayLength];
|
||||
vehicleDependentActivityStates = new Object[this.nuActivities][nuVehicleTypeKeys][initialStateArrayLength];
|
||||
// if(vehicleRoutingProblem.getFleetSize().equals(VehicleRoutingProblem.FleetSize.FINITE)){
|
||||
// isIndexedBased = true;
|
||||
// routeStatesArr = new Object[vrp.getVehicles().size() + 2][initialStateArrayLength];
|
||||
// vehicleDependentRouteStatesArr = new Object[vrp.getVehicles().size() + 2][nuVehicleTypeKeys][initialStateArrayLength];
|
||||
// }
|
||||
// else {
|
||||
isIndexedBased = false;
|
||||
routeStateMap = new HashMap<VehicleRoute, Object[]>();
|
||||
vehicleDependentRouteStateMap = new HashMap<VehicleRoute, Object[][]>();
|
||||
isIndexedBased = false;
|
||||
routeStateMap = new HashMap<VehicleRoute, Object[]>();
|
||||
vehicleDependentRouteStateMap = new HashMap<VehicleRoute, Object[][]>();
|
||||
// }
|
||||
problemStates = new Object[initialStateArrayLength];
|
||||
}
|
||||
|
||||
|
||||
private int getNuVehicleTypes(VehicleRoutingProblem vrp) {
|
||||
int maxIndex = 0;
|
||||
for (Vehicle v : vrp.getVehicles()) {
|
||||
|
|
|
|||
|
|
@ -534,7 +534,7 @@ public class VehicleRoutingProblem {
|
|||
* @author sschroeder
|
||||
*/
|
||||
public static enum FleetSize {
|
||||
FINITE, INFINITE
|
||||
FINITE, INFINITE, INFINITE_WITH_BREAKS
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -582,6 +582,10 @@ public class VehicleRoutingProblem {
|
|||
|
||||
private int nuActivities;
|
||||
|
||||
private int vehicleIndexCounter;
|
||||
|
||||
private final JobActivityFactory originalJobActivityFactory;
|
||||
|
||||
private final JobActivityFactory jobActivityFactory = new JobActivityFactory() {
|
||||
|
||||
@Override
|
||||
|
|
@ -603,6 +607,8 @@ public class VehicleRoutingProblem {
|
|||
this.nuActivities = builder.activityIndexCounter;
|
||||
this.allLocations = builder.allLocations;
|
||||
this.allJobs = builder.tentativeJobs;
|
||||
this.originalJobActivityFactory = builder.jobActivityFactory;
|
||||
this.vehicleIndexCounter = builder.vehicleIndexCounter;
|
||||
logger.info("setup problem: {}", this);
|
||||
}
|
||||
|
||||
|
|
@ -726,4 +732,25 @@ public class VehicleRoutingProblem {
|
|||
return acts;
|
||||
}
|
||||
|
||||
private void addBreak(Break aBreak) {
|
||||
if (activityMap.containsKey(aBreak))
|
||||
return;
|
||||
|
||||
List<AbstractActivity> breakActivities = originalJobActivityFactory.createActivities(aBreak);
|
||||
if (breakActivities.isEmpty())
|
||||
throw new IllegalArgumentException("At least one activity for break needs to be created by activityFactory!");
|
||||
for(AbstractActivity act : breakActivities) {
|
||||
act.setIndex(nuActivities);
|
||||
++nuActivities;
|
||||
}
|
||||
activityMap.put(aBreak, breakActivities);
|
||||
}
|
||||
|
||||
public void addVehicle(AbstractVehicle vehicle) {
|
||||
vehicle.setIndex(vehicleIndexCounter++);
|
||||
if (vehicle.getBreak() != null)
|
||||
addBreak(vehicle.getBreak());
|
||||
vehicles.add(vehicle);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import com.graphhopper.jsprit.core.problem.Location;
|
|||
import com.graphhopper.jsprit.core.problem.Skills;
|
||||
import com.graphhopper.jsprit.core.problem.job.Break;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Basic interface for vehicle-data.
|
||||
*
|
||||
|
|
@ -83,7 +85,9 @@ public interface Vehicle extends HasId, HasIndex {
|
|||
// default Object getUserData() {
|
||||
// return null;
|
||||
// };
|
||||
public abstract boolean isTaskPermited(String taskId);
|
||||
boolean isTaskPermited(String taskId);
|
||||
|
||||
public abstract void addProhibitedTask(String taskId);
|
||||
void addProhibitedTask(String taskId);
|
||||
|
||||
Collection<String> getProhibitedTasks();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,6 +107,10 @@ public class VehicleImpl extends AbstractVehicle {
|
|||
throw new IllegalArgumentException("NoVehicle should not have prohibited tasks");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getProhibitedTasks() {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -443,6 +447,11 @@ public class VehicleImpl extends AbstractVehicle {
|
|||
prohibitedTasks.add(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getProhibitedTasks() {
|
||||
return Collections.unmodifiableSet(prohibitedTasks);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -44,16 +44,8 @@ public class RandomInsertionTest {
|
|||
|
||||
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(2, numBreaks);
|
||||
assertEquals(1, jobCanBeServedByDriversCount.get("break_v1"), .001);
|
||||
assertEquals(1, jobCanBeServedByDriversCount.get("break_v2"), .001);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -176,7 +168,9 @@ public class RandomInsertionTest {
|
|||
};
|
||||
|
||||
final List<Job> unassigned = new ArrayList<>();
|
||||
unassigned.add(service1); unassigned.add(service2);
|
||||
unassigned.add(service1);
|
||||
unassigned.add(service2);
|
||||
|
||||
Collections.shuffle(unassigned);
|
||||
randomInsertion.sortJobs(unassigned);
|
||||
assertEquals(1, (int) randomInsertion.jobCanBeServedByDriversCount.get(service2.getId()));
|
||||
|
|
@ -185,6 +179,50 @@ public class RandomInsertionTest {
|
|||
assertEquals(service1, unassigned.get(1));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void sortTestWithTaskThatNotExist() {
|
||||
final HashSet<String> skillsService1 = new HashSet<>();
|
||||
skillsService1.add("a"); skillsService1.add("b");
|
||||
final HashSet<String> skillsDriver1 = new HashSet<>();
|
||||
skillsDriver1.add("a"); skillsDriver1.add("b");
|
||||
final HashSet<String> skillsDriver2 = new HashSet<>();
|
||||
skillsDriver2.add("c"); skillsDriver2.add("b");
|
||||
final HashSet<String> 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 Vehicle v1 = getVehicle("v1", Location.newInstance(0, 0), 0, 100, 20, skillsDriver1, false, 1, 1, false, null);
|
||||
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, null);
|
||||
|
||||
|
||||
final VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE)
|
||||
.addVehicle(v1)
|
||||
.addVehicle(v2)
|
||||
.addVehicle(v3)
|
||||
.addJob(service1);
|
||||
final RandomInsertion randomInsertion = new RandomInsertion(null, builder.build());
|
||||
|
||||
randomInsertion.random = new Random() {
|
||||
@Override
|
||||
public double nextDouble() {
|
||||
return 0.5;
|
||||
}
|
||||
};
|
||||
|
||||
final Break aBreak = Break.Builder.newInstance(UUID.randomUUID().toString()).setServiceTime(60).addTimeWindow(0, 160).build();
|
||||
final List<Job> unassigned = new ArrayList<>();
|
||||
unassigned.add(service1);
|
||||
unassigned.add(aBreak);
|
||||
|
||||
Collections.shuffle(unassigned);
|
||||
randomInsertion.sortJobs(unassigned);
|
||||
assertEquals(2, (int) randomInsertion.jobCanBeServedByDriversCount.get(service1.getId()));
|
||||
assertEquals(1, (int) randomInsertion.jobCanBeServedByDriversCount.get(aBreak.getId()));
|
||||
assertEquals(aBreak, 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()))
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import org.junit.Test;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
|
@ -356,4 +357,12 @@ public class StateManagerTest {
|
|||
}
|
||||
stateManager.putTypedInternalRouteState(route,myState,1.);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldSetPassedNuActivities() {
|
||||
final int nuActivities = 10 + new Random().nextInt(1_000);
|
||||
final StateManager stateManager = new StateManager(vrpMock, nuActivities);
|
||||
assertEquals(nuActivities, stateManager.nuActivities);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import org.junit.Test;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.matchers.JUnitMatchers.hasItem;
|
||||
|
|
@ -559,4 +560,30 @@ public class VehicleRoutingProblemTest {
|
|||
assertEquals(2, veh2.getVehicleTypeIdentifier().getIndex());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAddBreakIfNotExist() {
|
||||
VehicleImpl veh1 = VehicleImpl.Builder.newInstance("v1")
|
||||
.setStartLocation(TestUtils.loc("start", Coordinate.newInstance(0, 1)))
|
||||
.setBreak(Break.Builder.newInstance(UUID.randomUUID().toString()).setServiceTime(60).build())
|
||||
.setEndLocation(Location.newInstance("end")).build();
|
||||
final Service service = Service.Builder.newInstance("myService").setLocation(Location.newInstance("loc")).build();
|
||||
|
||||
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance().setFleetSize(FleetSize.INFINITE_WITH_BREAKS);
|
||||
vrpBuilder.addVehicle(veh1);
|
||||
vrpBuilder.addJob(service);
|
||||
final VehicleRoutingProblem vrp = vrpBuilder.build();
|
||||
|
||||
VehicleImpl veh2 = VehicleImpl.Builder.newInstance("v2")
|
||||
.setStartLocation(TestUtils.loc("start", Coordinate.newInstance(0, 1)))
|
||||
.setBreak(Break.Builder.newInstance(UUID.randomUUID().toString()).setServiceTime(20).build())
|
||||
.setEndLocation(Location.newInstance("end")).build();
|
||||
|
||||
assertEquals(0, veh2.getIndex());
|
||||
vrp.addVehicle(veh2);
|
||||
assertEquals(1, veh1.getIndex());
|
||||
assertEquals(2, veh2.getIndex());
|
||||
assertEquals(2, vrp.getActivities(veh1.getBreak()).get(0).getIndex());
|
||||
assertEquals(3, vrp.getActivities(veh2.getBreak()).get(0).getIndex());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ import com.graphhopper.jsprit.core.problem.job.Break;
|
|||
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
|
@ -256,6 +254,24 @@ public class VehicleImplTest {
|
|||
assertNull(three.getUserData());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProhibitedTasks() {
|
||||
Set<String> prohibitedTasks = new HashSet<>();
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
prohibitedTasks.add(UUID.randomUUID().toString());
|
||||
}
|
||||
VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build();
|
||||
VehicleImpl.Builder vehicleBuilder = VehicleImpl.Builder.newInstance("v").setType(type1)
|
||||
.setStartLocation(Location.newInstance("start"));
|
||||
|
||||
for (String task : prohibitedTasks) {
|
||||
vehicleBuilder.addExcludedTask(task);
|
||||
}
|
||||
|
||||
final Collection<String> prohibitedTasksReturned = vehicleBuilder.build().getProhibitedTasks();
|
||||
assertEquals(prohibitedTasks, prohibitedTasksReturned);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBreakTimesIncludedInKey() {
|
||||
VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("type").build();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue