5
votes

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

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 
    
1

1 Answers

8
votes

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.