python - Replacing complex-valued arguments of generic function object by two real-valued arguments -


curve fitting tools such in scipy tend assume parameters of model functions real-valued. when fitting model depends on complex-valued parameters complex-valued data set, 1 therefore first has create version of model, in each complex parameter replaced 2 real ones.

first, simple example:

# original function, representing model a,b may complex-valued def f(x, a, b):     return a+b*x  # modified function, complex parameters have been replaced 2 real ones def f_r(x, a_r, a_i, b_r, b_i):     return f(x, a_r + 1j*a_i, b_r+1j*b_i)  print( f(1,2+3j,4+5j) == f_r(1,2,3,4,5) ) 

note: output of model still complex-valued, can taken care of appropriately defining residual function.

now, instead of having write new code every function f, have "function factory" pass function object f list of booleans is_complex specifying arguments of f assumed complex-valued (and therefore need replaced 2 real-valued arguments). list of booleans e.g. inferred initial values provided f.

i new kind of problem, looked around on web , came across decorator module. before going generic case, here example above using functionmaker class:

import decorator  def f(x, a, b):     return a+b*x  f_r = decorator.functionmaker.create(     'f_r(x, a_r, a_i, b_r, b_i)',     'return f(x, a_r + 1j*a_i, b_r + 1j*b_i)',     dict(f=f)) 

for generic case, 1 can imagine synthesize 2 strings passed function maker:

import decorator import inspect  def f(x, a, b):     return a+b*x  def fmaker(f,is_complex):     argspec = inspect.getargspec(f)     args = argspec.args[:]     fname = f.func_name      s1 = "{}_r(".format(fname)     s2 = "return f("     arg, cplx in zip(args, is_complex):         if not cplx:             s1 += "{},".format(arg)             s2 += "{},".format(arg)         else:             s1 += "{}_r,".format(arg)             s1 += "{}_i,".format(arg)             s2 += "{}_r+1j*{}_i,".format(arg,arg)      s1 += ')'     s2 += ')'     return decorator.functionmaker.create(s1,s2,dict(f=f))  is_complex = [false, true, true] f_r = fmaker(f,is_complex)  # prints argspec(args=['x', 'a_r', 'a_i', 'b_r', 'b_i'], varargs=none, keywords=none, defaults=()) print(inspect.getargspec(f_r))  print( f(1,2+3j,4+5j) == f_r(1,2,3,4,5) ) 

this seems solve problem.

my question is: reasonable way of doing this? there better/simpler ways in python?

p.s. not computer scientist, if using technical terms incorrectly, please feel free revise.

you not have nasty string based generation, can use basic function closures create wrapper:

def complex_unroll(f, are_complex):      # function have access are_complex , f through python closure     # *args give access parameters list     def g(*args, **kwargs):         # new_args stores new list of parameters, complex ones         new_args = []         # arg_id iterator used keep track in original list         arg_id = 0         is_complex in are_complex:                     if is_complex:                 # if request complex unroll, merge 2 consequtive params                 new_args.append(args[arg_id] + 1j*args[arg_id+1])                 # , move iterator 2 slots                 arg_id += 2             else:                 # otherwise, copy argument                 new_args.append(args[arg_id])                 arg_id += 1         # return call original function f new args         return f(*new_args, **kwargs)      # our unroll function returns newly designed function g     return g 

and now

def f(x, a, b):     return a+b*x  def f_r(x, a_r, a_i, b_r, b_i):     return f(x, a_r + 1j*a_i, b_r+1j*b_i)  f_u = complex_unroll(f, [false, true, true])  print f(1,2+3j,4+5j) print f_r(1,2,3,4,5) print f_u(1,2,3,4,5)  f_u2 = complex_unroll(f, [true, true, true])  print f_u2(1,0,2,3,4,5) 

works desired.

why prefer path compared proposed 1 in question?

  • it not use any additional modules/libraries, basic mechanism of python's dealing arguments , closures. in particular solution reflection, analyzes defined function, quite complex operation compared try obtain.
  • it handles named arguments fine, if have f(x, a, b, flag), can still use g = complex_unroll(f, [false, true, true]) , call g(0, 0, 0, 0, 0, flag = true), fail in code. add support this, though.

Comments

Popular posts from this blog

ios - RestKit 0.20 — CoreData: error: Failed to call designated initializer on NSManagedObject class (again) -

java - Digest auth with Spring Security using javaconfig -

laravel - PDOException in Connector.php line 55: SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES) -