def test_benchmark_dag(self): """ Tests that random graph generators are working properly, and generates the benchmark data that is saved to `benchmark.txt` in the root directory for this project. """ # |V| = 4 pre_time_dag_one = time.time() output_dag_one = DAGSolver(self.matrix_input_dag_one).topological_sort() post_time_dag_one = time.time() solving_time_dag_one = post_time_dag_one - pre_time_dag_one self.assertIsNotNone(output_dag_one) score_dag_one = scoreSolution(self.matrix_input_dag_one, output_dag_one) file_string_one = "DAG, |V| = 4: Score = %.4f, Time = %.4f\n" % (score_dag_one, solving_time_dag_one) self.benchmark_file.write(file_string_one) print "Finished Benchmark 1, DAG" # |V| = 7 pre_time_dag_two = time.time() output_dag_two = DAGSolver(self.matrix_input_dag_two).topological_sort() post_time_dag_two = time.time() solving_time_dag_two = post_time_dag_two - pre_time_dag_two self.assertIsNotNone(output_dag_two) score_dag_two = scoreSolution(self.matrix_input_dag_two, output_dag_two) file_string_two = "DAG, |V| = 7: Score = %.4f, Time = %.4f\n" % (score_dag_two, solving_time_dag_two) self.benchmark_file.write(file_string_two) print "Finished Benchmark 2, DAG" # |V| = 20 pre_time_dag_three = time.time() output_dag_three = DAGSolver(self.matrix_input_dag_three).topological_sort() post_time_dag_three = time.time() solving_time_dag_three = post_time_dag_three - pre_time_dag_three self.assertIsNotNone(output_dag_three) score_dag_three = scoreSolution(self.matrix_input_dag_three, output_dag_three) file_string_three = "DAG, |V| = 20: Score = %.4f, Time = %.4f\n" % (score_dag_three, solving_time_dag_three) self.benchmark_file.write(file_string_three) print "Finished Benchmark 3, DAG" # |V| = 100 pre_time_dag_four = time.time() output_dag_four = DAGSolver(self.matrix_input_dag_four).topological_sort() post_time_dag_four = time.time() solving_time_dag_four = post_time_dag_four - pre_time_dag_four self.assertIsNotNone(output_dag_four) score_dag_four = scoreSolution(self.matrix_input_dag_four, output_dag_four) file_string_four = "DAG, |V| = 100: Score = %.4f, Time = %.4f\n" % (score_dag_four, solving_time_dag_four) self.benchmark_file.write(file_string_four) print "Finished Benchmark 4, DAG" # |V| = 1000 pre_time_dag_five = time.time() output_dag_five = DAGSolver(self.matrix_input_dag_five).topological_sort() post_time_dag_five = time.time() solving_time_dag_five = post_time_dag_five - pre_time_dag_five self.assertIsNotNone(output_dag_five) score_dag_five = scoreSolution(self.matrix_input_dag_five, output_dag_five) file_string_five = "DAG, |V| = 1000: Score = %.4f, Time = %.4f\n" % (score_dag_five, solving_time_dag_five) self.benchmark_file.write(file_string_five) print "Finished Benchmark 5, DAG"
def test_simulated_annealing(self): random.seed(170) observed_output_new_graph = SimulatedAnnealingSolver( self.initial_ordering_new_graph, self.matrix_new_graph ).maximum_acyclic_subgraph() expected_score_new_graph = 54.0 observed_score_new_graph = scoreSolution(self.matrix_new_graph, observed_output_new_graph) self.assertEquals(observed_score_new_graph, expected_score_new_graph) observed_output_foster = SimulatedAnnealingSolver( self.initial_ordering_foster, self.matrix_foster ).maximum_acyclic_subgraph() expected_score_foster = 113.0 observed_score_foster = scoreSolution(self.matrix_foster, observed_output_foster) self.assertEquals(observed_score_foster, expected_score_foster) expected_output_input_one = [0, 2, 1, 3] observed_output_input_one = SimulatedAnnealingSolver( self.initial_ordering_input_one, self.matrix_input_one ).maximum_acyclic_subgraph() self.assertEquals(observed_output_input_one, expected_output_input_one) expected_ouput_input_cycle = [0, 1, 2, 3] observed_output_input_cycle = SimulatedAnnealingSolver( self.initial_ordering_input_cycle, self.matrix_input_cycle ).maximum_acyclic_subgraph() self.assertEquals(observed_output_input_cycle, expected_ouput_input_cycle) expected_output_nonplanar_one = [7, 8, 9, 2, 12, 13, 3, 10, 11, 4, 5, 0, 1, 6] observed_output_nonplanar_one = SimulatedAnnealingSolver( self.initial_ordering_input_nonplanar_one, self.matrix_input_nonplanar_one ).maximum_acyclic_subgraph() self.assertEquals(observed_output_nonplanar_one, expected_output_nonplanar_one) expected_output_nonplanar_two = [1, 5, 7, 2, 0, 6, 4, 3] observed_output_nonplanar_two = SimulatedAnnealingSolver( self.initial_ordering_input_nonplanar_two, self.matrix_input_nonplanar_two ).maximum_acyclic_subgraph() self.assertEquals(observed_output_nonplanar_two, expected_output_nonplanar_two) observed_output_gray = SimulatedAnnealingSolver( self.initial_ordering_input_gray, self.matrix_input_gray ).maximum_acyclic_subgraph() expected_score_gray = 70.0 observed_score_gray = scoreSolution(self.matrix_input_gray, observed_output_gray) self.assertEquals(observed_score_gray, expected_score_gray)
def test_benchmark_feedback_arc_set_eades(self): # |V| = 4 pre_time_eades_one = time.time() output_solver_one = FinalSolver(self.matrix_input_brute_force_two) output_eades_one = output_solver_one.obtain_library_solution(output_solver_one.adj_matrix, force_eades=True) post_time_eades_one = time.time() solving_time_eades_one = post_time_eades_one - pre_time_eades_one self.assertIsNotNone(output_eades_one) score_eades_one = scoreSolution(self.matrix_input_brute_force_two, output_eades_one) file_string_one = "Eades Approximation, |V| = 4: Score = %.4f, Time = %.4f\n" % ( score_eades_one, solving_time_eades_one, ) self.benchmark_file.write(file_string_one) # |V| = 25 pre_time_eades_two = time.time() output_solver_two = FinalSolver(self.matrix_input_brute_force_five) output_eades_two = output_solver_two.obtain_library_solution(output_solver_two.adj_matrix) post_time_eades_two = time.time() solving_time_eades_two = post_time_eades_two - pre_time_eades_two self.assertIsNotNone(output_eades_two) score_eades_two = scoreSolution(self.matrix_input_brute_force_five, output_eades_two) file_string_two = "Eades Approximation, |V| = 25: Score = %.4f, Time = %.4f\n" % ( score_eades_two, solving_time_eades_two, ) self.benchmark_file.write(file_string_two) # |V| = 100 pre_time_eades_three = time.time() output_solver_three = FinalSolver(self.matrix_input_size_100) output_eades_three = output_solver_three.obtain_library_solution(output_solver_three.adj_matrix) post_time_eades_three = time.time() solving_time_eades_three = post_time_eades_three - pre_time_eades_three self.assertIsNotNone(output_eades_three) score_eades_three = scoreSolution(self.matrix_input_size_100, output_eades_three) file_string_three = "Eades Approximation, |V| = 100: Score = %.4f, Time = %.4f\n" % ( score_eades_three, solving_time_eades_three, ) self.benchmark_file.write(file_string_three) # |V| = 1000 pre_time_eades_four = time.time() output_solver_four = FinalSolver(self.matrix_input_size_1000) output_eades_four = output_solver_four.obtain_library_solution(output_solver_four.adj_matrix) post_time_eades_four = time.time() solving_time_eades_four = post_time_eades_four - pre_time_eades_four self.assertIsNotNone(output_eades_four) score_eades_four = scoreSolution(self.matrix_input_size_1000, output_eades_four) file_string_four = "Eades Approximation, |V| = 1000: Score = %.4f, Time = %.4f\n" % ( score_eades_four, solving_time_eades_four, ) self.benchmark_file.write(file_string_four)
def maximum_acyclic_subgraph_helper_efficient(self, graph): vertices = [i for i in range(len(graph))] shuffle(vertices) score_vertices = scoreSolution(graph, vertices) reverse_vertices = vertices[::-1] score_reverse = scoreSolution(graph, reverse_vertices) if score_vertices > score_reverse: return vertices else: return reverse_vertices
def test_benchmark_two_approximation(self): # |V| = 4 pre_time_two_approx_one = time.time() output_two_approx_one = TwoApproximationSolver(self.matrix_input_brute_force_two).maximum_acyclic_subgraph() post_time_two_approx_one = time.time() solving_time_two_approx_one = post_time_two_approx_one - pre_time_two_approx_one self.assertIsNotNone(output_two_approx_one) score_two_approx_one = scoreSolution(self.matrix_input_brute_force_two, output_two_approx_one) file_string_one = "Two Approximation, |V| = 4: Score = %.4f, Time = %.4f\n" % ( score_two_approx_one, solving_time_two_approx_one, ) self.benchmark_file.write(file_string_one) # |V| = 25 pre_time_two_approx_two = time.time() output_two_approx_two = TwoApproximationSolver(self.matrix_input_brute_force_five).maximum_acyclic_subgraph() post_time_two_approx_two = time.time() solving_time_two_approx_two = post_time_two_approx_two - pre_time_two_approx_two self.assertIsNotNone(output_two_approx_two) score_two_approx_two = scoreSolution(self.matrix_input_brute_force_five, output_two_approx_two) file_string_two = "Two Approximation, |V| = 25: Score = %.4f, Time = %.4f\n" % ( score_two_approx_two, solving_time_two_approx_two, ) self.benchmark_file.write(file_string_two) # |V| = 100 pre_time_two_approx_three = time.time() output_two_approx_three = TwoApproximationSolver(self.matrix_input_size_100).maximum_acyclic_subgraph() post_time_two_approx_three = time.time() solving_time_two_approx_three = post_time_two_approx_three - pre_time_two_approx_three self.assertIsNotNone(output_two_approx_three) score_two_approx_three = scoreSolution(self.matrix_input_size_100, output_two_approx_three) file_string_three = "Two Approximation, |V| = 100: Score = %.4f, Time = %.4f\n" % ( score_two_approx_three, solving_time_two_approx_three, ) self.benchmark_file.write(file_string_three) # |V| = 1000 pre_time_two_approx_four = time.time() output_two_approx_four = TwoApproximationSolver(self.matrix_input_size_1000).maximum_acyclic_subgraph() post_time_two_approx_four = time.time() solving_time_two_approx_four = post_time_two_approx_four - pre_time_two_approx_four self.assertIsNotNone(output_two_approx_four) score_two_approx_four = scoreSolution(self.matrix_input_size_1000, output_two_approx_four) file_string_four = "Two Approximation, |V| = 1000: Score = %.4f, Time = %.4f\n" % ( score_two_approx_four, solving_time_two_approx_four, ) self.benchmark_file.write(file_string_four)
def test_benchmark_simulated_annealing(self): # |V| = 4 pre_time_sa_one = time.time() output_sa_one = SimulatedAnnealingSolver( range(len(self.matrix_input_brute_force_two)), self.matrix_input_brute_force_two ).maximum_acyclic_subgraph() post_time_sa_one = time.time() solving_time_sa_one = post_time_sa_one - pre_time_sa_one self.assertIsNotNone(output_sa_one) score_sa_one = scoreSolution(self.matrix_input_brute_force_two, output_sa_one) file_string_one = "Simulated Annealing, |V| = 4: Score = %.4f, Time = %.4f\n" % ( score_sa_one, solving_time_sa_one, ) self.benchmark_file.write(file_string_one) # |V| = 25 pre_time_sa_two = time.time() output_sa_two = SimulatedAnnealingSolver( range(len(self.matrix_input_brute_force_five)), self.matrix_input_brute_force_five ).maximum_acyclic_subgraph() post_time_sa_two = time.time() solving_time_sa_two = post_time_sa_two - pre_time_sa_two self.assertIsNotNone(output_sa_two) score_sa_two = scoreSolution(self.matrix_input_brute_force_five, output_sa_two) file_string_two = "Simulated Annealing, |V| = 25: Score = %.4f, Time = %.4f\n" % ( score_sa_two, solving_time_sa_two, ) self.benchmark_file.write(file_string_two) # |V| = 100 pre_time_sa_three = time.time() output_sa_three = SimulatedAnnealingSolver( range(len(self.matrix_input_size_100)), self.matrix_input_size_100 ).maximum_acyclic_subgraph() post_time_sa_three = time.time() solving_time_sa_three = post_time_sa_three - pre_time_sa_three self.assertIsNotNone(output_sa_three) score_sa_three = scoreSolution(self.matrix_input_size_100, output_sa_three) file_string_three = "Simulated Annealing, |V| = 100: Score = %.4f, Time = %.4f\n" % ( score_sa_three, solving_time_sa_three, ) self.benchmark_file.write(file_string_three)
def test_benchmark_brute_force(self): # |V| = 2 pre_time_brute_force_one = time.time() output_brute_force_one = BruteForceSolver(self.matrix_input_brute_force_one).maximum_acyclic_subgraph() post_time_brute_force_one = time.time() solving_time_brute_force_one = post_time_brute_force_one - pre_time_brute_force_one self.assertIsNotNone(output_brute_force_one) score_brute_force_one = scoreSolution(self.matrix_input_brute_force_one, output_brute_force_one) file_string_one = "Brute Force, |V| = 2: Score = %.4f, Time = %.4f\n" % ( score_brute_force_one, solving_time_brute_force_one, ) self.benchmark_file.write(file_string_one) print ("Finished Benchmark 1, Brute Force") # |V| = 4 pre_time_brute_force_two = time.time() output_brute_force_two = BruteForceSolver(self.matrix_input_brute_force_two).maximum_acyclic_subgraph() post_time_brute_force_two = time.time() solving_time_brute_force_two = post_time_brute_force_two - pre_time_brute_force_two self.assertIsNotNone(output_brute_force_two) score_brute_force_two = scoreSolution(self.matrix_input_brute_force_two, output_brute_force_two) file_string_two = "Brute Force, |V| = 4: Score = %.4f, Time = %.4f\n" % ( score_brute_force_two, solving_time_brute_force_two, ) self.benchmark_file.write(file_string_two) print "Finished Benchmark 2, Brute Force" # |V| = 8 pre_time_brute_force_three = time.time() output_brute_force_three = BruteForceSolver(self.matrix_input_brute_force_three).maximum_acyclic_subgraph() post_time_brute_force_three = time.time() solving_time_brute_force_three = post_time_brute_force_three - pre_time_brute_force_three self.assertIsNotNone(output_brute_force_three) score_brute_force_three = scoreSolution(self.matrix_input_brute_force_three, output_brute_force_three) file_string_three = "Brute Force, |V| = 8: Score = %.4f, Time = %.4f\n" % ( score_brute_force_three, solving_time_brute_force_three, ) self.benchmark_file.write(file_string_three) print "Finished Benchmark 3, Brute Force"
def maximum_acyclic_subgraph(self): vertices = range(len(self.adj_matrix)) vertex_permutations = permutations(vertices) max_score = 0 max_ordering = vertices for permutation in vertex_permutations: score = scoreSolution(self.adj_matrix, permutation) if score > max_score: max_score = score max_ordering = permutation return list(max_ordering)
def test_benchmark_feedback_arc_set_ip(self): # |V| = 2 pre_time_ip_one = time.time() output_solver_one = FinalSolver(self.matrix_input_brute_force_one) output_ip_one = output_solver_one.obtain_library_solution(output_solver_one.adj_matrix, force_ip=True) post_time_ip_one = time.time() solving_time_ip_one = post_time_ip_one - pre_time_ip_one self.assertIsNotNone(output_ip_one) score_ip_one = scoreSolution(self.matrix_input_brute_force_one, output_ip_one) file_string_one = "Ip Approximation, |V| = 2: Score = %.4f, Time = %.4f\n" % (score_ip_one, solving_time_ip_one) self.benchmark_file.write(file_string_one) # |V| = 4 pre_time_ip_two = time.time() output_solver_two = FinalSolver(self.matrix_input_brute_force_two) output_ip_two = output_solver_two.obtain_library_solution(output_solver_two.adj_matrix, force_ip=True) post_time_ip_two = time.time() solving_time_ip_two = post_time_ip_two - pre_time_ip_two self.assertIsNotNone(output_ip_two) score_ip_two = scoreSolution(self.matrix_input_brute_force_two, output_ip_two) file_string_two = "Ip Approximation, |V| = 4: Score = %.4f, Time = %.4f\n" % (score_ip_two, solving_time_ip_two) self.benchmark_file.write(file_string_two) # |V| = 8 pre_time_ip_three = time.time() output_solver_three = FinalSolver(self.matrix_input_brute_force_three) output_ip_three = output_solver_three.obtain_library_solution(output_solver_three.adj_matrix, force_ip=True) post_time_ip_three = time.time() solving_time_ip_three = post_time_ip_three - pre_time_ip_three self.assertIsNotNone(output_ip_three) score_ip_three = scoreSolution(self.matrix_input_brute_force_three, output_ip_three) file_string_three = "Ip Approximation, |V| = 8: Score = %.4f, Time = %.4f\n" % ( score_ip_three, solving_time_ip_three, ) self.benchmark_file.write(file_string_three)
def test_final_solver(self): ''' TODO: Add more tests, especially on our own instances. Tests a variety of input graphs (the same as those tested for the two approximation). Since the algorithm is randomized, the seed is set, though this algorithm should converge towards an optimal solution at a much faster rate, especially on graphs of this size. Gyazo links are attached for the constructed graphs, and the first cut made is denoted for each graph (the seed is set accordingly). 1. Test input one: https://gyazo.com/74dcc4c2eccd617381867274ce981859 2. Test input DAG one: https://gyazo.com/eae09e06bf5f4b0150977bf487399001 3. Test input DAG two: https://gyazo.com/8b241b60a8339d993fcda0b6ca6401a6 4. Test input cycle: https://gyazo.com/48c0e885e8baca8c0bd34a2f290171c8 5. Test input nonplanar one: https://gyazo.com/e91def6e27e59de97a5a779b87e659a9 6. Test input nonplanar two: https://gyazo.com/1295ad7498c8f80ff7ff260287a8d0ae ''' random.seed(170) self.maxDiff = None expected_output_one = [2, 1, 3, 0] observed_output_one = \ FinalSolver(self.matrix_input_one).maximum_acyclic_subgraph() expected_score_one = 4.0 observed_score_one = scoreSolution(self.matrix_input_one, observed_output_one) self.assertEquals(observed_output_one, expected_output_one) self.assertEquals(observed_score_one, expected_score_one) expected_output_dag_one = [0, 1, 2, 3] observed_output_dag_one = \ FinalSolver(self.matrix_input_dag_one).maximum_acyclic_subgraph() expected_score_dag_one = 3.0 observed_score_dag_one = scoreSolution(self.matrix_input_dag_one, observed_output_dag_one) self.assertEquals(observed_output_dag_one, expected_output_dag_one) self.assertEquals(observed_score_dag_one, expected_score_dag_one) expected_output_cycle = [3, 0, 1, 2] observed_output_cycle = \ FinalSolver(self.matrix_input_cycle).maximum_acyclic_subgraph() expected_score_cycle = 3.0 observed_score_cycle = scoreSolution(self.matrix_input_cycle, observed_output_cycle) self.assertEquals(observed_output_cycle, expected_output_cycle) self.assertEquals(observed_score_cycle, expected_score_cycle) # Could also be linearized as [1, 2, 0, 3, 4, 5, 6] but the algorithm # should break ties arbitrarily and this is chosen expected_output_dag_two = [1, 0, 2, 3, 4, 5, 6] observed_output_dag_two = \ FinalSolver(self.matrix_input_dag_two).maximum_acyclic_subgraph() expected_score_dag_one = 8.0 observed_score_dag_one = scoreSolution(self.matrix_input_dag_two, observed_output_dag_two) self.assertEquals(observed_output_dag_two, expected_output_dag_two) self.assertEquals(observed_score_dag_one, expected_score_dag_one) expected_output_nonplanar_one = [8, 9, 10, 13, 0, 1, 2, 3, 4, 5, 11, 6, 7, 12] observed_output_nonplanar_one = \ FinalSolver(self.matrix_input_nonplanar_one).maximum_acyclic_subgraph() expected_score_nonplanar_one = 19.0 observed_score_nonplanar_one = scoreSolution( self.matrix_input_nonplanar_one, observed_output_nonplanar_one ) self.assertEquals(observed_output_nonplanar_one, expected_output_nonplanar_one) self.assertEquals(observed_score_nonplanar_one, expected_score_nonplanar_one) expected_output_nonplanar_two = [5, 0, 7, 6, 4, 3, 1, 2] observed_output_nonplanar_two = \ FinalSolver(self.matrix_input_nonplanar_two).maximum_acyclic_subgraph() expected_score_nonplanar_two = 18.0 observed_score_nonplanar_two = scoreSolution( self.matrix_input_nonplanar_two, observed_output_nonplanar_two ) self.assertEquals(observed_output_nonplanar_two, expected_output_nonplanar_two) self.assertEquals(observed_score_nonplanar_two, expected_score_nonplanar_two) observed_output_foster = \ FinalSolver(self.matrix_foster).maximum_acyclic_subgraph() expected_score_foster = 124.0 observed_score_foster = scoreSolution(self.matrix_foster, observed_output_foster) self.assertEquals(observed_score_foster, expected_score_foster) observed_output_gray = \ FinalSolver(self.matrix_input_gray).maximum_acyclic_subgraph() expected_score_gray = 75.0 observed_score_gray = scoreSolution(self.matrix_input_gray, observed_output_gray) self.assertEquals(observed_score_gray, expected_score_gray) observed_output_new_graph = \ FinalSolver(self.matrix_new_graph).maximum_acyclic_subgraph() expected_score_new_graph = 55.0 observed_score_new_graph = scoreSolution(self.matrix_new_graph, observed_output_new_graph) self.assertEquals(observed_score_new_graph, expected_score_new_graph)
def maximum_acyclic_subgraph(self): topo_sort = DAGSolver(self.adj_matrix).topological_sort() if topo_sort is not None: print "Score is %.4f" % scoreSolution(self.adj_matrix, topo_sort) return topo_sort # For some reason, this is returned in reverse order by the algorithm. # So reverse to get the topologically sorted SCCs. scc_graph = self.find_strongly_connected_components()[::-1] solution = [] for scc in scc_graph: scc_adj_matrix = self.create_scc_adj_matrix(scc) if len(scc_adj_matrix) <= 8: brute_force_solver = BruteForceSolver(scc_adj_matrix) brute_force_solution = brute_force_solver.maximum_acyclic_subgraph() scc_solution = [i for i in range(len(scc_adj_matrix))] for i in range(len(brute_force_solution)): scc_conversion_index = brute_force_solution[i] scc_solution[i] = scc[scc_conversion_index] else: pq = [] library_solution = self.obtain_library_solution(scc_adj_matrix) library_score = scoreSolution(scc_adj_matrix, library_solution) print "Finished scoring using library" two_approx_solver = TwoApproximationSolver(scc_adj_matrix) for i in range(1000): this_solution = two_approx_solver.maximum_acyclic_subgraph() this_score = scoreSolution(scc_adj_matrix, this_solution) # If pq still small, add this solution # Otherwise, new score better than the worst one so far if len(pq) < 5: heapq.heappush(pq, (this_score, this_solution)) elif this_score > pq[0][0]: heapq.heappushpop(pq, (this_score, this_solution)) print "Finished Two Approximation" # Add library solution last so it doesn't get overwritten heapq.heappush(pq, (library_score, library_solution)) annealing_score = -float('inf') annealing_solution = None while len(pq) > 0: curr_soln = heapq.heappop(pq) curr_ordering = curr_soln[1] simulated_annealing_solver = SimulatedAnnealingSolver( curr_ordering, scc_adj_matrix ) curr_annealing_solution = simulated_annealing_solver.maximum_acyclic_subgraph() curr_annealing_score = scoreSolution(scc_adj_matrix, curr_annealing_solution) if curr_annealing_score > annealing_score: annealing_score = curr_annealing_score annealing_solution = curr_annealing_solution scc_solution = [i for i in range(len(scc_adj_matrix))] for i in range(len(annealing_solution)): scc_conversion_index = annealing_solution[i] scc_solution[i] = scc[scc_conversion_index] solution.extend(scc_solution) print "Score is %.4f" % scoreSolution(self.adj_matrix, solution) return solution