André Walker-Loud <walksl...@gmail.com> wrote: > Hello python tutors, > > I am utilizing a 3rd party numerical minimization routine. This routine > requires an input function, which takes as arguments, only the variables > with which to solve for. But I don’t want to define all possible input > functions, in a giant switch, but rather, if I know I am fitting a > polynomial, I would like to just pass a list of parameters and have the > code know how to construct this function. > > To construct for example, a chisq function, you must pass not only the > variables to solve for, but also the data, uncertainties, and perhaps > other arguments. So it requires a little hacking to get it to work. With > the help of my friends and looking at similar code, I have come up with > two ways that work under my simple test cases, and I have a few questions > about them. > > The 3rd party minimizer utilizes the .func_code.co_varnames and > .func_code.co_argcount to determine the name and number of variables to > minimize. eg. > >> g = lambda x,c_0,c_1: c_0 + c_1 * x >> g.func_code.co_varnames > ('x', 'c_0', 'c_1’) >> g.func_code.co_argcount > 3 > > so what is needed is a function >> def f(c_0,c_1): >> …#construct chi_sq(c_0,c_1,x,y,…) > > ========= > METHOD 1: make classes to define functions > #create a function_structure which can be used to make the necessary > #func_code > class FunctionStruct: > def __init__(self, **kwds): > self.__dict__.update(kwds) > def __str__(self): > return self.__dict__.__str__() > def __repr__(self): > return self.__str__() > def __getitem__(self, s): > return self.__dict__[s] > > # then make a polynomial class which constructs a polynomial of order > # len(pars) > class PolynomialFunc: > def __init__(self,x,pars): > self.pars = pars > self.func_code = FunctionStruct(#create the variables used by > minimizer > co_argcount = len(pars), > co_varnames = tuple(['c_%i'%(i) for i in range(len(pars))]) > ) > def __call__(self): > self.poly = 0. > for n in range(self.func_code.co_argcount): > self.poly += self.pars[n] * x **n > return self.poly > # eg create a polynomial of order (1) which can be used in the minimizer > f = PolynomialFunc(x,[c_0,c_1]) > f.func_code.co_varnames > ('c_0', 'c_1’) > > ========= > METHOD 2: use strings, exec and globals to construct function > def minimize(pars,x,y,dy): > global g_x, g_y, g_dy > g_x = x; g_y = y; g_dy = dy > argnames = ['c_%i'%(i) for i in range(len(pars))] > funcargs = ", ".join(argnames) > funcdef = 'def chisq_mn(' + funcargs + '):\n' > funcdef += ' global g_x, g_y, g_dy\n' > funcdef += ' return chisq(['+funcargs+'],g_x,g_y,g_dy)\n’ #chisq is > defined in same file > # evaluate string and build function > print "funcdef=", funcdef > exec funcdef in globals() > > m = ThirdParty.setup_minimize(chisq_mn) > for i in range(len(pars)): > m.values[argnames[i]] = pars[i] > m.errors[argnames[i]] = 0.1 * pars[i] > return m > # then we can define > f = minimize(pars,x,y,dy,chisq_func) > > Question 1: > Is there a better way to accomplish (my hopefully clear) goals?
I think you are looking for closures: def make_poly(coeff): def poly(x): return sum(c * x ** n for n, c in enumerate(coeff)) return poly def minimize(x, y, dy): def chisq_mn(*args): return chisq(args, x, y, dy) return chisq_mn >>> def make_poly(coeff): ... def poly(x): ... return sum(c * x ** n for n, c in enumerate(coeff)) ... return poly ... >>> p = make_poly([1, 0, 1]) >>> for i in range(-4, 5): ... x = i*.25 ... print x, "->", p(x) ... -1.0 -> 2.0 -0.75 -> 1.5625 -0.5 -> 1.25 -0.25 -> 1.0625 0.0 -> 1.0 0.25 -> 1.0625 0.5 -> 1.25 0.75 -> 1.5625 1.0 -> 2.0 _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor