Exemplo n.º 1
0
    def __init__(self, frame):
        """Constructor.

        Parameters:
            frame: the FrameOptimizer instance."""
        self.frame = frame
        self.params = OptimizationParameters()
        self.params.optimization_running = False
        self.best = None
        self.best_coverage = 0
        self.average_coverage = 0
        self.best_chromosome = []
        self.currentGeneration = 0
        self.run_thread = None
        self.start_time = 0
        self.last_population = None
        self.generations = []
        self.last_plot_time = time.time()-10
        #Frequency of plotting
        self.plot_time_interval = 1
Exemplo n.º 2
0
class OptimizerController():
    """Controller for the coverage optimizer."""

    #--------------------------------------------------------------------
    def __init__(self, frame):
        """Constructor.

        Parameters:
            frame: the FrameOptimizer instance."""
        self.frame = frame
        self.params = OptimizationParameters()
        self.params.optimization_running = False
        self.best = None
        self.best_coverage = 0
        self.average_coverage = 0
        self.best_chromosome = []
        self.currentGeneration = 0
        self.run_thread = None
        self.start_time = 0
        self.last_population = None
        self.generations = []
        self.last_plot_time = time.time()-10
        #Frequency of plotting
        self.plot_time_interval = 1

    #--------------------------------------------------------------------
    def restore_buttons(self):
        """ Restore the button states to the initial value """
        self.frame.buttonStart.Enable(True)
        self.frame.buttonKeepGoing.Enable(False)
        self.frame.buttonApply.Enable(False)
        self.frame.buttonStop.Enable(False)

    #--------------------------------------------------------------------
    def update(self):
        """Update GUI elements to reflect the current status."""
        frm = self.frame #@type frm FrameOptimizer
        if frm is None:
            return
        if self.params.avoid_edges and not self.params.use_volume:
            edges = " (excluding edges)"
        else:
            edges = ""
        #Coverage stats
        frm.staticTextCoverage.SetLabel("Best Coverage%s: %7.2f %%" % (edges, self.best_coverage*100))
        frm.gaugeCoverage.SetValue(self.best_coverage*100)
        frm.staticTextAverage.SetLabel("Average Coverage%s: %7.2f %%" % (edges, self.average_coverage*100))
        frm.gaugeAverage.SetValue(self.average_coverage*100)
        #The generation counter
        maxgen = self.params.max_generations
        frm.gaugeGeneration.SetRange(maxgen)
        frm.gaugeGeneration.SetValue(self.currentGeneration)
        frm.staticTextGeneration.SetLabel("Generation %5d of %5d:" % (self.currentGeneration, maxgen))
        #The individual
        if not self.best is None:
            frm.textStatus.SetValue("Best individual has %7.3f coverage:\n%s" % (self.best.coverage, str(self.best.genomeList)))
            frm.buttonApply.Enable(True)
        else:
            frm.textStatus.SetValue("No best individual")
            frm.buttonApply.Enable(False)
        #The start/stop buttons enabling
        frm.buttonStart.Enable((self.run_thread is None))
        frm.buttonStop.Enable(not (self.run_thread is None))
        #The keep going button
        frm.buttonKeepGoing.Enable( not (self.last_population is None) and (self.run_thread is None) )

    #--------------------------------------------------------------------
    def start(self, event, *args):
        """Start the optimization."""
        self._want_abort = False
        self.start_time = time.time()
        self.init_data()
        #Start the thread
        self.params.use_old_population = False
        self.run_thread = OptimizationThread(self)
        #Set the buttons right away.
        frm = self.frame #@type frm FrameOptimizer
        frm.buttonStart.Enable((self.run_thread is None))
        frm.buttonStop.Enable(not (self.run_thread is None))

        self.frame.staticTextComplete.SetLabel("Optimization started...")
        if not event is None: event.Skip()

    #--------------------------------------------------------------------
    def keep_going(self, event):
        """Continue optimization, using the last saved population."""
        if self.last_population is None:
            wx.MessageDialog(self.frame, "Error! No saved population. You need to start the optimization at least once.").ShowModal()
            return

#        if s:
#            wx.MessageDialog("Number of sample orientations has changed. Cannot keep going with the old population.").ShowModal()
#            return;
        
        if (self.params.population != len(self.last_population)) or (self.last_population[0].listSize != self.params.number_of_orientations):
            wx.MessageDialog(self.frame, "Population size/number of orientations changed. The new population will be selected randomly from the old one, and may not be as good.", style=wx.OK).ShowModal()
        
        self._want_abort = False
        self.start_time = time.time()
        self.init_data()
        
        #Start the thread
        self.params.use_old_population = True
        self.params.add_trait("old_population", self.last_population)
        self.run_thread = OptimizationThread(self)

        #Set the buttons right away.
        frm = self.frame #@type frm FrameOptimizer
        frm.buttonStart.Enable((self.run_thread is None))
        frm.buttonStop.Enable(not (self.run_thread is None))

        self.frame.staticTextComplete.SetLabel("Optimization started...")
        if not event is None: event.Skip()

    #--------------------------------------------------------------------
    def stop(self, event, *args):
        """Stop the optimization."""
        self._want_abort = True
        #Will have to wait for the next generation to stop
        if not event is None: event.Skip()
        
    #--------------------------------------------------------------------
    def close_form(self, event, *args):
        """Call when the form is closing. Aborth the thread if it is running."""
        self._want_abort = True
        #Marker to avoid trying to change GUI
        self.frame = None
        #For the singleton
        global _instance
        _instance = None
        if not event is None: event.Skip()




    #--------------------------------------------------------------------
    def init_data(self):
        """Initialize and clear the GA data log."""
        self.generations = []

    #--------------------------------------------------------------------
    def add_data(self, ga):
        """Add one entry to the GA data log."""
        stats = ga.getStatistics()
        self.generations.append( GAData(ga.currentGeneration, stats["rawMax"], stats["rawAve"], stats["rawMin"]) )

    #--------------------------------------------------------------------
    def plot_data(self):
        """Plot whatever the data currently is"""
        self.frame.plotControl.draw(self.generations)
        self.last_plot_time = time.time()


    #--------------------------------------------------------------------
    def complete(self, ga, aborted, converged):
        """Called when the optimization completes.
        
        Parameters:
            ga: the GSimpleGA instance
            aborted: True if the optimization was aborted manually
            converged: True if the criterion was reached.
        """
        if aborted:
            label = "ABORTED - Optimization was aborted before completing!"
        elif converged:
            label = "SUCCESS - Optimization met the coverage criterion!"
        else:
            label = "FAILED - Reached the max. # of generations without enough coverage!"

        self.run_thread = None
        self.add_data(ga)
        #Make sure GUI updates
        wx.CallAfter(self.frame.staticTextComplete.SetLabel, label)
        wx.CallAfter(self.plot_data)
        wx.CallAfter(self.update)

        #Save the population
        self.last_population = ga.getPopulation()

        if self.params.auto_increment and not aborted and not converged:
            print "AUTO INCREMENTING !!!"
            #Try again with 1 more orientation
            self.params.number_of_orientations += 1
            wx.CallAfter(self.keep_going, None)
        else:
            #Done!
            print "Optimization finished in %.3f seconds." % (time.time() - self.start_time)

        
    #--------------------------------------------------------------------
    def step_callback(self, ga, *args):
        """Callback during evolution; used to abort it and to display
        stats."""
        #@type ga GSimpleGA
        op = self.params #@type op OptimizationParameters
        
        #Find the best individual
        self.best = ga.bestIndividual()
        self.best_coverage = self.best.coverage
        #More stats
        stats = ga.getStatistics()
        self.average_coverage = stats["rawAve"]
        #Other stats
        self.currentGeneration = ga.currentGeneration
        #Log the stats too
        self.add_data(ga)
        
        #Adjust settings while going on
        model.optimization.set_changeable_parameters(op, ga)

        #Update gui
        if time.time()-self.last_plot_time > self.plot_time_interval:
            #Enough time has passed, plot the graph
            wx.CallAfter(self.plot_data)
        wx.CallAfter(self.update)
        return self._want_abort






    #--------------------------------------------------------------------
    def apply(self, event, *args):
        """Apply the best results."""
        #TODO: Confirmation message box?
        positions = []

        # And add the fixed ones, if any
        if self.params.fixed_orientations:
            positions += self.params.fixed_orientations_list

        # Get the angles of the best one
        positions += model.optimization.get_angles(self.best)
            
        print "Applying best individual", self.best

        #This deletes everything in the list in the instrument
        del model.instrument.inst.positions[:]
        #Make sure to clear the parameters too, by giving it an empty dict() object.
        display_thread.clear_positions_selected()

        #This function does the calc. and shows a progress bar. Can be aborted too.
        gui_utils.do_calculation_with_progress_bar(positions)

        #GUI update
        model.messages.send_message(model.messages.MSG_POSITION_LIST_CHANGED)
        
        #Add it to the list of selected items
        if len(model.instrument.inst.angles) == 1:
	    model.instrument.inst.sort_positions_by(0)
        display_thread.select_position_coverage(model.instrument.inst.positions, update_gui=True)

        if not event is None: event.Skip()