0
votes

Currently, I have the following code that defines the function func

from scipy.optimize import minimize
import sympy as sp
x2=sp.Symbol('x2')
u2=sp.Symbol('u2')
fm=25*u2-20.0*(sp.sin(x2)) + 38.7296387*(sp.cos(x2)) - 38.7296387
def func(x2,u2):
    return -fm
def constraint1(u2,x2):
    return -u2+40*sp.sin(x2)+0.2
def constraint2(u2,x2):
    return -u2-40*sp.sin(x2)+0.2
b=[-1,1]
bnds=[b,b]
con1 = {'type': 'ineq', 'fun': constraint1}
con2 = {'type': 'ineq', 'fun': constraint2}
cons = ([con1,con2])
x0=[0,0]
solution = minimize(func,x0,method='SLSQP',bounds=bnds,constraints=cons)

I am minimizing f with respect to x2 and u2. SciPy's optimization toolbox doesn't allow for one to minimize functions with Sympy variables in the arguments. Is there a way I can do this?

1
Why aren't you writing your functions using numpy, which scipy does understand? If you really need sympy functionality (e.g. symbolically calculated derivatives), sympy's lambdify can convert the final functions to their numpy form. - JohanC
Sympy's lambdify is the best tool for converting a sympy expression into a numpy function. func needs to be valid numpy, without any sympy symbols or objects. Scipy is built on numpy, and "knows" nothing about sympy. - hpaulj
I have a mathematical model in python which gives equation and constraint in SymPy variables. I need to optimize the equation - Mukunthan s

1 Answers

1
votes

SymPy is a symbolic mathematics library while SciPy is a numeric mathematics library. SciPy does not understand anything to do with SymPy's symbols and it will only work with numeric values such as floats.

You must try and make every single variable have its own name in order to avoid confusion. That means clearly separating your numeric values of x with its symbolic values. For example, in func, you do nothing with your input values x2 and u2 possibly due to this confusion. fm is a symbolic expression that SciPy does not understand. To get a float from fm, you need to evaluate it at a point using subs().

The second mistake is that SciPy uses functions that take a single tuple input instead of a function with multiple float inputs. You need to separate the inputs yourself within the function.

The third mistake is swapping x2 and u2 between func, constraint1 and constraint2. This would cause the conditions' inputs to be swapped which would create a completely different constraint to what you were expecting.

Here is your code with these 3 fixes:

from scipy.optimize import minimize
import sympy as sp

x2_symbol = sp.Symbol('x2')
u2_symbol = sp.Symbol('u2')
fm = 25 * u2_symbol - 20.0 * (sp.sin(x2_symbol)) + 38.7296387 * (sp.cos(x2_symbol)) - 38.7296387

def func(x):
    x2_float, u2_float = x
    return -fm.subs([(x2_symbol, x2_float), (u2_symbol, u2_float)])

def constraint1(x):
    x2_float, u2_float = x
    return -u2_float + 40 * sp.sin(x2_float) + 0.2

def constraint2(x):
    x2_float, u2_float = x
    return -u2_float - 40 * sp.sin(x2_float) + 0.2

b = [-1, 1]
bounds = [b, b]
con1 = {'type': 'ineq', 'fun': constraint1}
con2 = {'type': 'ineq', 'fun': constraint2}
constraints = (con1, con2)
x0 = [0, 0]
solution = minimize(func, x0, method='SLSQP', bounds=bounds, constraints=constraints)
print(solution)

I assume fm was achieved from a previous solution to another problem and so must contain symbols. If not, this problem could be solved purely numerically with very little change to the code above.

You could also solve this problem purely symbolically using Karush–Kuhn–Tucker conditions. I may post a solution for that if I feel up to it.