Examples : WriteSolutionExample.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using VRSolver;
 
namespace Examples
{
    /// <summary>
    /// Shows how to get detailed information about each Resource's route, 
    /// such as arrival times, departure times, idle time, load constraints 
    /// etc.
    /// </summary>
    class WriteSolutionExample
    {
        /// <summary>
        /// Writes the routes for each Resource to a file. (Shows how to use
        /// The RouteItem, RouteMetrics and SolutionMetrics classes)
        /// </summary>
        internal static void WriteSolution(Solution solution, string fileName)
        {
            using (StreamWriter sw = new StreamWriter(fileName))
            {
                // 
                // First write a summary for the Solution 
                //
                SolutionMetrics solutionMetrics = solution.GetSolutionMetrics();
 
                sw.WriteLine("--------");
                sw.WriteLine("Solution");
                sw.WriteLine("--------");
                sw.WriteLine("Resources used    " + solutionMetrics.ResourceCount);
                sw.WriteLine("Total distance    " + solutionMetrics.TotalDistance.ToString("0.00"));
                sw.WriteLine("Total work time   " + GetDurationLabel((int)Math.Round(solutionMetrics.WorkTimeTotal.TotalMinutes)));
                sw.WriteLine("Total idle time   " + GetDurationLabel((int)Math.Round(solutionMetrics.IdleTimeTotal.TotalMinutes)));
                sw.WriteLine("Jobs not assigned " + solutionMetrics.UnassignedJobsCount);
                sw.WriteLine("Obj. Func. Value  " + solution.ObjectiveFunctionValue.ToString("0.00"));
                sw.WriteLine();
 
                //
                // Now write the summary and schedule for each route for each resource
                //
                int r = 0;
                foreach (Resource resource in solution.Problem.Resources)
                {
                    // Get the route information for this Resource
                    RouteItem[] routeItems = solution.GetDetailedRoute(resource);
 
                    // Nothing is assigned to the Resource if the length is less than three (only the start and end location)
                    if (routeItems.Length <= 2)
                        continue;
 
                    sw.WriteLine("R" + r++ + " (Resource " + resource.ID + ", Capacity " 
                                    + GetLoadLabel(resource.MaxLoad) 
                                    + ", Weight " + resource.UseCost + ")");
 
                    //
                    // Get the Metrics for this Resource's route
                    //
                    RouteMetrics routeMetrics = solution.GetRouteMetrics(resource);
 
                    //
                    // Write the summary header    
                    //
                    sw.WriteLine("Distance" + "\t" +
                                 "Duty time" + "\t" +
                                 "Drive time" + "\t" +
                                 "Idle" + "\t" +
                                 "Late" + "\t" +
                                 "Distance cost" + "\t" +
                                 "Min duty cost" + "\t" +
                                 "Max duty cost" + "\t" +
                                 "Value" + "\t");
 
                    sw.WriteLine(routeMetrics.TotalDistance.ToString("0.00") + "\t"
                                 + GetDurationLabel((int)routeMetrics.WorkTimeTotal.TotalMinutes) + "\t"
                                 + GetDurationLabel((int)routeMetrics.DrivingTimeTotal.TotalMinutes) + "\t"
                                 + GetDurationLabel((int)routeMetrics.IdleTimeTotal.TotalMinutes) + "\t"
                                 + GetDurationLabel((int)routeMetrics.LateTimeTotal.TotalMinutes) + "\t"
                                 + routeMetrics.DistanceCost.ToString("0.00") + "\t"
                                 + routeMetrics.MinWorkTimeCost.ToString("0.00") + "\t"
                                 + routeMetrics.MaxWorkTimeCost.ToString("0.00") + "\t"
                                 + routeMetrics.JobWeightTotal.ToString("0.00") + "\t"
                     );
 
                    // Write the route header    
                    string[] header = new string[] { " ""Location""Window""Target Window""Job Load""Service Time",
                                                    "Arrive""Idle""Late""Depart""Journey""Break""Current Load""Distance""Value" };
                    foreach (string str in header)
                        sw.Write(str + "\t");
                    sw.WriteLine();
 
                    int previousLocation = -1;
                    int locationChangeCounter = -1;
                    for (int i = 0; i < routeItems.Length; i++)
                    {
                        RouteItem item = routeItems[i];
 
                        if (item.JobPart.Loc.Index != previousLocation)
                            locationChangeCounter++;
                        previousLocation = item.JobPart.Loc.Index;
 
                        string name;
                        string window = GetTime(item.JobPart.WindowOpen) + "-" + GetTime(item.JobPart.WindowClose);
                        string softwindowend = item.JobPart.SoftWindowIsUsed ? GetTime(item.JobPart.SoftWindowClose) : "-";
                        string load = " ";
                        string service = " ";
                        string idle = " ";
                        string late = " ";
                        string arrival = " ";
                        string depart = " ";
                        string journey = " ";
                        string location = " ";
                        string distance = "0.0";
                        string jobvalue = " ";
                        string breakTime = GetDurationLabel((int)item.Break.TotalMinutes);
                        long previousBreakTime = i > 0 ? routeItems[i - 1].Break.Ticks : 0;
                        string currentload = GetLoadLabel(item.CurrentLoad);
                        if (string.IsNullOrEmpty(currentload))
                            currentload = "-";
 
                        if (item.ItemType == RouteItemType.Start)
                        {
                            name = "start";
                            depart = GetTime(item.DepartureTime);
                            journey = GetDurationLabel((int)item.TravelTimeToNext.TotalMinutes);
                            distance = item.DistanceToNext.ToString("0.0");
                            location = "[S] " + item.JobPart.Loc.Index.ToString("000");
                        }
                        else if (item.ItemType == RouteItemType.End)
                        {
                            name = "end";
                            arrival = GetTime(item.ArrivalTime);
                            location = "[E] " + item.JobPart.Loc.Index.ToString("000");
                        }
                        else
                        {
                            name = "j [" + item.JobPartIndex + "]" + " (" + item.JobPart.ID + ")";
                            load = GetLoadLabel(item.JobPart.LoadChange);
                            service = GetDurationLabel((int)item.ServiceTime.TotalMinutes);
                            idle = GetDurationLabel((int)Math.Ceiling(item.IdleTime.TotalMinutes));
                            late = GetDurationLabel((int)Math.Ceiling(item.LateTime.TotalMinutes));
                            arrival = GetTime(item.ArrivalTime);
                            depart = GetTime(item.DepartureTime);
                            journey = GetDurationLabel((int)item.TravelTimeToNext.TotalMinutes);
                            distance = item.DistanceToNext.ToString("0.0");
                            location = "[" + locationChangeCounter + "] " + item.JobPart.Loc.Index.ToString("000");
 
                            if (item.JobPartIndex == 0)
                                jobvalue = item.Job.UnassignedWeight.ToString();
                        }
 
                        sw.WriteLine(name + "\t" +
                                     location + "\t" +
                                     window + "\t" +
                                     softwindowend + "\t" +
                                     load + "\t" +
                                     service + "\t" +
                                     arrival + "\t" +
                                     idle + "\t" +
                                     late + "\t" +
                                     depart + "\t" +
                                     journey + "\t" +
                                     breakTime + "\t" +
                                     currentload + "\t" +
                                     distance + "\t" +
                                     jobvalue);
                    }
                }
            }
        }
        
        internal static void WriteSolutionBasicFormat(Solution solution, string fileName)
        {
            try
            {
                StreamWriter sw = new StreamWriter(fileName);
 
                foreach (Resource resource in solution.Problem.Resources)
                {
                    RouteItem[] routeSchedule = solution.GetDetailedRoute(resource);
                    sw.WriteLine(resource.ID);
                    foreach (RouteItem item in routeSchedule)
                    {
                        sw.Write(item.ItemType + "\t");
                        sw.Write(item.ID + "\t");
                        sw.Write(item.ArrivalTime + "\t");
                        sw.Write(item.IdleTime + "\t");
                        sw.Write(item.ServiceTime + "\t");
                        sw.Write(item.DepartureTime + "\t");
                        sw.Write(item.TravelTimeToNext + "\t");
                        sw.Write(item.Break + "\t");
                        sw.Write(item.DistanceToNext + "\t");
                        sw.WriteLine();
                    }
                    sw.WriteLine();
                    sw.WriteLine();
                }
 
                sw.WriteLine();
 
                Console.WriteLine("Written          : " + fileName);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
 
        /// <summary>
        /// Converts a load constraint to a string description
        /// </summary>
        internal static string GetLoadLabel(Dictionary<stringdouble> load)
        {
            StringBuilder sb = new StringBuilder();
            int c = 0;
            foreach (var kvp in load)
            {
                if (++c == load.Count)
                    sb.Append(kvp.Key + ":" + kvp.Value);
                else
                    sb.Append(kvp.Key + ":" + kvp.Value + ",");
            }
            return sb.ToString();
        }
 
        internal static string GetDurationLabel(int totalMinutes)
        {
            int hrs = totalMinutes / 60;
            int mins = totalMinutes % 60;
 
            if (hrs > 0)
            {
                if (mins > 0)
                    return hrs + "h" + mins.ToString("00");
                else
                    return hrs + "h";
            }
            else
                return mins.ToString();
        }
 
        internal static string GetTime(DateTime dateTime)
        {
            return dateTime.ToString("HHmm");
        }
 
        internal static string GetVersion()
        {
            Version version = System.Reflection.Assembly.GetAssembly(typeof(VRSolver.Solver)).GetName().Version;
            return version.Major + "." + version.Minor;
        }
    }
}