1
0
Fork 0
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:
kandelirina 2019-02-12 07:55:29 +02:00 committed by GitHub
parent ca72c6f05f
commit b6d7640f5a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 168 additions and 32 deletions

View file

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

View file

@ -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()) {

View file

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

View file

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

View file

@ -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()
*/

View file

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

View file

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

View file

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

View file

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