Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python scipy fsolve "mismatch between the input and output shape of the 'func' argument"

Tags:

python

scipy

Before I go into my problem, I've searched the relevant threads on stackoverflow with the same problem:

  • input/output error in scipy.optimize.fsolve
  • Python fsolve() complains about shape. Why?
  • fsolve - mismatch between input and output
  • I/O shape mismatch when using scipy.optimize.fsolve on 2-dimensional anonymous function array variable

From what I understand reading about this error,

raise TypeError(msg)
TypeError: fsolve: there is a mismatch between the input and output shape of the 'func' argument 'fsolve_function'

The issue is that the shape of the input and output are not the same.

In my code example below, I have the following:

  • input, initialGuess (the starting estimate to be used in the fsolve function in scipy.optimize). The input, initialGuess has 3 starting estimates for coordinates x,y and z. Therefore I expect my starting input estimate to have always three inputs.
  • output, out (non-linear simultaneous equations). In this example I have 4 non-linear equations.
  • scipy.optimize.fsolve raises the error highlighted above, because the input and output do not have the same shape. In my particular case, I want my input to always have three values (to guess the initial starting points of x, y, and z). The output in this case has 4 non-linear equations to solve using the initial input estimate.
  • Side note: Using the same input and output shape, eg. input shape of 3 [x, y, z] and output of 3 non-linear equations, fsolve will do the calculation accordingly. I'm just wondering how could you extend fsolve to use let's say equal or more than 4 non-linear simultaneous equations with just 3 input initial estimates?
  • Code below:

    from scipy.optimize import fsolve
    
    def fsolve_function(arguments):
        x = arguments[0]
        y = arguments[1]
        z = arguments[2]
    
        out = [(35.85 - x)**2 + (93.23 - y)**2 + (-39.50 - z)**2 - 15**2]
        out.append((42.1 - x)**2 + (81.68 - y)**2 + (-14.64 - z)**2 - 27**2)
        out.append((-70.90 - x)**2 + (-55.94 - y)**2 + (-68.62 - z)**2 - 170**2)
        out.append((-118.69 - x)**2 + (-159.80 - y)**2 + (-39.29 - z)**2 - 277**2)
    
        return out
    
    initialGuess = [35, 93, -39]
    result = fsolve(fsolve_function, initialGuess)
    print result 
    
like image 248
Djuro Mirkovic Avatar asked Jun 04 '15 06:06

Djuro Mirkovic


1 Answers

fsolve is a wrapper of MINPACK's hybrd, which requires the function's argument and output have the same number of elements. You can try other algorithms from the more general scipy.optimize.root that do not have this restriction (e.g. lm):

from scipy.optimize import fsolve, root

def fsolve_function(arguments):
    x = arguments[0]
    y = arguments[1]
    z = arguments[2]

    out = [(35.85 - x)**2 + (93.23 - y)**2 + (-39.50 - z)**2 - 15**2]
    out.append((42.1 - x)**2 + (81.68 - y)**2 + (-14.64 - z)**2 - 27**2)
    out.append((-70.90 - x)**2 + (-55.94 - y)**2 + (-68.62 - z)**2 - 170**2)
    out.append((-118.69 - x)**2 + (-159.80 - y)**2 + (-39.29 - z)**2 - 277**2)

    return out

initialGuess = [35, 93, -39]
result = root(fsolve_function, initialGuess, method='lm')
print(result.x)

Incidentally, it cannot find the actual zero --- is there supposed to be one at all?

You can also force fsolve to use your function if you supply it an initial guess with a "bogus" fourth variable:

initialGuess = [35, 93, -39, 0]

but I'm not sure how reliable are the results in this case.

like image 179
fjarri Avatar answered Nov 14 '22 12:11

fjarri