#region License Information
/* HeuristicLab
* Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HeuristicLab.Core;
using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
using HeuristicLab.Common;
using HeuristicLab.Problems.VehicleRouting.ProblemInstances;
using HeuristicLab.Problems.VehicleRouting.Interfaces;
using HeuristicLab.PDPSimulation.DomainModel;
using HeuristicLab.Data;
using HeuristicLab.PDPSimulation.Operators;
using HeuristicLab.Problems.VehicleRouting.Encodings.Potvin;
using HeuristicLab.Problems.VehicleRouting;
using HeuristicLab.PDPSimulation.DistanceMeasures;
using HeuristicLab.Optimization;
namespace HeuristicLab.PDPSimulation {
[Item("DynamicPDProblemInstance", "A dynamic PD instance.")]
[StorableClass]
public class DynamicPDProblemInstance: Item {
[Storable]
private List instances;
[Storable]
private HashSet solutions;
[Storable]
private List- tabuAttributes;
[Storable]
private Dictionary vehicleAssignment;
[Storable]
private Dictionary orderAssignment;
[Storable]
private double timeDelta;
[Storable]
private bool initialized;
public bool Initialized {
get { return initialized; }
}
public List StaticInstances {
get {
List result = new List();
foreach (DynPDPProblemInstance instance in instances)
result.Add(instance);
return result;
}
}
public IVRPProblemInstance StaticInstance {
get {
return instances[0];
}
}
public HashSet Solutions {
get { return solutions; }
}
public List
- TabuAttributes {
get { return tabuAttributes; }
}
public void SetInstanceCount(int count) {
if (count > 0) {
if (instances.Count > count)
instances.RemoveRange(0, instances.Count - count);
else
while(instances.Count < count)
instances.Add(instances[0].ShallowClone());
}
}
public DynamicPDProblemInstance(PickupDeliveryScenario scenario, ResultCollection results): base() {
vehicleAssignment = new Dictionary();
orderAssignment = new Dictionary();
solutions = new HashSet();
tabuAttributes = new List
- ();
timeDelta = 0;
initialized = false;
instances = new List();
instances.Add(new DynPDPProblemInstance(scenario, results));
}
[StorableConstructor]
private DynamicPDProblemInstance(bool deserializing) : base(deserializing) {
}
private DynamicPDProblemInstance(DynamicPDProblemInstance original, Cloner cloner)
: base(original, cloner) {
instances = new List();
foreach (DynPDPProblemInstance instance in original.instances)
instances.Add(cloner.Clone(instance));
vehicleAssignment = new Dictionary();
foreach (int key in original.vehicleAssignment.Keys)
vehicleAssignment.Add(key, original.vehicleAssignment[key]);
orderAssignment = new Dictionary();
foreach (int key in original.orderAssignment.Keys)
orderAssignment.Add(key, original.orderAssignment[key]);
solutions = new HashSet();
foreach (PotvinEncoding solution in original.solutions)
solutions.Add(cloner.Clone(solution));
tabuAttributes = new List
- ();
foreach (Item tabuAttribute in original.tabuAttributes)
tabuAttributes.Add(cloner.Clone
- (tabuAttribute));
timeDelta = original.timeDelta;
initialized = original.initialized;
}
public override IDeepCloneable Clone(Cloner cloner) {
return new DynamicPDProblemInstance(this, cloner);
}
public void SetCurrentPlan(PotvinEncoding plan) {
foreach (DynPDPProblemInstance instance in instances) {
if (instance.CurrentPlan != null)
solutions.Remove(instance.CurrentPlan);
instance.CurrentPlan = PotvinEncoding.ConvertFrom(plan, instance);
solutions.Add(instance.CurrentPlan);
}
}
public Guid GetOrder(int stop) {
return orderAssignment[stop - 1];
}
public List GetStops(Guid order) {
return (from a in orderAssignment where a.Value == order select a.Key).OrderBy(s => s).ToList();
}
public Guid GetVehicle(int index) {
return vehicleAssignment[index];
}
public void UpdateTime(double delta) {
foreach (DynPDPProblemInstance instance in instances) {
for (int i = 0; i < instance.DueTime.Length; i++) {
instance.DueTime[i] = Math.Max(0, instance.DueTime[i] - delta);
instance.ReadyTime[i] = Math.Max(0, instance.ReadyTime[i] - delta);
}
}
timeDelta += delta;
}
public void AddVehicle(Vehicle vehicle) {
throw new NotImplementedException();
}
private void AddOrder(DynPDPProblemInstance instance, Order order, ref int customerIdx, ref int depotIdx) {
orderAssignment[customerIdx] = order.Id;
instance.Demand[customerIdx] = order.Demand;
instance.PickupDeliveryLocation[customerIdx] = customerIdx + (order.ServiceRequest ? 1 : 2);
instance.ServiceTime[customerIdx] = order.PickupServiceTime;
instance.ReadyTime[customerIdx + depotIdx] = Math.Max(0, order.PickupReadyTime - timeDelta);
instance.DueTime[customerIdx + depotIdx] = Math.Max(0, order.PickupDueTime - timeDelta);
instance.Coordinates[customerIdx + depotIdx, 0] = order.PickupXCoord;
instance.Coordinates[customerIdx + depotIdx, 1] = order.PickupYCoord;
customerIdx++;
if (!order.ServiceRequest) {
orderAssignment[customerIdx] = order.Id;
instance.Demand[customerIdx] = -order.Demand;
instance.PickupDeliveryLocation[customerIdx] = customerIdx;
instance.ServiceTime[customerIdx] = order.DeliveryServiceTime;
instance.ReadyTime[customerIdx + depotIdx] = Math.Max(0, order.DeliveryReadyTime - timeDelta);
instance.DueTime[customerIdx + depotIdx] = Math.Max(0, order.DeliveryDueTime - timeDelta);
instance.Coordinates[customerIdx + depotIdx, 0] = order.DeliveryXCoord;
instance.Coordinates[customerIdx + depotIdx, 1] = order.DeliveryYCoord;
customerIdx++;
}
foreach (PotvinEncoding solution in solutions) {
if (!order.ServiceRequest && !solution.Unrouted.Contains(customerIdx - 1))
solution.Unrouted.Add(customerIdx - 1);
if (!solution.Unrouted.Contains(customerIdx))
solution.Unrouted.Add(customerIdx);
}
}
public void AddOrder(Order order) {
foreach (DynPDPProblemInstance instance in instances) {
int customerIdx = instance.Demand.Length;
int depotIdx = instance.Vehicles.Value;
int added = order.ServiceRequest ? 1 : 2;
(instance.Coordinates as IStringConvertibleMatrix).Rows += added;
(instance.ReadyTime as IStringConvertibleArray).Length += added;
(instance.DueTime as IStringConvertibleArray).Length += added;
(instance.Demand as IStringConvertibleArray).Length += added;
(instance.ServiceTime as IStringConvertibleArray).Length += added;
(instance.PickupDeliveryLocation as IStringConvertibleArray).Length += added;
AddOrder(instance, order, ref customerIdx, ref depotIdx);
instance.ResetDistanceMatrix();
}
}
public void UpdateVehicle(Vehicle vehicle, bool diversionAllowed) {
bool last = false;
for (int i = 0; i < instances.Count; i++) {
DynPDPProblemInstance instance = instances[i];
last = (i == instances.Count - 1);
int vehicleIdx = vehicleAssignment.First(kvp => kvp.Value == vehicle.Id).Key;
if (!diversionAllowed && vehicle.VehicleState == VehicleState.Moving)
instance.VehicleStates[vehicleIdx] = VehicleState.Waiting;
else
instance.VehicleStates[vehicleIdx] = vehicle.VehicleState;
if (diversionAllowed) {
instance.Coordinates[vehicleIdx, 0] = vehicle.PositionX;
instance.Coordinates[vehicleIdx, 1] = vehicle.PositionY;
instance.Capacity[vehicleIdx] = vehicle.Capacity;
instance.ResetDistanceMatrix();
if (vehicle.Distance > 0)
instance.VehicleUsed[vehicleIdx] = true;
} else {
var found = orderAssignment.Where(kvp => kvp.Value == vehicle.CurrentOrder).ToList();
if (found.Count() > 0) {
instance.Coordinates[vehicleIdx, 0] = vehicle.TargetPositionX;
instance.Coordinates[vehicleIdx, 1] = vehicle.TargetPositionY;
int target = -1, source = -1;
if (found.Count == 2 &&
(vehicle.CurrentAction == VehicleAction.Pickup || vehicle.CurrentAction == VehicleAction.Deliver)) {
if (instance.Demand[found[0].Key] >= 0) {
source = found[0].Key;
target = found[1].Key;
} else {
target = found[0].Key;
source = found[1].Key;
}
int vehicleId = vehicleAssignment.First(
kvp => kvp.Value == vehicle.Id).Key;
instance.PickupDeliveryLocation[target] = -vehicleId;
} else if (found.Count == 1 &&
(vehicle.CurrentAction == VehicleAction.Deliver)) {
source = found[0].Key;
}
if (source >= 0) {
if(last)
RemoveCustomer(source, vehicleIdx, diversionAllowed);
instance.ResetDistanceMatrix();
}
instance.VehicleUsed[vehicleIdx] = true;
}
}
instance.ReadyTime[vehicleIdx] = Math.Max(0, vehicle.ReadyTime - timeDelta);
vehicleAssignment[vehicleIdx] = vehicle.Id;
}
}
private void RemoveCustomer(int customer, int vehicle, bool diversionAllowed) {
foreach (DynPDPProblemInstance instance in instances) {
if (!diversionAllowed) {
instance.Capacity[vehicle] -= instance.Demand[customer];
}
int customers = instance.Cities.Value;
int depots = instance.Vehicles.Value;
for (int i = customer; i < customers - 1; i++) {
instance.Demand[i] = instance.Demand[i + 1];
instance.ServiceTime[i] = instance.ServiceTime[i + 1];
instance.PickupDeliveryLocation[i] = instance.PickupDeliveryLocation[i + 1];
int index = i + depots;
instance.ReadyTime[index] = instance.ReadyTime[index + 1];
instance.DueTime[index] = instance.DueTime[index + 1];
instance.Coordinates[index, 0] = instance.Coordinates[index + 1, 0];
instance.Coordinates[index, 1] = instance.Coordinates[index + 1, 1];
}
for (int i = 0; i < customers; i++) {
if (instance.PickupDeliveryLocation[i] > customer)
instance.PickupDeliveryLocation[i] -= 1;
}
(instance.Coordinates as IStringConvertibleMatrix).Rows -= 1;
(instance.ReadyTime as IStringConvertibleArray).Length -= 1;
(instance.DueTime as IStringConvertibleArray).Length -= 1;
(instance.Demand as IStringConvertibleArray).Length -= 1;
(instance.ServiceTime as IStringConvertibleArray).Length -= 1;
(instance.PickupDeliveryLocation as IStringConvertibleArray).Length -= 1;
}
foreach (PotvinEncoding solution in solutions) {
int i;
foreach (Tour tour in solution.Tours) {
i = 0;
while (i < tour.Stops.Count) {
if (tour.Stops[i] > (customer + 1)) {
tour.Stops[i] = tour.Stops[i] - 1;
i++;
} else if (tour.Stops[i] < (customer + 1)) {
i++;
} else {
tour.Stops.RemoveAt(i);
}
}
}
solution.Repair();
i = 0;
while (i < solution.Unrouted.Count) {
if (solution.Unrouted[i] > (customer + 1)) {
solution.Unrouted[i] = solution.Unrouted[i] - 1;
i++;
} else if (solution.Unrouted[i] < (customer + 1)) {
i++;
} else {
solution.Unrouted.RemoveAt(i);
}
}
}
Dictionary newOrderAssignment = new Dictionary();
foreach (int assigned in orderAssignment.Keys) {
if (assigned > customer)
newOrderAssignment[assigned - 1] = orderAssignment[assigned];
else if (assigned != customer)
newOrderAssignment[assigned] = orderAssignment[assigned];
}
orderAssignment = newOrderAssignment;
}
public void UpdateOrder(Order order, bool diversionAllowed) {
bool last = false;
for(int i = 0; i < instances.Count; i++) {
DynPDPProblemInstance instance = instances[i];
last = (i == instances.Count - 1);
var customers = orderAssignment.Where(
kvp => kvp.Value == order.Id).ToList();
int depots = instance.Vehicles.Value;
int vehicle = vehicleAssignment.First(
kvp => kvp.Value == order.Vehicle).Key;
int source = -1;
int target = -1;
if (order.OrderState == OrderState.PickingUp || order.OrderState == OrderState.PickedUp) {
if (!order.ServiceRequest && customers.Count == 2) {
if (instance.Demand[customers[0].Key] >= 0) {
source = customers[0].Key;
target = customers[1].Key;
} else {
source = customers[1].Key;
target = customers[0].Key;
}
instance.PickupDeliveryLocation[target] = -vehicle;
if (last)
RemoveCustomer(source, vehicle, diversionAllowed);
instance.ResetDistanceMatrix();
} else if (order.ServiceRequest && customers.Count == 1) {
target = customers[0].Key;
if (last)
RemoveCustomer(target, vehicle, diversionAllowed);
instance.ResetDistanceMatrix();
}
} else if (order.OrderState == OrderState.Delivering || order.OrderState == OrderState.Delivered) {
if (customers.Count == 1) {
target = customers[0].Key;
if (last)
RemoveCustomer(target, vehicle, diversionAllowed);
instance.ResetDistanceMatrix();
} else if (customers.Count == 2) {
if (instance.Demand[customers[0].Key] >= 0) {
source = customers[0].Key;
target = customers[1].Key;
} else {
source = customers[1].Key;
target = customers[0].Key;
}
if (last)
RemoveCustomer(source, vehicle, diversionAllowed);
if (last)
RemoveCustomer(target - 1, vehicle, diversionAllowed);
instance.ResetDistanceMatrix();
}
}
}
}
public void InitializeInstance(List vehicles, List orders) {
if (vehicles.Count > 0) {
foreach (DynPDPProblemInstance instance in instances) {
timeDelta = 0;
instance.Coordinates = new DoubleMatrix(vehicles.Count + orders.Count * 2, 2);
instance.DepotCoordinates = new DoubleMatrix(vehicles.Count, 2);
instance.ReadyTime = new DoubleArray(vehicles.Count + orders.Count * 2);
instance.DueTime = new DoubleArray(vehicles.Count + orders.Count * 2);
instance.Capacity = new DoubleArray(vehicles.Count);
instance.VehicleDepotAssignment = new IntArray(vehicles.Count);
instance.VehicleUsed = new BoolArray(vehicles.Count);
instance.VehicleStates.Clear();
for (int i = 0; i < vehicles.Count; i++) {
instance.VehicleStates.Add(VehicleState.Parked);
}
int depotIdx = 0;
int vehicleIdx = 0;
foreach (Vehicle vehicle in vehicles) {
vehicleAssignment[vehicleIdx] = vehicle.Id;
instance.Coordinates[depotIdx, 0] = vehicle.DepotX;
instance.Coordinates[depotIdx, 1] = vehicle.DepotY;
instance.DepotCoordinates[depotIdx, 0] = vehicle.DepotX;
instance.DepotCoordinates[depotIdx, 1] = vehicle.DepotY;
instance.ReadyTime[vehicleIdx] = 0;
instance.DueTime[vehicleIdx] = vehicle.DueTime;
instance.Capacity[vehicleIdx] = vehicle.Capacity;
instance.VehicleDepotAssignment[vehicleIdx] = depotIdx;
depotIdx++;
vehicleIdx++;
}
instance.Depots.Value = depotIdx;
instance.Vehicles.Value = vehicleIdx;
foreach (PotvinEncoding solution in solutions) {
(solution.VehicleAssignment as IStringConvertibleArray).Length = instance.Vehicles.Value;
}
instance.Demand = new DoubleArray(orders.Count * 2);
instance.ServiceTime = new DoubleArray(orders.Count * 2);
instance.PickupDeliveryLocation = new IntArray(orders.Count * 2);
int customerIdx = 0;
foreach (Order order in orders) {
AddOrder(instance, order, ref customerIdx, ref depotIdx);
}
if (customerIdx != orders.Count * 2) {
(instance.Coordinates as IStringConvertibleMatrix).Rows = vehicles.Count + customerIdx;
(instance.ReadyTime as IStringConvertibleArray).Length = vehicles.Count + customerIdx;
(instance.DueTime as IStringConvertibleArray).Length = vehicles.Count + customerIdx;
(instance.Demand as IStringConvertibleArray).Length = customerIdx;
(instance.ServiceTime as IStringConvertibleArray).Length = customerIdx;
(instance.PickupDeliveryLocation as IStringConvertibleArray).Length = customerIdx;
}
instance.ResetDistanceMatrix();
instance.Initialize();
}
initialized = true;
}
}
}
}