/// <summary> /// Create an exact solution using input data from the Console /// </summary> private static void RunExactConsole() { Node[] inputAsNodes = IO.ReadInputAsNodes(CENTER_RESEMBLANCE_CAP, ARTICULATION_POINT_MINIMUM); RecursiveSplit recSplit = new RecursiveSplit(inputAsNodes); RecursiveTree <Node> recTree = recSplit.GetBestTree(); string output = recTree.ToString(); Console.Write(output); }
/// <summary> /// Runs either the exact version of RecursiveSplit. Does not use any form of local search /// </summary> /// <param name="fileName">The name of the file to be used as input (without extension)</param> private static void RunExact(string fileName) { Console.WriteLine($"Starting file {fileName}..."); Node[] inputAsNodes = IO.ReadInputAsNodes($"..\\..\\..\\..\\..\\Testcases\\{fileName}.gr", CENTER_RESEMBLANCE_CAP, ARTICULATION_POINT_MINIMUM); RecursiveSplit recSplit = new RecursiveSplit(inputAsNodes); RecursiveTree <Node> recTree; recTree = recSplit.GetBestTree(); string output = recTree.ToString(); using (StreamWriter sw = new StreamWriter($"..\\..\\..\\..\\..\\Results\\{fileName}.tree", false)) { sw.Write(output); } Console.WriteLine($"Tree found with depth {recTree.Depth}."); Console.WriteLine(); }
/// <summary> /// Execute the program using simulated annealing /// </summary> /// <param name="fileName">The name of the file to be run, or empty if the console is used</param> /// <param name="console">Whether input form the console is used. If so, the program runs in quiet mode</param> private static void SimulatedAnnealing(string fileName = "", bool console = true) { if (!console) { Console.WriteLine($"Starting file {fileName}..."); } // The stopwatch keeps track of the total running time of the program stopwatchSingleRun.Start(); // Read the input, depending on whether the console is used a file is being read or console input Node[] inputAsNodes; if (!console) { inputAsNodes = IO.ReadInputAsNodes($"..\\..\\..\\..\\..\\Testcases\\{fileName}.gr", CENTER_RESEMBLANCE_CAP, ARTICULATION_POINT_MINIMUM); } else { inputAsNodes = IO.ReadInputAsNodes(CENTER_RESEMBLANCE_CAP, ARTICULATION_POINT_MINIMUM); } allNodes = inputAsNodes; // Create instances for the simunlated annealing and recursivesplit classes SimulatedAnnealing <State <RecursiveTree <Node> >, RecursiveTree <Node> > simulatedAnnealing = new SimulatedAnnealing <State <RecursiveTree <Node> >, RecursiveTree <Node> >(random, START_TEMP, RESET_TEMPERATURE_THRESHOLD, TEMP_MULTIPLIER, MULTIPLY_TEMP_PER_ITERATIONS, stopwatchSingleRun, MAX_TIME_TOTAL_SECONDS); RecursiveSplit recursiveSplit = new RecursiveSplit(inputAsNodes); // Find an initial solution where all nodes are in a single line RecursiveTreeState heurInitState = new RecursiveTreeState(BaseSolutionGenerator.LineRecursiveTree(ref allRecTreeNodes, allNodes), random, allRecTreeNodes); bestStateSoFar = heurInitState.Data.ToString(); if (!console) { Console.WriteLine($"Line found with depth {heurInitState.Data.Root.Depth}."); } initialSolutionsTimer.Start(); RecursiveTree <Node> bestTree = null; // Find an initial solution using the RecursiveSplit using a fast but bad heuristic if (allNodes.Length <= FASTER_HEURISTIC_CAP) { double maxTime = MAX_TIME_INITIAL_SOLUTIONS_SECONDS; if (allNodes.Length > INDEPENDENT_SET_CAP) { if (allNodes.Length > FAST_HEURISTIC_CAP) { maxTime *= 3; } else { maxTime *= 1.5; } } else if (allNodes.Length > FAST_HEURISTIC_CAP) { maxTime *= 1.5; } bestTree = recursiveSplit.GetHeuristicTree(initialSolutionsTimer, maxTime, true); if (!console) { Console.WriteLine($"Fastest heuristic tree found with depth {bestTree.Depth}."); } } // Find an initial solution using the RecursiveSplit using a decent but pretty slow heuristic if (allNodes.Length <= FAST_HEURISTIC_CAP) { double maxTime = MAX_TIME_INITIAL_SOLUTIONS_SECONDS; if (allNodes.Length > INDEPENDENT_SET_CAP) { maxTime *= 3; } else if (allNodes.Length > FASTER_HEURISTIC_CAP) { maxTime *= 1.5; } else { maxTime *= 2; } RecursiveTree <Node> treeFromFastHeuristic = recursiveSplit.GetHeuristicTree(initialSolutionsTimer, maxTime, false); if (bestTree == null || treeFromFastHeuristic.Depth < bestTree.Depth) { bestTree = treeFromFastHeuristic; } if (!console) { Console.WriteLine($"Fast heuristic tree found with depth {treeFromFastHeuristic.Depth}."); } } // If the problem instance is small enough, we would like to try to find an initial solution using independent sets if (allNodes.Length <= INDEPENDENT_SET_CAP) { double maxTime = MAX_TIME_INITIAL_SOLUTIONS_SECONDS * 3; RecursiveTree <Node> treeFromIndependentSet = IndependentSet.TreeFromIndependentSets(allNodes, initialSolutionsTimer, maxTime); if (bestTree == null || treeFromIndependentSet.Depth < bestTree.Depth) { bestTree = treeFromIndependentSet; } if (!console) { Console.WriteLine($"Independent set tree found with depth {treeFromIndependentSet.Depth}."); } } // Recreate the tree and save the best found initial solution as the initial solution for simulated annealing initialSolutionsTimer.Reset(); if (bestTree != null) { bestStateSoFar = bestTree.ToString(); RecreateTree(bestStateSoFar); heurInitState = new RecursiveTreeState(allRecTreeNodes[0].Root, random, allRecTreeNodes); } if (allNodes.Length <= SIMULATED_ANNEALING_CAP) { simulatedAnnealing.Search(heurInitState, ref bestStateSoFar); } // If the input from the console is not used, write the output to a file, otherwise write it back to the console if (!console) { using (StreamWriter sw = new StreamWriter($"..\\..\\..\\..\\..\\Results\\{fileName}.tree", false)) { sw.Write(bestStateSoFar); } } else { Console.Write(bestStateSoFar); } // Print the result and total time thus far if (!console) { // Stop the total of this problem instace stopwatchSingleRun.Stop(); Console.WriteLine($"Tree found with depth {bestStateSoFar.Split('\n')[0]} in {stopwatchSingleRun.Elapsed} seconds. (Total time: {allRunsTotalStopwatch.Elapsed})"); Console.WriteLine(); } // Reset the stopwatch for the next time the program is run stopwatchSingleRun.Reset(); }