Changeset 794


Ignore:
Timestamp:
06/12/15 17:08:44 (11 months ago)
Author:
mmckerns
Message:

add _update_objective and _live, to queue state changes to cost, penalty, etc;
enable _clipGuess to randomize within RangeBoundary?, use numpy.clip;
move bulk of _bootstrap into SetObjective?, for better method-order freedom;
_decorate_objective less likely to produce a uniform population;
rename _Finalize to Finalize; Step responds to change in state more like Solve

Location:
mystic/mystic
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • mystic/mystic/abstract_ensemble_solver.py

    r792 r794  
    255255        return bool(msg) 
    256256 
     257    def _update_objective(self): 
     258        """decorate the cost function with bounds, penalties, monitors, etc""" 
     259        # rewrap the cost if the solver has been run 
     260        self.Finalize() 
     261        return 
     262 
    257263 
    258264if __name__=='__main__': 
  • mystic/mystic/abstract_solver.py

    r792 r794  
    7676 
    7777 
     78import random 
    7879import numpy 
    7980from numpy import inf, shape, asarray, absolute, asfarray, seterr 
     
    155156        import mystic.termination 
    156157        self._EARLYEXIT       = mystic.termination.EARLYEXIT 
     158        self._live            = False  
    157159        return 
    158160 
     
    228230        else: #XXX: check if is arraylike? 
    229231            self._reducer = reducer 
    230         return 
     232        return self._update_objective() 
    231233 
    232234    def SetPenalty(self, penalty): 
     
    247249        else: #XXX: check for format: y' = penalty(x) ? 
    248250            self._penalty = penalty 
    249         return 
     251        return self._update_objective() 
    250252 
    251253    def SetConstraints(self, constraints): 
     
    263265        else: #XXX: check for format: x' = constraints(x) ? 
    264266            self._constraints = constraints 
    265         return 
     267        return self._update_objective() 
    266268 
    267269    def SetGenerationMonitor(self, monitor, new=False): 
     
    312314        if min is False or max is False: 
    313315            self._useStrictRange = False 
    314             return 
     316            return self._update_objective() 
    315317        #XXX: better to use 'defaultMin,defaultMax' or '-inf,inf' ??? 
    316318        if min is None: min = self._defaultMin 
     
    329331        self._strictMin = min 
    330332        self._strictMax = max 
    331         return 
    332  
    333     def _clipGuessWithinRangeBoundary(self, x0): #FIXME: use self.trialSolution? 
     333        return self._update_objective() 
     334 
     335    def _clipGuessWithinRangeBoundary(self, x0, at=True): 
    334336        """ensure that initial guess is set within bounds 
    335337 
     
    339341       #    raise ValueError, "initial guess must be length %s" % self.nDim 
    340342        x0 = asarray(x0) 
    341         lo = self._strictMin 
    342         hi = self._strictMax 
    343         # crop x0 at bounds 
     343        bounds = (self._strictMin,self._strictMax) 
     344        if not len(self._strictMin): return x0 
     345        # clip x0 at bounds 
    344346        settings = numpy.seterr(all='ignore') 
    345         x0[x0<lo] = lo[x0<lo] 
    346         x0[x0>hi] = hi[x0>hi] 
     347        x_ = x0.clip(*bounds) 
    347348        numpy.seterr(**settings) 
     349        if at: return x_ 
     350        # clip x0 within bounds 
     351        x_ = x_ != x0 
     352        x0[x_] = random.uniform(self._strictMin,self._strictMax)[x_] 
    348353        return x0 
    349354 
     
    391396            if min[i] is None: min[i] = self._defaultMin[0] 
    392397            if max[i] is None: max[i] = self._defaultMax[0] 
    393         import random 
    394398        #generate random initial values 
    395399        for i in range(len(self.population)): 
     
    591595    def SetObjective(self, cost, ExtraArgs=None):  # callback=None/False ? 
    592596        """decorate the cost function with bounds, penalties, monitors, etc""" 
    593         self._bootstrap_objective(cost, ExtraArgs) # callback=null (see above) 
    594         return 
    595  
    596     def _decorate_objective(self, cost, ExtraArgs=None): 
    597         """decorate the cost function with bounds, penalties, monitors, etc""" 
    598         raw = cost 
    599         if ExtraArgs is None: ExtraArgs = () 
    600         self._fcalls, cost = wrap_function(cost, ExtraArgs, self._evalmon) 
    601         if self._useStrictRange: 
    602             for i in range(self.nPop): 
    603                 self.population[i] = self._clipGuessWithinRangeBoundary(self.population[i]) 
    604             cost = wrap_bounds(cost, self._strictMin, self._strictMax) 
    605         cost = wrap_penalty(cost, self._penalty) 
    606         cost = wrap_nested(cost, self._constraints) 
    607         if self._reducer: 
    608            #cost = reduced(*self._reducer)(cost) # was self._reducer = (f,bool) 
    609             cost = reduced(self._reducer, arraylike=True)(cost) 
    610         # hold on to the 'wrapped' and 'raw' cost function 
    611         self._cost = (cost, raw, ExtraArgs) 
    612         return cost 
    613  
    614     def _bootstrap_objective(self, cost=None, ExtraArgs=None): 
    615         """HACK to enable not explicitly calling _decorate_objective""" 
    616597        _cost,_raw,_args = self._cost 
    617598        # check if need to 'wrap' or can return the stored cost 
    618599        if cost in [None, _raw, _cost] and ExtraArgs in [None, _args]: 
    619             return _cost 
     600            return 
    620601        # get cost and args if None was given 
    621602        if cost is None: cost = _raw 
     
    631612           #msg = '%s() invalid number of arguments (%d given)' % (name, val) 
    632613           #raise TypeError(msg) 
     614        # hold on to the 'raw' cost function 
     615        self._cost = (None, cost, ExtraArgs) 
     616        self._live = False 
     617        return 
     618 
     619    def _update_objective(self): 
     620        """decorate the cost function with bounds, penalties, monitors, etc""" 
     621        # rewrap the cost if the solver has been run 
     622        if False: # trigger immediately 
     623            self._decorate_objective(*self._cost[1:]) 
     624        else: # delay update until _bootstrap 
     625            self.Finalize() 
     626        return 
     627 
     628    def _decorate_objective(self, cost, ExtraArgs=None): 
     629        """decorate the cost function with bounds, penalties, monitors, etc""" 
     630        #print ("@", cost, ExtraArgs, max) 
     631        raw = cost 
     632        if ExtraArgs is None: ExtraArgs = () 
     633        self._fcalls, cost = wrap_function(cost, ExtraArgs, self._evalmon) 
     634        if self._useStrictRange: 
     635            indx = list(self.popEnergy).index(self.bestEnergy) 
     636            ngen = self.generations #XXX: no random if generations=0 ? 
     637            for i in range(self.nPop): 
     638                self.population[i] = self._clipGuessWithinRangeBoundary(self.population[i], (not ngen) or (i is indx)) 
     639            cost = wrap_bounds(cost, self._strictMin, self._strictMax) 
     640        cost = wrap_penalty(cost, self._penalty) 
     641        cost = wrap_nested(cost, self._constraints) 
     642        if self._reducer: 
     643           #cost = reduced(*self._reducer)(cost) # was self._reducer = (f,bool) 
     644            cost = reduced(self._reducer, arraylike=True)(cost) 
     645        # hold on to the 'wrapped' and 'raw' cost function 
     646        self._cost = (cost, raw, ExtraArgs) 
     647        self._live = True 
     648        return cost 
     649 
     650    def _bootstrap_objective(self, cost=None, ExtraArgs=None): 
     651        """HACK to enable not explicitly calling _decorate_objective""" 
     652        _cost,_raw,_args = self._cost 
     653        # check if need to 'wrap' or can return the stored cost 
     654        if cost in [None, _raw, _cost] and ExtraArgs in [None, _args] \ 
     655          and self._live: 
     656            return _cost 
    633657        # 'wrap' the 'new' cost function with _decorate 
    634         return self._decorate_objective(cost, args) 
    635         #XXX: **CAUTION** when _decorate called, solver._fcalls will be reset 
     658        self.SetObjective(cost, ExtraArgs) 
     659        return self._decorate_objective(*self._cost[1:]) 
     660        #XXX: when _decorate called, solver._fcalls will be reset ? 
    636661 
    637662    def _Step(self, cost=None, ExtraArgs=None, **kwds): 
     
    681706        return 
    682707 
    683     def _Finalize(self, **kwds): 
     708    def Finalize(self, **kwds): 
    684709        """cleanup upon exiting the main optimization loop""" 
    685         pass 
     710        self._live = False 
     711        return 
    686712 
    687713    def _process_inputs(self, kwds): 
     
    732758    If the algorithm does not meet the given termination conditions after 
    733759    the call to "Step", the solver may be left in an "out-of-sync" state. 
    734     When abandoning an non-terminated solver, one should call "_Finalize" 
     760    When abandoning an non-terminated solver, one should call "Finalize" 
    735761    to make sure the solver is fully returned to a "synchronized" state. 
    736762 
     
    753779            self._Step(**kwds) #FIXME: not all kwds are given in __doc__ 
    754780            if self.Terminated(): # then cleanup/finalize 
    755                 self._Finalize() 
     781                self.Finalize() 
    756782 
    757783            # get termination message and log state 
  • mystic/mystic/differential_evolution.py

    r793 r794  
    201201        return 
    202202 
     203    def SetConstraints(self, constraints): 
     204        """apply a constraints function to the optimization 
     205 
     206input:: 
     207    - a constraints function of the form: xk' = constraints(xk), 
     208      where xk is the current parameter vector. Ideally, this function 
     209      is constructed so the parameter vector it passes to the cost function 
     210      will satisfy the desired (i.e. encoded) constraints.""" 
     211        if not constraints: 
     212            self._constraints = lambda x: x 
     213        elif not callable(constraints): 
     214            raise TypeError, "'%s' is not a callable function" % constraints 
     215        else: #XXX: check for format: x' = constraints(x) ? 
     216            self._constraints = constraints 
     217        return # doesn't use wrap_nested 
     218 
    203219    def _decorate_objective(self, cost, ExtraArgs=None): 
    204220        """decorate cost function with bounds, penalties, monitors, etc""" 
     221        #print ("@", cost, ExtraArgs, max) 
    205222        raw = cost 
    206223        if ExtraArgs is None: ExtraArgs = () 
    207224        self._fcalls, cost = wrap_function(cost, ExtraArgs, self._evalmon) 
    208225        if self._useStrictRange: 
     226            indx = list(self.popEnergy).index(self.bestEnergy) 
     227            ngen = self.generations #XXX: no random if generations=0 ? 
    209228            for i in range(self.nPop): 
    210                 self.population[i] = self._clipGuessWithinRangeBoundary(self.population[i]) 
     229                self.population[i] = self._clipGuessWithinRangeBoundary(self.population[i], (not ngen) or (i is indx)) 
    211230            cost = wrap_bounds(cost, self._strictMin, self._strictMax) 
    212231        cost = wrap_penalty(cost, self._penalty) 
     
    216235        # hold on to the 'wrapped' and 'raw' cost function 
    217236        self._cost = (cost, raw, ExtraArgs) 
     237        self._live = True 
    218238        return cost 
    219239 
     
    221241        """perform a single optimization iteration 
    222242        Note that ExtraArgs should be a *tuple* of extra arguments""" 
    223         # HACK to enable not explicitly calling _decorate_objective 
    224         cost = self._bootstrap_objective(cost, ExtraArgs) 
    225243        # process and activate input settings 
    226244        settings = self._process_inputs(kwds) 
    227245        for key in settings: 
    228246            exec "%s = settings['%s']" % (key,key) 
     247 
     248        # HACK to enable not explicitly calling _decorate_objective 
     249        cost = self._bootstrap_objective(cost, ExtraArgs) 
    229250 
    230251        init = False  # flag to do 0th iteration 'post-initialization' 
     
    372393        return 
    373394 
     395    def SetConstraints(self, constraints): 
     396        """apply a constraints function to the optimization 
     397 
     398input:: 
     399    - a constraints function of the form: xk' = constraints(xk), 
     400      where xk is the current parameter vector. Ideally, this function 
     401      is constructed so the parameter vector it passes to the cost function 
     402      will satisfy the desired (i.e. encoded) constraints.""" 
     403        if not constraints: 
     404            self._constraints = lambda x: x 
     405        elif not callable(constraints): 
     406            raise TypeError, "'%s' is not a callable function" % constraints 
     407        else: #XXX: check for format: x' = constraints(x) ? 
     408            self._constraints = constraints 
     409        return # doesn't use wrap_nested 
     410 
    374411    def _decorate_objective(self, cost, ExtraArgs=None): 
    375412        """decorate cost function with bounds, penalties, monitors, etc""" 
     413        #print ("@", cost, ExtraArgs, max) 
    376414        raw = cost 
    377415        if ExtraArgs is None: ExtraArgs = () 
     
    384422        fcalls, cost = wrap_function(cost, ExtraArgs, evalmon) 
    385423        if self._useStrictRange: 
     424            indx = list(self.popEnergy).index(self.bestEnergy) 
     425            ngen = self.generations #XXX: no random if generations=0 ? 
    386426            for i in range(self.nPop): 
    387                 self.population[i] = self._clipGuessWithinRangeBoundary(self.population[i]) 
     427                self.population[i] = self._clipGuessWithinRangeBoundary(self.population[i], (not ngen) or (i is indx)) 
    388428            cost = wrap_bounds(cost, self._strictMin, self._strictMax) 
    389429        cost = wrap_penalty(cost, self._penalty) 
     
    393433        # hold on to the 'wrapped' and 'raw' cost function 
    394434        self._cost = (cost, raw, ExtraArgs) 
     435        self._live = True 
    395436        return cost 
    396437 
     
    398439        """perform a single optimization iteration 
    399440        Note that ExtraArgs should be a *tuple* of extra arguments""" 
    400         # HACK to enable not explicitly calling _decorate_objective 
    401         cost = self._bootstrap_objective(cost, ExtraArgs) 
    402441        # process and activate input settings 
    403442        settings = self._process_inputs(kwds) 
    404443        for key in settings: 
    405444            exec "%s = settings['%s']" % (key,key) 
     445 
     446        # HACK to enable not explicitly calling _decorate_objective 
     447        cost = self._bootstrap_objective(cost, ExtraArgs) 
    406448 
    407449        init = False  # flag to do 0th iteration 'post-initialization' 
  • mystic/mystic/scipy_optimize.py

    r792 r794  
    6363 
    6464 
    65 from mystic.tools import unpair 
     65from mystic.tools import wrap_function, unpair, wrap_nested 
     66from mystic.tools import wrap_bounds, wrap_penalty, reduced 
    6667 
    6768import numpy 
     
    142143        return 
    143144 
     145    def _decorate_objective(self, cost, ExtraArgs=None): 
     146        """decorate the cost function with bounds, penalties, monitors, etc""" 
     147        #print ("@", cost, ExtraArgs, max) 
     148        raw = cost 
     149        if ExtraArgs is None: ExtraArgs = () 
     150        self._fcalls, cost = wrap_function(cost, ExtraArgs, self._evalmon) 
     151        if self._useStrictRange: 
     152            if self.generations: 
     153                #NOTE: pop[0] was best, may not be after resetting simplex 
     154                for i,j in enumerate(self._setSimplexWithinRangeBoundary()): 
     155                    self.population[i+1] = self.population[0].copy() 
     156                    self.population[i+1][i] = j 
     157            else: 
     158                self.population[0] = self._clipGuessWithinRangeBoundary(self.population[0]) 
     159            cost = wrap_bounds(cost, self._strictMin, self._strictMax) 
     160        cost = wrap_penalty(cost, self._penalty) 
     161        cost = wrap_nested(cost, self._constraints) 
     162        if self._reducer: 
     163           #cost = reduced(*self._reducer)(cost) # was self._reducer = (f,bool) 
     164            cost = reduced(self._reducer, arraylike=True)(cost) 
     165        # hold on to the 'wrapped' and 'raw' cost function 
     166        self._cost = (cost, raw, ExtraArgs) 
     167        self._live = True 
     168        return cost 
     169 
    144170    def _Step(self, cost=None, ExtraArgs=None, **kwds): 
    145171        """perform a single optimization iteration 
    146172        Note that ExtraArgs should be a *tuple* of extra arguments""" 
    147         # HACK to enable not explicitly calling _decorate_objective 
    148         cost = self._bootstrap_objective(cost, ExtraArgs) 
    149173        # process and activate input settings 
    150174        settings = self._process_inputs(kwds) 
    151175        for key in settings: 
    152176            exec "%s = settings['%s']" % (key,key) 
     177 
     178        # HACK to enable not explicitly calling _decorate_objective 
     179        cost = self._bootstrap_objective(cost, ExtraArgs) 
    153180 
    154181        rho = 1; chi = 2; psi = 0.5; sigma = 0.5; 
     
    466493        """perform a single optimization iteration 
    467494        Note that ExtraArgs should be a *tuple* of extra arguments""" 
    468         # HACK to enable not explicitly calling _decorate_objective 
    469         cost = self._bootstrap_objective(cost, ExtraArgs) 
    470495        # process and activate input settings 
    471496        settings = self._process_inputs(kwds) 
    472497        for key in settings: 
    473498            exec "%s = settings['%s']" % (key,key) 
     499 
     500        # HACK to enable not explicitly calling _decorate_objective 
     501        cost = self._bootstrap_objective(cost, ExtraArgs) 
    474502 
    475503        direc = self._direc #XXX: throws Error if direc=None after generation=0 
     
    575603        return #XXX: call Terminated ? 
    576604 
    577     def _Finalize(self, **kwds): 
     605    def Finalize(self, **kwds): 
    578606        """cleanup upon exiting the main optimization loop""" 
    579         self.energy_history = None # resync with 'best' energy 
    580         self._stepmon(self.bestSolution, self.bestEnergy, self.id) 
    581         # if savefrequency matches, then save state 
    582         self._AbstractSolver__save_state() 
     607        if self.energy_history != None: 
     608            self.energy_history = None # resync with 'best' energy 
     609            self._stepmon(self.bestSolution, self.bestEnergy, self.id) 
     610            # if savefrequency matches, then save state 
     611            self._AbstractSolver__save_state() 
     612        self._live = False 
    583613        return 
    584614 
Note: See TracChangeset for help on using the changeset viewer.