private void GetInitialSolutions() { tspSolution = new TspSolution(new TspProblem(tspCities)); vehicleRoutingSolution = new VehicleRoutingSolution(new VehicleRoutingProblem(routingCustomers, routingVehicles)); floorplanSolution = new FloorplanSolution(new FloorplanProblem(floorplanRectangles)).Shuffle(1) as FloorplanSolution; for (int i = 0; i < 12; i++) { floorplanSolution = floorplanSolution.Transcode() as FloorplanSolution; } }
/// <summary> /// This is the entry point for the default solver /// which just finds a valid random tour /// </summary> /// <returns> /// results array for GUI that contains three ints: cost of solution, time spent to find solution, number of /// solutions found during search (not counting initial BSSF estimate) /// </returns> public string[] DefaultSolveProblem() { var count = 0; var results = new string[3]; var perm = new int[_cities.Length]; _route = new List <City>(); var rnd = new Random(); var timer = new Stopwatch(); timer.Start(); do { int i; for (i = 0; i < perm.Length; i++) // create a random permutation template { perm[i] = i; } for (i = 0; i < perm.Length; i++) { var swap = i; while (swap == i) { swap = rnd.Next(0, _cities.Length); } var temp = perm[i]; perm[i] = perm[swap]; perm[swap] = temp; } _route.Clear(); for (i = 0; i < _cities.Length; i++) // Now build the route using the random permutation { _route.Add(_cities[perm[i]]); } _bssf = new TspSolution(_route); count++; } while (double.IsPositiveInfinity(CostOfBssf())); // until a valid route is found timer.Stop(); results[Cost] = CostOfBssf().ToString(CultureInfo.CurrentCulture); // load results array results[Time] = timer.Elapsed.ToString(); results[Count] = count.ToString(); return(results); }
/// <summary> /// Perform calculation for next path iteration, reporting progress. /// Progress report must be handled in class creating a member of this class. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void SolverDoWork(object sender, DoWorkEventArgs e) { // Start calculating runtime var startTime = DateTime.Now; // Thread sleeps allow user time to visually process each update var threadSleepLength = (e.Argument as Tuple <Tsp, int>).Item2; var sleepCount = 0; var tsp = (e.Argument as Tuple <Tsp, int>).Item1; var tspSolution = new TspSolution(); var shortestPath = new Path(); var unvisitedCities = new Path(tsp.Cities); var calculationAmount = 0; while (shortestPath.Count != tsp.Cities.Count) { // Get next stage of path this.TraverseNext(ref shortestPath, ref unvisitedCities, ref calculationAmount); // Update solution tspSolution.ShortestPath = shortestPath; tspSolution.Runtime = (DateTime.Now - startTime).TotalSeconds - ((double)threadSleepLength / 1000) * sleepCount; tspSolution.CalculationAmount = calculationAmount; // Calculate completion percentage var progressPercentage = Convert.ToInt32((shortestPath.Count * 100) / tsp.Cities.Count); // Report progress (sender as BackgroundWorker).ReportProgress(progressPercentage, tspSolution); // Sleep to allow user to visually process update if (threadSleepLength > 0) { sleepCount++; System.Threading.Thread.Sleep(threadSleepLength); } } // Return solution e.Result = tspSolution; }
/* 2-Opt solution is based on psuedo code found at https://en.wikipedia.org/wiki/2-opt */ private TspSolution threeOptSwapB(TspSolution curRoute, int i, int j, int k) { List <City> newRoute = new List <City>(); curRoute = new TspSolution(pre_shift(curRoute.Route, i)); // 2.take route[i] to route[k] and add them in reverse order to new_route for (int p = j; p >= 0; p--) { newRoute.Add(curRoute.Route[p]); } for (int p = k - 1; p > j; p--) { newRoute.Add(curRoute.Route[p]); } for (int p = k; p < curRoute.Route.Count; p++) { newRoute.Add(curRoute.Route[p]); } return(new TspSolution(post_shift(newRoute, i))); }
/* 2-Opt solution is based on psuedo code found at https://en.wikipedia.org/wiki/2-opt */ private TspSolution twoOptSwap(TspSolution curRoute, int i, int k) { List <City> newRoute = new List <City>(); // 1.take route[1] to route[i - 1] and add them in order to new_route for (int p = 0; p < i; p++) { newRoute.Add(curRoute.Route[p]); } // 2.take route[i] to route[k] and add them in reverse order to new_route for (int p = k; p >= i; p--) { newRoute.Add(curRoute.Route[p]); } // 3.take route[k + 1] to end and add them in order to new_route for (int p = k + 1; p < curRoute.Route.Count; p++) { newRoute.Add(curRoute.Route[p]); } return(new TspSolution(newRoute)); }
//O(n^2) private bool isCompleteSolution(TspSolution tspSolution) { if (tspSolution.Route.Count != _cities.Length) { return(false); } //O(n^2) for (int i = 0; i < _cities.Length; i++) { //O(n) if (!tspSolution.Route.Contains(_cities[i])) { return(false); } if (i + 1 < _cities.Length && tspSolution.Route[i].CostToGetTo(tspSolution.Route[i + 1]) == double.PositiveInfinity) { return(false); } } return(true); }
//if (_mode == HardMode.Modes.Hard) //{ // var upperBound = double.PositiveInfinity; // for (var startCity = 0; startCity < _cities.Length; ++startCity) // { // var testState = BranchBoundCalc(baseState, startCity); // if (testState == null || testState.LowerBound >= upperBound) continue; // upperBound = testState.LowerBound; // bestState = testState; // } //} //else ///////////////////////////////////////////////////////////////////////////////////////////// // These additional solver methods will be implemented as part of the group project. //////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// finds the greedy tour starting from each city and keeps the best (valid) one /// </summary> /// <returns> /// results array for GUI that contains three ints: cost of solution, time spent to find solution, number of /// solutions found during search (not counting initial BSSF estimate) /// </returns> public string[] GreedySolveProblem() { var results = new string[3]; var timer = new Stopwatch(); Debug.Assert(_cities.Length > 0); timer.Start(); var costMatrix = new TspState(_cities).CostMatrix; if (_mode == HardMode.Modes.Hard) { // CostOfBssf() is still used because new TspState reduces the matrix once var cost = double.PositiveInfinity; for (var startCity = 0; startCity < _cities.Length; ++startCity) { var thisResult = FastGreedyCalc(startCity, costMatrix); if (thisResult.Item1 >= cost) { continue; } cost = thisResult.Item1; _bssf = new TspSolution(thisResult.Item2.Select(i => _cities[i])); } } else { var cityIndexes = FastGreedyCalc(0, costMatrix); _bssf = new TspSolution(cityIndexes.Item2.Select(i => _cities[i])); } timer.Stop(); results[Cost] = CostOfBssf().ToString(CultureInfo.InvariantCulture); results[Time] = timer.Elapsed.ToString(); results[Count] = (_cities.Length + 1).ToString(); return(results); }
private void DrawGraphOf(TspSolution tspSolution, bool graphShouldConnect = true, TravellingSalesmanProblemLibrary.Path cities = null) { // Clear the graph of previous solution this.cityMap.Children.Clear(); // Set the list of all cities to the shortest path if it is null cities = cities == null ? new TravellingSalesmanProblemLibrary.Path(tspSolution.ShortestPath) : cities; // Plot each city on the graph foreach (var city in cities) { // Dimensions are modified to space them out on the graph var cityX = city.Coordinate.X * CITY_COORDINATE_MODIFIER; var cityY = city.Coordinate.Y * CITY_COORDINATE_MODIFIER; // Create a visual representation of the point on the graph var cityEllipse = new Ellipse() { Height = CITY_CIRCLE_DIAMETER, Width = CITY_CIRCLE_DIAMETER, Stroke = Brushes.Black, Margin = new Thickness(cityX - CITY_CIRCLE_DIAMETER / 2, cityY - CITY_CIRCLE_DIAMETER / 2, 0, 0) }; // Add ellipse to graph this.cityMap.Children.Add(cityEllipse); // Create a label for the point var cityTextBlock = new TextBlock() { Text = Convert.ToString(city.Name) }; // Set label coordinates Canvas.SetLeft(cityTextBlock, cityX + CITY_LABEL_BUFFER); Canvas.SetTop(cityTextBlock, cityY - CITY_LABEL_BUFFER); // Add label to graph this.cityMap.Children.Add(cityTextBlock); } // Create points list for graphing var points = new TravellingSalesmanProblemLibrary.Path(tspSolution.ShortestPath); // Re-add the first city to connect the graph if (graphShouldConnect) { points.Add(points[0]); } // Add lines to the graph for (int i = 0; i < points.Count - 1; i++) { // Create a line between the current point and the next var line = new Line() { X1 = points[i].Coordinate.X * CITY_COORDINATE_MODIFIER, Y1 = points[i].Coordinate.Y * CITY_COORDINATE_MODIFIER, X2 = points[i + 1].Coordinate.X * CITY_COORDINATE_MODIFIER, Y2 = points[i + 1].Coordinate.Y * CITY_COORDINATE_MODIFIER, Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 2 }; // Add line to graph this.cityMap.Children.Add(line); } // Update all label text var shortestPathLength = graphShouldConnect ? tspSolution.ShortestPath.CompleteLength : tspSolution.ShortestPath.Length; this.shortestPath.Text = $"{Math.Round(shortestPathLength, 4)} m"; this.runtime.Text = $"{Math.Round(tspSolution.Runtime * 1000, 4)} ms"; this.calculationCount.Text = $"{tspSolution.CalculationAmount}"; }
static void Main(string[] args) { //FloorplanProblem problem = new FloorplanProblem(50); //FloorplanSolution solution = new FloorplanSolution(problem); //Swap swap = new Swap(problem.Dimension); //Shift shift = new Shift(problem.Dimension); //FullLeafMove leaf = new FullLeafMove(problem.Dimension); //List<Operator> operations = new List<Operator> { swap, shift, leaf }; TspProblem problem = new TspProblem(100); TspSolution solution = new TspSolution(problem); Swap swap = new Swap(problem.Dimension, 1); Shift shift = new Shift(problem.Dimension, 2); TwoOpt twoOpt = new TwoOpt(problem.Dimension, 3); List <Operator> operations = new List <Operator> { swap, shift, twoOpt }; MultistartParameters multistartOptions = new MultistartParameters() { InstancesNumber = 1, OutputFrequency = 500, }; LocalDescentParameters ldParameters = new LocalDescentParameters() { DetailedOutput = true, Seed = 0, Operators = operations, IsSteepestDescent = false }; SimulatedAnnealingParameters saParameters = new SimulatedAnnealingParameters() { InitProbability = 0.3, TemperatureCooling = 0.97, UseWeightedNeighborhood = true, DetailedOutput = false, Seed = 0, Operators = operations, }; MultistartParameters ldMultistartParameters = (MultistartParameters)multistartOptions.Clone(); ldMultistartParameters.Parameters = ldParameters; MultistartParameters saMultistartParameters = (MultistartParameters)multistartOptions.Clone(); saMultistartParameters.Parameters = saParameters; LocalDescent ld = new LocalDescent(ldParameters); SimulatedAnnealing sa = new SimulatedAnnealing(saParameters); ParallelMultistart pld = new ParallelMultistart(ldMultistartParameters); ParallelMultistart psa = new ParallelMultistart(saMultistartParameters); List <string> operators = new List <string>(); IPermutation sol = solution; foreach (IPermutation s in ld.Minimize(solution)) { Console.WriteLine("{0}, {1:f}s, {2}, {3}, {4}, {5}", s.CostValue, s.TimeInSeconds, s.IterationNumber, s.IsCurrentBest, s.IsFinal, sol.CostValue - s.CostValue); sol = s; operators.Add(s.OperatorTag); } //var groups = operators.GroupBy(s => s).Select(s => new { Operator = s.Key, Count = s.Count() }); //var dictionary = groups.ToDictionary(g => g.Operator, g => g.Count); //foreach (var o in groups) //{ // Console.WriteLine("{0} = {1}", o.Operator, o.Count); //} Console.WriteLine("Done"); Console.ReadLine(); }
public string[] ThreeOptSolveProblem() { var results = new string[3]; // get initial bssf using default algorithm int i, swap, temp, count = 0; int[] perm = new int[_cities.Length]; _route = new List <City>(); Random rnd = new Random(); do { for (i = 0; i < perm.Length; i++) // create a random permutation template { perm[i] = i; } for (i = 0; i < perm.Length; i++) { swap = i; while (swap == i) { swap = rnd.Next(0, _cities.Length); } temp = perm[i]; perm[i] = perm[swap]; perm[swap] = temp; } _route.Clear(); for (i = 0; i < _cities.Length; i++) // Now build the route using the random permutation { _route.Add(_cities[perm[i]]); } _bssf = new TspSolution(_route); } while (CostOfBssf() == double.PositiveInfinity); // until a valid route is found Stopwatch timer = new Stopwatch(); timer.Start(); count = 0; TspSolution prevSolution = _bssf; bool found = false; do { double bestDist = _bssf.CostOfRoute(); found = false; for (i = 0; i < _bssf.Route.Count - 2; i++) { for (int j = i + 1; j < _bssf.Route.Count - 1; j++) { for (int k = j + 1; k < _bssf.Route.Count; k++) { TspSolution newRoute1 = threeOptSwapA(_bssf, i, j, k); TspSolution newRoute2 = threeOptSwapB(_bssf, i, j, k); TspSolution newRoute3 = threeOptSwapC(_bssf, i, j, k); TspSolution newRoute4 = twoOptSwap(_bssf, i, j); TspSolution newRoute5 = twoOptSwap(_bssf, j, k); TspSolution newRoute6 = twoOptSwap(_bssf, i, k); double newDist1 = newRoute1.CostOfRoute(); double newDist2 = newRoute2.CostOfRoute(); double newDist3 = newRoute3.CostOfRoute(); double newDist4 = newRoute4.CostOfRoute(); double newDist5 = newRoute5.CostOfRoute(); double newDist6 = newRoute6.CostOfRoute(); if (isCompleteSolution(newRoute1) && newDist1 < bestDist && newDist1 <= newDist2 && newDist1 <= newDist3 && newDist1 <= newDist4 && newDist1 <= newDist5 && newDist1 <= newDist6) { prevSolution = _bssf; _bssf = newRoute1; found = true; count++; break; } if (isCompleteSolution(newRoute2) && newDist2 < bestDist && newDist2 <= newDist1 && newDist2 <= newDist3 && newDist2 <= newDist4 && newDist2 <= newDist5 && newDist2 <= newDist6) { prevSolution = _bssf; _bssf = newRoute2; found = true; count++; break; } if (isCompleteSolution(newRoute3) && newDist3 < bestDist && newDist3 <= newDist2 && newDist3 <= newDist1 && newDist3 <= newDist4 && newDist3 <= newDist5 && newDist3 <= newDist6) { prevSolution = _bssf; _bssf = newRoute3; found = true; count++; break; } if (isCompleteSolution(newRoute4) && newDist4 < bestDist && newDist4 <= newDist2 && newDist4 <= newDist1 && newDist4 <= newDist3 && newDist4 <= newDist5 && newDist4 <= newDist6) { prevSolution = _bssf; _bssf = newRoute4; found = true; count++; break; } if (isCompleteSolution(newRoute5) && newDist5 < bestDist && newDist5 <= newDist2 && newDist5 <= newDist1 && newDist5 <= newDist4 && newDist5 <= newDist3 && newDist5 <= newDist6) { prevSolution = _bssf; _bssf = newRoute5; found = true; count++; break; } if (isCompleteSolution(newRoute6) && newDist6 < bestDist && newDist6 <= newDist2 && newDist6 <= newDist1 && newDist6 <= newDist4 && newDist6 <= newDist5 && newDist6 <= newDist3) { prevSolution = _bssf; _bssf = newRoute6; found = true; count++; break; } } if (found) { break; } } if (found) { break; } } } while (found); timer.Stop(); results[Cost] = _bssf.CostOfRoute().ToString(); results[Time] = timer.Elapsed.ToString(); results[Count] = count.ToString(); return(results); }
public string[] TwoOptSolveProblem() { var results = new string[3]; // get initial bssf using default algorithm int i, swap, temp, count = 0; int[] perm = new int[_cities.Length]; _route = new List <City>(); Random rnd = new Random(); do { for (i = 0; i < perm.Length; i++) // create a random permutation template { perm[i] = i; } for (i = 0; i < perm.Length; i++) { swap = i; while (swap == i) { swap = rnd.Next(0, _cities.Length); } temp = perm[i]; perm[i] = perm[swap]; perm[swap] = temp; } _route.Clear(); for (i = 0; i < _cities.Length; i++) // Now build the route using the random permutation { _route.Add(_cities[perm[i]]); } _bssf = new TspSolution(_route); } while (CostOfBssf() == double.PositiveInfinity); // until a valid route is found Stopwatch timer = new Stopwatch(); timer.Start(); count = 0; TspSolution prevSolution = _bssf; bool found = false; do { double bestDist = _bssf.CostOfRoute(); for (i = 0; i < _bssf.Route.Count; i++) { found = false; for (int k = i + 1; k < _bssf.Route.Count; k++) { TspSolution newRoute = twoOptSwap(_bssf, i, k); double newDist = newRoute.CostOfRoute(); if (isCompleteSolution(newRoute) && newDist < bestDist) { prevSolution = _bssf; _bssf = newRoute; found = true; count++; break; } } if (found) { break; } } } while (found); timer.Stop(); results[Cost] = _bssf.CostOfRoute().ToString(); results[Time] = timer.Elapsed.ToString(); results[Count] = count.ToString(); return(results); }
/// <summary> /// performs a Branch and Bound search of the state space of partial tours /// stops when time limit expires and uses BSSF as solution /// </summary> /// <returns> /// results array for GUI that contains three ints: cost of solution, time spent to find solution, number of /// solutions found during search (not counting initial BSSF estimate) /// </returns> public string[] BranchBoundSolveProblem() { var results = new string[3]; var timer = new Stopwatch(); Debug.Assert(_cities.Length > 0); var baseState = new TspState(_cities); timer.Start(); var n = _cities.Length; var queue = new FastPriorityQueue <TspState>(n * n * n); baseState = baseState.Visit(0); queue.Enqueue(baseState, baseState.Heuristic()); // The current best complete route var bestState = GreedyCalc(baseState); var upperBound = bestState?.LowerBound ?? double.PositiveInfinity; var stored = 0; var pruned = 0; var maxStates = 0; var updates = 0; while (queue.Count > 0) { if (queue.Count > maxStates) { maxStates = queue.Count; } // Get best state to check based on heuristic. // Runs in O(log n) time. var state = queue.Dequeue(); // Branch for (var toCity = 0; toCity < n; ++toCity) { // If we can't visit the city, no need to consider it if (!state.CanVisit(toCity)) { continue; } var branchState = state.Visit(toCity); // Bound if (branchState.LowerBound < upperBound) { if (branchState.IsComplete) { ++updates; // On a complete instance, no need to add it to the queue. Debug.Assert(branchState.CostMatrix.Cast <double>().All(double.IsPositiveInfinity), "Cost Matrix is not all infinity"); upperBound = branchState.LowerBound; bestState = branchState; continue; } ++stored; if (queue.Count + 5 >= queue.MaxSize) { queue.Resize(queue.MaxSize * 2); } // Runs in O(log n) time queue.Enqueue(branchState, branchState.Heuristic()); } else { ++pruned; } } // Abandon ship and give the best result otherwise if (timer.ElapsedMilliseconds > _timeLimit) { break; } } timer.Stop(); Debug.Assert(bestState != null && bestState.IsComplete); _bssf = StateToSolution(bestState); results[Cost] = CostOfBssf().ToString(CultureInfo.InvariantCulture); // load results array results[Time] = timer.Elapsed.ToString(); results[Count] = $"{maxStates}/{updates}/{stored}/{pruned}"; return(results); }
private void bwTsp_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = (BackgroundWorker)sender; algorithmStatus.Text = "Press ESC to cancel"; TspProblem problem = new TspProblem(tspCities); TspSolution startSolution = new TspSolution(problem); Swap swap = new Swap(problem.Dimension, 1); Shift shift = new Shift(problem.Dimension, 2); TwoOpt twoOpt = new TwoOpt(problem.Dimension, 3); List <Operator> operations = new List <Operator> { swap, shift, twoOpt }; MultistartParameters multistartParameters = (MultistartParameters)multistartOptions.Clone(); LocalDescentParameters ldParameters = new LocalDescentParameters() { Name = "TSP LD", Seed = seed, DetailedOutput = true, Operators = operations }; SimulatedAnnealingParameters saParameters = new SimulatedAnnealingParameters() { Name = "TSP SA", InitProbability = 0.5, TemperatureCooling = 0.91, MinCostDeviation = 10E-3, Seed = seed, DetailedOutput = true, Operators = operations }; StackedParameters ssParameters = new StackedParameters() { Name = "B", DetailedOutput = true, OptimizationAlgorithms = new Type[] { typeof(LocalDescent), typeof(SimulatedAnnealing), typeof(LocalDescent) }, Parameters = new OptimizationParameters[] { ldParameters, saParameters, ldParameters } }; switch (optimizerType) { case 0: { multistartParameters.Parameters = ldParameters; multistartParameters.OptimizationAlgorithm = typeof(LocalDescent); } break; case 1: { multistartParameters.Parameters = saParameters; multistartParameters.OptimizationAlgorithm = typeof(SimulatedAnnealing); } break; case 2: { saParameters.InitProbability = 0.007; saParameters.MinCostDeviation = 10E-2; multistartParameters.Parameters = ssParameters; multistartParameters.OptimizationAlgorithm = typeof(StackedSearch); } break; case 3: { saParameters.InitProbability = 0.007; saParameters.MinCostDeviation = 10E-2; multistartParameters.InstancesNumber = 3; multistartParameters.Parameters = ssParameters; multistartParameters.OptimizationAlgorithm = typeof(StackedSearch); } break; } tspOptimizer = new ParallelMultistart(multistartParameters); toRenderBackground = false; foreach (ISolution solution in tspOptimizer.Minimize(startSolution)) { if (worker.CancellationPending) { tspOptimizer.Stop(); e.Cancel = true; } if (e.Cancel) { solution.IsFinal = false; } worker.ReportProgress(0); } }