#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.PDPSimulation.SimulationCore;
using HeuristicLab.Parameters;
using HeuristicLab.Data;
using System.Threading;
using HeuristicLab.Common;
using HeuristicLab.PDPSimulation.DomainModel;
using HeuristicLab.Optimization;
using HeuristicLab.Analysis;
namespace HeuristicLab.PDPSimulation {
[Item("PickupDeliverySimulation", "A pickup and delivery simulation.")]
[Creatable("Simulations")]
[StorableClass]
public sealed class PickupDeliverySimulation: Simulation {
#region parameters
public OptionalValueParameter OptimizationParameter {
get { return (OptionalValueParameter)Parameters["PickupDeliveryOptimization"]; }
}
public OptionalValueParameter WaitingStrategyParameter {
get { return (OptionalValueParameter)Parameters["WaitingStrategy"]; }
}
public OptionalValueParameter AnalyzerParameter {
get { return (OptionalValueParameter)Parameters["Analyzer"]; }
}
public ValueParameter TimeStepParameter {
get { return (ValueParameter)Parameters["TimeStep"]; }
}
public ValueParameter ResultCollectionIntervalParameter {
get { return (ValueParameter)Parameters["ResultCollectionInterval"]; }
}
public ValueParameter SynchronizedParameter {
get { return (ValueParameter)Parameters["Synchronized"]; }
}
public ValueParameter DelayParameter {
get { return (ValueParameter)Parameters["Delay"]; }
}
public ValueParameter InitialDelayParameter {
get { return (ValueParameter)Parameters["InitialDelay"]; }
}
private ValueParameter SeedParameter {
get { return (ValueParameter)Parameters["Seed"]; }
}
private ValueParameter SetSeedRandomlyParameter {
get { return (ValueParameter)Parameters["SetSeedRandomly"]; }
}
#endregion
#region properties
public double SimulationTime {
get {
return simulationTime;
}
private set {
simulationTime = value;
}
}
public double TimeStep {
get {
return TimeStepParameter.Value.Value;
}
}
private double ResultCollectionInterval {
get {
return ResultCollectionIntervalParameter.Value.Value;
}
}
private bool Synchronized {
get {
return SynchronizedParameter.Value.Value;
}
}
private int Delay {
get {
return DelayParameter.Value.Value;
}
}
public override Type ProblemType {
get { return typeof(PickupDeliveryScenario); }
}
private PickupDeliveryScenario Scenario {
get {
return Problem as PickupDeliveryScenario;
}
}
private PickupDeliveryOptimization Optimization {
get { return OptimizationParameter.Value; }
}
private WaitingStrategy WaitingStrategy {
get { return WaitingStrategyParameter.Value; }
}
private PickupDeliveryAnalyzer Analyzer {
get { return AnalyzerParameter.Value; }
}
#endregion
#region constructors
public PickupDeliverySimulation()
: base() {
Parameters.Add(new OptionalValueParameter("PickupDeliveryOptimization", new BestInsertion()));
Parameters.Add(new OptionalValueParameter("WaitingStrategy", new DriveFirstWaitingStrategy()));
Parameters.Add(new OptionalValueParameter("Analyzer", new PickupDeliveryAnalyzer()));
Parameters.Add(new ValueParameter("TimeStep", "The time progress after every tick", new DoubleValue(1)));
Parameters.Add(new ValueParameter("ResultCollectionInterval", "The result collection interval", new DoubleValue(1)));
Parameters.Add(new ValueParameter("Synchronized", "Indicates if the simulation and optimization should be synchronized", new BoolValue(true)));
Parameters.Add(new ValueParameter("Delay", "The delay after each tick", new IntValue(0)));
Parameters.Add(new ValueParameter("InitialDelay", "The initial delay", new IntValue(0)));
Parameters.Add(new ValueParameter("Seed", "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
Parameters.Add(new ValueParameter("SetSeedRandomly", "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
OptimizationParameter.GetsCollected = false;
orders = new List();
vehicles = new List();
AttachEventHandlers();
SetOptimizationSimulation();
SetOptimizationScenario();
SetWaitingStrategy();
SetWaitingStrategyScenario();
}
[StorableConstructor]
private PickupDeliverySimulation(bool deserializing) : base(deserializing) {
}
[StorableHook(HookType.AfterDeserialization)]
private void AfterDeserialization() {
AttachEventHandlers();
}
private PickupDeliverySimulation(PickupDeliverySimulation original, Cloner cloner)
: base(original, cloner) {
orders = new List();
foreach (Order order in original.orders) {
orders.Add(cloner.Clone(order));
}
vehicles = new List();
foreach (Vehicle vehicle in original.vehicles) {
vehicles.Add(cloner.Clone(vehicle));
}
simulationTime = original.simulationTime;
newSimulationTime = original.newSimulationTime;
lastResultCollection = original.lastResultCollection;
simulationObject = cloner.Clone(original.simulationObject);
AttachEventHandlers();
}
public override IDeepCloneable Clone(Cloner cloner) {
return new PickupDeliverySimulation(this, cloner);
}
[StorableHook(HookType.AfterDeserialization)]
private void AttachEventHandlers() {
OptimizationParameter.ValueChanged += new EventHandler(OptimizationParameter_ValueChanged);
WaitingStrategyParameter.ValueChanged += new EventHandler(WaitingStrategyParameter_ValueChanged);
if(Scenario != null)
Scenario.ScenarioChanged += new EventHandler(Scenario_ScenarioChanged);
}
void Scenario_ScenarioChanged(object sender, EventArgs e) {
SetOptimizationScenario();
SetWaitingStrategy();
SetWaitingStrategyScenario();
Prepare();
}
void WaitingStrategyParameter_ValueChanged(object sender, EventArgs e) {
SetWaitingStrategy();
SetWaitingStrategyScenario();
}
void OptimizationParameter_ValueChanged(object sender, EventArgs e) {
SetOptimizationSimulation();
SetOptimizationScenario();
SetWaitingStrategy();
}
protected override void OnProblemChanged() {
base.OnProblemChanged();
SetOptimizationScenario();
SetWaitingStrategy();
SetWaitingStrategyScenario();
if (Scenario != null)
Scenario.ScenarioChanged += new EventHandler(Scenario_ScenarioChanged);
}
#endregion
#region state
[Storable]
private List orders;
public List Orders {
get {
lock (orders) {
return new List(orders);
}
}
}
public Order GetOrder(Guid orderId) {
lock (orders) {
return orders.FirstOrDefault(o => o.Id == orderId);
}
}
public double OrderRangeX {
get { return Scenario.OrderRangeX(); }
}
public double OrderRangeY {
get { return Scenario.OrderRangeY(); }
}
private bool AllOrdersDelivered() {
bool delivered = true;
foreach(Order order in orders) {
if (order.OrderState != OrderState.Delivered) {
delivered = false;
break;
}
}
return delivered;
}
[Storable]
private List vehicles;
public List Vehicles {
get {
return new List(vehicles);
}
}
public Vehicle GetVehicle(Guid vehicleId) {
return vehicles.FirstOrDefault(v => v.Id == vehicleId);
}
private bool AllVehiclesAtDepot() {
bool atDepot = true;
foreach (Vehicle vehicle in vehicles) {
if ((vehicle.VehicleState != VehicleState.Parked && vehicle.VehicleState != VehicleState.Waiting) ||
vehicle.PositionX != vehicle.DepotX ||
vehicle.PositionY != vehicle.DepotY) {
atDepot = false;
break;
}
}
return atDepot;
}
public PDAction GetAction(Vehicle vehicle) {
if (Optimization != null)
return Optimization.GetAction(vehicle);
else
return null;
}
[Storable]
private double newSimulationTime;
[Storable]
private double simulationTime;
[Storable]
private double lastResultCollection;
[Storable]
private SimulationObject simulationObject;
#endregion
#region events
public delegate void SimulationStateChangedHandler(BaseObject obj, SimulationStateChange change);
public event SimulationStateChangedHandler SimulationStateChanged;
private void OnSimulationStateChanged(BaseObject obj, SimulationStateChange change) {
SimulationStateChangedHandler handler = SimulationStateChanged;
if (handler != null)
handler(obj, change);
}
#endregion
#region synchronization
private EventWaitHandle wh;
private void InitWaitHandle() {
if(wh != null)
wh.Dispose();
wh = null;
if (Synchronized)
wh = new EventWaitHandle(false, EventResetMode.AutoReset);
}
private void SignalWaitHandle() {
if (wh != null)
wh.Set();
}
public void WaitForSimulation() {
if (wh != null)
wh.WaitOne();
}
private void WaitForOptimization() {
if (Optimization != null)
Optimization.WaitForOptimization();
}
#endregion
#region simulation logic
private void UpdateVisualization() {
if (Analyzer != null)
Analyzer.UpdateVisualization(this, Scenario, Results);
}
private void UpdateSimulationState() {
if (Optimization != null) {
foreach (PDAction action in Optimization.GetActions()) {
BaseObject obj = vehicles.FirstOrDefault(v => v.Id == action.BaseObjectId);
if(obj == null)
obj = orders.FirstOrDefault(o => o.Id == action.BaseObjectId);
List changes = action.Perform(obj, SimulationTime, TimeStep);
foreach (PDChange change in changes)
OnSimulationStateChanged(change.BaseObject, change.ChangeType);
}
}
}
private void UpdateResults(bool stopped) {
if (stopped || SimulationTime == 0 ||
(SimulationTime - lastResultCollection) >= ResultCollectionInterval) {
UpdateVisualization();
if (Analyzer != null) {
Analyzer.Analyze(this, Scenario, Results);
}
lastResultCollection = SimulationTime;
}
if (Analyzer != null) {
Analyzer.Tick(this, Scenario, Results);
}
}
private void UpdateOrders() {
lock (orders) {
IEnumerable newOrders = Scenario.GetOrders(SimulationTime, newSimulationTime);
foreach (Order order in newOrders) {
orders.Add(order);
OnSimulationStateChanged(order, SimulationStateChange.OrderCreated);
}
if (!Scenario.MoreOrders(newSimulationTime))
OnSimulationStateChanged(simulationObject, SimulationStateChange.NoMoreOrders);
}
}
private void CreateSimulation() {
vehicles.Clear();
orders.Clear();
simulationObject = new SimulationObject();
lastResultCollection = 0;
simulationTime = 0;
newSimulationTime = 0;
//create vehicles
for (int i = 0; i < Scenario.VehicleCapacitiesParameter.Value.Length; i++) {
Vehicle v = new Vehicle();
v.VehicleState = VehicleState.Parked;
v.Availibility = 1;
v.DepotX = v.PositionX = v.TargetPositionX = Scenario.DepotCoordinatesParameter.Value[i, 0];
v.DepotY = v.PositionY = v.TargetPositionY = Scenario.DepotCoordinatesParameter.Value[i, 1];
v.Capacity = v.TotalCapacity = Scenario.VehicleCapacitiesParameter.Value[i];
v.ReadyTime = Scenario.VehicleReadyTimesParameter.Value[i];
v.DueTime = Scenario.VehicleDueTimesParameter.Value[i];
vehicles.Add(v);
OnSimulationStateChanged(v, SimulationStateChange.VehicleCreated);
}
//create initial orders
UpdateOrders();
UpdateResults(false);
UpdateVisualization();
}
protected override void OnPrepared() {
base.OnPrepared();
PrepareOptimization();
simulationTime = 0;
newSimulationTime = 0;
}
private void InitSimulation() {
pausePending = false;
stopPending = false;
InitWaitHandle();
if (simulationTime == 0) {
PrepareOptimization();
CreateSimulation();
SignalWaitHandle();
if (OptimizationRequired()) {
StartOptimization();
Thread.Sleep(InitialDelayParameter.Value.Value);
WaitForOptimization();
} else {
Thread.Sleep(InitialDelayParameter.Value.Value);
}
Step();
}
}
private void StartOptimization() {
if (Optimization != null) {
Optimization.Start(Synchronized);
}
}
private void StopOptimization() {
if (Optimization != null)
Optimization.Stop();
}
private void PrepareOptimization() {
if (Optimization != null)
Optimization.Prepare();
}
private void SetOptimizationScenario() {
if (Optimization != null)
Optimization.SetScenario(Scenario);
}
private void SetOptimizationSimulation() {
if (Optimization != null)
Optimization.SetSimulation(this);
}
private void SetWaitingStrategyScenario() {
if (WaitingStrategy != null)
WaitingStrategy.SetScenario(Scenario);
}
private void SetWaitingStrategy() {
if (Optimization != null)
Optimization.SetWaitingStrategy(WaitingStrategyParameter.Value);
}
private bool OptimizationRunning() {
bool running = false;
if (Optimization != null)
running = Optimization.Running();
return running;
}
private void RelocateVehicles() {
if (Optimization != null)
Optimization.RelocateVehicles();
}
private bool OptimizationRequired() {
bool required = false;
if (Optimization != null)
required = Optimization.OptimizationRequired();
return required;
}
private void WaitForOptimizationExit() {
if (Optimization != null) {
while (Optimization.Running()) {
Thread.Sleep(100);
SignalWaitHandle();
}
Optimization.Exit();
}
}
private void StopSimulation() {
SignalWaitHandle();
StopOptimization();
}
private bool pausePending;
public override void Pause() {
base.Pause();
pausePending = true;
}
private bool stopPending;
public override void Stop() {
base.Stop();
stopPending = true;
}
private void Step() {
//next step
SimulationTime = newSimulationTime;
newSimulationTime = SimulationTime + TimeStep;
}
protected override void Run(CancellationToken cancellationToken) {
InitSimulation();
while (!AllOrdersDelivered() || Scenario.MoreOrders(SimulationTime) || (Scenario.RelocateBackToDepot && !AllVehiclesAtDepot())) {
//perform actions
UpdateSimulationState();
UpdateOrders();
UpdateResults(false);
Step();
if (OptimizationRequired()) {
SignalWaitHandle();
if (!OptimizationRunning() && !(pausePending || stopPending)) {
SignalWaitHandle();
StartOptimization();
}
WaitForOptimization();
} else {
RelocateVehicles();
}
if (pausePending || stopPending) {
if (!OptimizationRunning()) {
cancellationToken.ThrowIfCancellationRequested();
} else
StopOptimization();
}
Thread.Sleep(Delay);
}
if (Optimization != null)
Optimization.RemoveCompletedActions();
UpdateResults(true);
Results.Add(new Result("Finished", new BoolValue(true)));
Thread.Sleep(500);
StopSimulation();
WaitForOptimizationExit();
}
}
#endregion
}