Problem with incorrect response of the minimize function of the scipy library in Python

89 Views Asked by At

To calculate electrical circuits, I encountered the problem of an incorrect response from the minimize functions when calculating circuits with a parallel connection. For example this:

parallel connections

Creating a matrix of connections and fill in the resistance matrix: Equation of the form: A*x = V ,where function sum(F * x**3) -> minimum

import numpy as np
from scipy.optimize import minimize, LinearConstraint

def CreateArrays(A,V):
    A = np.array(A) #matrix of connections
    V = np.array(V)
    buf = [0.1 for i in range(len(A[0]))]
    x0 = np.array(buf)
    return A,V,x0

def start(A,V,F):
    def obj_func(x):
        return np.sum(F * x**3)
    A,V,x0 = CreateArrays(A,V)
    lincon = LinearConstraint(A, lb=V, ub=V)
    
    res = minimize(obj_func, x0, method='trust-constr', constraints=lincon)
    return res.x
#Matrix of connections, vector V, vector F
I = start([[1, 0, 1], [0, -1, -1], [-1, 1, 0]], 
      [100, -100, 0],[1e-4, 1e-4, 8e-4])
print(I)

The result is [33.36666667 33.36666667 66.63333333] but it's a mistake; the true result is [66.63333333, 66.63333333, 33.36666667], where value of function is minimum. The higher the resistance, the lower the electric currents.

I find minimum with this code:

f = [1e-4,1e-4,8e-4]
s=0

save = 0.5
x = [0.5,0.5,99.5]
for i in range(len(x)):
    s = s + f[i] * x[i]**3
mini = s                     #start minimum
print(mini)
j = 0.5
while j < 100:
    x = [j, j, 100-j]  
    s=0
    for i in range(len(x)):
        s = s + f[i] * x[i]**3 
    if s < mini:
        mini = s
        save = x  
    j =j +  0.5
print(mini,save)
1

There are 1 best solutions below

1
On BEST ANSWER

It seems like the problem is here:

lincon = LinearConstraint(A, lb=V, ub=V)

This constraint seemed to mess up SLSQP, COBYLA, and trust-constr. SLSQP complains about singular constraint matrices. COBYLA complains that it only supports ineq constraints, not eq constraints. trust-constr works, but make no progress once it has found a solution that satisfies the constraints.

I found two things that helped.

The first was to use a better initial guess for x0, by starting with something that obeys the constraints.

def CreateArrays(A,V):
    A = np.array(A) #matrix of connections
    V = np.array(V)
    x0 = np.linalg.lstsq(A, V, rcond=None)[0]
    return A,V,x0

The second thing was to give the linear constraint some wiggle room, and allow it to be off in either direction by an epsilon. Initially, the linear constraint is allowed to vary by 0.001, and it is reduced from there.

def start(A,V,F):
    def obj_func(x):
        ret = np.sum(F * x**3)
        return ret
    A,V,x0 = CreateArrays(A,V)
    for eps in [1e-3, 1e-6, 1e-9, 0]:
        lincon = LinearConstraint(A, lb=V - eps, ub=V + eps)
        res = minimize(obj_func, x0, method='trust-constr', constraints=lincon)
        x0 = res.x
    return res.x

With these changes, trust-constr and COBYLA can both solve this.