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

Reply via email to