JamesHudson81
JamesHudson81

Reputation: 2273

struggling minimizing non linear function

I am looking forward to minimize a non linear function with 3 arguments (x1,x2 and x3)

My sources of information are:

I do not belong to a mathematical area, so first off forgive me if I am using incorrect wording / expressions.

This is my code :

import numpy as np
from scipy.optimize import minimize

def rosen(x1,x2,x3):
    return np.sqrt(((x1**2)*0.002)+((x2**2)*0.0035)+((x3**2)*0.0015)+(2*x1*x2*0.015)+(2*x1*x3*0.01)+(2*x2*x3*0.02))

I think that the first step is okey up to here..

Then it is required to state the:

x0 : ndarray
Initial guess. len(x0) is the dimensionality of the minimization problem.

Given that I am stating 3 args in the minimization function I shall state a 3 dim array , such like this?

x0=np.array([1,1,1])

res = minimize(rosen, x0)
print(res.x)

The undesired output is:

rosen() missing 2 required positional arguments: 'x2' and 'x3'

Which I do not really understand where shall I state the positional arguments.

Apart from that I would like to set some bounds for the outputing values for x1,x2,x3 .

Which I tried

res = minimize(rosen, x0,  bounds=([0,None]),options={"disp": False})

Which outputs also that :

ValueError: length of x0 != length of bounds

How should I then express the bounds inside the res then?

The desired output would be simply to output an array for x1,x2,x3 according to the minimization of the function where each value is minimun 0, as stated in the bounds and that the sum of the args add up to 1.

Upvotes: 0

Views: 752

Answers (1)

sascha
sascha

Reputation: 33522

Function-definition

Read the docs carefully, e.g. for your function-def:

fun : callable

The objective function to be minimized. Must be in the form f(x, *args). The
optimizing argument, x, is a 1-D array of points, and args is a tuple of any
additional fixed parameters needed to completely specify the function.

Your function should take a 1d-array, while you implement the multi-argument for multi-variables approach!

Changing:

def rosen(x1,x2,x3):
    return np.sqrt(((x1**2)*0.002)+((x2**2)*0.0035)+((x3**2)*0.0015)+(2*x1*x2*0.015)+(2*x1*x3*0.01)+(2*x2*x3*0.02))

def rosen(x):
    x1,x2,x3 = x # unpack vector for your kind of calculations
    return np.sqrt(((x1**2)*0.002)+((x2**2)*0.0035)+((x3**2)*0.0015)+(2*x1*x2*0.015)+(2*x1*x3*0.01)+(2*x2*x3*0.02))

should work. This is a bit a repair-something-to-keep-my-other-code approach but won't hurt much in this example. Usually you implement your function-definition on the 1d-array-input assumption!

Bounds

Again from the docs:

bounds : sequence, optional

Bounds for variables (only for L-BFGS-B, TNC and SLSQP). (min, max) pairs for each
element in x, defining the bounds on that parameter. Use None for one of min or max
when there is no bound in that direction.

So you need n_vars pairs! Easily achieved by using a list-comprehension, deducing the necessary info from x0.

res = minimize(rosen, x0,  bounds=[[0,None] for i in range(len(x0))],options={"disp": False})

Make variables sum up to 1 / Constraints

Your comment implies you want the variables to sum up to 1. You would need to use an equality-constraint then (only 1 solver supporting this and inequality-constraints; one other only inequality-constraints; the rest no constraints; solver will be picked automatically if none explicitly given).

It looks somewhat like:

cons = ({'type': 'eq', 'fun': lambda x:  sum(x) - 1})  # read docs to understand!
                                                       # to think about:
                                                       # sum vs. np.sum
                                                       # (not much diff here)
res = minimize(rosen, x0,  bounds=[[0,None] for i in range(len(x0))],options={"disp": False}, constraints=cons)

For the case of x nonnegative, the constraint is usually called the probability-simplex.

(untested code; conceptually correct!)

Upvotes: 2

Related Questions