private OptimizationResult GetModel()
        {
            // unavailable
            var unavailableDay1Before = (int.MinValue, day1Start);
            var unavailableBetween    = (day1End, day2Start);
            var unavailableDay2After  = (day2End, int.MaxValue);

            var input = new OptimizationInput();

            {
                input.Santas = new Santa[]
                {
                    new Santa
                    {
                        Id = 100,
                    },
                    new Santa
                    {
                        Id = 200,
                    },
                };
                input.Visits = new Visit[]
                {
                    new Visit
                    {
                        Id       = 0,
                        Duration = duration1,
                        Desired  = new(int, int)[]
 public static GoogleRoutingConfig GetDefault(OptimizationInput input)
 {
     return(new GoogleRoutingConfig
     {
         MaxNumberOfAdditionalSantas = input.NumberOfSantas(),
         Mode = input.NumberOfVisits() <= 50 ? SolvingMode.Default : SolvingMode.Fast,
     });
 }
示例#3
0
 public GenAlgConfig(OptimizationInput input, int maxNumberOfAdditionalSantas = 0)
 {
     if (maxNumberOfAdditionalSantas < 0)
     {
         throw new ArgumentOutOfRangeException(nameof(maxNumberOfAdditionalSantas), maxNumberOfAdditionalSantas, "must not be negative");
     }
     PopulationSize    = CalculatePopulationSize(input);
     MaxNumberOfSantas = input.Santas.Length + maxNumberOfAdditionalSantas;
 }
示例#4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="input"></param>
        /// <param name="config"></param>
        public ParallelGenAlgSolver(OptimizationInput input, ParallelGenAlgConfig config)
        {
            if (!config.GenAlgConfig.IsValid())
            {
                throw new ArgumentException("the given GenAlgConfig must not be invalid", nameof(config));
            }

            this.input  = input;
            this.config = config;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="input"></param>
        /// <param name="config"></param>
        public GenAlgSolver(OptimizationInput input, GenAlgConfig config)
        {
            if (!config.IsValid())
            {
                throw new ArgumentException("must not be invalid", "config");
            }

            this.input  = input;
            this.config = config;
        }
示例#6
0
        /// <summary>
        /// Instantiates a new LocalSolver.Solver class with the given optimization input
        /// </summary>
        /// <param name="input">the optimization input being used to solve the problem</param>
        /// <param name="config">config for this solver</param>
        public Solver(OptimizationInput input, LocalSolverConfig config)
        {
            if (config.MaxNumberOfAdditionalSantas < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(config), config.MaxNumberOfAdditionalSantas, $"{nameof(config.MaxNumberOfAdditionalSantas)} must not be negative");
            }

            this.input  = input;
            this.config = config;
        }
        public Task <OptimizationOutput> OptimizeAsync(OptimizationInput input, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }

            var inputJson = JsonConvert.SerializeObject(input, JsonSerializerSettings);

            return(OptimizeAsync(inputJson, cancellationToken));
        }
        public static RoutingData Convert(OptimizationInput input, int maxNumberOfAdditionalSantas)
        {
            var data = new RoutingData(input);

            CreateSantas(data, maxNumberOfAdditionalSantas);
            CreateVisits(data);
            CreateUnavailable(data);
            CreateDesired(data);
            CreateStartEnd(data);

            return data;
        }
示例#9
0
        public RepairOperation(OptimizationInput input, Dictionary <int, int> alleleToVisitIdMapping)
        {
            if (alleleToVisitIdMapping == null)
            {
                throw new ArgumentNullException();
            }

            this.input   = input;
            needRepair   = input.Visits.Any(v => v.IsBreak);
            breakMapping = new Dictionary <int, int[]>();
            if (needRepair)
            {
                CreateBreakMapping(alleleToVisitIdMapping);
            }
        }
示例#10
0
        private static int CalculatePopulationSize(OptimizationInput input)
        {
            const int sizeDefault = 262144;
            const int sizeBigger  = 16;

            // number of visits
            var x = input.Visits.Count(v => !v.IsBreak) + input.Visits.Count(v => v.IsBreak) * input.Days.Length;
            // PopulationSize
            double y;

            // x -> y
            // 10 -> 262144
            // 20 -> 262144
            // 31 -> 262144
            // 34 -> 262144
            // 50 -> 131072
            // 100 -> 16384
            // 200 -> 16
            // 1000 -> 16

            if (x <= 34) // [-inf,34]
            {
                y = sizeDefault;
            }
            else if (x > 34 && x <= 50) // (34,50]
            {
                // linear interpolation
                // generated with https://mycurvefit.com/
                // linear fit method: linear regression
                // y = -8192*x + 540672
                y = -8192 * x + 540672;
            }
            else if (x > 50 && x < 200) // (50,200)
            {
                // non-linear approximation
                // generated with https://mycurvefit.com/
                // non-linear fit method: exponential basic
                // y = -250.92 + 1036717 * e ^ (-0.0413231 * x)
                y = Math.Round(-250.92 + 1036717 * Math.Pow(Math.E, (-0.0413231 * x)));
            }
            else // [200,inf]
            {
                y = sizeBigger;
            }

            return((int)y);
        }
        public static ISolver CreateSolver(OptimizationInput input, ISolverConfig solverConfig)
        {
            switch (solverConfig)
            {
            case ILPConfig ilp:
                return(new ILPSolver(input, ilp));

            case ManualConfig manual:
                return(new ManualSolver(input, manual));

            case LocalSolverConfig ls:
                return(new Solver(input, ls));

            case ParallelGenAlgConfig pga:
                return(new ParallelGenAlgSolver(input, pga));

            case GoogleRoutingConfig gr:
                return(new GoogleRoutingSolver(input, gr));
            }
            return(null);
        }
示例#12
0
        public VRPCallbackSolver(OptimizationInput input)
        {
            this.input = input;

            visitDurations = input.Visits.Select(v => v.Duration).Prepend(0).ToArray();
            distances      = new int[input.Visits.Length + 1, input.Visits.Length + 1];
            for (int i = 1; i < distances.GetLength(0); i++)
            {
                for (int j = 1; j < distances.GetLength(1); j++)
                {
                    distances[i, j] = input.RouteCosts[i - 1, j - 1];
                }
            }

            for (int i = 1; i < distances.GetLength(0); i++)
            {
                distances[i, 0] = input.Visits[i - 1].WayCostToHome;
                distances[0, i] = input.Visits[i - 1].WayCostFromHome;
            }

            distances[0, 0] = 0;
        }
示例#13
0
        private static Dictionary <int, int> CreateAlleles(OptimizationInput input)
        {
            var alleleToVisitIdMapping = new Dictionary <int, int>();

            // normal visits
            foreach (var visitId in input.Visits.Where(v => !v.IsBreak).Select(v => v.Id))
            {
                alleleToVisitIdMapping.Add(visitId, visitId);
            }
            // breaks
            var nextVisitId = input.Visits.Select(v => v.Id).Append(0).Max() + 1;

            foreach (var breakId in input.Visits.Where(v => v.IsBreak).Select(v => v.Id))
            {
                alleleToVisitIdMapping.Add(breakId, breakId);
                foreach (var _ in input.Days.Skip(1))
                {
                    alleleToVisitIdMapping.Add(nextVisitId++, breakId);
                }
            }
            return(alleleToVisitIdMapping);
        }
示例#14
0
        /// <summary>
        /// Returns generated genotypes and mapping from allele to visitId.
        /// The returned Genotypes are already repaired.
        /// </summary>
        /// <param name="input"></param>
        /// <param name="numberOfIndividuals"></param>
        /// <param name="maxNumberOfSantas"></param>
        /// <returns>Population and the AlleleToVisitIdMapping</returns>
        public (List <Genotype>, Dictionary <int, int>) Generate(OptimizationInput input, int numberOfIndividuals, int maxNumberOfSantas)
        {
            var numberOfSeparators     = input.Days.Length * maxNumberOfSantas - 1;
            var alleleToVisitIdMapping = CreateAlleles(input);

            var elements = new Genotype();

            elements.AddRange(alleleToVisitIdMapping.Keys);
            elements.AddRange(Enumerable.Range(-numberOfSeparators, numberOfSeparators));

            var repairOperation = new RepairOperation(input, alleleToVisitIdMapping);
            var population      = new List <Genotype>(numberOfIndividuals);

            for (int i = 0; i < numberOfIndividuals; i++)
            {
                elements.Shuffle(random);
                var genotype = new Genotype(elements);
                repairOperation.Repair(genotype);
                population.Add(genotype);
            }
            return(population, alleleToVisitIdMapping);
        }
        /// <summary>
        /// Creates a new solver
        /// </summary>
        /// <param name="input"></param>
        /// <param name="vrpTimeLimitFactor"></param>
        public Solver(OptimizationInput input, double vrpTimeLimitFactor, string name = "")
        {
            this.input = input;
            this.vrpTimeLimitFactor = vrpTimeLimitFactor;
            this.name = name;

            visitDurations = input.Visits.Select(v => v.Duration).Prepend(0).ToArray();
            distances      = new int[input.Visits.Length + 1, input.Visits.Length + 1];
            for (int i = 1; i < distances.GetLength(0); i++)
            {
                for (int j = 1; j < distances.GetLength(1); j++)
                {
                    distances[i, j] = input.RouteCosts[i - 1, j - 1];
                }
            }

            for (int i = 1; i < distances.GetLength(0); i++)
            {
                distances[i, 0] = input.Visits[i - 1].WayCostToHome;
                distances[0, i] = input.Visits[i - 1].WayCostFromHome;
            }

            distances[0, 0] = 0;
        }
示例#16
0
 /// <summary>
 /// Only use this, if you really need to.
 /// </summary>
 /// <param name="maxNumberOfSantas"></param>
 /// <param name="maxNumberOfGenerations"></param>
 /// <param name="populationSize"></param>
 public GenAlgConfig(OptimizationInput input, int maxNumberOfAdditionalSantas, int maxNumberOfGenerations, int populationSize)
 {
     MaxNumberOfSantas      = input.Santas.Length + maxNumberOfAdditionalSantas;
     MaxNumberOfGenerations = maxNumberOfGenerations;
     PopulationSize         = populationSize;
 }
 public ManualSolver(OptimizationInput input, ManualConfig config)
 {
     this.input  = input;
     this.config = config;
 }
示例#18
0
        public SolverVariables(LSModel model, int numberOfRoutes, List <Visit> visits, int[,] routeCosts, OptimizationInput optimizationInput, int numberOfFakeSantas)
        {
            Model              = model;
            Visits             = visits;
            NumberOfRoutes     = numberOfRoutes;
            OptimizationInput  = optimizationInput;
            NumberOfFakeSantas = numberOfFakeSantas;
            NumberOfSantas     = optimizationInput.Santas.Length;

            SantaUsed                = new LSExpression[numberOfRoutes];
            VisitSequences           = new LSExpression[numberOfRoutes + 1];
            SantaWalkingTime         = new LSExpression[numberOfRoutes];
            SantaRouteTime           = new LSExpression[numberOfRoutes];
            SantaVisitDurations      = new LSExpression[numberOfRoutes];
            SantaDesiredDuration     = new LSExpression[numberOfRoutes];
            SantaUnavailableDuration = new LSExpression[numberOfRoutes];
            SantaVisitStartingTimes  = new LSExpression[numberOfRoutes];

            SantaOvertime              = new LSExpression[numberOfRoutes];
            SantaWaitBeforeStart       = new LSExpression[numberOfRoutes];
            SantaWaitBetweenVisit      = new LSExpression[numberOfRoutes][];
            SantaWaitBetweenVisitArray = new LSExpression[numberOfRoutes];

            int numberOfVisits = Visits.Count;
            var longestDay     = OptimizationInput.Days.Max(d => d.to - d.from);

            for (var k = 0; k < numberOfRoutes; k++)
            {
                VisitSequences[k]       = Model.List(numberOfVisits);
                SantaOvertime[k]        = Model.Int(0, int.MaxValue);
                SantaWaitBeforeStart[k] = Model.Int(0, longestDay);

                SantaWaitBetweenVisit[k] = new LSExpression[numberOfVisits];
                for (var i = 0; i < SantaWaitBetweenVisit[k].Length; i++)
                {
                    SantaWaitBetweenVisit[k][i] = Model.Int(0, longestDay);
                }

                SantaWaitBetweenVisitArray[k] = Model.Array(SantaWaitBetweenVisit[k]);
            }

            // overflow for unused santa breaks
            VisitSequences[numberOfRoutes] = model.List(numberOfVisits);

            DistanceArray         = model.Array(RouteCostJagged(Visits, routeCosts));
            DistanceFromHomeArray = model.Array(Visits.Select(v => v.WayCostFromHome).ToArray());
            DistanceToHomeArray   = model.Array(Visits.Select(v => v.WayCostToHome).ToArray());
            VisitDurationArray    = model.Array(Visits.Select(v => v.Duration).ToArray());

            // desired
            var visitsOnlyDesired = visits
                                    .Select(v =>
                                            // fake arr
                                            v.Desired.Length == 0
                        ? new[] { new[] { -1, -1 } }
                        : v.Desired.Select(d => new[] { d.from, d.to }).ToArray()
                                            )
                                    .ToArray();

            VisitDesiredArray      = model.Array(visitsOnlyDesired);
            VisitDesiredCountArray = model.Array(visits.Select(v => v.Desired.Length).ToArray());

            // unavailable
            var visitsOnlyUnavailable = visits
                                        .Select(v =>
                                                // fake arr
                                                v.Unavailable.Length == 0
                        ? new[] { new[] { -1, -1 } }
                        : v.Unavailable.Select(d => new[] { d.from, d.to }).ToArray()
                                                )
                                        .ToArray();

            VisitUnavailableArray      = model.Array(visitsOnlyUnavailable);
            VisitUnavailableCountArray = model.Array(visits.Select(v => v.Unavailable.Length).ToArray());
        }
示例#19
0
 public ILPIp5GurobiSolver(OptimizationInput input, ILPIp5GurobiConfig ip5GurobiConfig)
 {
     this.input           = input;
     this.ip5GurobiConfig = ip5GurobiConfig;
 }
示例#20
0
        public static ISolverConfig CreateSolverConfig(RouteCalculation routeCalculation, OptimizationInput input)
        {
            switch (routeCalculation.Algorithm)
            {
            case AlgorithmType.ILP:
                return
                    (new ILPConfig
                {
                    TimeSliceDuration = Properties.Settings.Default.TimeSliceDurationSeconds,
                    ClusteringMIPGap = Properties.Settings.Default.MIPGapClustering,
                    ClusteringTimeLimitMiliseconds = (long)(0.7 * routeCalculation.TimeLimitMiliseconds),
                    SchedulingMIPGap = Properties.Settings.Default.MIPGapScheduling,
                    SchedulingTimeLimitMiliseconds = (long)(0.3 * routeCalculation.TimeLimitMiliseconds),
                });

            case AlgorithmType.LocalSolver:
                return
                    (new LocalSolverConfig
                {
                    VrpTimeLimitFactor = 0.1,
                    VrptwTimeLimitFactor = 0.8,
                    MaxNumberOfAdditionalSantas = routeCalculation.MaxNumberOfAdditionalSantas,
                });

            case AlgorithmType.GeneticAlgorithm:
                return
                    (new ParallelGenAlgConfig(new GenAlgConfig(input, routeCalculation.MaxNumberOfAdditionalSantas), Properties.Settings.Default.NumberOfGARuns));

            case AlgorithmType.GoogleRouting:
                return(new GoogleRoutingConfig(routeCalculation.MaxNumberOfAdditionalSantas, SolvingMode.All));

            case AlgorithmType.Hybrid:
                throw new ArgumentException("Algorithm type Hybrid not allowed", nameof(routeCalculation.Algorithm));

            default:
                throw new ArgumentOutOfRangeException(nameof(routeCalculation), routeCalculation, "Unknown AlgorithmType. Cannot create a StartData.");
            }
        }
 public ILPSolver(OptimizationInput input, ILPConfig config)
 {
     this.input  = input;
     this.config = config;
 }
 public RoutingData(OptimizationInput input)
 {
     Input = input;
 }
        public OptimizationResult Solve(long timeLimitMilliseconds, EventHandler <ProgressReport> progress, EventHandler <string> consoleProgress)
        {
            if (timeLimitMilliseconds < config.ClusteringTimeLimitMiliseconds + config.SchedulingTimeLimitMiliseconds)
            {
                throw new ArgumentOutOfRangeException(nameof(timeLimitMilliseconds), timeLimitMilliseconds, "must be at least the sum of ClusteringTimeLimit and SchedulingTimeLimit");
            }

            consoleProgress?.Invoke(this, "Solving started");

            var sw = Stopwatch.StartNew();

            var clusteringSolverVariableBuilder = new ClusteringSolverVariableBuilder(input, config.TimeSliceDuration);
            var clusteringSolverInputData       = clusteringSolverVariableBuilder.Build();
            var clusteringSolver =
                new Algorithm.Clustering.ClusteringILPSolver(clusteringSolverInputData);


#if WriteMPS && DEBUG
            System.IO.File.WriteAllText($@"C:\Temp\iRuettae\ILP\Clustering\{new Guid()}.mps", clusterinSolver.ExportMPS());
#endif
            var clusteringTimeLimitMiliseconds = config.ClusteringTimeLimitMiliseconds;
            if (clusteringTimeLimitMiliseconds == 0)
            {
                // avoid surpassing timelimit
                clusteringTimeLimitMiliseconds = timeLimitMilliseconds;
            }

            var phase1ResultState = clusteringSolver.Solve(config.ClusteringMIPGap, clusteringTimeLimitMiliseconds);
            if (!(new[] { ResultState.Feasible, ResultState.Optimal }).Contains(phase1ResultState))
            {
                return(new OptimizationResult()
                {
                    OptimizationInput = input,
                    Routes = new Route[] { },
                    TimeElapsed = sw.ElapsedMilliseconds / 1000,
                });
            }

            var phase1Result = clusteringSolver.GetResult();
            progress?.Invoke(this, new ProgressReport(0.5));
            consoleProgress?.Invoke(this, "Clustering done");
            consoleProgress?.Invoke(this, $"Clustering Result: {phase1Result}");


            var schedulingSovlerVariableBuilders = new List <SchedulingSolverVariableBuilder>();
            foreach (var santa in Enumerable.Range(0, phase1Result.Waypoints.GetLength(0)))
            {
                foreach (var day in Enumerable.Range(0, phase1Result.Waypoints.GetLength(1)))
                {
                    var cluster = phase1Result.Waypoints[santa, day];
                    var schedulingOptimizationInput = new OptimizationInput
                    {
                        Visits     = input.Visits.Where(v => cluster.Select(w => w.Visit - 1).Contains(v.Id)).ToArray(),
                        Santas     = new[] { input.Santas[santa] },
                        Days       = new[] { input.Days[day] },
                        RouteCosts = input.RouteCosts,
                    };

                    schedulingSovlerVariableBuilders.Add(new SchedulingSolverVariableBuilder(config.TimeSliceDuration, schedulingOptimizationInput, cluster.OrderBy(wp => wp.StartTime).Select(wp => wp.Visit).ToArray()));
                }
            }

            var schedulingInputVariables = schedulingSovlerVariableBuilders
                                           .Where(vb => vb.Visits != null && vb.Visits.Count > 1)
                                           .Select(vb => vb.Build());


            var routeResults = schedulingInputVariables
                               .AsParallel()
                               .Select(schedulingInputVariable =>
            {
                var schedulingSolver = new Algorithm.Scheduling.SchedulingILPSolver(schedulingInputVariable);

#if WriteMPS && DEBUG
                System.IO.File.WriteAllText($@"C:\Temp\iRuettae\ILP\Scheduling\{new Guid()}.mps", schedulingSolver.ExportMPS());
#endif


                var clusteringExtraTime            = Math.Max(0, clusteringTimeLimitMiliseconds - sw.ElapsedMilliseconds);
                var schedulingTimelimitMiliseconds = config.SchedulingTimeLimitMiliseconds + clusteringExtraTime;
                if (schedulingTimelimitMiliseconds == 0 && timeLimitMilliseconds != 0)
                {
                    // avoid surpassing timelimit
                    schedulingTimelimitMiliseconds = Math.Max(1, timeLimitMilliseconds - sw.ElapsedMilliseconds);
                }

                var schedulingResultState = schedulingSolver.Solve(config.SchedulingMIPGap, schedulingTimelimitMiliseconds);
                if (!(new[] { ResultState.Feasible, ResultState.Optimal }).Contains(schedulingResultState))
                {
                    var realWaypointList = new List <Algorithm.Waypoint>();

                    // take presolved and return it
                    for (int i = 0; i < schedulingInputVariable.Presolved.Length; i++)
                    {
                        var i1        = i;
                        var currVisit = input.Visits.FirstOrDefault(v => v.Id == schedulingInputVariable.Presolved[i1] - 1);

                        var timeStamp = schedulingInputVariable.DayStarts[0];
                        if (i > 0)
                        {
                            var lastVisit = input.Visits.FirstOrDefault(v => v.Id == schedulingInputVariable.Presolved[i - 1] - 1);

                            timeStamp  = realWaypointList.Last().StartTime + lastVisit.Duration;
                            timeStamp += i > 1
                                    ? input.RouteCosts[lastVisit.Id, currVisit.Id]
                                    : currVisit.WayCostFromHome;
                        }

                        realWaypointList.Add(new Algorithm.Waypoint(currVisit.Equals(default(Visit)) ? Constants.VisitIdHome : currVisit.Id,
                                                                    timeStamp));
                    }
                    var absolutlyLastVisit = input.Visits.FirstOrDefault(v => v.Id == schedulingInputVariable.Presolved[schedulingInputVariable.Presolved.Length - 1] - 1);
                    realWaypointList.Add(new Algorithm.Waypoint(Constants.VisitIdHome, realWaypointList.Last().StartTime + absolutlyLastVisit.Duration + absolutlyLastVisit.WayCostToHome));

                    return(new Algorithm.Route(1, 1)
                    {
                        SantaIds = schedulingInputVariable.SantaIds,
                        Waypoints = new[, ]
                        {
                            { realWaypointList }
                        }
                    });
                }

                var route = schedulingSolver.GetResult();

                for (int i = 0; i < route.Waypoints.GetLength(0); i++)
                {
                    for (int j = 0; j < route.Waypoints.GetLength(1); j++)
                    {
                        var realWaypointList = new List <Algorithm.Waypoint>();

                        var waypointList = route.Waypoints[i, j];
                        // copy for later lambda expression
                        var jCopy = j;
                        waypointList.ForEach(wp =>
                        {
                            wp.Visit = wp.Visit == 0
                                    ? Constants.VisitIdHome
                                    : schedulingInputVariable.VisitIds[wp.Visit - 1];
                            wp.StartTime  = Math.Max(wp.StartTime, 0);
                            wp.StartTime *= config.TimeSliceDuration;
                            wp.StartTime += schedulingInputVariable.DayStarts[jCopy];
                            realWaypointList.Add(wp);
                        });
                        route.Waypoints[i, j] = realWaypointList;
                    }
                }
                return(route);
            })
                               .ToList();

            progress?.Invoke(this, new ProgressReport(0.99));
            consoleProgress?.Invoke(this, "Scheduling done");
            consoleProgress?.Invoke(this, $"Scheduling Result:{Environment.NewLine}" +
                                    routeResults.Where(r => r != null).Select(r => r.ToString()).Aggregate((acc, c) => acc + Environment.NewLine + c));

            // construct new output elem
            var optimizationResult = new OptimizationResult()
            {
                OptimizationInput = input,
                Routes            = routeResults.Select(r => r != null ? new Route
                {
                    SantaId   = r.SantaIds[0],
                    Waypoints = r.Waypoints[0, 0].Select(origWp => new Waypoint
                    {
                        VisitId   = origWp.Visit,
                        StartTime = origWp.StartTime
                    }).ToArray(),
                } : new Route()).ToArray(),
            };

            progress?.Invoke(this, new ProgressReport(1));

            // assign total elapsed time
            sw.Stop();
            optimizationResult.TimeElapsed = sw.ElapsedMilliseconds / 1000;
            return(optimizationResult);
        }
示例#24
0
 public Decoder(OptimizationInput input, Dictionary <int, int> alleleToVisitIdMapping)
 {
     this.input = input;
     this.alleleToVisitIdMapping = alleleToVisitIdMapping;
 }