Evgeni Sergeev
Evgeni Sergeev

Reputation: 23601

fsolve returns complex solution — how to limit to real search space only?

Sometimes the fsolve(..) function in Matlab returns a solution with non-zero imaginary part. It's not discussed in its help page how to select whether the search space should be complex-valued or real-valued. There is obviously a big difference, as we're giving it twice as many degrees of freedom if we allow the variables to take on complex values.

The specific example that got me into this trouble was:

>> fsolve(@(x) [-exp(x(1)*x(2)^0.9)+exp(x(1).*(1+x(2)).^0.9) - (1-1e-7), ...
                 exp(x(1)*x(2)^0.9)*0.9*x(1)/x(2)^(0.1)], [10 1])

Equation solved, inaccuracy possible.

The vector of function values is near zero, as measured by the default value
of the function tolerance. However, the last step was ineffective.

<stopping criteria details>


ans =

  18.3396 + 0.2529i  -1.0000 - 0.0000i

How to restrict the domain to real numbers only?

Upvotes: 2

Views: 8808

Answers (1)

Evgeni Sergeev
Evgeni Sergeev

Reputation: 23601

This post by MathWorks Support says that if the objective function ever returns a complex number, then fsolve(..) automatically switches to treat the input variable as being complex as well.

I don't see this as logical behaviour, but that's the way it works. See rant below.

In the example from the question this probably happens because fsolve(..) calls the anonymous function with x(2) being negative at some point, which the function then raises to the power of 0.1, producing a complex output.

Anyway, the two suggestions in the above post are to

  1. Constrain the domain.

  2. Or adjust the function to not return complex numbers.

Now, there is no way documented on fsolve's help page of bounding the domain, but checking this answer, it turns out that there is a function lsqnonlin(..), which is very similar to fsolve(..), except that it does allow us to specify lower and upper bounds on the variables. Also, it uses the same input format and algorithms, with the only conspicuous difference being that it doesn't include the "trust region dogleg" method, that fsolve(..) does.

This solved my problem.

The other idea, to use a change of variables, could also work.


<rant> If a function returns complex values and we would like to find a point where it's zero, we would effectively be setting two constraints on the input variables using just one equation. Why should that imply that our search space is complex? These issues are independent. But fsolve(..) tries to be helpful. It's easy to get around this once you know it's happening. </rant>

Upvotes: 2

Related Questions