/**
*
*/
package rinde.sim.pdptw.central;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.newLinkedList;
import static com.google.common.collect.Sets.newHashSet;
import static com.google.common.collect.Sets.newLinkedHashSet;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import javax.annotation.Nullable;
import javax.measure.Measure;
import javax.measure.quantity.Duration;
import javax.measure.quantity.Length;
import javax.measure.quantity.Velocity;
import javax.measure.unit.SI;
import javax.measure.unit.Unit;
import rinde.sim.core.Simulator;
import rinde.sim.core.SimulatorAPI;
import rinde.sim.core.graph.Point;
import rinde.sim.core.model.ModelProvider;
import rinde.sim.core.model.pdp.PDPModel;
import rinde.sim.core.model.pdp.PDPModel.ParcelState;
import rinde.sim.core.model.pdp.PDPModel.VehicleParcelActionInfo;
import rinde.sim.core.model.pdp.Parcel;
import rinde.sim.pdptw.central.GlobalStateObject.VehicleStateObject;
import rinde.sim.pdptw.common.DefaultParcel;
import rinde.sim.pdptw.common.DefaultVehicle;
import rinde.sim.pdptw.common.PDPRoadModel;
import rinde.sim.pdptw.common.ParcelDTO;
import rinde.sim.pdptw.common.StatisticsDTO;
import rinde.sim.pdptw.common.VehicleDTO;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.math.DoubleMath;
/**
* @author Rinde van Lon <rinde.vanlon@cs.kuleuven.be>
*
*/
public final class Solvers {
private Solvers() {}
/**
* Creates a builder for creating {@link SimulationSolver} instances. For more
* information see {@link AdapterBuilder}.
* @param sol The solver to use internally.
* @return The builder.
*/
public static AdapterBuilder<SimulationSolver> solverBuilder(Solver sol) {
return new AdapterBuilder<SimulationSolver>(sol);
}
/**
* Creates a builder for creating {@link SimulationConverter} instances.
* @return The builder.
*/
public static AdapterBuilder<SimulationConverter> converterBuilder() {
return new AdapterBuilder<SimulationConverter>(null);
}
/**
* Computes the duration which is required to travel the specified distance
* with the given velocity. Note: although time is normally a long, we use
* double here instead. Converting it to long in this method would introduce
* rounding in a too early stage.
* @param speed The travel speed.
* @param distance The distance to travel.
* @param outputTimeUnit The time unit to use for the output.
* @return The time it takes to travel the specified distance with the
* specified speed.
*/
public static double computeTravelTime(Measure<Double, Velocity> speed,
Measure<Double, Length> distance, Unit<Duration> outputTimeUnit) {
// meters
return Measure.valueOf(distance.doubleValue(SI.METER)
// divided by m/s
/ speed.doubleValue(SI.METERS_PER_SECOND),
// gives seconds
SI.SECOND)
// convert to desired unit
.doubleValue(outputTimeUnit);
}
/**
* Computes a {@link StatisticsDTO} instance for the given
* {@link GlobalStateObject} and routes. For each vehicle in the state the
* specified route is used and its arrival times, tardiness and travel times
* are computed. The resulting {@link StatisticsDTO} has the same properties
* as performing a simulation with the same state. However, since the current
* state may be half-way a simulation, it is possible that the returned
* statistics describe only a partial simulation. As a result
* {@link StatisticsDTO#totalDeliveries} does not necessarily equal
* {@link StatisticsDTO#totalPickups}.
* @param state The state which represents a simulation.
* @param routes Specifies the route the vehicles are currently following,
* must be of same size as the number of vehicles (one route per
* vehicle). If this is <code>null</code> the
* {@link VehicleStateObject#route} field must be set instead for
* <b>each</b> vehicle.
* @return The statistics that will be generated when executing this
* simulation.
*/
public static StatisticsDTO computeStats(GlobalStateObject state,
@Nullable ImmutableList<ImmutableList<ParcelDTO>> routes) {
final Optional<ImmutableList<ImmutableList<ParcelDTO>>> r = Optional
.fromNullable(routes);
if (r.isPresent()) {
checkArgument(
state.vehicles.size() == r.get().size(),
"Exactly one route should be supplied for every vehicle in state. %s vehicle(s) in state, received %s route(s).",
state.vehicles.size(), r.get().size());
}
double totalDistance = 0;
int totalDeliveries = 0;
int totalPickups = 0;
long pickupTardiness = 0;
long deliveryTardiness = 0;
long overTime = 0;
final long startTime = state.time;
long maxTime = 0;
int movedVehicles = 0;
final Set<ParcelDTO> parcels = newHashSet();
final ImmutableList.Builder<ImmutableList<Long>> arrivalTimesBuilder = ImmutableList
.builder();
for (int i = 0; i < state.vehicles.size(); i++) {
final VehicleStateObject vso = state.vehicles.get(i);
checkArgument(r.isPresent() || vso.route.isPresent());
final ImmutableList.Builder<Long> truckArrivalTimesBuilder = ImmutableList
.builder();
truckArrivalTimesBuilder.add(state.time);
ImmutableList<ParcelDTO> route;
if (r.isPresent()) {
route = r.get().get(i);
} else {
route = vso.route.get();
}
parcels.addAll(route);
long time = state.time;
Point vehicleLocation = vso.location;
final Measure<Double, Velocity> speed = Measure.valueOf(vso.speed,
state.speedUnit);
final Set<ParcelDTO> seen = newHashSet();
for (int j = 0; j < route.size(); j++) {
final ParcelDTO cur = route.get(j);
final boolean inCargo = vso.contents.contains(cur)
|| seen.contains(cur);
seen.add(cur);
if (vso.destination != null && j == 0) {
checkArgument(
vso.destination == cur,
"If a vehicle has a destination, the first position in the route must equal this. Expected %s, is %s.",
vso.destination, cur);
}
boolean firstAndServicing = false;
if (j == 0 && vso.remainingServiceTime > 0) {
// we are already at the service location
firstAndServicing = true;
truckArrivalTimesBuilder.add(time);
time += vso.remainingServiceTime;
} else {
// vehicle is not there yet, go there first, then service
final Point nextLoc = inCargo ? cur.destinationLocation
: cur.pickupLocation;
final Measure<Double, Length> distance = Measure.valueOf(
Point.distance(vehicleLocation, nextLoc), state.distUnit);
totalDistance += distance.getValue();
vehicleLocation = nextLoc;
final long tt = DoubleMath.roundToLong(
computeTravelTime(speed, distance, state.timeUnit),
RoundingMode.CEILING);
time += tt;
}
if (inCargo) {
// check if we are early
if (cur.deliveryTimeWindow.isBeforeStart(time)) {
time = cur.deliveryTimeWindow.begin;
}
if (!firstAndServicing) {
truckArrivalTimesBuilder.add(time);
time += cur.deliveryDuration;
}
// delivering
if (cur.deliveryTimeWindow.isAfterEnd(time)) {
final long tardiness = time - cur.deliveryTimeWindow.end;
deliveryTardiness += tardiness;
}
totalDeliveries++;
} else {
// check if we are early
if (cur.pickupTimeWindow.isBeforeStart(time)) {
time = cur.pickupTimeWindow.begin;
}
if (!firstAndServicing) {
truckArrivalTimesBuilder.add(time);
time += cur.pickupDuration;
}
// picking up
if (cur.pickupTimeWindow.isAfterEnd(time)) {
final long tardiness = time - cur.pickupTimeWindow.end;
pickupTardiness += tardiness;
}
totalPickups++;
}
}
// go to depot
final Measure<Double, Length> distance = Measure.valueOf(
Point.distance(vehicleLocation, vso.startPosition), state.distUnit);
totalDistance += distance.getValue();
final long tt = DoubleMath.roundToLong(
computeTravelTime(speed, distance, state.timeUnit),
RoundingMode.CEILING);
time += tt;
// check overtime
if (vso.availabilityTimeWindow.isAfterEnd(time)) {
overTime += time - vso.availabilityTimeWindow.end;
}
maxTime = Math.max(maxTime, time);
truckArrivalTimesBuilder.add(time);
arrivalTimesBuilder.add(truckArrivalTimesBuilder.build());
if (time > startTime) {
// time has progressed -> the vehicle has moved
movedVehicles++;
}
}
final int totalParcels = parcels.size();
final int totalVehicles = state.vehicles.size();
final long simulationTime = maxTime - startTime;
return new ExtendedStats(totalDistance, totalPickups, totalDeliveries,
totalParcels, totalParcels, pickupTardiness, deliveryTardiness, 0,
simulationTime, true, totalVehicles, overTime, totalVehicles,
movedVehicles, state.timeUnit, state.distUnit, state.speedUnit,
arrivalTimesBuilder.build());
}
/**
* Converts the specified collection containing {@link DefaultParcel}s into an
* {@link ImmutableList} of {@link ParcelDTO}s.
* @param parcels The parcels to convert.
* @return A list of {@link ParcelDTO}s in the same order as in the provided
* collection.
*/
public static ImmutableList<ParcelDTO> toDtoList(
Collection<DefaultParcel> parcels) {
final ImmutableList.Builder<ParcelDTO> builder = ImmutableList.builder();
for (final DefaultParcel dp : parcels) {
builder.add(dp.dto);
}
return builder.build();
}
/**
* Converts the specified collection of collections containing
* {@link DefaultParcel}s into a list of lists containing {@link ParcelDTO}s.
* @param routes The collection of collections of parcels to convert.
* @return A list of lists of {@link ParcelDTO}s in the same order as the
* provided lists.
*/
public static ImmutableList<ImmutableList<ParcelDTO>> toDtoLists(
Collection<? extends Collection<DefaultParcel>> routes) {
final ImmutableList.Builder<ImmutableList<ParcelDTO>> newRoutes = ImmutableList
.builder();
for (final Collection<DefaultParcel> route : routes) {
newRoutes.add(toDtoList(route));
}
return newRoutes.build();
}
// converts the routes received from Solver.solve(..) into a format which is
// expected by the simulator
static List<Queue<DefaultParcel>> convertRoutes(StateContext cont,
List<? extends List<ParcelDTO>> routes) {
final ImmutableList.Builder<Queue<DefaultParcel>> routesBuilder = ImmutableList
.builder();
for (final List<ParcelDTO> route : routes) {
final Queue<DefaultParcel> newRoute = newLinkedList();
for (final ParcelDTO dto : route) {
checkArgument(cont.parcelMap.containsKey(dto),
"Parcel %s is not known in the context.", dto);
newRoute.add(cont.parcelMap.get(dto));
}
routesBuilder.add(newRoute);
}
return routesBuilder.build();
}
static Collection<DefaultParcel> conv(Collection<Parcel> input) {
final List<DefaultParcel> l = newArrayList();
for (final Parcel p : input) {
checkArgument(p instanceof DefaultParcel);
l.add((DefaultParcel) p);
}
return l;
}
static StateContext convert(PDPRoadModel rm, PDPModel pm,
Collection<DefaultVehicle> vehicles,
Collection<DefaultParcel> availableParcels, Measure<Long, Duration> time,
Optional<ImmutableList<ImmutableList<DefaultParcel>>> currentRoutes) {
final ImmutableMap<VehicleDTO, DefaultVehicle> vehicleMap = toVehicleMap(vehicles);
final ImmutableList.Builder<VehicleStateObject> vbuilder = ImmutableList
.builder();
final ImmutableMap.Builder<ParcelDTO, DefaultParcel> allParcels = ImmutableMap
.builder();
@Nullable
Iterator<ImmutableList<DefaultParcel>> routeIterator = null;
if (currentRoutes.isPresent()) {
checkArgument(currentRoutes.get().size() == vehicles.size(),
"The number of routes (%s) must equal the number of vehicles (%s).",
currentRoutes.get().size(), vehicles.size());
routeIterator = currentRoutes.get().iterator();
}
final ImmutableMap.Builder<ParcelDTO, DefaultParcel> availableDestParcels = ImmutableMap
.builder();
for (final DefaultVehicle v : vehicles) {
final ImmutableMap<ParcelDTO, DefaultParcel> contentsMap = contentsToMap(
pm, v);
@Nullable
ImmutableList<DefaultParcel> route = null;
if (routeIterator != null) {
route = routeIterator.next();
}
vbuilder.add(convertToVehicleState(rm, pm, v, contentsMap, route,
availableDestParcels));
allParcels.putAll(contentsMap);
}
final ImmutableMap<ParcelDTO, DefaultParcel> availableMap = toMap(availableParcels);
final ImmutableMap<ParcelDTO, DefaultParcel> availableDestMap = availableDestParcels
.build();
final Map<ParcelDTO, DefaultParcel> toAdd = Maps.difference(availableMap,
availableDestMap).entriesOnlyOnRight();
allParcels.putAll(availableMap);
allParcels.putAll(toAdd);
final ImmutableSet<ParcelDTO> availableParcelsKeys = ImmutableSet
.<ParcelDTO> builder()
.addAll(availableMap.keySet())
.addAll(toAdd.keySet()).build();
return new StateContext(new GlobalStateObject(availableParcelsKeys,
vbuilder.build(), time.getValue().longValue(), time.getUnit(),
rm.getSpeedUnit(), rm.getDistanceUnit()), vehicleMap,
allParcels.build());
}
static ImmutableMap<ParcelDTO, DefaultParcel> contentsToMap(PDPModel pm,
DefaultVehicle vehicle) {
// this is ok since we actually check the type
@SuppressWarnings({ "unchecked", "rawtypes" })
final Set<DefaultParcel> ps = Collections.checkedSet(
(Set) newLinkedHashSet(pm.getContents(vehicle)), DefaultParcel.class);
return toMap(ps);
}
// TODO check for bugs
static VehicleStateObject convertToVehicleState(PDPRoadModel rm, PDPModel pm,
DefaultVehicle vehicle, ImmutableMap<ParcelDTO, DefaultParcel> contents,
@Nullable ImmutableList<DefaultParcel> route,
ImmutableMap.Builder<ParcelDTO, DefaultParcel> availableDestBuilder) {
final boolean isIdle = pm.getVehicleState(vehicle) == PDPModel.VehicleState.IDLE;
long remainingServiceTime = 0;
@Nullable
DefaultParcel destination = null;
if (!isIdle) {
final VehicleParcelActionInfo vpai = pm.getVehicleActionInfo(vehicle);
destination = ((DefaultParcel) vpai.getParcel());
remainingServiceTime = vpai.timeNeeded();
} else if (!rm.isVehicleDiversionAllowed()) {
// check whether the vehicle is already underway to parcel
destination = rm.getDestinationToParcel(vehicle);
}
// destinations which are not yet picked up should be put in the builder
if (destination != null && !pm.getParcelState(destination).isPickedUp()) {
availableDestBuilder.put(destination.dto, destination);
}
@Nullable
ImmutableList<ParcelDTO> r = null;
if (route != null) {
r = toDtoList(route);
}
return new VehicleStateObject(vehicle.getDTO(), rm.getPosition(vehicle),
contents.keySet(), remainingServiceTime, destination == null ? null
: destination.dto, r);
}
static ImmutableMap<ParcelDTO, DefaultParcel> toMap(
Collection<DefaultParcel> parcels) {
final ImmutableMap.Builder<ParcelDTO, DefaultParcel> parcelMapBuilder = ImmutableMap
.builder();
for (final DefaultParcel dp : parcels) {
parcelMapBuilder.put(dp.dto, dp);
}
return parcelMapBuilder.build();
}
static ImmutableMap<VehicleDTO, DefaultVehicle> toVehicleMap(
Collection<DefaultVehicle> vehicles) {
final ImmutableMap.Builder<VehicleDTO, DefaultVehicle> vehicleMapBuilder = ImmutableMap
.builder();
for (final DefaultVehicle dp : vehicles) {
vehicleMapBuilder.put(dp.getDTO(), dp);
}
return vehicleMapBuilder.build();
}
/**
* Converter that converts simulations into {@link StateContext} instances
* which are needed to call {@link Solver#solve(GlobalStateObject)}.
* @author Rinde van Lon <rinde.vanlon@cs.kuleuven.be>
*/
public interface SimulationConverter {
/**
* Converts the simulation into a {@link StateContext} object.
* @param args {@link SolveArgs}.
* @return {@link StateContext}.
*/
StateContext convert(SolveArgs args);
}
/**
* Builder for specifying parameters used in {@link SimulationSolver} and
* {@link SimulationConverter}.
* @author Rinde van Lon <rinde.vanlon@cs.kuleuven.be>
*/
public static final class SolveArgs {
Optional<Collection<DefaultParcel>> parcels;
Optional<ImmutableList<ImmutableList<DefaultParcel>>> currentRoutes;
private SolveArgs() {
parcels = Optional.absent();
currentRoutes = Optional.absent();
}
/**
* @return {@link SolveArgs} builder.
*/
public static SolveArgs create() {
return new SolveArgs();
}
/**
* Indicates that receivers of this object should use all parcels it knows.
* @return This, as per the builder pattern.
*/
public SolveArgs useAllParcels() {
parcels = Optional.absent();
return this;
}
/**
* Indicates that receivers of this object should use only the parcels that
* are specified.
* @param ps The parcels to use.
* @return This, as per the builder pattern.
*/
public SolveArgs useParcels(Collection<DefaultParcel> ps) {
parcels = Optional.of(ps);
return this;
}
/**
* Indicates that receivers of this object should use no current routes for
* the vehicles it knows about.
* @return This, as per the builder pattern.
*/
public SolveArgs noCurrentRoutes() {
currentRoutes = Optional.absent();
return this;
}
/**
* Indicates that receivers of this object should use the specified current
* routes for the vehicles it knows about. The number of specified route
* needs to match the number of known vehicles.
* @param cr The current routes to use.
* @return This, as per the builder pattern.
*/
public SolveArgs useCurrentRoutes(
ImmutableList<ImmutableList<DefaultParcel>> cr) {
currentRoutes = Optional.of(cr);
return this;
}
}
/**
* Adapter for {@link Solver}s.
* @author Rinde van Lon <rinde.vanlon@cs.kuleuven.be>
*/
public static class SimulationSolver implements SimulationConverter {
final Optional<Solver> solver;
final SimulatorAPI simulator;
final PDPRoadModel roadModel;
final PDPModel pdpModel;
final List<DefaultVehicle> vehicles;
SimulationSolver(Optional<Solver> s, PDPRoadModel rm, PDPModel pm,
SimulatorAPI sim, List<DefaultVehicle> vs) {
solver = s;
simulator = sim;
roadModel = rm;
pdpModel = pm;
vehicles = vs;
}
/**
* Calls the {@link Solver} to solve the problem as defined by the current
* simulation state.
* @param args {@link SolveArgs} specifying what information to include.
* @return A list containing routes for each vehicle known to this solver.
*/
public List<Queue<DefaultParcel>> solve(SolveArgs args) {
return solve(convert(args));
}
/**
* Calls the {@link Solver} to solve the problem as defined by the current
* simulation state.
* @param state The {@link StateContext} that specifies the current
* simulation state.
* @return A list of routes, one for each vehicle.
*/
public List<Queue<DefaultParcel>> solve(StateContext state) {
return Solvers.convertRoutes(state, solver.get().solve(state.state));
}
@Override
public StateContext convert(SolveArgs args) {
final Collection<DefaultVehicle> vs = vehicles.isEmpty() ? roadModel
.getObjectsOfType(DefaultVehicle.class) : vehicles;
final Collection<DefaultParcel> ps = args.parcels.isPresent() ? args.parcels
.get()
: conv(pdpModel.getParcels(ParcelState.ANNOUNCED,
ParcelState.AVAILABLE, ParcelState.PICKING_UP));
return Solvers.convert(roadModel, pdpModel, vs, ps, time(),
args.currentRoutes);
}
Measure<Long, Duration> time() {
return Measure.valueOf(simulator.getCurrentTime(),
simulator.getTimeUnit());
}
}
/**
* Builder for creating adapters for {@link Solver}s that need to solve
* simulation instances. For creating an adapter four different pieces of
* information are required, each can be supplied to this builder via a
* variety of methods which are listed below.
* <ul>
* <li>{@link PDPRoadModel} - can be supplied directly, via a
* {@link ModelProvider} or via {@link Simulator} instance</li>
* <li>{@link PDPModel} - can be supplied directly, via a
* {@link ModelProvider} or via {@link Simulator} instance</li>
* <li>{@link SimulatorAPI} - can be supplied directly or via a
* {@link Simulator} instance.</li>
* <li>A number of {@link DefaultVehicle}s - can be supplied directly or if
* not supplied all vehicles available in the {@link PDPRoadModel} instance
* will be used.</li>
* </ul>
*
* @param <T> The type of adapter to produce.
* @author Rinde van Lon <rinde.vanlon@cs.kuleuven.be>
*/
public static class AdapterBuilder<T extends SimulationConverter> {
Simulator simulator;
SimulatorAPI simulatorApi;
ModelProvider modelProvider;
PDPRoadModel roadModel;
PDPModel pdpModel;
final List<DefaultVehicle> vehicles;
final Optional<Solver> solver;
AdapterBuilder(@Nullable Solver s) {
solver = Optional.fromNullable(s);
vehicles = newArrayList();
}
/**
* @param sim The {@link Simulator} to provide to the adapter.
* @return This, as per the builder pattern.
*/
public AdapterBuilder<T> with(Simulator sim) {
simulator = sim;
return this;
}
/**
* @param mp The {@link ModelProvider} to use for extracting the models.
* Calls to this method take precedence over
* {@link #with(Simulator)}.
* @return This, as per the builder pattern.
*/
public AdapterBuilder<T> with(ModelProvider mp) {
modelProvider = mp;
return this;
}
/**
* @param rm The {@link PDPRoadModel} to use in the adapter. Calls to this
* method take precedence over {@link #with(ModelProvider)} and
* {@link #with(Simulator)}.
* @return This, as per the builder pattern.
*/
public AdapterBuilder<T> with(PDPRoadModel rm) {
roadModel = rm;
return this;
}
/**
* @param pm The {@link PDPModel} to use in the adapter. Calls to this
* method take precedence over {@link #with(ModelProvider)} and
* {@link #with(Simulator)}.
* @return This, as per the builder pattern.
*/
public AdapterBuilder<T> with(PDPModel pm) {
pdpModel = pm;
return this;
}
/**
* @param sim The {@link SimulatorAPI} to use in the adapter. Calls to this
* method take precedence over {@link #with(Simulator)}.
* @return This, as per the builder pattern.
*/
public AdapterBuilder<T> with(SimulatorAPI sim) {
simulatorApi = sim;
return this;
}
/**
* Adds the specified vehicle to the resulting adapter, the vehicle will be
* included in the resulting adapter. When no vehicles are supplied, the
* adapter will use all vehicles in {@link PDPRoadModel}.
* @param dv The {@link DefaultVehicle} to add.
* @return This, as per the builder pattern.
*/
public AdapterBuilder<T> with(DefaultVehicle dv) {
vehicles.add(dv);
return this;
}
/**
* Adds the specified vehicles to the resulting adapter, the vehicles will
* be included in the resulting adapter. When no vehicles are supplied, the
* adapter will use all vehicles in {@link PDPRoadModel}.
* @param dv The {@link DefaultVehicle}s to include.
* @return This, as per the builder pattern.
*/
public AdapterBuilder<T> with(List<? extends DefaultVehicle> dv) {
vehicles.addAll(dv);
return this;
}
/**
* Builds the adapter.
* @return The newly created adapter.
*/
@SuppressWarnings("unchecked")
public T build() {
PDPRoadModel rm = roadModel;
PDPModel pm = pdpModel;
if (rm == null || pm == null) {
// in this case we need a model provider
ModelProvider mp = modelProvider;
if (mp == null) {
checkArgument(
simulator != null,
"Attempt to find a model provider failed. Either provide the models directly, provide a model provider or a simulator.");
mp = simulator.getModelProvider();
}
if (rm == null) {
rm = mp.getModel(PDPRoadModel.class);
}
if (pm == null) {
pm = mp.getModel(PDPModel.class);
}
}
SimulatorAPI sapi = simulatorApi;
if (sapi == null) {
sapi = simulator;
}
if (sapi != null && rm != null && pm != null) {
return (T) new SimulationSolver(solver, rm, pm, sapi, vehicles);
} else {
throw new IllegalArgumentException(
"Not all required components could be found, PDPRoadModel: " + rm
+ ", PDPModel: " + pm + ", SimulatorAPI: " + sapi);
}
}
/**
* Builds an adapter which can deal with only one vehicle.
* @return A new created adapter.
*/
public T buildSingle() {
checkArgument(vehicles.size() == 1);
return build();
}
}
/**
* Value object containing representing the state of a simulation. It contains
* a {@link GlobalStateObject} (the actual state) and two maps with references
* to the original vehicles and parcels. Using these maps the state object can
* be translated back to the original simulation objects.
* @author Rinde van Lon <rinde.vanlon@cs.kuleuven.be>
*/
public static class StateContext {
/**
* A reference to the {@link GlobalStateObject}.
*/
public final GlobalStateObject state;
/**
* A mapping of {@link VehicleDTO} to {@link DefaultVehicle}.
*/
public final ImmutableMap<VehicleDTO, DefaultVehicle> vehicleMap;
/**
* A mapping of {@link ParcelDTO} to {@link DefaultParcel}.
*/
public final ImmutableMap<ParcelDTO, DefaultParcel> parcelMap;
StateContext(GlobalStateObject state,
ImmutableMap<VehicleDTO, DefaultVehicle> vehicleMap,
ImmutableMap<ParcelDTO, DefaultParcel> parcelMap) {
this.state = state;
this.vehicleMap = vehicleMap;
this.parcelMap = parcelMap;
}
}
// only used for testing
static class ExtendedStats extends StatisticsDTO {
private static final long serialVersionUID = 3682772955122186862L;
final ImmutableList<ImmutableList<Long>> arrivalTimes;
ExtendedStats(double dist, int pick, int del, int parc, int accP,
long pickTar, long delTar, long compT, long simT, boolean finish,
int atDepot, long overT, int total, int moved, Unit<Duration> time,
Unit<Length> distUnit, Unit<Velocity> speed,
ImmutableList<ImmutableList<Long>> arrivalTimes) {
super(dist, pick, del, parc, accP, pickTar, delTar, compT, simT, finish,
atDepot, overT, total, moved, time, distUnit, speed);
this.arrivalTimes = arrivalTimes;
}
}
}