/// <summary> /// Returns true if the route statistics exceed our exit criteria /// </summary> /// <param name="routeStatistics">the generated metrics for the route</param> /// <param name="driver">the driver of the route</param> /// <returns>true if route exceeds criteria, otherwise false</returns> public bool ExeedsExitCriteria(RouteStatistics routeStatistics, Driver driver) { var result = routeStatistics.TotalTravelTime > driver.AvailableDrivingTime || routeStatistics.TotalTime > driver.AvailableDutyTime; if (result && this._logger.IsDebugEnabled) { if (routeStatistics.TotalTravelTime > driver.AvailableDrivingTime) { this._logger.Debug("Route exceeds AvailableDrivingTime. TotalTravelTime={0}, AvailableDrivingTime={1}", routeStatistics.TotalTravelTime.TotalHours, driver.AvailableDrivingTime.TotalHours); } if (routeStatistics.TotalTime > driver.AvailableDutyTime) { this._logger.Debug("Route exceeds AvailableDutyTime. TotalTime={0}, AvailableDutyTime={1}", routeStatistics.TotalTime.TotalHours, driver.AvailableDutyTime.TotalHours); } } if (result) { return(result); } return(result); }
/// <summary> /// Compares route solutions /// </summary> public int CompareRouteStatistics(RouteStatistics left, RouteStatistics right) { var leftMeasure = _objectiveFunction.GetObjectiveMeasure(left); var rightMeasure = _objectiveFunction.GetObjectiveMeasure(right); return(leftMeasure.CompareTo(rightMeasure)); }
/// <summary> /// Returns true if the given route solution is feasable within time windows and exit criteria /// </summary> /// <param name="nodeRouteSolution"></param> /// <returns></returns> public bool IsFeasableRouteSolution(NodeRouteSolution nodeRouteSolution) { var driverNode = nodeRouteSolution.DriverNode; var currentNodeEndTime = driverNode.Driver.EarliestStartTime; var cumulativeRouteStatistics = new RouteStatistics(); var allNodes = nodeRouteSolution.AllNodes; for (int i = 0; i < allNodes.Count - 1; i++) { var nodeTiming = _nodeService.GetNodeTiming(allNodes[i], allNodes[i + 1], currentNodeEndTime, cumulativeRouteStatistics); if (nodeTiming.IsFeasableTimeWindow) { // is it a feasable route var lastConnection = _nodeService.GetNodeConnection(nodeTiming.Node, driverNode); var finalRouteStatistics = nodeTiming.CumulativeRouteStatistics + lastConnection.RouteStatistics; if (_routeExitFunction.ExeedsExitCriteria(finalRouteStatistics, driverNode.Driver)) { return(false); } } else { return(false); } currentNodeEndTime = nodeTiming.EndExecutionTime; cumulativeRouteStatistics = nodeTiming.CumulativeRouteStatistics; } return(true); }
public double GetObjectiveMeasure(RouteStatistics statistics) { var result = (statistics.TotalTime.TotalSeconds - statistics.TotalIdleTime.TotalSeconds) * ((double)1 / (statistics.DriversWithAssignments + 1)); return(result); }
public JobNode(Job job, double[,] statisticsMatrix) : this(job) { RouteStatisticsMatrix = statisticsMatrix; RouteStatistics = new RouteStatistics { DriversWithAssignments = 1, PriorityValue = job.Priority, TotalCapacity = 0, //TotalExecutionTime = statisticsMatrix[] }; }
/// <summary> /// Returns the <see cref="NodeTiming"/> for the next node /// </summary> /// <returns></returns> public NodeTiming GetNodeTiming(INode currentNode, INode nextNode, DateTime currentNodeEndTime, RouteStatistics currentRouteStatistics) { var connection = GetNodeConnection(currentNode, nextNode); DateTime nextNodeArrivalTime = currentNodeEndTime + connection.LocalRouteStatistics.TotalTime; bool isFirstStop = currentNode is DriverNode; // determine if time arrived within time window and calculate wait time bool early = nextNodeArrivalTime < nextNode.WindowStart; bool late = nextNodeArrivalTime > nextNode.WindowEnd; bool isFeasableTimeWindow = false; TimeSpan waitTime = TimeSpan.Zero; if (early) { waitTime = nextNode.WindowStart.Subtract(nextNodeArrivalTime); TimeSpan maxWaitTime = isFirstStop ? _configuration.MaximumWaitTimeBeforeStart : _configuration.MaximumWaitTimeAtStop; isFeasableTimeWindow = waitTime < maxWaitTime; } else if (late) { // we started past the time window isFeasableTimeWindow = false; } else { isFeasableTimeWindow = true; } DateTime nextNodeStartTime = nextNodeArrivalTime + waitTime; DateTime nextNodeEndTime = nextNodeStartTime + nextNode.LocalRouteStatistics.TotalTime; RouteStatistics cumulativeRouteStatistics = currentRouteStatistics + connection.LocalRouteStatistics + nextNode.LocalRouteStatistics; var result = new NodeTiming() { Node = nextNode, ArrivalTime = nextNodeArrivalTime, StartTime = nextNodeStartTime, EndTime = nextNodeEndTime, IsFeasableTimeWindow = isFeasableTimeWindow, CumulativeRouteStatistics = cumulativeRouteStatistics }; //var st = (result.ArrivalTime - DateTime.Now.Date).TotalMinutes; //var et = (result.EndTime - DateTime.Now.Date).TotalMinutes; //Console.WriteLine("{0},{1},{2}", nextNode, st, et); return(result); }
/// <summary> /// Compares route solutions /// </summary> public int Compare(RouteStatistics left, RouteStatistics right) { if (left.DriversWithAssignments == 1 || right.DriversWithAssignments == 1) { ; } double leftMeasure = _objectiveFunction.GetObjectiveMeasure(left); double rightMeasure = _objectiveFunction.GetObjectiveMeasure(right); return(leftMeasure.CompareTo(rightMeasure)); }
/// <summary> /// Computes the Solution Performance Statistics /// </summary> /// <param name="solution">The solution from which the report is generated</param> /// <returns>The generated Performance Statistics from the Solution</returns> public SolutionPerformanceStatistics GetSolutionPerformanceStatistics(Solution solution) { var truckStatisticBySolution = new Dictionary <NodeRouteSolution, TruckPerformanceStatistics>(); var totalRouteStatisticsByTruckState = new Dictionary <TruckState, RouteStatistics>(); var totalPerformanceStatistics = new PerformanceStatistics(); var totalRouteStatistics = new RouteStatistics(); foreach (var routeSolution in solution.RouteSolutions) { // calculate truck performance statistics var truckStatistics = CalculateTruckPerformanceStatistics(routeSolution); truckStatisticBySolution[routeSolution] = truckStatistics; // calculate total route statistics by truck state foreach (var truckState in truckStatistics.RouteStatisticsByTruckState.Keys) { if (!totalRouteStatisticsByTruckState.ContainsKey(truckState)) { totalRouteStatisticsByTruckState[truckState] = new RouteStatistics(); } totalRouteStatisticsByTruckState[truckState] += truckStatistics.RouteStatisticsByTruckState[truckState]; } // sum up performance & route stats totalPerformanceStatistics += truckStatistics.PerformanceStatistics; totalRouteStatistics += truckStatistics.RouteStatistics; } double solutionCount = solution.RouteSolutions.Count; var result = new SolutionPerformanceStatistics { TruckStatistics = truckStatisticBySolution, TotalRouteStatisticsByTruckState = totalRouteStatisticsByTruckState, TotalRouteStatistics = totalRouteStatistics, NumberOfBackhauls = totalPerformanceStatistics.NumberOfBackhauls, AverageNumberOfBackhauls = totalPerformanceStatistics.NumberOfBackhauls / solutionCount, NumberOfLoadmatches = totalPerformanceStatistics.NumberOfLoadmatches, AverageNumberOfLoadmatches = totalPerformanceStatistics.NumberOfLoadmatches / solutionCount, NumberOfJobs = totalPerformanceStatistics.NumberOfJobs, AverageNumberOfJobs = totalPerformanceStatistics.NumberOfJobs / solutionCount, AverageDriverDutyHourUtilization = totalPerformanceStatistics.DriverDutyHourUtilization / solutionCount, AverageDriverDrivingUtilization = totalPerformanceStatistics.DriverDrivingUtilization / solutionCount, DrivingTimePercentage = totalRouteStatistics.TotalTravelTime.TotalHours / totalRouteStatistics.TotalTime.TotalHours, WaitingTimePercentage = totalRouteStatistics.TotalIdleTime.TotalHours / totalRouteStatistics.TotalTime.TotalHours }; return(result); }
/// <summary> /// Generates node sequence iteration /// </summary> /// <param name="nodes"></param> /// <param name="driverNode"> </param> /// <returns></returns> public virtual NodeRouteSolution GenerateRouteSolution(IList <INode> nodes, DriverNode driverNode) { IList <INode> processedNodes = new List <INode>(); INode currentNode = driverNode; var startTime = driverNode.Driver.EarliestStartTime; var currentNodeEndTime = startTime; var cumulativeRouteStatistics = new RouteStatistics(); int exitCounter = 0; while (exitCounter++ < 1000) { // getting avaiable nodes that have not been processed var feasibleNodeTimings = GetFeasibleNodes(nodes, driverNode, processedNodes, currentNodeEndTime, cumulativeRouteStatistics); if (!feasibleNodeTimings.Any()) { break; } var feasibleNodeTimingsByNode = feasibleNodeTimings.ToDictionary(f => f.Node); // build probability matrix for the available nodes var probabilityData = _probabilityMatrix.BuildProbabilityDataMatrix(currentNode, feasibleNodeTimings); // find a suitable node based on the cumulative probability var selectedNode = (INode)_probabilityMatrix.GetNominatedElement(probabilityData); processedNodes.Add(selectedNode); currentNode = selectedNode; // now we update the current node's end time var selectedNodeTiming = feasibleNodeTimingsByNode[selectedNode]; if (processedNodes.Count == 1 && selectedNodeTiming.DepartureTime != currentNodeEndTime) { startTime = selectedNodeTiming.DepartureTime; } currentNodeEndTime = selectedNodeTiming.EndExecutionTime; cumulativeRouteStatistics = selectedNodeTiming.CumulativeRouteStatistics; } // create solution object var result = _routeService.CreateRouteSolution(processedNodes, driverNode); result.StartTime = startTime; return(result); }
/// <summary> /// Creates a route segment statistics /// </summary> /// <param name="startTime"></param> /// <param name="startStop"></param> /// <param name="endStop"></param> /// <returns></returns> public RouteSegmentStatistics CreateRouteSegmentStatistics(TimeSpan startTime, RouteStop startStop, RouteStop endStop) { // determine if time arrived within time window and calculate wait time bool early = startTime < endStop.WindowStart; bool late = startTime > endStop.WindowEnd; TimeSpan waitTime = TimeSpan.Zero; bool whiffed = false; if (early) { waitTime = endStop.WindowStart.Subtract(startTime); whiffed = waitTime > _configuration.MaximumWaitTimeAtStop; } else if (late) { // we started past the time window whiffed = true; } var executionTime = _routeStopDelayService.GetDelay(endStop); // calculate the trip between the current and next stop var tripLength = CalculateTripLength(startStop, endStop); var routeStatistics = new RouteStatistics() { TotalExecutionTime = executionTime, TotalWaitTime = waitTime, TotalTravelTime = tripLength.Time, TotalTravelDistance = tripLength.Distance, }; var result = new RouteSegmentStatistics { StartStop = startStop, EndStop = endStop, StartTime = startTime, Statistics = routeStatistics, WhiffedTimeWindow = whiffed }; return(result); }
/// <summary> /// Calculates the toal route statistics a list of route stops /// </summary> /// <param name="stops"></param> /// <param name="ignoreFirstStopDelays"> </param> /// <returns></returns> public RouteStatistics CalculateRouteStatistics(IList <RouteStop> stops, bool ignoreFirstStopDelays, RouteStop lastNodeEndStop = null) { var result = new RouteStatistics(); for (int i = 0; i < stops.Count; i++) { var currentStop = stops[i]; var previousStop = i > 0 ? stops[i - 1] : null; if (!ignoreFirstStopDelays || !(i == 0 || i == stops.Count - 1)) { var executionTime = _routeStopDelayService.GetExecutionTime(previousStop, currentStop, TimeSpan.Zero); var staticStats = new RouteStatistics() { TotalExecutionTime = executionTime, }; result += staticStats; } // add travel cost if (i < stops.Count - 1) { var nextStop = stops[i + 1]; // calculate the trip between the current and next stop var tripLength = CalculateTripLength(currentStop, nextStop); var travelStats = new RouteStatistics() { TotalTravelTime = tripLength.Time, TotalTravelDistance = tripLength.Distance, }; result += travelStats; } } return(result); }
/// <summary> /// Calculates the toal route statistics a list of route stops /// </summary> /// <param name="stops"></param> /// <param name="ignoreFirstStopDelays"> </param> /// <returns></returns> public RouteStatistics CalculateRouteStatistics(IList <RouteStop> stops, bool ignoreFirstStopDelays = false) { var result = new RouteStatistics(); // TODO : This does not take WaitTime into account for (int i = 0; i < stops.Count; i++) { var currentStop = stops[i]; if (!ignoreFirstStopDelays && (i == 0 || i == stops.Count - 1)) { var executionTime = _routeStopDelayService.GetDelay(currentStop); var staticStats = new RouteStatistics() { TotalExecutionTime = executionTime, }; result += staticStats; } // add travel cost if (i < stops.Count - 1) { var nextStop = stops[i + 1]; // calculate the trip between the current and next stop var tripLength = CalculateTripLength(currentStop, nextStop); var travelStats = new RouteStatistics() { TotalTravelTime = tripLength.Time, TotalTravelDistance = tripLength.Distance, }; result += travelStats; } } return(result); }
public bool JobNodeTimings(IList <Job> jobs, Driver driver, out List <NodeTiming> nodeTimings, out IList <int> ints) { nodeTimings = new List <NodeTiming>(); ints = new List <int>(); if (driver == null || jobs == null || !jobs.Any()) { { return(true); } } var jobNodes = jobs.Select((job, i) => _jobNodeService.CreateJobNode(job, null, i != 0)).Cast <INode>().ToList(); var driverNode = new DriverNode(driver); var processedNodes = new List <INode>(); var cumulativeRouteStatistics = new RouteStatistics(); //var routeSolution = GenerateRouteSolution(jobNodes, driverNode); //GetFeasibleNodes(jobNodes, driverNode, processedNodes, ) //var isFirstStop = processedNodes.Count == 0; //var currentNode = isFirstStop ? driverNode : processedNodes.Last(); // first check feasibility for driver to first node var nodeTimingResult = _routeStatisticsService.GetNodeTiming( driverNode, jobNodes.FirstOrDefault(), driverNode.WindowStart, cumulativeRouteStatistics); if (!nodeTimingResult.IsFeasableTimeWindow) { // all are infeasible { ints = jobNodes.Select(p => p.Id).ToList(); return(true); } } nodeTimings = new List <NodeTiming>() { nodeTimingResult }; for (int i = 1; i < jobNodes.Count; i++) { var currentNode = (JobNode)jobNodes[i]; var lastNode = jobNodes[i - 1]; var iterationStartTime = nodeTimingResult.EndExecutionTime; nodeTimingResult = _routeStatisticsService.GetNodeTiming( lastNode, currentNode, iterationStartTime, cumulativeRouteStatistics); nodeTimingResult.CumulativeRouteStatistics = cumulativeRouteStatistics + nodeTimingResult.CumulativeRouteStatistics; if (_routeExitFunction.ExeedsExitCriteria(nodeTimingResult.CumulativeRouteStatistics, driverNode.Driver)) { nodeTimingResult.IsFeasableTimeWindow = false; } nodeTimings.Add(nodeTimingResult); } var lastLeg = _routeStatisticsService.GetRouteStatistics(nodeTimingResult.Node, driverNode, nodeTimingResult.EndExecutionTime); var finalRouteStatistics = nodeTimingResult.CumulativeRouteStatistics + lastLeg; if (_routeExitFunction.ExeedsExitCriteria(finalRouteStatistics, driverNode.Driver)) { nodeTimingResult.IsFeasableTimeWindow = false; } nodeTimings.Add(nodeTimingResult); return(false); }
public virtual NodeRouteSolution GenerateIterativeRouteSolution(IList <INode> nodes, DriverNode driverNode, bool reOrder = true) { IList <INode> processedNodes = new List <INode>(); INode currentNode = driverNode; var startTime = driverNode.Driver.EarliestStartTimeSpan; var currentNodeEndTime = startTime; var cumulativeRouteStatistics = new RouteStatistics(); nodes = SortINodes(nodes, driverNode.Driver, reOrder).ToList(); int exitCounter = 0; while (exitCounter++ < 1000) { nodes = nodes.Where(x => !processedNodes.Select(y => y.Id).ToList().Contains(x.Id)).ToList(); // getting avaiable nodes that have not been processed if (!nodes.Any()) { break; } var feasibleNodeTimingsList = SortINodes(nodes, driverNode.Driver, reOrder).ToList(); var firstHitFeasibleNodeTiming = feasibleNodeTimingsList.FirstOrDefault(y => y.WindowEnd > currentNodeEndTime); if (firstHitFeasibleNodeTiming == null) { break; } var firstHitFeasibleNodeTimingNode = firstHitFeasibleNodeTiming; var selectedNode = firstHitFeasibleNodeTimingNode; var selectedJobNode = selectedNode is JobNode ? selectedNode as JobNode : null; var processedRouteStops = processedNodes.SelectMany(x => x.RouteStops); var provisionalRouteStops = new Queue <RouteStop>(); foreach (var processedRouteStop in processedRouteStops) { provisionalRouteStops.Enqueue(processedRouteStop); } foreach (var routeStop in selectedNode.RouteStops) { provisionalRouteStops.Enqueue(routeStop); } var tempJob = new Job { RouteStops = provisionalRouteStops.Select(x => x).ToList(), IsHazmat = selectedJobNode != null && selectedJobNode.Job != null ? selectedJobNode.Job.IsHazmat : false }; var tempJobNode = _jobNodeService.CreateJobNode(tempJob, driverNode.Driver.EarliestStartTimeSpan, false); if (!tempJobNode.IsInvalid) { var serviceTimeIndex = _jobNodeService.GetMatrixIndex("ServiceTime"); var waitTimeIndex = _jobNodeService.GetMatrixIndex("WaitTime"); var travelTimeIndex = _jobNodeService.GetMatrixIndex("TravelTime"); var entryCount = tempJobNode.RouteStatisticsMatrix.GetLength(1); var travelTime = TimeSpan.Zero; var serviceTime = TimeSpan.Zero; var waitTime = TimeSpan.Zero; for (var i = 0; i < entryCount; i++) { travelTime += TimeSpan.FromSeconds(tempJobNode.RouteStatisticsMatrix[travelTimeIndex, i]); serviceTime += TimeSpan.FromSeconds(tempJobNode.RouteStatisticsMatrix[serviceTimeIndex, i]); waitTime += TimeSpan.FromSeconds(tempJobNode.RouteStatisticsMatrix[waitTimeIndex, i]); } var statistics = new RouteStatistics { TotalExecutionTime = serviceTime, TotalIdleTime = waitTime, TotalTravelTime = travelTime, TotalQueueTime = TimeSpan.Zero }; if (!_routeExitFunction.ExeedsExitCriteria(statistics, driverNode.Driver) && _routeExitFunction.MeetsPortCriteria(tempJobNode.RouteStops, driverNode.Driver) && PassesFilterCriteria(driverNode, tempJobNode, new List <INode>()) ) { processedNodes.Add(selectedNode); driverNode.Driver.EarliestStartTime = tempJobNode.WindowStart.Ticks; } else { nodes.RemoveAt(0); } } else { nodes.RemoveAt(0); } } // create solution object, adjust start time var result = _routeService.CreateRouteSolution(driverNode, processedNodes); var driverStartTicks = Math.Max(driverNode.Driver.EarliestStartTime, startTime.Ticks); result.StartTime = TimeSpan.FromTicks(driverStartTicks); var s = string.Join("\t", result.Nodes.Select(f => "[" + f.Id + "]").ToArray()); Console.WriteLine(s); Console.WriteLine(result.RouteStatistics.ToString()); return(result); }
/// <summary> /// Generates node sequence iteration /// </summary> /// <param name="nodes"></param> /// <param name="driverNode"> </param> /// <returns></returns> public virtual NodeRouteSolution GenerateRouteSolution(IList <INode> nodes, DriverNode driverNode) { IList <INode> processedNodes = new List <INode>(); INode currentNode = driverNode; var startTime = driverNode.Driver.EarliestStartTimeSpan; var currentNodeEndTime = startTime; var cumulativeRouteStatistics = new RouteStatistics(); int exitCounter = 0; while (exitCounter++ < 1000) { // getting avaiable nodes that have not been processed var feasibleNodeTimings = GetFeasibleNodes(nodes, driverNode, processedNodes, currentNodeEndTime, cumulativeRouteStatistics); if (!feasibleNodeTimings.Any()) { break; } var feasibleNodeTimingsByNode = feasibleNodeTimings.ToDictionary(f => f.Node); // build probability matrix for the available nodes var probabilityData = _probabilityMatrix.BuildProbabilityDataMatrix(currentNode, feasibleNodeTimings); // find a suitable node based on the cumulative probability var selectedNode = (INode)_probabilityMatrix.GetNominatedElement(probabilityData); selectedNode.DepartureTime = feasibleNodeTimingsByNode[selectedNode].DepartureTime; // set the Departure Time // break if we nominated the driver node if (selectedNode == driverNode) { break; } processedNodes.Add(selectedNode); currentNode = selectedNode; // now we update the current node's end time var selectedNodeTiming = feasibleNodeTimingsByNode[selectedNode]; if (processedNodes.Count == 1 && selectedNodeTiming.DepartureTime != currentNodeEndTime.Ticks) { startTime = new TimeSpan(selectedNodeTiming.DepartureTime); } currentNodeEndTime = selectedNodeTiming.EndExecutionTime; cumulativeRouteStatistics = selectedNodeTiming.CumulativeRouteStatistics; var processedRouteStops = processedNodes.SelectMany(x => x.RouteStops); var provisionalRouteStops = new Queue <RouteStop>(); foreach (var processedRouteStop in processedRouteStops) { provisionalRouteStops.Enqueue(processedRouteStop); } foreach (var routeStop in selectedNode.RouteStops) { provisionalRouteStops.Enqueue(routeStop); } var tempJob = new Job { RouteStops = provisionalRouteStops.Select(x => x).ToList() }; var tempJobNode = _jobNodeService.CreateJobNode(tempJob, driverNode.Driver.EarliestStartTimeSpan, false); if (!tempJobNode.IsInvalid) { var serviceTimeIndex = _jobNodeService.GetMatrixIndex("ServiceTime"); var waitTimeIndex = _jobNodeService.GetMatrixIndex("WaitTime"); var travelTimeIndex = _jobNodeService.GetMatrixIndex("TravelTime"); var entryCount = tempJobNode.RouteStatisticsMatrix.GetLength(1); var travelTime = TimeSpan.Zero; var serviceTime = TimeSpan.Zero; var waitTime = TimeSpan.Zero; for (var i = 0; i < entryCount; i++) { travelTime += TimeSpan.FromSeconds(tempJobNode.RouteStatisticsMatrix[travelTimeIndex, i]); serviceTime += TimeSpan.FromSeconds(tempJobNode.RouteStatisticsMatrix[serviceTimeIndex, i]); waitTime += TimeSpan.FromSeconds(tempJobNode.RouteStatisticsMatrix[waitTimeIndex, i]); } var statistics = new RouteStatistics { TotalExecutionTime = serviceTime, TotalIdleTime = waitTime, TotalTravelTime = travelTime, TotalQueueTime = TimeSpan.Zero }; if (!_routeExitFunction.ExeedsExitCriteria(statistics, driverNode.Driver)) { processedNodes.Add(selectedNode); driverNode.Driver.EarliestStartTime = tempJobNode.WindowStart.Ticks; } } } // create solution object, adjust start time var result = _routeService.CreateRouteSolution(driverNode, processedNodes); var driverStartTicks = Math.Max(driverNode.Driver.EarliestStartTime, startTime.Ticks); result.StartTime = TimeSpan.FromTicks(driverStartTicks); var s = string.Join("\t", result.Nodes.Select(f => "[" + f.Id + "]").ToArray()); Console.WriteLine(s); Console.WriteLine(result.RouteStatistics.ToString()); return(result); }
public Drayage.Optimization.Model.Planning.Plan MapDomainToModelWithoutPlaceHolder(FRATIS.SFL.Domain.Planning.Plan plan) { var model = new Plan(); model.InjectFrom <DomainToModelValueInjection>(plan); foreach (var driverPlan in plan.DriverPlans) { var modelDriverPlan = model.DriverPlans.FirstOrDefault(f => f.Id == driverPlan.Id); if (modelDriverPlan == null) { continue; } var driver = driverPlan.Driver ?? _driverService.GetById(driverPlan.DriverId); var driverModel = new Drayage.Optimization.Model.Orders.Driver(); driverModel.InjectFrom <DomainToModelValueInjection>(driver); modelDriverPlan.Driver = driverModel.InjectFrom(driver) as Drayage.Optimization.Model.Orders.Driver; modelDriverPlan.RouteSegmentStatistics = new List <RouteSegmentStatistics>(); if (driverPlan.Driver.IsPlaceholderDriver) { continue; } modelDriverPlan.JobPlans = modelDriverPlan.JobPlans.OrderBy(f => f.SortOrder).ToList(); foreach (var jobPlan in driverPlan.JobPlans) { //var driverPlanJob = _planService.GetPlanDriverJobsById(jobPlan.Id); var modelJobPlan = modelDriverPlan.JobPlans.FirstOrDefault(f => f.Id == jobPlan.Id); modelJobPlan.Job = modelJobPlan.Job ?? new Drayage.Optimization.Model.Orders.Job(); MapDomainToModel(jobPlan.Job, modelJobPlan.Job, plan.PlanConfig.DueDate); } if (driverPlan.RouteSegmentMetrics == null) { driverPlan.RouteSegmentMetrics = new List <RouteSegmentMetric>(); } foreach (var x in driverPlan.RouteSegmentMetrics) { var rss = new RouteSegmentStatistics(); var endStop = ConvertRouteStop(x.EndStop); var startStop = ConvertRouteStop(x.StartStop); var statistics = new RouteStatistics(); var startTime = new TimeSpan(x.StartTime ?? 0); statistics.TotalCapacity = 0; statistics.TotalExecutionTime = new TimeSpan(x.TotalExecutionTime); statistics.TotalIdleTime = new TimeSpan(x.TotalIdleTime); statistics.TotalQueueTime = new TimeSpan(x.TotalQueueTime); statistics.TotalTravelDistance = x.TotalTravelDistance; statistics.TotalTravelTime = new TimeSpan(x.TotalTravelTime); rss.EndStop = endStop; rss.StartStop = startStop; rss.StartTime = startTime; rss.Statistics = statistics; rss.WhiffedTimeWindow = false; modelDriverPlan.RouteSegmentStatistics.Add(rss); } } return(model); }
/// <summary> /// Returns the objective measure that we are minimizing /// </summary> /// <param name="routeStatistics">the route from which the selection criteria is selected</param> /// <returns>the value of the selection criteria</returns> public double GetObjectiveMeasure(RouteStatistics routeStatistics) { return((double)routeStatistics.TotalTravelDistance); }
/// <summary> /// Returns the objective measure that we are minimizing /// </summary> /// <param name="routeStatistics"></param> /// <returns></returns> public double GetObjectiveMeasure(RouteStatistics routeStatistics) { return(routeStatistics.TotalTime.TotalMinutes); }
/// <summary> /// Returns the objective measure that we are minimizing /// </summary> /// <param name="statistics"></param> /// <returns></returns> public double GetObjectiveMeasure(RouteStatistics statistics) { return(statistics.TotalTime.TotalSeconds); }
/// <summary> /// Calculates the route statistics for a list of stops /// </summary> /// <param name="stops"></param> /// <param name="startTime"></param> /// <param name="ignoreFirstStopDelays"> </param> /// <returns></returns> public RouteStatistics CalculateRouteStatistics(IList <RouteStop> stops, TimeSpan startTime, bool ignoreFirstStopDelays, RouteStop lastNodeEndStop = null) { var result = new RouteStatistics(); var currentTime = startTime; for (int i = 0; i < stops.Count; i++) { var currentStop = stops[i]; var previousStop = i > 0 ? stops[i - 1] : lastNodeEndStop; var waitTime = TimeSpan.Zero; if (currentTime < currentStop.WindowStart) { // early waitTime = currentStop.WindowStart.Subtract(currentTime); } else if (currentTime > currentStop.WindowEnd) { ; // late //var lateTime = currentTime.Subtract(currentStop.WindowEnd); } if (ignoreFirstStopDelays) { if (i != 0) { var executionTime = _routeStopDelayService.GetExecutionTime(previousStop, currentStop, currentTime); var staticStats = new RouteStatistics() { TotalExecutionTime = executionTime, TotalIdleTime = waitTime, }; result += staticStats; } } else { // todo refactor var executionTime = _routeStopDelayService.GetExecutionTime(previousStop, currentStop, currentTime); var staticStats = new RouteStatistics() { TotalExecutionTime = executionTime, TotalIdleTime = waitTime, }; result += staticStats; } // update current time with accumulated total time currentTime = startTime + result.TotalTime; // add travel cost if (i < stops.Count - 1) { var nextStop = stops[i + 1]; if (currentStop.Location != null && nextStop.Location != null) { // calculate the trip between the current and next stop var tripLength = CalculateTripLength(currentStop, nextStop, currentTime); var queueTime = _routeStopDelayService.GetQueueTime(currentStop, nextStop, currentTime); var travelStats = new RouteStatistics() { TotalTravelTime = tripLength.Time, TotalTravelDistance = tripLength.Distance, TotalQueueTime = queueTime, }; result += travelStats; } } // update current time once again with accumulated total time currentTime = startTime + result.TotalTime; } return(result); }
public RouteSegmentStatistics CreateRouteSegmentStatistics(TimeSpan startTime, RouteStop startStop, RouteStop endStop, bool setIdleTime = true, bool driverFirstStop = false) { if (startTime.Days > 0) { startTime = new TimeSpan(startTime.Hours, startTime.Minutes, startTime.Seconds); } if (startStop.WindowStart > endStop.WindowStart) { endStop.WindowStart = endStop.WindowStart.Add(TimeSpan.FromDays(1)); } if (startStop.WindowEnd > endStop.WindowEnd) { endStop.WindowEnd = endStop.WindowEnd.Add(TimeSpan.FromDays(1)); } // calculate the trip between the current and next stop var tripLength = CalculateTripLength(startStop, endStop); // determine if time arrived within time window and calculate wait time var adjustedStartTime = startTime.Ticks - tripLength.Time.Ticks; if (adjustedStartTime < startTime.Ticks) { adjustedStartTime = startTime.Ticks; } var earlyLateFlagTime = new TimeSpan((startTime + tripLength.Time).Hours, (startTime + tripLength.Time).Minutes, (startTime + tripLength.Time).Seconds); bool early = earlyLateFlagTime < endStop.WindowStart; bool late = earlyLateFlagTime > endStop.WindowEnd; TimeSpan idleTime = TimeSpan.Zero; bool whiffed = false; if (early) { if (setIdleTime) { idleTime = endStop.WindowStart.Subtract(startTime); } var idleTime2 = idleTime.Ticks - tripLength.Time.Ticks; if (idleTime2 > startTime.Ticks) { // idletime 2 is the new adjusted start time if (setIdleTime) { idleTime = new TimeSpan(idleTime2); } } whiffed = idleTime > _configuration.MaximumIdleTimeAtStop; // subtract travel time if not driver start time } else if (late) { // we started past the time window whiffed = true; } bool isDriverFirstSegment = true; if (idleTime > tripLength.Time) { idleTime = idleTime - tripLength.Time; } var arrivalTimeAtEndStop = new TimeSpan((startTime + tripLength.Time).Hours, (startTime + tripLength.Time).Minutes, (startTime + tripLength.Time).Seconds); var executionTime = _routeStopDelayService.GetExecutionTime(startStop, endStop, arrivalTimeAtEndStop, driverFirstStop); TimeSpan queueTime = _routeStopDelayService.GetQueueTime(startStop, endStop, arrivalTimeAtEndStop); var routeStatistics = new RouteStatistics() { TotalExecutionTime = executionTime, TotalIdleTime = idleTime, TotalTravelTime = tripLength.Time, TotalTravelDistance = tripLength.Distance, TotalQueueTime = queueTime }; var result = new RouteSegmentStatistics { StartStop = startStop, EndStop = endStop, StartTime = startTime, Statistics = routeStatistics, WhiffedTimeWindow = whiffed }; return(result); }
public virtual List <NodeTiming> GetFeasibleNodes(IList <INode> availableNodes, DriverNode driverNode, IList <INode> processedNodes, TimeSpan currentNodeEndTime, RouteStatistics cumulativeRouteStatistics) { var isFirstStop = (processedNodes.Count == 0); var currentNode = isFirstStop ? driverNode : processedNodes.Last(); if (currentNode is JobNode) { ; } var filteredAvailableNodes = new List <INode>(); // filter available nodes based on predefined criteria foreach (var availableNode in availableNodes) { if (availableNode is JobNode) { //if (PassesFilterCriteria(driverNode, (JobNode)availableNode)) { filteredAvailableNodes.Add(availableNode); } } else { filteredAvailableNodes.Add(availableNode); // we are only filtering JobNodes } } availableNodes = filteredAvailableNodes.ToList(); // get the node timings for all of the available nodes var nodeTimings = availableNodes.Except(processedNodes) .Select(nextNode => _nodeService.GetNodeTiming(currentNode, nextNode, currentNodeEndTime, cumulativeRouteStatistics)) .ToList(); var feasibleNodes = new List <NodeTiming>(); foreach (var nodeTiming in nodeTimings.Where(f => f.IsFeasableTimeWindow)) { var finalConnection = _nodeService.GetNodeConnection(nodeTiming.Node, driverNode); var finalRouteStatistics = nodeTiming.CumulativeRouteStatistics + finalConnection.RouteStatistics; if (!_routeExitFunction.ExeedsExitCriteria(finalRouteStatistics, driverNode.Driver)) { feasibleNodes.Add(nodeTiming); } } return(feasibleNodes); }
public virtual List <NodeTiming> GetFeasibleNodes(IList <INode> availableNodes, DriverNode driverNode, IList <INode> processedNodes, TimeSpan currentNodeEndTime, RouteStatistics cumulativeRouteStatistics) { var isFirstStop = (processedNodes.Count == 0); var currentNode = isFirstStop ? driverNode : processedNodes.Last(); var filteredAvailableNodes = new List <INode>(); var updatedNodes = new List <INode>(); if (currentNode is JobNode) { // update nodes to adjust for potentially shortened execution time foreach (var n in availableNodes) { if (n is JobNode) { var node = _jobNodeService.CreateJobNode(((JobNode)n).Job, currentNodeEndTime, IsExecutionTimeIgnored(currentNode, n)); updatedNodes.Add(node); } else { updatedNodes.Add(n); } } availableNodes = updatedNodes.ToList(); } // filter available nodes based on predefined criteria foreach (var availableNode in availableNodes) { if (availableNode is JobNode) { if (PassesFilterCriteria(driverNode, (JobNode)availableNode, filteredAvailableNodes)) { filteredAvailableNodes.Add(availableNode); } else { ; } } else { filteredAvailableNodes.Add(availableNode); // we are only filtering JobNodes } } availableNodes = filteredAvailableNodes.ToList(); // get the node timings for all of the available nodes var unprocessedNodes = availableNodes.Where(x => !processedNodes.Select(y => y.Id).ToList().Contains(x.Id)); unprocessedNodes = new List <INode>(); foreach (var availableNode in availableNodes) { var processedNodesIds = processedNodes.Select(x => x.Id); if (!processedNodesIds.Contains(availableNode.Id)) { unprocessedNodes = unprocessedNodes.Concat(new List <INode> { availableNode }); } } var nodeTimings = unprocessedNodes.Select(nextNode => _routeStatisticsService.GetNodeTiming(currentNode, nextNode, currentNodeEndTime, cumulativeRouteStatistics)); var feasibleNodes = new List <NodeTiming>(); foreach (var nodeTiming in nodeTimings.Where(f => f.IsFeasableTimeWindow)) { // calculate for return home to driver node var lastLeg = _routeStatisticsService.GetRouteStatistics(nodeTiming.Node, driverNode, nodeTiming.EndExecutionTime); var finalRouteStatistics = nodeTiming.CumulativeRouteStatistics + lastLeg; if (!_routeExitFunction.ExeedsExitCriteria(finalRouteStatistics, driverNode.Driver)) { feasibleNodes.Add(nodeTiming); } } return(feasibleNodes); }
/// <summary> /// Returns the <see cref="NodeTiming"/> for the next node /// </summary> /// <returns></returns> public virtual NodeTiming GetNodeTiming(INode startNode, INode endNode, TimeSpan startNodeEndTime, RouteStatistics currentRouteStatistics) { bool isFirstStop = startNode is DriverNode; var connectionRouteStatistics = GetRouteStatistics(startNode, endNode, startNodeEndTime); var originalStartNodeEndTime = startNodeEndTime.Ticks; if (isFirstStop) { var travelTime = connectionRouteStatistics.TotalTravelTime.Ticks; var driverStartTime = originalStartNodeEndTime; var jobNodeEnd = endNode.WindowEnd.Ticks; var jobNodeStart = endNode.WindowStart.Ticks; startNodeEndTime = TimeSpan.FromTicks(Math.Max(jobNodeEnd - travelTime, driverStartTime)); startNodeEndTime = TimeSpan.FromTicks(Math.Max(jobNodeStart - travelTime, driverStartTime)); } TimeSpan endNodeArrivalTime = startNodeEndTime + connectionRouteStatistics.TotalTravelTime; // cbs 16 Sep 14 Scheduling Night Shift starts with day orders if (endNodeArrivalTime.Days > 0) { endNodeArrivalTime = endNodeArrivalTime.Add(TimeSpan.FromDays(endNodeArrivalTime.Days * -1)); } // determine if time arrived within time window and calculate wait time var firstStopWaitMinutes = isFirstStop ? endNodeArrivalTime.Subtract(TimeSpan.FromTicks(originalStartNodeEndTime)).TotalMinutes : 0; var isDriverAlreadyLate = startNodeEndTime > endNode.WindowEnd; var isFirstStopWithinDelayPeriod = isFirstStop && !isDriverAlreadyLate && firstStopWaitMinutes <= _configuration.MaximumIdleTimeBeforeStart.TotalMinutes; bool early = endNodeArrivalTime <= endNode.WindowStart; bool late = (endNodeArrivalTime > endNode.WindowEnd) || (isFirstStop && !isFirstStopWithinDelayPeriod); bool isFeasableTimeWindow = false; TimeSpan idleTime = TimeSpan.Zero; if (early) { // if we are early to make it to the first stop, there's no need to wait, we will // adjust the nextNodeArrivalTime to reflect the windowStartTime of the first // location to goto. if (!isFirstStop) { idleTime = endNode.WindowStart.Subtract(endNodeArrivalTime); } else { startNodeEndTime = endNode.WindowStart - connectionRouteStatistics.TotalTime; startNodeEndTime = endNode.WindowStart - connectionRouteStatistics.TotalNonIdleTime; endNodeArrivalTime = startNodeEndTime + connectionRouteStatistics.TotalTravelTime; idleTime = endNode.WindowStart.Subtract(endNodeArrivalTime); } var maxIdleTime = isFirstStop ? _configuration.MaximumIdleTimeBeforeStart : _configuration.MaximumIdleTimeAtStop; isFeasableTimeWindow = idleTime < maxIdleTime; } else if (late) { // we started past the time window isFeasableTimeWindow = false; } else { isFeasableTimeWindow = true; } var endNodeRouteStatistics = GetRouteStatistics(endNode, endNodeArrivalTime); TimeSpan queueTime = endNodeRouteStatistics.TotalQueueTime; TimeSpan nextNodeStartTime = endNodeArrivalTime + idleTime; TimeSpan nextNodeEndTime = nextNodeStartTime + endNodeRouteStatistics.TotalTime; // wait? RouteStatistics localRouteStatistics = new RouteStatistics() { TotalIdleTime = idleTime }; RouteStatistics cumulativeRouteStatistics = currentRouteStatistics + connectionRouteStatistics + endNodeRouteStatistics + localRouteStatistics; var result = new NodeTiming() { Node = endNode, DepartureTime = startNodeEndTime.Ticks, ArrivalTime = endNodeArrivalTime, StartExecutionTime = nextNodeStartTime, IdleTime = isFirstStop ? TimeSpan.Zero : idleTime, QueueTime = queueTime, EndExecutionTime = nextNodeEndTime, IsFeasableTimeWindow = isFeasableTimeWindow, CumulativeRouteStatistics = cumulativeRouteStatistics }; return(result); }
/// <summary> /// Returns the <see cref="NodeTiming"/> for the next node /// </summary> /// <returns></returns> public virtual NodeTiming GetNodeTiming(INode startNode, INode endNode, TimeSpan currentNodeEndTime, RouteStatistics currentRouteStatistics) { var connection = GetNodeConnection(startNode, endNode); TimeSpan nextNodeArrivalTime = currentNodeEndTime + connection.RouteStatistics.TotalTime; TimeSpan nextNodeCompletionTime = endNode.RouteStops != null ? nextNodeArrivalTime.Add( endNode.RouteStops.FirstOrDefault().StopDelay.Value) : nextNodeArrivalTime; bool isFirstStop = startNode is DriverNode; bool early = nextNodeArrivalTime < endNode.WindowStart; bool late = nextNodeArrivalTime > endNode.WindowEnd; bool isFeasableTimeWindow = false; TimeSpan waitTime = TimeSpan.Zero; if (early) { waitTime = endNode.WindowStart.Subtract(nextNodeArrivalTime); TimeSpan maxWaitTime = isFirstStop ? _configuration.MaximumWaitTimeBeforeStart : _configuration.MaximumWaitTimeAtStop; isFeasableTimeWindow = waitTime < maxWaitTime; if (isFirstStop && isFeasableTimeWindow) { waitTime = TimeSpan.Zero; currentNodeEndTime = endNode.WindowStart - connection.RouteStatistics.TotalTime; nextNodeArrivalTime = currentNodeEndTime + connection.RouteStatistics.TotalTime; } } else if (late) { // we started past the time window isFeasableTimeWindow = false; } else { isFeasableTimeWindow = true; } var cumulatingCompletionTime = new TimeSpan(nextNodeCompletionTime.Ticks); if (isFeasableTimeWindow) { // make sure that the following subsequent route stops would not be violated if (endNode is JobNode) { var jn = endNode as JobNode; for (int i=1; i<jn.RouteStops.Count; i++) { var rs = jn.RouteStops[i]; var rsConnection = GetNodeConnection( new JobNode() { RouteStops = new List<RouteStop>() { jn.RouteStops[i - 1] }, }, new JobNode() { RouteStops = new List<RouteStop>() { rs } }); var nextStopArrivalTime = cumulatingCompletionTime.Add(rsConnection.RouteStatistics.TotalTravelTime); bool isWaitRequired = nextStopArrivalTime <= rs.WindowStart; cumulatingCompletionTime = isWaitRequired ? rs.WindowStart.Add(rs.StopDelay.Value) : nextStopArrivalTime.Add(rs.StopDelay.Value); for (int q=i; q < jn.RouteStops.Count; q++) { var nextStop = jn.RouteStops[q]; bool nextStopEarly = cumulatingCompletionTime < nextStop.WindowStart; bool nextStopLate = cumulatingCompletionTime > nextStop.WindowEnd; if (nextStopLate) { isFeasableTimeWindow = false; } else if (nextStopEarly) { // todo - check to see waiting time, driver limits } } } } } TimeSpan nextNodeStartTime = nextNodeArrivalTime + waitTime; TimeSpan nextNodeEndTime = nextNodeStartTime + endNode.RouteStatistics.TotalTime; RouteStatistics localRouteStatistics = new RouteStatistics() {TotalWaitTime = waitTime}; RouteStatistics cumulativeRouteStatistics = currentRouteStatistics + connection.RouteStatistics + endNode.RouteStatistics + localRouteStatistics; var result = new NodeTiming() { Node = endNode, DepartureTime = currentNodeEndTime, ArrivalTime = nextNodeArrivalTime, StartExecutionTime = nextNodeStartTime, EndExecutionTime = cumulatingCompletionTime, IsFeasableTimeWindow = isFeasableTimeWindow, CumulativeRouteStatistics = cumulativeRouteStatistics }; return result; }
/// <summary> /// Returns the objective measure that we are minimizing /// </summary> /// <param name="routeStatistics"></param> /// <returns></returns> public double GetObjectiveMeasure(RouteStatistics routeStatistics) { //var priorityValue = Math.Pow(1, (double)routeStatistics.PriorityValue * 10000); //return (double)routeStatistics.TotalTravelDistance / priorityValue; return((double)routeStatistics.TotalTravelDistance); }
public double GetObjectiveMeasure(RouteStatistics statistics) { var result = statistics.TotalTime.TotalSeconds + (1000000 * statistics.UnassignedJobs); return(result); }