1 """
2 Parameter class
3 """
4 from numpy import arcsin, cos, sin, sqrt, inf, nan, random
5
6 try:
7 from collections import OrderedDict
8 except ImportError:
9 from ordereddict import OrderedDict
10
11 import re
12 from . import uncertainties
13
14
15 RESERVED_WORDS = ('and', 'as', 'assert', 'break', 'class', 'continue',
16 'def', 'del', 'elif', 'else', 'except', 'exec',
17 'finally', 'for', 'from', 'global', 'if', 'import', 'in',
18 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise',
19 'return', 'try', 'while', 'with', 'True', 'False',
20 'None', 'eval', 'execfile', '__import__', '__package__')
21
22 NAME_MATCH = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$").match
29
32 """a custom dictionary of Parameters. All keys must be
33 strings, and valid Python symbol names, and all values
34 must be Parameters.
35
36 Custom methods:
37 ---------------
38
39 add()
40 add_many()
41 """
45
54
55 - def add(self, name, value=None, vary=True, min=None, max=None, expr=None):
56 """convenience function for adding a Parameter:
57 with p = Parameters()
58 p.add(name, value=XX, ....)
59
60 is equivalent to
61 p[name] = Parameter(name=name, value=XX, ....
62 """
63 self.__setitem__(name, Parameter(value=value, name=name, vary=vary,
64 min=min, max=max, expr=expr))
65
67 """convenience function for adding a list of Parameters:
68 Here, you must provide a sequence of tuples, each containing
69 at least the name. The order in each tuple is the following:
70 name, value, vary, min, max, expr
71 with p = Parameters()
72 p.add_many( (name1, val1, True, None, None, None),
73 (name2, val2, True, 0.0, None, None),
74 (name3, val3, False, None, None, None),
75 (name4, val4))
76
77 """
78 for para in parlist:
79 self.add(*para)
80
82 """A Parameter is the basic Parameter going
83 into Fit Model. The Parameter holds many attributes:
84 value, vary, max_value, min_value, constraint expression.
85 The value and min/max values will be be set to floats.
86 """
87 - def __init__(self, name=None, value=None, vary=True,
88 min=None, max=None, expr=None):
89 self.name = name
90 self._val = value
91 self.user_value = value
92 self.init_value = value
93 self.min = min
94 self.max = max
95 self.vary = vary
96 self.expr = expr
97 self.deps = None
98 self.stderr = None
99 self.correl = None
100 if self.max is not None and value > self.max:
101 self._val = self.max
102 if self.min is not None and value < self.min:
103 self._val = self.min
104 self.from_internal = lambda val: val
105
107 s = []
108 if self.name is not None:
109 s.append("'%s'" % self.name)
110 sval = repr(self._val)
111 if self.stderr is not None:
112 sval = "value=%s +/- %.3g" % (sval, self.stderr)
113 if not self.vary and self.expr is None:
114 sval = "value=%s (fixed)" % (sval)
115 s.append(sval)
116 s.append("bounds=[%s:%s]" % (repr(self.min), repr(self.max)))
117 if self.expr is not None:
118 s.append("expr='%s'" % (self.expr))
119 return "<Parameter %s>" % ', '.join(s)
120
122 """set up Minuit-style internal/external parameter transformation
123 of min/max bounds.
124
125 returns internal value for parameter from self.value (which holds
126 the external, user-expected value). This internal values should
127 actually be used in a fit....
128
129 As a side-effect, this also defines the self.from_internal method
130 used to re-calculate self.value from the internal value, applying
131 the inverse Minuit-style transformation. This method should be
132 called prior to passing a Parameter to the user-defined objective
133 function.
134
135 This code borrows heavily from JJ Helmus' leastsqbound.py
136 """
137 if self.min in (None, -inf) and self.max in (None, inf):
138 self.from_internal = lambda val: val
139 _val = self._val
140 elif self.max in (None, inf):
141 self.from_internal = lambda val: self.min - 1 + sqrt(val*val + 1)
142 _val = sqrt((self._val - self.min + 1)**2 - 1)
143 elif self.min in (None, -inf):
144 self.from_internal = lambda val: self.max + 1 - sqrt(val*val + 1)
145 _val = sqrt((self.max - self._val + 1)**2 - 1)
146 else:
147 self.from_internal = lambda val: self.min + (sin(val) + 1) * \
148 (self.max - self.min) / 2
149 _val = arcsin(2*(self._val - self.min)/(self.max - self.min) - 1)
150 return _val
151
153 """returns scaling factor for gradient the according to Minuit-style
154 transformation.
155 """
156 if self.min in (None, -inf) and self.max in (None, inf):
157 return 1.0
158 elif self.max in (None, inf):
159 return val / sqrt(val*val + 1)
160 elif self.min in (None, -inf):
161 return -val / sqrt(val*val + 1)
162 else:
163 return cos(val) * (self.max - self.min) / 2.0
164
165
167 """get value, with bounds applied"""
168 if (self._val is not nan and
169 isinstance(self._val, uncertainties.Variable)):
170 self._val = self._val.nominal_value
171
172 if self.min is None:
173 self.min = -inf
174 if self.max is None:
175 self.max = inf
176 if self.max < self.min:
177 self.max, self.min = self.min, self.max
178
179 try:
180 if self.min > -inf:
181 self._val = max(self.min, self._val)
182 if self.max < inf:
183 self._val = min(self.max, self._val)
184 except(TypeError, ValueError):
185 self._val = nan
186 return self._val
187
188 @property
190 "get value"
191 return self._getval()
192
193 @value.setter
195 "set value"
196 self._val = val
200
202 "abs"
203 return abs(self._getval())
204
206 "neg"
207 return -self._getval()
208
210 "positive"
211 return +self._getval()
212
214 "not zero"
215 return self._getval() != 0
216
218 "int"
219 return int(self._getval())
220
222 "long"
223 return long(self._getval())
224
226 "float"
227 return float(self._getval())
228
232
234 "+"
235 return self._getval() + other
236
238 "-"
239 return self._getval() - other
240
242 "/"
243 return self._getval() / other
244 __truediv__ = __div__
245
247 "//"
248 return self._getval() // other
249
251 "divmod"
252 return divmod(self._getval(), other)
253
255 "%"
256 return self._getval() % other
257
259 "*"
260 return self._getval() * other
261
263 "**"
264 return self._getval() ** other
265
267 ">"
268 return self._getval() > other
269
271 ">="
272 return self._getval() >= other
273
275 "<="
276 return self._getval() <= other
277
279 "<"
280 return self._getval() < other
281
283 "=="
284 return self._getval() == other
286 "!="
287 return self._getval() != other
288
290 "+ (right)"
291 return other + self._getval()
292
294 "/ (right)"
295 return other / self._getval()
296 __rtruediv__ = __rdiv__
297
299 "divmod (right)"
300 return divmod(other, self._getval())
301
303 "// (right)"
304 return other // self._getval()
305
307 "% (right)"
308 return other % self._getval()
309
311 "* (right)"
312 return other * self._getval()
313
315 "** (right)"
316 return other ** self._getval()
317
319 "- (right)"
320 return other - self._getval()
321
323 "test for Parameter-ness"
324 return (isinstance(x, Parameter) or
325 x.__class__.__name__ == 'Parameter')
326