# Multi-variable FunctionInterpolation with the range of one variable as a function of another

How can I modify my FunctionInterpolation code so that the boundary of one of the variables is a function of another variable?

testfn = FunctionInterpolation[Sin[Sqrt[y - x]], {y, 0, 10}, {x, 0, y}]

FunctionInterpolation::range: Argument {x,0,y} is not in the form of a range specification, {x, xmin, xmax}. >>

I couldn't find this exact issue so I hope this is not a duplicate. Most of the posts that came up as a result of searching this error was about a variable range for plotting, but it doesn't seem that I can use the same approaches for defining an interpolation function with dependent ranges while using FunctionInterpolation?

• What about f = FunctionInterpolation[Sin[Sqrt[y - ty]], {y, 0, 10}, {t, 0, 1}] ? Apr 5, 2016 at 17:58
• @BlacKow hmm.. that's interesting. So you are suggesting that we can always change the variables? Also, then we can't have f[y,x] directly,right? We should define t and use f[y,y/t] instead? Apr 5, 2016 at 18:07
• I'm not sure if it's impossible to use them directly, it's more like a dirty hack... also you will need to call it as f[y,x/y] Apr 5, 2016 at 18:10
• @BlacKow right x/y, I don't know what I was thinking. Thanks, I might be able to adopt this hack. however, with this method, there's another issue of problematic y=0 too. Apr 5, 2016 at 18:14

One drawback to FunctionInterpolation on multivariate functions is that (apparently) it does no recursive subdivision to make a more accurate interpolation. (You can manually increase the density of the uniform grid with InterpolationPoints.)

Another approach would be to use the FEM functionality and ElementMeshInterpolation to construct the InterpolatingFunction. With a suitable "MeshRefinementFunction", one can adaptively refine the mesh to improve the accuracy of the interpolation as needed.

Here is an example using the OP's test function. First a mesh refinement function is constructed that tells ToElementMesh to refine the mesh where the error is too great (see below for further discussion of the error). We also use an area criterion to stop refinement when the area of the triangles get too small (which also keeps the interpolation from getting unnecessarily big). The tolerance levels for each can be adjusted to suit one's needs.

Needs["NDSolveFEM"]

ClearAll[meshRefine];
Block[{x, y, z, m},
With[{f = Function[{y, x}, Sin[Sqrt[y - x]]],          (* function to interpolate *)
interp = Simplify@ Quiet@ InterpolatingPolynomial[   (* linear interpolation-- *)
{{{y[[1]], x[[1]]}, z[[1]]},                      (* the symbols x, y, z, m *)
{{y[[2]], x[[2]]}, z[[2]]},                      (* becomes variables in Compile *)
{{y[[3]], x[[3]]}, z[[3]]}},
{m[[1]], m[[2]]}]},
meshRefine = Compile[{{vertices, _Real, 2}, {area, _Real, 0}},
Block[{x, y, z, m, f1, f2},
y = vertices[[All, 1]];
x = vertices[[All, 2]];
If[y[[3]] >= x[[3]] && y[[2]] >= x[[2]] && y[[1]] >= x[[1]],
z = f[y, x];
m = Mean[vertices];      (* use centroid as test point for error estimate *)
f1 = interp;             (* use linear interpolation to estimate error *)
f2 = f[m[[1]], m[[2]]];  (* compare with function at centroid *)
Abs[f1 - f2] > 1*^-3 &&  (* precision/accuracy measure for the interpolation *)
area > 2*^-4,           (* limit on subdivision of triangles *)
False]
]]]];

reg = ImplicitRegion[y >= x, {{y, 0, 10}, {x, 0, 10}}];
emesh = ToElementMesh[reg,
"ImproveBoundaryPosition" -> False,  (* else boundary points don't satisfy y >= x *)
"MeshRefinementFunction" -> meshRefine]
testfn = ElementMeshInterpolation[{emesh},
Function[{y, x}, Sin[Sqrt[y - x]]] @@@ emesh["Coordinates"]]


Let's examine the results. The refinement is greater where f is changing more rapidly (high second derivative):

Show[emesh["Wireframe"], Frame -> True]


Plot3D[testfn[y, x], {y, x} ∈ emesh]


The refinement is fairly consistent measured by the accuracy of the interpolation. It is slightly greater at the boundary y == x because the refinement is stopped by the area criterion. The mesh created by ToElementMesh is quadratic, but we used linear interpolation to set a criterion for the error. (I suppose that for a sufficiently fine mesh, if the linear interpolation error estimate is $\epsilon$, then the actual interpolation error will be of the order $C\,\epsilon^2$, for a suitable constant $C$ that probably depends on the function f. In any case, we used $\epsilon=10^{-3}$ as a cut-off an got an interpolation with an error around $10^{-5}$.)

Plot3D[testfn[y, x] - Sin[Sqrt[y - x]] // RealExponent,
{y, x} ∈ emesh, PlotRange -> {-10, 0}]