source: sasview/park-1.2.1/park/fitmc.py @ f3efa09

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalccostrafo411magnetic_scattrelease-4.1.1release-4.1.2release-4.2.2release_4.0.1ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249ticket885unittest-saveload
Last change on this file since f3efa09 was 084afb4, checked in by pkienzle, 10 years ago

fix random initial conditions for infinite ranges in amoeba fit

  • Property mode set to 100644
File size: 6.3 KB
Line 
1
2# The job queue needs to be in a transaction/rollback protected database.
3# If the server is rebooted, long running jobs should continue to work.
4#
5from __future__ import division
6import numpy
7
8import simplex
9
10import fitresult, pmap, fit
11
12__all__ = ['fitmc', 'FitMCJob']
13
14class LocalFit(object):
15    """
16    Abstract interface for a local minimizer
17
18    See `park.fitmc.FitSimplex` for a concrete implementation.
19    """
20    def fit(self, objective, x0):
21        """
22        Minimize the value of a fitness function.
23
24        See `park.fitmc.Fitness` for the definition of the goodness of fit
25        object.  x0 is a vector containing the initial value for the fit.
26        """
27    def abort(self):
28        """
29        Cancel the fit.  This will be called from a separate execution
30        thread.  The fit should terminate as soon as possible after this
31        function has been called.  Ideally this would interrupt the
32        cur
33        """
34
35class FitSimplex(LocalFit):
36    """
37    Local minimizer using Nelder-Mead simplex algorithm.
38
39    Simplex is robust and derivative free, though not very efficient.
40
41    This class wraps the bounds contrained Nelder-Mead simplex
42    implementation for `park.simplex.simplex`.
43    """
44    radius = 0.05
45    """Size of the initial simplex; this is a portion between 0 and 1"""
46    xtol = 1
47    #xtol = 1e-4
48    """Stop when simplex vertices are within xtol of each other"""
49    ftol = 1e-4
50    """Stop when vertex values are within ftol of each other"""
51    maxiter = None
52    """Maximum number of iterations before fit terminates"""
53    def fit(self, fitness, x0):
54        """Run the fit"""
55        self.cancel = False
56        pars = fitness.fit_parameters()
57        bounds = numpy.array([p.range for p in pars]).T
58        result = simplex.simplex(fitness, x0, bounds=bounds,
59                                 radius=self.radius, xtol=self.xtol,
60                                 ftol=self.ftol, maxiter=self.maxiter,
61                                 abort_test=self._iscancelled)
62        #print "calls:",result.calls
63        #print "simplex returned",result.x,result.fx
64        # Need to make our own copy of the fit results so that the
65        # values don't get stomped on by the next fit iteration.
66        fitpars = [fitresult.FitParameter(pars[i].name,pars[i].range,v)
67                   for i,v in enumerate(result.x)]
68        res = fitresult.FitResult(fitpars, result.calls, result.fx)
69        # Compute the parameter uncertainties from the jacobian
70        res.calc_cov(fitness)
71        return res
72
73    def abort(self):
74        """Cancel the fit in progress from another thread of execution"""
75        # Effectively an atomic operation; rely on GIL to protect it.
76        self.cancel = True
77        # Abort the current function evaluation if possible.
78        if hasattr(fitness,'abort'): self.fitness.abort()
79
80    def _iscancelled(self): return self.cancel
81
82class MapMC(object):
83    """
84    Evaluate a local fit at a particular start point.
85
86    This is the function to be mapped across a set of start points for the
87    monte carlo map-reduce implementation.
88
89    See `park.pmap.Mapper` for required interface.
90    """
91    def __init__(self, minimizer, fitness):
92        self.minimizer, self.fitness = minimizer, fitness
93    def __call__(self, x0):
94        return self.minimizer.fit(self.fitness,x0)
95    def abort(self):
96        self.minimizer.abort()
97
98class CollectMC(object):
99    """
100    Collect the results from multiple start points in a Monte Carlo fit engine.
101
102    See `park.pmap.Collector` for required interface.
103    """
104    def __init__(self, number_expected, handler):
105        self.number_expected = number_expected
106        """Number of starting points to check with local optimizer"""
107        self.iterations = 0
108        self.best = None
109        self.calls = 0
110        self.handler = handler
111        self.handler.done = False
112    def __call__(self, result):
113        # Keep track of the amount of work done
114        self.iterations += 1
115        self.calls += result.calls
116        if self.best is None or result.fitness < self.best.fitness:
117            self.best = result
118            self.handler.result = result
119            self.handler.improvement()
120        # Progress should go after improvement in case the fit handler
121        # wants to suppress intermediate improvements
122        self.handler.progress(self.iterations, self.number_expected)
123    def abort(self):
124        self.handler.done = True
125        self.handler.abort()
126    def finalize(self):
127        self.handler.result.calls = self.calls
128        self.handler.done = True
129        self.handler.finalize()
130    def error(self, msg):
131        self.handler.done = True
132        self.handler.error(msg)
133
134def fitmc(fitness, x0, bounds, localfit, n, handler):
135    """
136    Run a monte carlo fit.
137
138    This procedure maps a local optimizer across a set of n initial points.
139    The initial parameter value defined by the fitness parameters defines
140    one initial point.  The remainder are randomly generated within the
141    bounds of the problem.
142
143    localfit is the local optimizer to use.  It should be a bounded
144    optimizer following the `park.fitmc.LocalFit` interface.
145
146    handler accepts updates to the current best set of fit parameters.
147    See `park.fitresult.FitHandler` for details.
148    """
149    # Generate random number within bounds.  If bounds are indefinite, use [0,1]
150    # If bounds are semi-definite, use [low,low+1] or [high-1,high], depending
151    # on which limit is unbounded.
152    lo,hi = bounds
153    inf_lo = numpy.isinf(lo)
154    inf_hi = numpy.isinf(hi)
155    delta = hi-lo
156    delta[inf_lo|inf_hi] = 1.0
157    lo[inf_lo] = hi[inf_lo] - 1.0
158    lo[inf_lo&inf_hi] = 0.0
159    P = numpy.random.rand(n,len(x0))*delta+lo
160    #print "Population",P
161    P[0] = x0
162
163    pmap.pmapreduce(MapMC(localfit,fitness),
164                    CollectMC(n,handler),
165                    P)
166
167class FitMC(fit.Fitter):
168    """
169    Monte Carlo optimizer.
170
171    This implements `park.fit.Fitter`.
172    """
173    localfit = FitSimplex()
174    start_points = 10
175
176    def _fit(self, objective, x0, bounds):
177        """
178        Run a monte carlo fit.
179
180        This procedure maps a local optimizer across a set of initial points.
181        """
182        fitmc(objective, x0, bounds, self.localfit,
183              self.start_points, self.handler)
184
185if __name__ == "__main__":
186    fit.demo2(FitMC(localfit=FitSimplex(),start_points=10))
Note: See TracBrowser for help on using the repository browser.