All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rinde.sim.pdptw.central.arrays.ArraysSolvers Maven / Gradle / Ivy

The newest version!
/**
 * 
 */
package rinde.sim.pdptw.central.arrays;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Sets.newHashSet;

import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Nullable;
import javax.measure.Measure;
import javax.measure.converter.UnitConverter;
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.graph.Point;
import rinde.sim.pdptw.central.GlobalStateObject;
import rinde.sim.pdptw.central.GlobalStateObject.VehicleStateObject;
import rinde.sim.pdptw.central.Solvers;
import rinde.sim.pdptw.common.ParcelDTO;
import rinde.sim.util.TimeWindow;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.UnmodifiableIterator;
import com.google.common.math.DoubleMath;

/**
 * @author Rinde van Lon 
 * 
 */
public final class ArraysSolvers {

  // TODO create a Converter class which uses the Units as constructor
  // parameters. All methods can then easily access them, making most of the
  // code much cleaner.

  private ArraysSolvers() {}

  /**
   * Converts the list of points on a plane into a travel time matrix. For
   * distance between two points the Euclidean distance is used, i.e. no
   * obstacles or graph structure are considered. See
   * {@link #toTravelTimeMatrix(List, Unit, Measure, Unit, RoundingMode)} for
   * more options.
   * @param points The set of points which will be converted to a travel time
   *          matrix.
   * @param speed the speed in m/s.
   * @param rm The rounding mode, see {@link RoundingMode}.
   * @return A n x n travel time matrix, where n is
   *         the size of the points list.
   */
  public static int[][] toTravelTimeMatrix(List points, double speed,
      RoundingMode rm) {
    return toTravelTimeMatrix(points, SI.METER,
        Measure.valueOf(speed, SI.METERS_PER_SECOND), SI.SECOND, rm);
  }

  /**
   * Converts the list of points on a plane into a travel time matrix. For
   * distance between two points the euclidean distance is used, i.e. no
   * obstacles or graph structure are considered.
   * @param points The set of points which will be converted to a travel time
   *          matrix.
   * @param distUnit The {@link Unit} that is used for distances (
   *          {@link Length}) between the specified points.
   * @param speed The travel speed specified as a {@link Measure} which includes
   *          its {@link Unit}.
   * @param outputTimeUnit The output time {@link Unit} to which all times are
   *          converted, e.g. if {@link SI#SECOND} is specified the travel times
   *          will be in seconds.
   * @param rm When computing the travel times they often need to be rounded.
   *          The rounding mode indicates how numbers are rounded, see
   *          {@link RoundingMode} for the available options.
   * @return A n x n travel time matrix, where n is
   *         the size of the points list.
   */
  public static int[][] toTravelTimeMatrix(List points,
      Unit distUnit, Measure speed,
      Unit outputTimeUnit, RoundingMode rm) {
    checkArgument(points.size() >= 2);
    final int[][] matrix = new int[points.size()][points.size()];
    for (int i = 0; i < points.size(); i++) {
      for (int j = 0; j < i; j++) {
        if (i != j) {
          // compute distance
          final Measure dist = Measure.valueOf(
              Point.distance(points.get(i), points.get(j)), distUnit);
          // calculate duration in desired unit
          final double duration = Solvers.computeTravelTime(speed, dist,
              outputTimeUnit);
          // round duration
          final int tt = DoubleMath.roundToInt(duration, rm);
          matrix[i][j] = tt;
          matrix[j][i] = tt;
        }
      }
    }
    return matrix;
  }

  /**
   * Converts the {@link GlobalStateObject} into an {@link ArraysObject} using
   * the specified output time unit.
   * @param state The state to convert.
   * @param outputTimeUnit The {@link Unit} to use as time in the resulting
   *          object.
   * @return An {@link ArraysObject} using the specified output time unit.
   */
  public static ArraysObject toSingleVehicleArrays(GlobalStateObject state,
      Unit outputTimeUnit) {

    final UnitConverter timeConverter = state.timeUnit
        .getConverterTo(outputTimeUnit);

    final VehicleStateObject v = state.vehicles.iterator().next();

    // we check all vehicles in case this method is used in other contexts
    final ImmutableSet.Builder cargoBuilder = ImmutableSet.builder();
    for (final VehicleStateObject vs : state.vehicles) {
      cargoBuilder.addAll(vs.contents);
    }
    final Set inCargo = cargoBuilder.build();

    // there are always two locations: the current vehicle location and
    // the depot
    final int numLocations = 2 + (state.availableParcels.size() * 2)
        + inCargo.size();

    final int[] releaseDates = new int[numLocations];
    final int[] dueDates = new int[numLocations];
    final int[][] servicePairs = new int[state.availableParcels.size()][2];
    final int[] serviceTimes = new int[numLocations];

    // we need to create two mappings:
    // parceldto -> pickup index / deliver index
    // index -> parceldto
    final ImmutableMap.Builder parcel2indexBuilder = ImmutableMap
        .builder();
    final ImmutableMap.Builder index2parcelBuilder = ImmutableMap
        .builder();

    // we wrap the points in PointWrapper to avoid problems with (possibly)
    // duplicates in the points
    final ImmutableList.Builder points = ImmutableList.builder();
    points.add(v.location);

    int index = 1;
    int spIndex = 0;
    for (final ParcelDTO p : state.availableParcels) {
      serviceTimes[index] = DoubleMath.roundToInt(
          timeConverter.convert(p.pickupDuration), RoundingMode.CEILING);
      // add pickup location and time window
      points.add(p.pickupLocation);
      final int deliveryIndex = index + state.availableParcels.size();
      final ParcelIndexObj pio = new ParcelIndexObj(p, index, deliveryIndex);
      parcel2indexBuilder.put(p, pio);
      index2parcelBuilder.put(index, pio);
      index2parcelBuilder.put(deliveryIndex, pio);

      final int[] tw = convertTW(p.pickupTimeWindow, state.time, timeConverter);
      releaseDates[index] = tw[0];
      dueDates[index] = tw[1];
      checkState(releaseDates[index] <= dueDates[index]);

      // link the pair with its delivery location (see next loop)
      servicePairs[spIndex++] = new int[] { index, deliveryIndex };

      index++;
    }
    checkState(spIndex == state.availableParcels.size(), "%s %s",
        state.availableParcels.size(), spIndex);

    final List deliveries = new ImmutableList.Builder()
        .addAll(state.availableParcels).addAll(inCargo).build();
    for (final ParcelDTO p : deliveries) {
      serviceTimes[index] = DoubleMath.roundToInt(
          timeConverter.convert(p.deliveryDuration), RoundingMode.CEILING);

      points.add(p.destinationLocation);
      if (inCargo.contains(p)) {
        final ParcelIndexObj pio = new ParcelIndexObj(p, -1, index);
        parcel2indexBuilder.put(p, pio);
        index2parcelBuilder.put(index, pio);
      }

      final int[] tw = convertTW(p.deliveryTimeWindow, state.time,
          timeConverter);
      releaseDates[index] = tw[0];
      dueDates[index] = tw[1];
      checkState(releaseDates[index] <= dueDates[index]);

      index++;
    }
    checkState(index == numLocations - 1);

    // the start position of the truck points to the depot location
    points.add(v.startPosition);

    // end of the day
    dueDates[index] = fixTWend(v.availabilityTimeWindow.end, state.time,
        timeConverter);

    releaseDates[index] = Math.min(0, dueDates[index]);

    final Measure speed = Measure.valueOf(v.speed,
        state.speedUnit);

    final ImmutableList pointList = points.build();
    final ImmutableMap parcel2indexMap = parcel2indexBuilder
        .build();
    final ImmutableMap index2parcelMap = index2parcelBuilder
        .build();

    final int[][] travelTime = ArraysSolvers.toTravelTimeMatrix(pointList,
        state.distUnit, speed, outputTimeUnit, RoundingMode.CEILING);

    @Nullable
    SolutionObject[] sol = null;
    if (v.route.isPresent() && state.vehicles.size() == 1) {
      // the assumption is that if the current route of one vehicle is known,
      // the routes of all vehicles should be known.
      sol = toCurrentSolutions(state, parcel2indexMap, travelTime,
          releaseDates, dueDates, serviceTimes, new int[][] { travelTime[0] },
          new int[] { 0 });
    }
    return new ArraysObject(travelTime, releaseDates, dueDates, servicePairs,
        serviceTimes, sol, pointList, parcel2indexMap, index2parcelMap);
  }

  @Nullable
  static SolutionObject[] toCurrentSolutions(GlobalStateObject state,
      Map mapping, int[][] travelTime,
      int[] releaseDates, int[] dueDates, int[] serviceTimes,
      int[][] vehicleTravelTimes, int[] remainingServiceTimes) {
    final SolutionObject[] sols = new SolutionObject[state.vehicles.size()];
    for (int i = 0; i < state.vehicles.size(); i++) {
      sols[i] = convertRouteToSolutionObject(state, state.vehicles.get(i),
          mapping, travelTime, releaseDates, dueDates, serviceTimes,
          vehicleTravelTimes[i], remainingServiceTimes[i]);
    }
    return sols;
  }

  static SolutionObject convertRouteToSolutionObject(GlobalStateObject state,
      VehicleStateObject vso, Map mapping,
      int[][] travelTime, int[] releaseDates, int[] dueDates,
      int[] serviceTimes, int[] vehicleTravelTimes, int remainingServiceTime) {
    final int[] route = new int[vso.route.get().size() + 2];

    final Set seen = newHashSet();
    for (int i = 0; i < vso.route.get().size(); i++) {
      final ParcelDTO dto = vso.route.get().get(i);

      if (vso.contents.contains(dto) || seen.contains(dto)) {
        // it is in cargo
        route[i + 1] = mapping.get(dto).deliveryIndex;
      } else {
        checkArgument(state.availableParcels.contains(dto),
            "This parcel should be available but is not: %s.", dto);
        // it is available
        route[i + 1] = mapping.get(dto).pickupIndex;
      }
      // TODO add error msg
      checkArgument(route[i + 1] > 0);
      seen.add(dto);
    }
    route[route.length - 1] = travelTime.length - 1;
    final int[] arrivalTimes = computeArrivalTimes(route, travelTime,
        remainingServiceTime, vehicleTravelTimes, serviceTimes, releaseDates);

    final int tardiness = computeRouteTardiness(route, arrivalTimes,
        serviceTimes, dueDates, remainingServiceTime);
    final int tt = computeTotalTravelTime(route, travelTime, vehicleTravelTimes);
    return new SolutionObject(route, arrivalTimes, tt + tardiness);
  }

  static int[] computeArrivalTimes(int[] route, int[][] travelTime,
      int remainingServiceTime, int[] vehicleTravelTimes, int[] serviceTimes,
      int[] releaseDates) {
    final int[] arrivalTimes = new int[route.length];

    checkArgument(route.length >= 2);
    checkArgument(route[0] == 0);

    arrivalTimes[0] = 0;

    for (int j = 1; j < route.length; j++) {
      final int prev = route[j - 1];
      final int cur = route[j];

      // we compute the travel time. If it is the first step in the
      // route, we use the time from vehicle location to the next
      // location in the route.
      final int tt = j == 1 ? vehicleTravelTimes[cur] : travelTime[prev][cur];

      if (j == 1 && remainingServiceTime > 0) {
        checkArgument(tt == 0, "%s", tt);
      }

      // service time is different in case we were already halfway with the
      // servicing (as defined by remainingServiceTime)
      final int st = (j == 2 && remainingServiceTime > 0) ? remainingServiceTime
          : serviceTimes[prev];
      // we compute the first possible arrival time for the vehicle to
      // arrive at location i, given that it first visited location
      // i-1
      final int earliestArrivalTime = arrivalTimes[j - 1] + st + tt;

      // we also have to take into account the time window
      final int minArrivalTime = Math.max(earliestArrivalTime,
          releaseDates[cur]);
      arrivalTimes[j] = minArrivalTime;
    }
    return arrivalTimes;
  }

  /**
   * Converts the specified {@link GlobalStateObject} into an
   * {@link MVArraysObject} using the specified time unit.
   * @param state The state to convert.
   * @param outputTimeUnit The unit to use for time.
   * @return A {@link MVArraysObject} using the specified output time unit.
   */
  public static MVArraysObject toMultiVehicleArrays(GlobalStateObject state,
      Unit outputTimeUnit) {
    final ArraysObject singleVehicleArrays = toSingleVehicleArrays(state,
        outputTimeUnit);
    checkArgument(state.vehicles.size() > 0, "We need at least one vehicle");

    final int[][] vehicleTravelTimes = toVehicleTravelTimes(state,
        singleVehicleArrays, outputTimeUnit);
    final int[][] inventories = toInventoriesArray(state, singleVehicleArrays);
    final int[] remainingServiceTimes = toRemainingServiceTimes(state,
        outputTimeUnit);

    final int[] currentDestinations = toVehicleDestinations(state,
        singleVehicleArrays);

    @Nullable
    SolutionObject[] sols = null;
    if (state.vehicles.iterator().next().route.isPresent()) {
      // the assumption is that if the current route of one vehicle is known,
      // the routes of all vehicles should be known.
      sols = toCurrentSolutions(state, singleVehicleArrays.parcel2index,
          singleVehicleArrays.travelTime, singleVehicleArrays.releaseDates,
          singleVehicleArrays.dueDates, singleVehicleArrays.serviceTimes,
          vehicleTravelTimes, remainingServiceTimes);
    }

    return new MVArraysObject(singleVehicleArrays, sols, vehicleTravelTimes,
        inventories, remainingServiceTimes, currentDestinations);
  }

  /**
   * Converts a {@link SolutionObject} into a list of {@link ParcelDTO}s.
   * @param sol The solution to convert.
   * @param index2parcel Mapping of indices to {@link ParcelDTO}s.
   * @return A list containing the route as specified by the
   *         {@link SolutionObject}.
   */
  public static ImmutableList convertSolutionObject(
      SolutionObject sol, Map index2parcel) {
    final ImmutableList.Builder builder = ImmutableList.builder();
    // ignore first (current pos) and last (depot)
    for (int i = 1; i < sol.route.length - 1; i++) {
      builder.add(index2parcel.get(sol.route[i]).dto);
    }
    return builder.build();
  }

  static int[] toVehicleDestinations(GlobalStateObject state, ArraysObject sva) {
    final int v = state.vehicles.size();
    final UnmodifiableIterator iterator = state.vehicles
        .iterator();

    final int[] destinations = new int[v];
    for (int i = 0; i < v; i++) {
      final VehicleStateObject cur = iterator.next();
      final ParcelDTO dest = cur.destination;
      if (dest != null) {
        checkArgument(sva.parcel2index.containsKey(dest));
        final boolean isInCargo = cur.contents.contains(dest);
        final ParcelIndexObj pio = sva.parcel2index.get(dest);
        final int index = isInCargo ? pio.deliveryIndex : pio.pickupIndex;
        destinations[i] = index;
      } else {
        destinations[i] = 0;
      }
      checkArgument(destinations[i] >= 0, "Invalid destination.", dest);
    }
    return destinations;
  }

  static int[][] toVehicleTravelTimes(GlobalStateObject state,
      ArraysObject sva, Unit outputTimeUnit) {
    final int v = state.vehicles.size();
    final int n = sva.travelTime.length;
    // compute vehicle travel times
    final int[][] vehicleTravelTimes = new int[v][n];

    final UnmodifiableIterator iterator = state.vehicles
        .iterator();

    for (int i = 0; i < v; i++) {
      final VehicleStateObject cur = iterator.next();
      final Measure speed = Measure.valueOf(cur.speed,
          state.speedUnit);

      final ParcelDTO dest = cur.destination;
      if (dest != null) {
        // only add travel time for current dest
        for (int j = 1; j < n; j++) {
          vehicleTravelTimes[i][j] = Integer.MAX_VALUE;
        }
        final boolean isInCargo = cur.contents.contains(dest);
        final ParcelIndexObj pio = sva.parcel2index.get(dest);
        final int index = isInCargo ? pio.deliveryIndex : pio.pickupIndex;

        checkArgument(index > 0);
        vehicleTravelTimes[i][index] = computeRoundedTravelTime(speed,
            Measure.valueOf(
                Point.distance(cur.location, sva.location2index.get(index)),
                state.distUnit), outputTimeUnit);

      } else {
        // add travel time for every location
        for (int j = 1; j < n; j++) {
          vehicleTravelTimes[i][j] = computeRoundedTravelTime(speed,
              Measure.valueOf(
                  Point.distance(cur.location, sva.location2index.get(j)),
                  state.distUnit), outputTimeUnit);
        }
      }
    }
    return vehicleTravelTimes;
  }

  static int computeRoundedTravelTime(Measure speed,
      Measure dist, Unit outputTimeUnit) {
    return DoubleMath.roundToInt(
        Solvers.computeTravelTime(speed, dist, outputTimeUnit),
        RoundingMode.CEILING);
  }

  static int[][] toInventoriesArray(GlobalStateObject state, ArraysObject sva) {
    final UnmodifiableIterator iterator = state.vehicles
        .iterator();

    final ImmutableList.Builder> invPairBuilder = ImmutableList
        .builder();
    for (int i = 0; i < state.vehicles.size(); i++) {
      final VehicleStateObject cur = iterator.next();
      for (final ParcelDTO dp : cur.contents) {
        invPairBuilder.add(ImmutableList.of(i,
            sva.parcel2index.get(dp).deliveryIndex));
      }
    }
    final ImmutableList> inventoryPairs = invPairBuilder
        .build();

    final int[][] inventories = new int[inventoryPairs.size()][2];
    for (int i = 0; i < inventoryPairs.size(); i++) {
      inventories[i][0] = inventoryPairs.get(i).get(0);
      inventories[i][1] = inventoryPairs.get(i).get(1);
    }
    return inventories;
  }

  static int[] toRemainingServiceTimes(GlobalStateObject state,
      Unit outputTimeUnit) {
    final UnmodifiableIterator iterator = state.vehicles
        .iterator();
    final int[] remainingServiceTimes = new int[state.vehicles.size()];
    for (int i = 0; i < state.vehicles.size(); i++) {
      remainingServiceTimes[i] = DoubleMath.roundToInt(
          Measure.valueOf(iterator.next().remainingServiceTime, state.timeUnit)
              .doubleValue(outputTimeUnit), RoundingMode.CEILING);
    }
    return remainingServiceTimes;
  }

  /**
   * Computes the total travel time of the specified route.
   * @param route The route.
   * @param travelTime The travel time matrix.
   * @param vehicleTravelTimes The vehicle travel time for the vehicle that is
   *          driving the specified route.
   * @return The travel time of the specified route.
   */
  public static int computeTotalTravelTime(int[] route, int[][] travelTime,
      int[] vehicleTravelTimes) {
    int totalTravelTime = 0;
    for (int i = 1; i < route.length; i++) {
      if (i == 1) {
        totalTravelTime += vehicleTravelTimes[route[i]];
      } else {
        totalTravelTime += travelTime[route[i - 1]][route[i]];
      }
    }
    return totalTravelTime;
  }

  /**
   * Computes the total tardiness of the specified route with the specified
   * arrivalTimes.
   * @param route The route with length >= 2.
   * @param arrivalTimes The arrival times at every index of the route.
   * @param serviceTimes The full serviceTimes array containing all locations,
   *          using the original indices.
   * @param dueDates The full dueDates array containing all locations, using the
   *          original indices.
   * @param remainingServiceTime The remaining service time for the position at
   *          index 1, if any, 0 otherwise.
   * @return The sum tardiness.
   */
  public static int computeRouteTardiness(int[] route, int[] arrivalTimes,
      int[] serviceTimes, int[] dueDates, int remainingServiceTime) {
    int tardiness = 0;
    // start at index 1 since there can be no tardiness at start location
    for (int i = 1; i < route.length; i++) {
      int st;
      if (i == 1 && remainingServiceTime > 0) {
        st = remainingServiceTime;
      } else {
        st = serviceTimes[route[i]];
      }
      final int lateness = (arrivalTimes[i] + st) - dueDates[route[i]];
      if (lateness > 0) {
        tardiness += lateness;
      }
    }
    return tardiness;
  }

  /**
   * Sums the objective values of all provided {@link SolutionObject}s.
   * @param sols The {@link SolutionObject}s.
   * @return The sum objective value.
   */
  public static int computeTotalObjectiveValue(SolutionObject[] sols) {
    int obj = 0;
    for (final SolutionObject sol : sols) {
      obj += sol.objectiveValue;
    }
    return obj;
  }

  /**
   * Sums the objective values of all provided {@link SolutionObject}s. The
   * input values are treated as instances of the inputUnit and are
   * converted to the outputUnit.
   * @param sols The {@link SolutionObject}s.
   * @param inputUnit The time unit of the input values.
   * @param outputUnit The time unit to convert the values to.
   * @return The sum objective value in the outputUnit.
   */
  public static int computeTotalObjectiveValue(SolutionObject[] sols,
      Unit inputUnit, Unit outputUnit) {
    return Measure.valueOf(computeTotalObjectiveValue(sols), inputUnit)
        .intValue(outputUnit);
  }

  static int[] convertTW(TimeWindow tw, long time, UnitConverter timeConverter) {
    final int releaseDate = fixTWstart(tw.begin, time, timeConverter);
    final int dueDate = fixTWend(tw.end, time, timeConverter);
    if (releaseDate > dueDate) {
      // if this happens, we know this is the result of rounding behavior:
      // release is rounded up, due is rounded down. We also know that the
      // difference is only 1. Therefore we flip the values.
      checkArgument(Math.abs(dueDate - releaseDate) == 1);
      return new int[] { dueDate, releaseDate };
    }
    return new int[] { releaseDate, dueDate };
  }

  static int fixTWstart(long start, long time, UnitConverter timeConverter) {
    return DoubleMath.roundToInt(timeConverter.convert(start - time),
        RoundingMode.CEILING);
  }

  static int fixTWend(long end, long time, UnitConverter timeConverter) {
    return DoubleMath.roundToInt(timeConverter.convert(end - time),
        RoundingMode.FLOOR);
  }

  /**
   * Object which specifies the parameters of
   * {@link SingleVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], SolutionObject)}
   * . Also includes additional information which is required to interpret the
   * resulting {@link SolutionObject}.
   * @author Rinde van Lon 
   */
  public static class ArraysObject {
    /**
     * See
     * {@link SingleVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], SolutionObject)}
     * .
     */
    public final int[][] travelTime;

    /**
     * See
     * {@link SingleVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], SolutionObject)}
     * .
     */
    public final int[] releaseDates;

    /**
     * See
     * {@link SingleVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], SolutionObject)}
     * .
     */
    public final int[] dueDates;

    /**
     * See
     * {@link SingleVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], SolutionObject)}
     * .
     */
    public final int[][] servicePairs;

    /**
     * See
     * {@link SingleVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], SolutionObject)}
     * .
     */
    public final int[] serviceTimes;

    /**
     * See
     * {@link MultiVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], int[][], int[][], int[], int[], SolutionObject[])}
     * .
     */
    @Nullable
    public final SolutionObject[] currentSolutions;

    /**
     * A bidirectional mapping between locations and their index.
     */
    public final ImmutableList location2index;

    /**
     * A mapping between parcels and their locations.
     */
    public final ImmutableMap parcel2index;

    /**
     * A mapping between indices and parcels/locations.
     */
    public final ImmutableMap index2parcel;

    ArraysObject(int[][] travelTime, int[] releaseDates, int[] dueDates,
        int[][] servicePairs, int[] serviceTimes,
        @Nullable SolutionObject[] currentSolutions,
        ImmutableList locations,
        ImmutableMap parcel2index,
        ImmutableMap index2parcel) {
      this.travelTime = travelTime;
      this.releaseDates = releaseDates;
      this.dueDates = dueDates;
      this.servicePairs = servicePairs;
      this.serviceTimes = serviceTimes;
      this.currentSolutions = currentSolutions;
      location2index = locations;
      this.parcel2index = parcel2index;
      this.index2parcel = index2parcel;
    }

    ArraysObject(int[][] travelTime, int[] releaseDates, int[] dueDates,
        int[][] servicePairs, int[] serviceTimes,
        @Nullable SolutionObject[] currentSolutions) {
      this(travelTime, releaseDates, dueDates, servicePairs, serviceTimes,
          currentSolutions, ImmutableList. of(), ImmutableMap
              . of(), ImmutableMap
              . of());
    }
  }

  /**
   * Object which specifies the parameters of
   * {@link MultiVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], int[][], int[][], int[], int[], SolutionObject[])}
   * . Also includes additional information which is required to interpret the
   * resulting {@link SolutionObject}.
   * @author Rinde van Lon 
   */
  public static class MVArraysObject extends ArraysObject {
    /**
     * See
     * {@link MultiVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], int[][], int[][], int[], int[], SolutionObject[])}
     * .
     */
    public final int[][] vehicleTravelTimes;

    /**
     * See
     * {@link MultiVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], int[][], int[][], int[], int[], SolutionObject[])}
     * .
     */
    public final int[][] inventories;

    /**
     * See
     * {@link MultiVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], int[][], int[][], int[], int[], SolutionObject[])}
     * .
     */
    public final int[] remainingServiceTimes;

    /**
     * See
     * {@link MultiVehicleArraysSolver#solve(int[][], int[], int[], int[][], int[], int[][], int[][], int[], int[], SolutionObject[])}
     * .
     */
    public final int[] currentDestinations;

    MVArraysObject(int[][] travelTime, int[] releaseDates, int[] dueDates,
        int[][] servicePairs, int[] serviceTimes,
        @Nullable SolutionObject[] currentSolutions,
        ImmutableList locations,
        ImmutableMap parcel2index,
        ImmutableMap index2parcel,
        int[][] vehicleTravelTimes, int[][] inventories,
        int[] remainingServiceTimes, int[] currentDestinations) {
      super(travelTime, releaseDates, dueDates, servicePairs, serviceTimes,
          currentSolutions, locations, parcel2index, index2parcel);
      this.vehicleTravelTimes = Arrays.copyOf(vehicleTravelTimes,
          vehicleTravelTimes.length);
      this.inventories = Arrays.copyOf(inventories, inventories.length);
      this.remainingServiceTimes = Arrays.copyOf(remainingServiceTimes,
          remainingServiceTimes.length);
      this.currentDestinations = Arrays.copyOf(currentDestinations,
          currentDestinations.length);
    }

    MVArraysObject(ArraysObject ao,
        @Nullable SolutionObject[] currentSolutions,
        int[][] vehicleTravelTimes, int[][] inventories,
        int[] remainingServiceTimes, int[] currentDestinations) {
      this(ao.travelTime, ao.releaseDates, ao.dueDates, ao.servicePairs,
          ao.serviceTimes, currentSolutions, ao.location2index,
          ao.parcel2index, ao.index2parcel, vehicleTravelTimes, inventories,
          remainingServiceTimes, currentDestinations);
    }

    MVArraysObject(int[][] travelTime, int[] releaseDates, int[] dueDates,
        int[][] servicePairs, int[] serviceTimes, int[][] vehicleTravelTimes,
        int[][] inventories, int[] remainingServiceTimes,
        int[] currentDestinations, @Nullable SolutionObject[] curSolutions) {
      super(travelTime, releaseDates, dueDates, servicePairs, serviceTimes,
          curSolutions);
      this.vehicleTravelTimes = Arrays.copyOf(vehicleTravelTimes,
          vehicleTravelTimes.length);
      this.inventories = Arrays.copyOf(inventories, inventories.length);
      this.remainingServiceTimes = Arrays.copyOf(remainingServiceTimes,
          remainingServiceTimes.length);
      this.currentDestinations = Arrays.copyOf(currentDestinations,
          currentDestinations.length);
    }
  }

  static class ParcelIndexObj {
    final ParcelDTO dto;
    final int pickupIndex;
    final int deliveryIndex;

    ParcelIndexObj(ParcelDTO dto, int pickupIndex, int deliveryIndex) {
      this.dto = dto;
      this.pickupIndex = pickupIndex;
      this.deliveryIndex = deliveryIndex;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy