To me the question is more about calculating the function than generating the plot.
Given an equation that cannot be solved symbolically, we can approximate the implicit function with NDSolve
. (There are several examples on this site., e.g., Getting an InterpolatingFunction from a ContourPlot, Plotting implicitly-defined space curves.)
implicitFunction::usage = "implicitFunction[equation, {y, y0}, {x, x0, start, end}]";
Begin["implicitFunction`"];
implicitFunction[eq_, {f_Symbol, f1_?NumericQ},
{x_Symbol, x1_?NumericQ, xmin_?NumericQ, xmax_?NumericQ}] :=
Block[{f0, xt},
f0 = f /. FindRoot[eq /. x -> x1, {f, f1}];
NDSolveValue[
{eq /. {x -> x[xt], f -> f[xt]}, x'[xt] == 1, f[x1] == f0, x[x1] == x1},
f, {xt, xmin, xmax}]
];
End[];
We need to propose a domain for our approximation and approximate initial values for x
and y
. FindRoot
is used to refine the initial value for the function x
.
eq1 = Exp[x y] == y;
ξ = implicitFunction[eq1, {x, 0}, {y, 1, -3, 3}];
NDSolveValue::ndsz: At implicitFunction`xt == 1.111713753522611`*^-16
, step size is effectively zero; singularity or stiff system suspected. >>
The warning just means that NDSolve
has computed the domain for us:
ξ["Domain"]
(* {{1.11171*10^-16, 3.}} *)
Plot[ξ[y] + y, Evaluate @ Flatten[{y, ξ["Domain"]}]]
One could further process the result by wrapping the interpolating function with FindRoot
. For this we need to add the attribute HoldAll
. The following could be incorporated as a second definition of implicitFunction
, but here I'll simply make a second definition. The only advantage is when a more accurate value is needed. One can take advantage of the FindRoot
options.
SetAttributes[implicitFunction2, HoldAll];
implicitFunction2[eq_, f_Symbol, x_Symbol, init_: (0 &), opts : OptionsPattern[FindRoot]][x1_?NumericQ] :=
Block @@ Hold[{f, x}, f /. FindRoot[eq /. x -> x1, {f, init[x1]}]];
The init
function supplies the initial value for the root. We can use the NDSolve
interpolating function to do that (at least within its domain).
ξ2 = implicitFunction2[eq1, x, y, ξ];
Plot[ξ2[y] + y, Evaluate@Flatten[{y, ξ["Domain"]}]]
(* plot looks the same as above *)
This form also works with the default init
, but that is because the equation is easy to solve from any starting point.
ξ2 = implicitFunction2[eq1, x, y];
Of course, it's slower than just using ξ
.
ClearAll[f, g, h]; f[x_, y_] := x + y; g[y_] := Log[y]/y; h[y_] := f[g[y], y]
$\endgroup$