Skip to main content

equation solving - Forcing FindRoot to return only real solutions


FindRoot documentation reports that if the equation and the initial point are reals, the solutions are searched in the real domain. However, in the following case I get a complex solution


FindRoot[eq, {h, 1.7}]
{h -> -0.990042 - 0.689686 I}

Same for



Assuming[Reals, FindRoot[eq, {h, 1.7}]]

Where eq is the following. What can I do to force Mathematica to return only real solutions?


eq = 0.2888960456513873` \[Sqrt](0.4149486782073932` + (0.5637605604986459` + 
h)^2) \[Sqrt](0.4756674436221575` + (0.9900423417575865` +
h)^2) + 2.2076945564517114` h \[Sqrt](0.4149486782073932` +
(0.5637605604986459` +
h)^2) \[Sqrt](0.4756674436221575` + (0.9900423417575865` +
h)^2) + 6.735521430523215` h^2 \[Sqrt](0.4149486782073932` +
(0.5637605604986459` +

h)^2) \[Sqrt](0.4756674436221575` + (0.9900423417575865` +
h)^2) + 10.54153050379155` h^3 \[Sqrt](0.4149486782073932` +
(0.5637605604986459` +
h)^2) \[Sqrt](0.4756674436221575` + (0.9900423417575865` +
h)^2) + 8.93280406600778` h^4 \[Sqrt](0.4149486782073932` +
(0.5637605604986459` +
h)^2) \[Sqrt](0.4756674436221575` + (0.9900423417575865` +
h)^2) + 3.8752891330788843` h^5 \[Sqrt](0.4149486782073932` +
(0.5637605604986459` +
h)^2) \[Sqrt](0.4756674436221575` + (0.9900423417575865` +

h)^2) + 0.666148416209407` h^6 \[Sqrt](0.4149486782073932` +
(0.5637605604986459` +
h)^2) \[Sqrt](0.4756674436221575` + (0.9900423417575865` +
h)^2) + 0.4167441738314279` \[Sqrt](0.4756674436221575` +
(0.9900423417575865` +
h)^2) \[Sqrt](1 - (0.4444444444444444`
(-0.022551321792606827` + (0.5637605604986459` +
h)^2)^2)/(0.4149486782073932` + (0.5637605604986459` +
h)^2))

Answer




It will be more convenient to define the function eq this way :


eq[h_] := the formula

Real solutions


For a general technique of using FindRoot the way you would like I recommend to read this post : First positive root. However in order to demonstrate how it works for real numbers we should have a different equation since this one has no real solutions :


NSolve[ eq[h] == 0, h, Reals]


{}


Sometimes it is reasonable to restrict the search for roots to a special region, e.g. if we add an inequality 0 < h < 3 then we don't have to specify the domain Reals because the system understands that h must be real :


NSolve[ eq[h] == 0 && 0 < h < 3, h ]

General remarks on using NSolve you could find here : Solve an equation in R+ since they are valid for Solve as well as for NSolve.


For the function f we can find a global minimum of the real part :


nmin = { h /. #[[2]], #[[1]]}& @ NMinimize[ Re @ eq[h], h]


{-1.83596, 0.100607}


For an idea what we can expect let's plot the real and imaginary parts of f :


Plot[{Re @ eq[h], Im @ eq[h]}, {h, -3, 2}, PlotStyle -> Thick, PlotRange -> {-1, 4}, 
Epilog -> {Red, PointSize[0.015], Point[nmin]},
PlotLegends -> {Placed["Expressions", {Left, Center}]}]

enter image description here


Even though eq has no real roots we can see that one can expect real solutions e.g. for eq[h] - 3/2 near h == -2 and h == 0, using FindRoot with appropriate starting points we find :


FindRoot[ eq[h] - 3/2, #]& /@ {{h, -2}, {h, 0}}



 {{h -> -2.15793}, {h -> 0.14209}}

For deeper understandig of the behavior of the eq function we should take a look at the complex plane.


Complex solutions


The complex roots can be rewritten as pairs of real numbers :


pts = {Re @ #, Im @ #}& /@ (h /. NSolve[ eq[h] == 0, h])


{{-1.86925, 0.135055}, {-1.86925, -0.135055}, {-1.08654, 0.84989},
{-1.08654, -0.84989}, {-0.990042, 0.689686}, {-0.990042, -0.689686},

{-0.0268207, 0.391104}, {-0.0268207, -0.391104}}

Let's visualize the function eq in the complex plane :


GraphicsRow[ 
Table[ Show[ ContourPlot @@@ {
{ g[eq[x + I y]], {x, -2.5, 0.5}, {y, -1.5, 1.5},
PlotLabel -> Style[ g[HoldForm @ eq[x + I y]], Blue, 25],
ColorFunction -> "DeepSeaColors", Epilog -> { Darker @ Green, PointSize[0.03],
Point[pts] } },
{ Re @ eq[x + I y] == 0, {x, -2.5, 0.5}, {y, -1.5, 1.5},

ContourStyle -> {Red, Thick}},
{ Im @ eq[x + I y] == 0, {x, -2.5, 0.5}, {y, -1.5, 1.5}, PlotPoints -> 50,
MaxRecursion -> 3, ContourStyle -> {Cyan, Thick}}}],

{g, {Re, Im}} ] ]

enter image description here


The green points denote the complex roots, you can see that there are no real roots. The red lines are solutions to Re[ eq[h] ] == 0 while the cyan lines denote solutions to Im[ eq[h] ] == 0. One can see a that there are some branch cuts on the plots, i.e. the definition of the function eq is reliable only if we use it in appropriate regions in the complex plane.


Comments

Popular posts from this blog

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...