Optimización de Python usando sympy lambdify y scipy

Estoy tratando de maximizar una función definida por Sympy pero no puedo hacer que funcione. La idea básica se puede resumir de la siguiente manera:

import sympy from scipy.optimize import minimize from sympy.utilities.lambdify import lambdify a,b,G = sympy.symbols('ab G') func = (G - a)**2 + b my_func = lambdify((G,a,b), -1*func) results = minimize(my_func,[0.1,0.1,0.1]) 

El código funciona si defino una función de una sola variable, pero mientras tenga más de una variable, recibo el siguiente mensaje de error.

  TypeError: () takes exactly 3 arguments (1 given) 

¿Puede alguien ayudarme a identificar dónde salió mal?

Como señaló @Dair, la etiqueta de sympy en general requiere más de un argumento, mientras que scipy espera solo un argumento, una lista (o una matriz) que contenga todos los valores de cada variable. Debido a que mi función objective se define más convenientemente usando sympy, necesito encontrar una manera de evitar esta incompatibilidad entre sympy y scipy.

@lhcgeneva señaló la respuesta a una pregunta similar . Esta respuesta no maneja convenientemente un gran número de variables independientes, especialmente cuando el número de variables independientes puede cambiar, lo que requiere que se redefina la versión “vectorizada” de la función objective. Sin embargo, inspirado en esta publicación, descubrí la siguiente solución usando * tuple ():

  import sympy from scipy.optimize import minimize from sympy.utilities.lambdify import lambdify a,b,G = sympy.symbols('ab G') func = -1*((G - a)**2 + b) my_func = lambdify((G,a,b), func) def my_func_v(x): return my_func(*tuple(x)) results = minimize(my_func_v,[0.1,0.1,0.1]) 

En el ejemplo que di, parece innecesario usar * tuple (), pero para el problema que quiero resolver, me ahorra muchos problemas. Aquí hay un ejemplo que es más similar a la pregunta que quiero resolver.

 NUM_VAR = 10 x = np.array(sympy.symbols('x0:%d'%NUM_VAR)) func = np.sum((x-1)**2) my_func = lambdify(x, func) def my_func_v(x): return my_func(*tuple(x)) results = minimize(my_func_v,np.zeros(NUM_VAR)) 

Esta cosa * tuple () puede evitar que escriba todos los elementos de x como el siguiente (para el caso de NUM_VAR = 10):

 def my_func_v(x): return my_func(x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9]) 

Además, no necesitamos cambiar my_func_v cuando NUM_VAR cambia.