0

I have a function of four input variables which I am trying to minimize using the Levenburg-Marquardt optimization method. The previous results where the Hessian/Gradient is calculated using Forward Difference Approximation wasn't accurate enough so, I wanted to add the Hessian/Gradient as a callable argument to the least_squares() method. This is what I have tried --

Using Sympy, I calculated the gradient and the Hessian using

gradient_vec = [diff(obj_func, var) for var in (x1, x2, y1, y2)]
hessian_mat = [[obj_func.diff(var1).diff(var2) for var1 in list((x1, x2, y1, y2))] for var2 in list((x1, x2, y1, y2))]
grad_func = lambdify([x1, x2, y1, y2, f], gradient_vec, 'numpy')
hess_matr_func = lambdify([x1, x2, y1, y2, f], hessian_mat, 'numpy')

where f is an additional argument to both the gradient and hessian functions. In my leastsq function call I have (my objective function has only one input),

result = leastsq(obj_fun, x0=np.random.uniform(size=(4,)), Dfun=grad_func, args=(f,))

I run this and I keep getting this error

TypeError: obj_fun() takes 1 positional argument but 2 were given

So, I tried the least_squares() function with method='lm' argument and when I pass the Hessian as,

result = least_squares(obj_fun, x0=np.random.uniform(size=(4,), method='lm', jac=hess_matr_func, args=(f,))

And I still get the same error. How do I pass an argument *args but to the Gradient/Hessian callables alone? I tried using the functools.partial to create a wrapper around the callable function and even that didn't help. Thanks very much for your help!

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Can you post the code for your objective function? – Siva-Sg May 07 '19 at 05:28
  • The objective function is proprietary, I'm afraid, I cannot post it here. But it has two complex numbers which change with frequency ```f```. Since optimizing over C^n == R^2n, I have four variables in my search space. – Vijay Karthik May 07 '19 at 05:36
  • Assuming this error `TypeError: obj_fun() takes 1 positional argument but 2 were given` is in your `obj_fun()`, you need to change the declaration of your function to `def obj_fun(x, *args): ` and then unpack your passed variable using `f = args[0]`. Otherwise, you need to edit your question, without a minimal code example to reproduce the error, there is not much we can do. – SuperKogito May 07 '19 at 11:33

1 Answers1

0

I don't think you can have different arguments for the function and its derivatives.

One way around could be to store that extra argument as an attribute (python functions can have attributes, too). Or create a class with a single-argument method and store that extra attribute on the instance.

ev-br
  • 24,968
  • 9
  • 65
  • 78
  • Could you elaborate a bit on your solution, please? I have now come to a solution of using Lambda function of one variable to wrap around my ```hess_matr_func()```. It is an ugly solution but it is what I could do. Any small example can help. Thanks! – Vijay Karthik May 12 '19 at 17:07