def test_determine_colour(self): """ Ensure colours are returned with the relevant values. """ gui = Visualizer(None) assert gui._determine_colour(0) == 'red' assert gui._determine_colour(1) == 'green' assert gui._determine_colour(2) == 'cyan' assert gui._determine_colour(3) == 'blue' assert gui._determine_colour(500) == 'blue'
def start(self): """ Begins gui. """ self.__root = Tk() self._gui = Visualizer(self.__root) self._gui.subscribe(self) # Register to gui self.subscribe(self._gui) # Register gui to this self.__root.protocol("WM_DELETE_WINDOW", self._gui_close) self.__root.mainloop()
def test_validate_input(self): """ Tests the validation of input. """ gui = Visualizer(None) gui._builder.get_object = Mock() returnable = Mock() returnable.get = Mock() returnable.get.return_value = "Not valid" # Check error raised when invalid value is given gui._builder.get_object.return_value = returnable try: gui._validate_input() assert False except Exception: assert True
def test_notifying_observers(self): """ Ensures the norifying of observers happens with the correct argument. """ gui = Visualizer(None) observer = Mock() # Setup with a fake observer observer.update = Mock() gui._observers = [observer] gui._builder.get_object = Mock() # Setup fake values returnable = Mock() returnable.get = Mock() returnable.get.return_value = "999" # Look for 999 gui._builder.get_object.return_value = returnable gui._notify_observers() observer.update.assert_called_with({"method": "999", "clique_size": 999, "graph_size": 999})
def test_draw_graph(self, det_col): """ Ensures a graph is drawn with the corredct items. """ gui = Visualizer(None) fake_canvas = Mock() fake_canvas.create_oval = Mock() fake_canvas.create_line = Mock() fake_canvas.winfo_width = Mock(return_value=5) fake_canvas.winfo_height = Mock(return_value=5) gui._builder = Mock() gui._builder.get_object = Mock() gui._builder.get_object.return_value = fake_canvas # Test vertice drawing g = Graph() # Setup graph vertex_one = Vertex(0) g.add_vertex(vertex_one) g.add_vertex(Vertex(1)) g.add_vertex(Vertex(2)) gui._draw_graph(g) # Try drawing assert fake_canvas.create_oval.call_count == 3 # Test edge drawing edge = Edge(0, vertex_one, vertex_one, colour=5) # Setup (Continued from above) g.add_edge(edge) gui._draw_graph(g) # Try drawing det_col.assert_called_with(5) assert fake_canvas.create_line.call_count == 1
def test_init(self, builder_mock, handlers_mock, obs_mck, sub_mck): """ Tests the initialisation of the gui. """ builder_mock.add_from_file = Mock() builder_mock.get_object = Mock() gui = Visualizer(None) # Do the thing sub_mck.assert_called_with(gui) # Ensure parent constructors are called. obs_mck.assert_called_with(gui) assert builder_mock.call_count == 1 # Ensure builder has been created. assert handlers_mock.call_count == 1 # Ensure event handlers have been added.
def test_update(self, thrd): """ Ensures the view updates if a graph is provided. """ gui = Visualizer(None) args = {"graph": "GRAPH", "generation": "gen", "evals": "evals", "best_fitness": 0.999, "finished": "fin", "history": {"fitness": [1], "evaluation": [1]}} # Try with a graph gui.update(args) assert thrd.call_count == 1 args = {} # Try without a graph gui.update(args) assert thrd.call_count == 1 # (Continuing from previous test)
def test_btn_solve(self, validate_mock, notify_mock): """ Ensure action checks validation before notifying observers. """ gui = Visualizer(None) validate_mock.return_value = True # Try with valid input gui._btn_solve_press() assert notify_mock.call_count == 1 validate_mock.return_value = False # Try with invalid input gui._btn_solve_press() assert notify_mock.call_count == 1 # (Last test added one)
class Simulator(Subject, Observer): """ A simulator to process party problems. """ def __init__(self): """ Initializes a user interface and sets up callbacks. """ Subject.__init__(self) Observer.__init__(self) self._graph = None self._method = None self._algo_thread = None self._poll_thread = None self._gui = None def start(self): """ Begins gui. """ self.__root = Tk() self._gui = Visualizer(self.__root) self._gui.subscribe(self) # Register to gui self.subscribe(self._gui) # Register gui to this self.__root.protocol("WM_DELETE_WINDOW", self._gui_close) self.__root.mainloop() def _gui_close(self): """ The gui has been closed, cut threads. """ self._method._set_finished_flag(True) if self._algo_thread is not None: self._algo_thread.join() if self._poll_thread is not None: self._poll_thread.join() self.__root.destroy() raise SystemExit def _solve(self, clique_size, graph_size, method): """ Solves the given clique problem. """ # Generate a Graph self._graph = ConnectedGraph(graph_size) # Generate an equation to solve and its variables result = self._generate_equation(clique_size) self._equation = result[0] var_set = result[1] self._goal_fitness = len(self._equation._clauses) # Generate a method to solve equation self._method = self._determine_method(method)() # Run algorithm on a seperate thread self._algo_thread = Thread(target=self._method.run, args=( self._equation, len(var_set), )) # Run poller on seperate thread self._poll_thread = Thread(target=self._poll) self._algo_thread.start() self._poll_thread.start() def _determine_method(self, method): """ Returns the Genetic Algorithm class to be instantiated. """ if method == "EvoSAP": print("EvoSAP - Original") return EvoSAP elif method == "FlipGA": print("FlipGA - Original") return FlipGA elif method == "BlindGA": print("BlindGA - Original") return BlindGA elif method == "EvoSAP1": print("EvoSAP - Mutation 1") return EvoSAP_1 elif method == "EvoSAP2": print("EvoSAP - Mutation 2") return EvoSAP_2 elif method == "FlipGA1": print("FlipGA - Mutation 1") return FlipGA_1 elif method == "FlipGA2": print("FlipGA - Mutation 2") return FlipGA_2 def _poll(self): """ Polls the algorithm, updating observers when required. """ cur_fit = -1 org = None sleep(2) while not self._method.is_finished(): org = self._method.get_best_genome() if org is not None: self._method.get_best_genome().evaluate(self._equation) # Update graph self._generate_graph(org) # Update observers self._notify_observers(org) sleep(2) # Update when finished org = self._method.get_best_genome() self._generate_graph(org) self._notify_observers(org) def _generate_graph(self, org): """ Generates a graph based on current state of method's best orgnism. """ genome = org.get_genes() count = 1 for gene in genome: # For each gene (edge) if gene.get_information(): self._graph.get_edge(count).set_colour(1) else: self._graph.get_edge(count).set_colour(0) count = count + 1 def _generate_equation(self, clique_size): """ Generates a boolean equation and variable set based on the parameters. """ # Generate string equivalent bln_eq_str = "" var_set = [] vertex_combinations = combinations( self._graph.get_vertices(), clique_size) # Get all combinations of vertices for combination in vertex_combinations: # Generate clause and inverse clause clause_one = "" clause_two = "" for edge in self._graph.get_edges( ): # Get all edges in this combination if (edge.get_origin() in combination) and (edge.get_target() in combination): edge_id = str( edge.get_id()) # Found an edge in this combination var_id = "{" + edge_id + "}" clause_one = clause_one + "+¬" + var_id + "" clause_two = clause_two + "+" + var_id + "" # Format clause clause_one = "(" + clause_one[ 1:] + ")" # The substring removes the first redundant "AND" symbol clause_two = "(" + clause_two[1:] + ")" # Add clause to equation bln_eq_str = bln_eq_str + "." + clause_one + "." + clause_two # Generate variables list for edge in self._graph.get_edges(): var_id = "{" + str(edge.get_id()) + "}" var_set.append(var_id) # Format Equation bln_eq_str = bln_eq_str[1:] # Removes redundant AND symbol # Generate equation object return (Equation(bln_eq_str), var_set) def _notify_observers(self, org): """ Notifies observers of genetic parameters and graph. """ best_genome = self._method.get_best_genome() if best_genome is not None: args = { "generation": self._method.get_generation(), "evals": self._method.get_num_evaluations(), "best_fitness": best_genome.evaluate(self._equation), "graph": self._graph, "finished": self._method.is_finished(), "history": { "fitness": list(self._method.get_fitness_history()), "evaluation": list(self._method.get_evaluation_history()) } } for o in self._observers: o.update(args) def update(self, args): """ Get clique and graph size and begin simulation. """ clique_size = args['clique_size'] graph_size = args['graph_size'] method = args['method'] self._solve(clique_size, graph_size, method)