#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 { if (!Results.ContainsKey("SimulationTime")) { return 0; } else { DoubleValue simulationTime = (Results["SimulationTime"].Value as DoubleValue); return simulationTime.Value; } } private set { if (!Results.ContainsKey("SimulationTime")) { Results.Add(new Result("SimulationTime", new DoubleValue(0))); } Results["SimulationTime"].Value = new DoubleValue(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)); } 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 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() { bool update = false; 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); if (changes.Count > 0) update = true; } } if (update) UpdateVisualization(); } 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; newSimulationTime = TimeStep; //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(); newSimulationTime = 0; } private void InitSimulation() { pausePending = false; stopPending = false; InitWaitHandle(); if (!Results.ContainsKey("SimulationTime")) { PrepareOptimization(); CreateSimulation(); SignalWaitHandle(); if (OptimizationRequired()) { StartOptimization(); Thread.Sleep(InitialDelayParameter.Value.Value); WaitForOptimization(); } else { Thread.Sleep(InitialDelayParameter.Value.Value); } } } 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) Optimization.WaitForExit(); } 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; } protected override void Run(CancellationToken cancellationToken) { InitSimulation(); while (!AllOrdersDelivered() || Scenario.MoreOrders(newSimulationTime) || (Scenario.RelocateBackToDepot && !AllVehiclesAtDepot())) { //perform actions UpdateSimulationState(); //next step SimulationTime = newSimulationTime; newSimulationTime = SimulationTime + TimeStep; UpdateOrders(); UpdateResults(false); 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 }