Changeset 785


Ignore:
Timestamp:
02/19/15 20:39:03 (15 months ago)
Author:
mmckerns
Message:

refactor Solve is Step while not Terminated; radius, xtol, strategy are sticky;
fix: DESolver2 missing self._terminated and NP = max(...);
rename CheckTermination? to Terminated, Step to _Step (and add new Step);
rename _RegisterObjective to _decorate_objective, _exitMain to _Finalize;

Location:
mystic/mystic
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • mystic/mystic/abstract_ensemble_solver.py

    r784 r785  
    207207        raise NotImplementedError, "must be overwritten..." 
    208208 
    209     def CheckTermination(self, disp=False, info=False, termination=None): 
     209    def Terminated(self, disp=False, info=False, termination=None): 
    210210        """check if the solver meets the given termination conditions 
    211211 
  • mystic/mystic/abstract_solver.py

    r784 r785  
    540540        return 
    541541 
    542     def CheckTermination(self, disp=False, info=False, termination=None): 
     542    def Terminated(self, disp=False, info=False, termination=None): 
    543543        """check if the solver meets the given termination conditions 
    544544 
     
    592592        return 
    593593 
    594     def _RegisterObjective(self, cost, ExtraArgs=None): 
     594    def SetObjective(self, cost, ExtraArgs=None, fetch=False): 
     595        """set the objective, decorated with bounds, penalties, monitors, etc""" 
     596        cost = self._bootstrap_objective(cost, ExtraArgs=None) 
     597        return cost if fetch else None 
     598 
     599    def _decorate_objective(self, cost, ExtraArgs=None): 
    595600        """decorate cost function with bounds, penalties, monitors, etc""" 
    596601        if ExtraArgs is None: ExtraArgs = () 
     
    610615 
    611616    def _bootstrap_objective(self, cost=None, ExtraArgs=None): 
    612         """HACK to enable not explicitly calling _RegisterObjective""" 
     617        """HACK to enable not explicitly calling _decorate_objective""" 
    613618        args = None 
    614619        if cost is None: # 'use existing cost' 
    615620            cost,args = self._cost # use args, unless override with ExtraArgs 
    616621        if ExtraArgs is not None: args = ExtraArgs 
    617         if self._cost[0] is None: # '_RegisterObjective not yet called' 
     622        if self._cost[0] is None: # '_decorate_objective not yet called' 
    618623            if args is None: args = () 
    619             cost = self._RegisterObjective(cost, args) 
     624            cost = self._decorate_objective(cost, args) 
    620625        return cost 
    621626 
    622     def Step(self, cost=None, ExtraArgs=None, **kwds): 
     627    def _Step(self, cost=None, ExtraArgs=None, **kwds): 
    623628        """perform a single optimization iteration 
    624629 
     
    666671        return 
    667672 
    668     def _exitMain(self, **kwds): 
     673    def _Finalize(self, **kwds): 
    669674        """cleanup upon exiting the main optimization loop""" 
    670675        pass 
     
    673678        """process and activate input settings""" 
    674679        #allow for inputs that don't conform to AbstractSolver interface 
     680        #NOTE: not sticky: callback, disp 
     681        #NOTE: sticky: EvaluationMonitor, StepMonitor, penalty, constraints 
    675682        settings = \ 
    676683       {'callback':None,     #user-supplied function, called after each step 
     
    688695        return settings 
    689696 
     697    def Step(self, cost=None, termination=None, ExtraArgs=None, **kwds): 
     698        """Take a single optimiztion step using the given 'cost' function. 
     699 
     700Description: 
     701 
     702    Uses an optimization algorithm to take one 'step' toward 
     703    the minimum of a function of one or more variables. 
     704 
     705Inputs: 
     706 
     707    cost -- the Python function or method to be minimized. 
     708 
     709Additional Inputs: 
     710 
     711    termination -- callable object providing termination conditions. 
     712    ExtraArgs -- extra arguments for cost. 
     713 
     714Further Inputs: 
     715 
     716    callback -- an optional user-supplied function to call after each 
     717        iteration.  It is called as callback(xk), where xk is 
     718        the current parameter vector.  [default = None] 
     719    disp -- non-zero to print convergence messages. 
     720 
     721Notes: 
     722    If the algorithm does not meet the given termination conditions after 
     723    the call to "Step", the solver may be left in an "out-of-sync" state. 
     724    When abandoning an non-terminated solver, one should call "_Finalize" 
     725    to make sure the solver is fully returned to a "synchronized" state. 
     726 
     727    To run the solver until termination, call "Solve()".  Alternately, use 
     728    Terminated()" as the condition in a while loop over "Step". 
     729        """ 
     730        disp = kwds.pop('disp', False) 
     731 
     732        # register: cost, termination, ExtraArgs 
     733        cost = self._bootstrap_objective(cost, ExtraArgs) 
     734        if termination is not None: self.SetTermination(termination) 
     735 
     736        # check termination before 'stepping' 
     737        if len(self._stepmon): 
     738            msg = self.Terminated(disp=disp, info=True) or None 
     739        else: msg = None 
     740 
     741        # if not terminated, then take a step 
     742        if msg is None: 
     743            self._Step(**kwds) #FIXME: not all kwds are given in __doc__ 
     744            if self.Terminated(): # then cleanup/finalize 
     745                self._Finalize() 
     746 
     747            # get termination message and log state 
     748            msg = self.Terminated(disp=disp, info=True) or None 
     749            if msg: 
     750                self._stepmon.info('STOP("%s")' % msg) 
     751                self.__save_state(force=True) 
     752        return msg 
     753 
    690754    def Solve(self, cost=None, termination=None, ExtraArgs=None, **kwds): 
    691755        """Minimize a 'cost' function with given termination conditions. 
     
    693757Description: 
    694758 
    695     Uses an optimization algorith to find the minimum of 
     759    Uses an optimization algorithm to find the minimum of 
    696760    a function of one or more variables. 
    697761 
     
    713777    disp -- non-zero to print convergence messages. 
    714778        """ 
    715         # HACK to enable not explicitly calling _RegisterObjective 
    716         cost = self._bootstrap_objective(cost, ExtraArgs) 
    717779        # process and activate input settings 
    718780        sigint_callback = kwds.pop('sigint_callback', None) 
    719781        settings = self._process_inputs(kwds) 
    720         for key in settings: 
    721             exec "%s = settings['%s']" % (key,key) 
    722782 
    723783        # set up signal handler 
     
    729789        if self._handle_sigint: signal.signal(signal.SIGINT,self.signal_handler) 
    730790 
    731        ## decorate cost function with bounds, penalties, monitors, etc 
    732        #self._RegisterObjective(cost, ExtraArgs)    #XXX: SetObjective ? 
    733         # register termination function 
    734         if termination is not None: 
    735             self.SetTermination(termination) 
    736  
    737         # the initital optimization iteration 
    738         if not len(self._stepmon): # do generation = 0 
    739             self.Step(**settings)  # includes settings['callback'] 
     791        # register: cost, termination, ExtraArgs 
     792        cost = self._bootstrap_objective(cost, ExtraArgs) 
     793        if termination is not None: self.SetTermination(termination) 
     794        #XXX: self.Step(cost, termination, ExtraArgs, **settings) ? 
    740795 
    741796        # the main optimization loop 
    742         while not self.CheckTermination(): 
    743             self.Step(**settings)  # includes settings['callback'] 
    744         else: self._exitMain() 
     797        while not self.Step(**settings): #XXX: remove need to pass settings? 
     798            continue 
    745799 
    746800        # restore default handler for signal interrupts 
    747801        signal.signal(signal.SIGINT,signal.default_int_handler) 
    748  
    749         # log any termination messages 
    750         msg = self.CheckTermination(disp=disp, info=True) 
    751         if msg: self._stepmon.info('STOP("%s")' % msg) 
    752         # save final state 
    753         self.__save_state(force=True) 
    754802        return 
    755803 
  • mystic/mystic/differential_evolution.py

    r784 r785  
    5858    - EvaluationMonitor = Monitor() 
    5959    - StepMonitor = Monitor() 
    60     - strategy = Best1Exp 
     60    - strategy = Best1Bin 
    6161    - termination = ChangeOverGeneration(ftol,gtol), if gtol provided 
    6262          ''      = VTRChangeOverGenerations(ftol), otherwise 
     
    171171        self.scale         = 0.8 
    172172        self.probability   = 0.9 
     173        self.strategy      = 'Best1Bin' 
    173174        ftol = 5e-3 
    174175        from mystic.termination import VTRChangeOverGeneration 
     
    200201        return 
    201202 
    202     def _RegisterObjective(self, cost, ExtraArgs=None): 
     203    def _decorate_objective(self, cost, ExtraArgs=None): 
    203204        """decorate cost function with bounds, penalties, monitors, etc""" 
    204205        if ExtraArgs is None: ExtraArgs = () 
     
    216217        return cost 
    217218 
    218     def Step(self, cost=None, ExtraArgs=None, **kwds): 
     219    def _Step(self, cost=None, ExtraArgs=None, **kwds): 
    219220        """perform a single optimization iteration 
    220221        Note that ExtraArgs should be a *tuple* of extra arguments""" 
    221         # HACK to enable not explicitly calling _RegisterObjective 
     222        # HACK to enable not explicitly calling _decorate_objective 
    222223        cost = self._bootstrap_objective(cost, ExtraArgs) 
    223224        # process and activate input settings 
     
    275276        # initialize termination conditions, if needed 
    276277        if init: self._termination(self) #XXX: at generation 0 or always? 
    277         return #XXX: call CheckTermination ? 
     278        return #XXX: call Terminated ? 
    278279 
    279280    def _process_inputs(self, kwds): 
    280281        """process and activate input settings""" 
    281282        #allow for inputs that don't conform to AbstractSolver interface 
     283        #NOTE: not sticky: callback, disp 
     284        #NOTE: sticky: EvaluationMonitor, StepMonitor, penalty, constraints 
     285        #NOTE: sticky: strategy, CrossProbability, ScalingFactor 
    282286        settings = super(DifferentialEvolutionSolver, self)._process_inputs(kwds) 
    283         from mystic.strategy import Best1Bin 
     287        from mystic import strategy 
     288        strategy = getattr(strategy,self.strategy,strategy.Best1Bin) #XXX: None? 
    284289        settings.update({\ 
    285         'strategy':Best1Bin})#mutation strategy (see mystic.strategy) 
    286         probability=0.9      #potential for parameter cross-mutation 
    287         scale=0.8            #multiplier for mutation impact 
     290        'strategy': strategy})       #mutation strategy (see mystic.strategy) 
     291        probability=self.probability #potential for parameter cross-mutation 
     292        scale=self.scale             #multiplier for mutation impact 
    288293        [settings.update({i:j}) for (i,j) in kwds.items() if i in settings] 
    289294        self.probability = kwds.get('CrossProbability', probability) 
    290295        self.scale = kwds.get('ScalingFactor', scale) 
     296        self.strategy = getattr(settings['strategy'],'__name__','Best1Bin') 
    291297        return settings 
    292298 
     
    345351All important class members are inherited from AbstractSolver. 
    346352        """ 
    347         #XXX: raise Error if npop <= 4? 
     353        NP = max(NP, dim, 4) #XXX: raise Error if npop <= 4? 
    348354        super(DifferentialEvolutionSolver2, self).__init__(dim, npop=NP) 
    349355        self.genealogy     = [ [] for j in range(NP)] 
    350356        self.scale         = 0.8 
    351357        self.probability   = 0.9 
     358        self.strategy      = 'Best1Bin' 
     359        ftol = 5e-3 
     360        from mystic.termination import VTRChangeOverGeneration 
     361        self._termination = VTRChangeOverGeneration(ftol) 
    352362         
    353363    def UpdateGenealogyRecords(self, id, newchild): 
     
    359369        return 
    360370 
    361     def _RegisterObjective(self, cost, ExtraArgs=None): 
     371    def _decorate_objective(self, cost, ExtraArgs=None): 
    362372        """decorate cost function with bounds, penalties, monitors, etc""" 
    363373        if ExtraArgs is None: ExtraArgs = () 
     
    380390        return cost 
    381391 
    382     def Step(self, cost=None, ExtraArgs=None, **kwds): 
     392    def _Step(self, cost=None, ExtraArgs=None, **kwds): 
    383393        """perform a single optimization iteration 
    384394        Note that ExtraArgs should be a *tuple* of extra arguments""" 
    385         # HACK to enable not explicitly calling _RegisterObjective 
     395        # HACK to enable not explicitly calling _decorate_objective 
    386396        cost = self._bootstrap_objective(cost, ExtraArgs) 
    387397        # process and activate input settings 
     
    444454        # initialize termination conditions, if needed 
    445455        if init: self._termination(self) #XXX: at generation 0 or always? 
    446         return #XXX: call CheckTermination ? 
     456        return #XXX: call Terminated ? 
    447457 
    448458    def _process_inputs(self, kwds): 
    449459        """process and activate input settings""" 
    450460        #allow for inputs that don't conform to AbstractSolver interface 
     461        #NOTE: not sticky: callback, disp 
     462        #NOTE: sticky: EvaluationMonitor, StepMonitor, penalty, constraints 
     463        #NOTE: sticky: strategy, CrossProbability, ScalingFactor 
    451464        settings = super(DifferentialEvolutionSolver2, self)._process_inputs(kwds) 
    452         from mystic.strategy import Best1Bin 
     465        from mystic import strategy 
     466        strategy = getattr(strategy,self.strategy,strategy.Best1Bin) #XXX: None? 
    453467        settings.update({\ 
    454         'strategy':Best1Bin})#mutation strategy (see mystic.strategy) 
    455         probability=0.9      #potential for parameter cross-mutation 
    456         scale=0.8            #multiplier for mutation impact 
     468        'strategy': strategy})       #mutation strategy (see mystic.strategy) 
     469        probability=self.probability #potential for parameter cross-mutation 
     470        scale=self.scale             #multiplier for mutation impact 
    457471        [settings.update({i:j}) for (i,j) in kwds.items() if i in settings] 
    458472        self.probability = kwds.get('CrossProbability', probability) 
    459473        self.scale = kwds.get('ScalingFactor', scale) 
     474        self.strategy = getattr(settings['strategy'],'__name__','Best1Bin') 
    460475        return settings 
    461476 
  • mystic/mystic/ensemble.py

    r784 r785  
    227227 
    228228        # log any termination messages 
    229         msg = self.CheckTermination(disp=disp, info=True) 
     229        msg = self.Terminated(disp=disp, info=True) 
    230230        if msg: self._stepmon.info('STOP("%s")' % msg) 
    231231        # save final state 
     
    413413 
    414414        # log any termination messages 
    415         msg = self.CheckTermination(disp=disp, info=True) 
     415        msg = self.Terminated(disp=disp, info=True) 
    416416        if msg: self._stepmon.info('STOP("%s")' % msg) 
    417417        # save final state 
     
    523523 
    524524    # code below here pushes output to scipy.optimize.fmin interface 
    525     msg = solver.CheckTermination(disp=False, info=True) 
     525    msg = solver.Terminated(disp=False, info=True) 
    526526 
    527527    x = solver.bestSolution 
     
    654654 
    655655    # code below here pushes output to scipy.optimize.fmin interface 
    656     msg = solver.CheckTermination(disp=False, info=True) 
     656    msg = solver.Terminated(disp=False, info=True) 
    657657 
    658658    x = solver.bestSolution 
  • mystic/mystic/scipy_optimize.py

    r784 r785  
    9292        self.popEnergy.append(self._init_popEnergy) 
    9393        self.population.append([0.0 for i in range(dim)]) 
     94        self.radius= 0.05 #percentage change for initial simplex values 
    9495        xtol, ftol = 1e-4, 1e-4 
    9596        from mystic.termination import CandidateRelativeTolerance as CRT 
     
    141142        return 
    142143 
    143     def Step(self, cost=None, ExtraArgs=None, **kwds): 
     144    def _Step(self, cost=None, ExtraArgs=None, **kwds): 
    144145        """perform a single optimization iteration 
    145146        Note that ExtraArgs should be a *tuple* of extra arguments""" 
    146         # HACK to enable not explicitly calling _RegisterObjective 
     147        # HACK to enable not explicitly calling _decorate_objective 
    147148        cost = self._bootstrap_objective(cost, ExtraArgs) 
    148149        # process and activate input settings 
     
    259260        # initialize termination conditions, if needed 
    260261        if init: self._termination(self) #XXX: at generation 0 or always? 
    261         return #XXX: call CheckTermination ? 
     262        return #XXX: call Terminated ? 
    262263 
    263264    def _process_inputs(self, kwds): 
    264265        """process and activate input settings""" 
    265266        #allow for inputs that don't conform to AbstractSolver interface 
     267        #NOTE: not sticky: callback, disp 
     268        #NOTE: sticky: EvaluationMonitor, StepMonitor, penalty, constraints 
     269        #NOTE: sticky: radius 
    266270        settings = super(NelderMeadSimplexSolver, self)._process_inputs(kwds) 
    267271        settings.update({\ 
    268         'radius':0.05})      #percentage change for initial simplex values 
     272        'radius':self.radius}) #percentage change for initial simplex values 
    269273        [settings.update({i:j}) for (i,j) in kwds.items() if i in settings] 
     274        self.radius = settings['radius'] 
    270275        return settings 
    271276 
     
    453458        #                  [x1, fx, bigind, delta] 
    454459        self.__internals = [x1, fx,      0,   0.0] 
     460        self.xtol  = 1e-4  #line-search error tolerance 
    455461        ftol, gtol = 1e-4, 2 
    456462        from mystic.termination import NormalizedChangeOverGeneration as NCOG 
     
    461467        return 
    462468 
    463     def Step(self, cost=None, ExtraArgs=None, **kwds): 
     469    def _Step(self, cost=None, ExtraArgs=None, **kwds): 
    464470        """perform a single optimization iteration 
    465471        Note that ExtraArgs should be a *tuple* of extra arguments""" 
    466         # HACK to enable not explicitly calling _RegisterObjective 
     472        # HACK to enable not explicitly calling _decorate_objective 
    467473        cost = self._bootstrap_objective(cost, ExtraArgs) 
    468474        # process and activate input settings 
     
    471477            exec "%s = settings['%s']" % (key,key) 
    472478 
    473         direc = self._direc 
     479        direc = self._direc #XXX: throws Error if direc=None after generation=0 
    474480        x = self.population[0]   # bestSolution 
    475481        fval = self.popEnergy[0] # bestEnergy 
     
    571577        # initialize termination conditions, if needed 
    572578        if init: self._termination(self) #XXX: at generation 0 or always? 
    573         return #XXX: call CheckTermination ? 
    574  
    575     def _exitMain(self, **kwds): 
     579        return #XXX: call Terminated ? 
     580 
     581    def _Finalize(self, **kwds): 
    576582        """cleanup upon exiting the main optimization loop""" 
    577583        self.energy_history = None # resync with 'best' energy 
     
    584590        """process and activate input settings""" 
    585591        #allow for inputs that don't conform to AbstractSolver interface 
     592        #NOTE: not sticky: callback, disp 
     593        #NOTE: sticky: EvaluationMonitor, StepMonitor, penalty, constraints 
     594        #NOTE: sticky: xtol, direc 
    586595        settings = super(PowellDirectionalSolver, self)._process_inputs(kwds) 
    587596        settings.update({\ 
    588         'xtol':1e-4})        #line-search error tolerance 
     597        'xtol':self.xtol})   #line-search error tolerance 
    589598        direc=self._direc    #initial direction set 
    590599        [settings.update({i:j}) for (i,j) in kwds.items() if i in settings] 
    591600        self._direc = kwds.get('direc', direc) 
     601        self.xtol = settings['xtol'] 
    592602        return settings 
    593603 
Note: See TracChangeset for help on using the changeset viewer.