Skip to main content

interpolation - Complex continuation of an interpolated function


Context


I have a complicated real function defined implicitly by a series of imbricated numerical integration. I need to make a continuation of this function for a complex variable which is easily performed keeping the structure of imbricated integrations.


However, because I then need to perform a lot of computations afterwards everything works fine except that it is very very slow. I would rather manipulate something that does not require performing over and over the same integrations and thus came the idea to interpolate this function in an appropriated interval.


Now I can interpolate the real part and the imaginary parts of the prolonged function as multivariable expressions but it seems way more smarter, at least on paper, to interpolate the real function directly and then perform a complex continuation.


Question



Is there a way to do that directly ? I think if I could get the coefficients of the polynomial used by Interpolation (Hermite by default) I could perform this.




Attempt


For the sake of argument let me take an arbitrary function $f$ so that I can give you a more precise coded version of what I want to do.


MyFunc[a_] := 6 a^2 ;
MyTable = Table[{a, MyFunc[a]}, {a, -1, 2, 0.1}];
MyApproximateFunc = Interpolation[MyTable];
GraphicsRow[{Plot[MyFunc[a], {a, -1, 2}],Plot[MyApproximateFunc[a], {a, -1, 2}]}]

enter image description here But then


MyApproximateFunc[1 + I]


only returns something like enter image description here


However I can always do :


MyFunc[a_, b_] := Im[6*(a + I b)^2];
MyTable = Table[{a, b, MyFunc[a, b]}, {a, -1, 2, 0.1}, {b, -1, 2, 0.1}] // Flatten[#, 1] &;
MyApproximateFunc = Interpolation[MyTable];

GraphicsRow[{Plot3D[MyFunc[a, b], {a, -1, 2}, {b, -1, 2}], Plot3D[MyApproximateFunc[a , b], {a, -1, 2}, {b, -1, 2}]}]

and the same thing for the real part.


enter image description here



I am new to the Mathematica StackExchange even if I have used StackExchange before =)



Answer



There are limitations to extending polynomial interpolation on a real interval to the complex plane. The limitations are related to the Bernstein ellipse (see also Trefethen, Approximation Theory and Approximation Practice esp. Ch. 8 or this excerpt, pp. 41f, Bernstein (1912), etc.). Updated: You imply you can interpolate over complex values in the domain (I think I misread or overlooked this initially), in which case there is a way to get an accurate interpolation over a disk, as alluded to by @J.M. in a comment above. See for instance, Boyd, Solving Transcendental Equations. There is an update below the examples of extending real interpolation. It show an example that gives a much better approximation over a complex disk.


Extending real interpolations to the complex plane


Below are three interpolation schemes for approximating a Bessel function on a real interval, Chebyshev, Legendre, and a uniform grid. The first two are more accurate over a larger domain and show how outside the Bernstein ellipse, the interpolation fails to converge to the function. The third scheme suffers from the well-known Runge phenomenon on the real line and does not extend as gracefully to the complex plane. The plots show the relative error on the complex plane and the (real) interpolation interval {a, b}. The error in the complex plane is clipped at 0.001.


Note that interpolation is sensitive to whether the function is entire or has singularities/poles. It's probable that if the accuracy of the approximation of the function at the interpolation nodes on the real interval is limited, it will impact the accuracy of the extension to the complex plane.


func[x_] := BesselJ[0, x];
{a, b} = {0, 20};(*interval of approximation*)

(* Chebyshev interpolation *)

nnodes = 64;(* degree *)
xnodes = Rescale[N[Sin[π/2 Range[-nnodes, nnodes, 2]/nnodes]], {-1, 1}, {a, b}];
ynodes = func /@ xnodes;
wts = Developer`ToPackedArray@Table[(-1.)^n, {n, 0, nnodes}];
wts[[{1, -1}]] = 1/2.;

(* interpolating function if[] *)
if = Statistics`Library`BarycentricInterpolation[xnodes, ynodes, Weights -> wts];

errplot[{-15, -3}, {x, a - 0.1 (b - a), b + 0.1 (b - a)}, {y, -7.5, 7.5},

PlotLabel -> "Chebyshev interpolation"]
Plot[relerr[x] // RealExponent, {x, a, b}]


(* Gauss-Legendre interpolation *)
nnodes = 64;(* degree *)
{xnodes, wts} = Most@NIntegrate`GaussRuleData[nnodes + 1, MachinePrecision];
wts = (b - a) wts;
wts = (-1)^Range[0, nnodes] Sqrt[(1 - Rescale[xnodes, {0, 1}, {-1, 1}]^2) wts];
xnodes = Rescale[xnodes, {0, 1}, {a, b}];

ynodes = Developer`ToPackedArray[func /@ xnodes, Real];
if = Statistics`Library`BarycentricInterpolation[xnodes, ynodes, Weights -> wts];

errplot[{-14, -3}, {x, a - 0.1 (b - a), b + 0.1 (b - a)}, {y, -7.5, 7.5},
PlotLabel -> "Gauss-Legendre interpolation"]
Plot[relerr[x] // RealExponent, {x, a, b}]


(* regular grid: caveat the Runge phenomenon *)
nnodes = 64; (* degree *)

xnodes = Rescale[N[Range[0, nnodes]/nnodes], {0, 1}, {a, b}];
ynodes = func /@ xnodes;
if = Statistics`Library`BarycentricInterpolation[xnodes, ynodes];

errplot[{-14, -3}, {x, a - 0.1 (b - a), b + 0.1 (b - a)}, {y, -7.5, 7.5},
PlotLabel -> "Regular grid: caveat the Runge phenomenon"]
Plot[relerr[x] // RealExponent, {x, a, b}]


Here's the Chebyshev interpolation with some white noise on the order of $10^{-10}$ added. It reduces the accuracy on the real line by about 5-6 digits as expected with machine precision, but it also reduces the size of the ellipse (the minor axis parallel to the imaginary axis).



(* Chebyshev interpolation with noise *)
nnodes = 64;(* degree *)
xnodes = Rescale[N[Sin[π/2 Range[-nnodes, nnodes, 2]/nnodes]], {-1, 1}, {a, b}];
ynodes = func /@ xnodes;
ynodes += RandomReal[1*^-10 {-1, 1}, Length@ynodes]; (* add noise *)
wts = Developer`ToPackedArray@Table[(-1.)^n, {n, 0, nnodes}];
wts[[{1, -1}]] = 1/2.;
if = Statistics`Library`BarycentricInterpolation[xnodes, ynodes, Weights -> wts];

errplot[{-11, -3}, {x, a - 0.1 (b - a), b + 0.1 (b - a)}, {y, -7.5, 7.5},

PlotLabel -> "Chebyshev interpolation with noise"]
Plot[relerr[x] // RealExponent, {x, a, b}]


If you're satisfied with a less accurate interpolation, then a low-degree polynomial can be used, for which the Bernstein ellipse plays less of a role. Here's a regular interval with fewer points that gives a few digits of accuracy, but it gives such accuracy over a large segment of the complex plane:


(* "Regular grid: low degree, low accuracy" *)
nnodes = 20;(* degree *)
xnodes = Rescale[N[Range[0, nnodes]/nnodes], {0, 1}, {a, b}];
ynodes = func /@ xnodes;
if = Statistics`Library`BarycentricInterpolation[xnodes, ynodes];


errplot[{-14, -3}, {x, a - 0.1 (b - a), b + 0.1 (b - a)}, {y, -7.5, 7.5},
PlotLabel -> "Regular grid, low degree: greater convergence to lower accuracy"]
Plot[relerr[x] // RealExponent, {x, a, b}]




Update: Complex interpolation


Below is an interpolation through points on a circle in the complex plane with the diameter given by the real interval {a, b}. This gives a highly accurate approximation of the function within the circle, provided the function has no poles inside or on the circle. (The peaks in relative error along the real line inside the disk are due the roots of the Bessel function func[z].)


(* Fourier interpolation on a complex disk *)

nn = 64; (* number of interpolation points *)
z0 = (a + b)/2; (* center of circle *)
rr = (a + b)/2; (* radius of circle *)
wp = MachinePrecision; (* working precision *)
tj = 2 Pi*Range[0, nn - 1]/nn;
zj = N[z0 + rr Exp[I tj], wp]; (* interpolation nodes *)
fj = func /@ zj; (* function values on nodes *)
if = Statistics`Library`BarycentricInterpolation[zj, fj,
Weights -> Exp[2 Pi I Range[0., nn - 1]/nn]];


errplot[{-15, -5},
{x, a - 0.1 (b - a), b + 0.1 (b - a)},
{y, -(a + b)/2 - 0.1 (b - a), (a + b)/2 + 0.1 (b - a)},
PlotLabel -> "Fourier interpolation on a complex disk"]


Appendix: Plotting utilities


In relerr[z] there are some "smoothing" parameters, wp and acc. Since error can be noisy, especially in a log plot (via RealExponent[] above) when the error is small, I've added a small constant on the order of rounding error at the working precision. These are akin to Precision and Accuracy in Mathematica. This speeds up Plot3D by reducing adaptive refinement and affects the error negligibly.


(* error plot utilities *)
ClearAll[relerr, errleg, colorlist, errplot];

relerr[z_,
wp_: Rationalize[$MachinePrecision, 0],
acc_: Rationalize[$
MachinePrecision, 0]] :=
10^-wp + Abs@(if[z] - func[z])/(10^-acc + Abs@func[z]);
colorlist0 = Join[
Table[Blend[{ColorData[97][2], White}, n/8], {n, 0, 4}],
Table[Blend[{ColorData[97][1], White}, n/8], {n, 0, 4}]];
colorlist[{min0_, max0_}] :=
With[{min = min0 - 1, max = max0 + 1},
PadRight[#, max - min + 1, #] &@RotateLeft[colorlist0, Mod[min, 10]]

];
errleg[{min0_, max0_}] :=
With[{min = min0 - 1, max = max0 + 1},
BarLegend[{colorlist[{min, max}], 10.^{min, max}},
10.^Range[min, max],
LegendLabel -> "Rel.err."]
];
SetAttributes[errplot, HoldAll];
errplot[errRange_, {x_, x1_, x2_}, {y_, y1_, y2_}, opts___] :=
Legended[

Plot3D[relerr[x + I y] // RealExponent, {x, x1, x2}, {y, y1, y2},
opts,
Mesh -> {Range @@ errRange}, MeshFunctions -> {#3 &},
MeshShading -> colorlist[errRange],
AxesLabel -> {HoldForm[x], HoldForm[I y], "log err"},
NormalsFunction -> None, ViewPoint -> {0, -1, 5},
PlotRange -> errRange + {-1, 0}, FaceGrids -> {{0, 0, 1}}],
errleg[errRange]
];

Comments

Popular posts from this blog

plotting - Filling between two spheres in SphericalPlot3D

Manipulate[ SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, Mesh -> None, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], {n, 0, 1}] I cant' seem to be able to make a filling between two spheres. I've already tried the obvious Filling -> {1 -> {2}} but Mathematica doesn't seem to like that option. Is there any easy way around this or ... Answer There is no built-in filling in SphericalPlot3D . One option is to use ParametricPlot3D to draw the surfaces between the two shells: Manipulate[ Show[SphericalPlot3D[{1, 2 - n}, {θ, 0, Pi}, {ϕ, 0, 1.5 Pi}, PlotPoints -> 15, PlotRange -> {-2.2, 2.2}], ParametricPlot3D[{ r {Sin[t] Cos[1.5 Pi], Sin[t] Sin[1.5 Pi], Cos[t]}, r {Sin[t] Cos[0 Pi], Sin[t] Sin[0 Pi], Cos[t]}}, {r, 1, 2 - n}, {t, 0, Pi}, PlotStyle -> Yellow, Mesh -> {2, 15}]], {n, 0, 1}]

plotting - Plot 4D data with color as 4th dimension

I have a list of 4D data (x position, y position, amplitude, wavelength). I want to plot x, y, and amplitude on a 3D plot and have the color of the points correspond to the wavelength. I have seen many examples using functions to define color but my wavelength cannot be expressed by an analytic function. Is there a simple way to do this? Answer Here a another possible way to visualize 4D data: data = Flatten[Table[{x, y, x^2 + y^2, Sin[x - y]}, {x, -Pi, Pi,Pi/10}, {y,-Pi,Pi, Pi/10}], 1]; You can use the function Point along with VertexColors . Now the points are places using the first three elements and the color is determined by the fourth. In this case I used Hue, but you can use whatever you prefer. Graphics3D[ Point[data[[All, 1 ;; 3]], VertexColors -> Hue /@ data[[All, 4]]], Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}]

plotting - Mathematica: 3D plot based on combined 2D graphs

I have several sigmoidal fits to 3 different datasets, with mean fit predictions plus the 95% confidence limits (not symmetrical around the mean) and the actual data. I would now like to show these different 2D plots projected in 3D as in but then using proper perspective. In the link here they give some solutions to combine the plots using isometric perspective, but I would like to use proper 3 point perspective. Any thoughts? Also any way to show the mean points per time point for each series plus or minus the standard error on the mean would be cool too, either using points+vertical bars, or using spheres plus tubes. Below are some test data and the fit function I am using. Note that I am working on a logit(proportion) scale and that the final vertical scale is Log10(percentage). (* some test data *) data = Table[Null, {i, 4}]; data[[1]] = {{1, -5.8}, {2, -5.4}, {3, -0.8}, {4, -0.2}, {5, 4.6}, {1, -6.4}, {2, -5.6}, {3, -0.7}, {4, 0.04}, {5, 1.0}, {1, -6.8}, {2, -4.7}, {3, -1.