Fast application of InterpolatingFunction over transformed coordinates
up vote
2
down vote
favorite
I have an InterpolatingFunction
that takes $(x, y)$ coordinates as input and I would like to apply it to a series of data that is rotated by $frac{pi}{4}$ into $(frac{1}{sqrt{2}}(x+y), frac{1}{sqrt{2}}(x-y)))$ coordinates.
Here's a sample function:
FunctionInterpolation[
Sin[θ]*Cos[ϕ],
{θ, 0, 2 π},
{ϕ, 0, π}
]
Furthermore, if the value is off the interpolation grid I don't want to extrapolate, but would rather provide a default value. In general my use case has very steep walls and so I basically make this infinity.
Now, I've written code to do this quickly using Compile
, but I'd like to generalize this and potentially do better. The Compile
code is long (and still has a "MainEvaluate"
call) so I'll post it as an answer at some later time.
So what's the fastest way to apply that InterpolatingFunction
to a transformed set of coordinates (we can assume the transformation can be compiled) with a default value off the standard grid?
performance-tuning
add a comment |
up vote
2
down vote
favorite
I have an InterpolatingFunction
that takes $(x, y)$ coordinates as input and I would like to apply it to a series of data that is rotated by $frac{pi}{4}$ into $(frac{1}{sqrt{2}}(x+y), frac{1}{sqrt{2}}(x-y)))$ coordinates.
Here's a sample function:
FunctionInterpolation[
Sin[θ]*Cos[ϕ],
{θ, 0, 2 π},
{ϕ, 0, π}
]
Furthermore, if the value is off the interpolation grid I don't want to extrapolate, but would rather provide a default value. In general my use case has very steep walls and so I basically make this infinity.
Now, I've written code to do this quickly using Compile
, but I'd like to generalize this and potentially do better. The Compile
code is long (and still has a "MainEvaluate"
call) so I'll post it as an answer at some later time.
So what's the fastest way to apply that InterpolatingFunction
to a transformed set of coordinates (we can assume the transformation can be compiled) with a default value off the standard grid?
performance-tuning
add a comment |
up vote
2
down vote
favorite
up vote
2
down vote
favorite
I have an InterpolatingFunction
that takes $(x, y)$ coordinates as input and I would like to apply it to a series of data that is rotated by $frac{pi}{4}$ into $(frac{1}{sqrt{2}}(x+y), frac{1}{sqrt{2}}(x-y)))$ coordinates.
Here's a sample function:
FunctionInterpolation[
Sin[θ]*Cos[ϕ],
{θ, 0, 2 π},
{ϕ, 0, π}
]
Furthermore, if the value is off the interpolation grid I don't want to extrapolate, but would rather provide a default value. In general my use case has very steep walls and so I basically make this infinity.
Now, I've written code to do this quickly using Compile
, but I'd like to generalize this and potentially do better. The Compile
code is long (and still has a "MainEvaluate"
call) so I'll post it as an answer at some later time.
So what's the fastest way to apply that InterpolatingFunction
to a transformed set of coordinates (we can assume the transformation can be compiled) with a default value off the standard grid?
performance-tuning
I have an InterpolatingFunction
that takes $(x, y)$ coordinates as input and I would like to apply it to a series of data that is rotated by $frac{pi}{4}$ into $(frac{1}{sqrt{2}}(x+y), frac{1}{sqrt{2}}(x-y)))$ coordinates.
Here's a sample function:
FunctionInterpolation[
Sin[θ]*Cos[ϕ],
{θ, 0, 2 π},
{ϕ, 0, π}
]
Furthermore, if the value is off the interpolation grid I don't want to extrapolate, but would rather provide a default value. In general my use case has very steep walls and so I basically make this infinity.
Now, I've written code to do this quickly using Compile
, but I'd like to generalize this and potentially do better. The Compile
code is long (and still has a "MainEvaluate"
call) so I'll post it as an answer at some later time.
So what's the fastest way to apply that InterpolatingFunction
to a transformed set of coordinates (we can assume the transformation can be compiled) with a default value off the standard grid?
performance-tuning
performance-tuning
asked 3 hours ago
b3m2a1
26k256152
26k256152
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
up vote
2
down vote
Setting up the function and the default value. Notice that I force Mathematica to use machine precision numbers in f
.
f = FunctionInterpolation[Sin[θ]*Cos[ϕ], {θ, 0., 2. π}, {ϕ, 0., 1. π}];
default = 0.;
Generating several example points.
n = 100000;
x = RandomReal[{0, 2 Pi}, {n}];
y = RandomReal[{0, Pi}, {n}];
{x, y} = 1/Sqrt[2.] {x + y, x - y};
Now, let's find the points within the domain of f
:
inregionQ = UnitStep[x] UnitStep[2 Pi - x] UnitStep[y] UnitStep[Pi - y];
idx = Random`Private`PositionsOf[inregionQ, 1];
And let's apply f
only to these points:
result = ConstantArray[default, Length[x]];
result[[idx]] = f[x[[idx]], y[[idx]]]; // AbsoluteTiming // First
0.741009
It is still not super fast but the reason is that InterpolatingFunction
s are rather slow. As we may use a regular tensor grid for f
, applying it to many points at once could be way faster with a more appropriate binning and parallelization strategy...
Just for comparison: This is the timing of the evalation of the original function:
result2 = ConstantArray[default, Length[x]];
result2[[idx]] = Sin[x[[idx]]] Cos[y[[idx]]]; // AbsoluteTiming // First
0.001445
It is more than 500 times faster. This tells us (i) that the function to interpolate has to be very complex in order to take advantage of FunctionInterpolation
and (ii) that there must be a lot potential to improve the performance of InterpolationFunction
.
Interesting approach. Never seenRandom`Private`PositionsOf
but it looks useful, esp. withUnitStep
for picking indices.
– b3m2a1
2 hours ago
Yeah, Carl Woll used it a couple of times. I really like it. It is much faster thanPosition
for finding integers and it is also faster thanPick[Range[Length[inregionQ]],inregionQ,1]
.
– Henrik Schumacher
2 hours ago
Ah, I see. Yeah. Dunno. It is a black box for me and I only use it for integer lists anyway. I suspect a compiled function behind it, so I do not expect much flexibility from it.
– Henrik Schumacher
2 hours ago
Per your comparison, I have no analytic form for my original thing and probably no hope ever to have an analytic form. I could try some fits but what fit to use it a mystery as it's a high dimensional system. Hence my hope to deal with interpolation really nicely.
– b3m2a1
2 hours ago
1
Yeah. I did not mean to poke you about that. My hope was more towards a random WRI developer stumbling upon this and feeling an itching... ;)
– Henrik Schumacher
1 hour ago
add a comment |
up vote
1
down vote
Here's my version of this. I use it internally in a discretized function object to provide a nice compiled functional form. One other thing this does is allow you to set some coordinates to a constant value to take slices through the function:
iInterpCompile[interp_, coords_, preProcessor_, def_, min_] :=
Module[{potInterp = interp, dom = interp[[1]], j = 1},
Block[{crds, pt, gps},
Module[
{
getPot,
varBlock,
varBlock2,
preCoords
},
getPot[a_] := Apply[potInterp, a];
preCoords =
Quiet@
preProcessor@
Map[
If[# === Automatic,
Compile`GetElement[crds, j++],
#
] &,
coords
];
j = 1;
(* bounds checking for test *)
With[
{
test =
With[
{
tests =
MapThread[
#[[1]] <=
If[NumericQ[#2],
j++; #2,
Compile`GetElement[pt, j++]
] <= #[[2]] &,
{dom, preCoords}
]
},
If[MemberQ[tests, False],
False,
And @@ DeleteCases[tests, True]
]
],
crdSpec = preCoords,
means = Mean /@ dom,
fn =
Compile[
{{crds, _Real, 1}},
Evaluate@preCoords,
RuntimeAttributes -> {Listable}
]
},
Compile @@
Hold[(* True Compile body but with Hold for code injection *)
{{gps, _Real, 2}},
Module[
{
pts = fn@gps,
ongrid = Table[0, {i, Length@gps}],
intres,
midpt = means,
interpvals,
interpcounter,
interppts,
i = 1,
barrier = def,
minimum = min
},
interppts = Table[midpt, {i, Length@pts}];
(* Find points in domain *)
interpcounter = 0;
Do[
If[test,
ongrid[[i]] = 1;
interppts[[++interpcounter]] = pt
];
i++,
{pt, pts}
];
(* Apply InterpolatingFunction only once (one MainEval call) *)
If[interpcounter > 0,
intres = interppts[[;; interpcounter]];
interpvals = getPot[Transpose@intres] - minimum;
(* Pick points that are in domain *)
interpcounter = 0;
Map[
If[# == 1, interpvals[[++interpcounter]], barrier] &,
ongrid
],
Table[barrier, {i, Length@gps}]
]
],
{{getPot[_], _Real, 1}},
RuntimeOptions -> {
"EvaluateSymbolically" -> False,
"WarningMessages" -> False
},
CompilationOptions -> {"InlineExternalDefinitions" -> True},
RuntimeAttributes -> {Listable}
]
]
]
]
]
Options[InterpCompile] =
{
"CoordinateTransformation" -> Identity,
"Minimum" -> 0.,
"Default" -> 0.,
"Mode" -> "Vector"
};
InterpCompile[
interp_,
coordSpec : {(Automatic | _?NumericQ) ..} | Automatic : Automatic,
ops : OptionsPattern
] :=
If[OptionValue["Mode"] === "Vector",
iInterpCompile[
interp,
Replace[
coordSpec,
Automatic :> ConstantArray[Automatic, Length@interp[[1]]]
],
OptionValue["CoordinateTransformation"],
OptionValue["Default"],
OptionValue["Minimum"]
]
]
Here's a sample usage. First set up the compiled function:
ga =
CoordinateBoundsArray[
{{0., 2. π}, {0., 1. π}},
{π/24., π/24.}
];
fn =
Interpolation@
Flatten[
Join[
ga,
Map[
{Sin[#[[1]]]*Cos[#[[2]]]} &,
ga,
{2}
],
3
],
1
];
cf =
InterpCompile[fn,
"CoordinateTransformation" ->
(1/Sqrt[2.]*
{
#[[2]] + #[[1]], #[[1]] - #[[2]]
}
&
)];
Then test the timing:
cf@testGrid; // RepeatedTiming
{0.47, Null}
And plot the result:
cf@testGrid // ListPlot3D[#, PlotRange -> All] &
It's only barely faster than Henrik's method and multiple orders of magnitude more complex, but on the other hand it's pretty much fully general, which is convenient.
We can also use it to take slices through the interpolation:
With[
{
cf2 =
InterpCompile[fn,
{Automatic, #},
"CoordinateTransformation" ->
(1/Sqrt[2.]*
{
#[[2]] + #[[1]], #[[1]] - #[[2]]
}
&
)]
},
Transpose@{#, cf2@Transpose@{#}} &@Range[-8, 8, .001] //
ListLinePlot[#, ImageSize -> 250] &
] & /@ Range[-3, 3] // Partition[#, 2] & // GraphicsGrid
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
Setting up the function and the default value. Notice that I force Mathematica to use machine precision numbers in f
.
f = FunctionInterpolation[Sin[θ]*Cos[ϕ], {θ, 0., 2. π}, {ϕ, 0., 1. π}];
default = 0.;
Generating several example points.
n = 100000;
x = RandomReal[{0, 2 Pi}, {n}];
y = RandomReal[{0, Pi}, {n}];
{x, y} = 1/Sqrt[2.] {x + y, x - y};
Now, let's find the points within the domain of f
:
inregionQ = UnitStep[x] UnitStep[2 Pi - x] UnitStep[y] UnitStep[Pi - y];
idx = Random`Private`PositionsOf[inregionQ, 1];
And let's apply f
only to these points:
result = ConstantArray[default, Length[x]];
result[[idx]] = f[x[[idx]], y[[idx]]]; // AbsoluteTiming // First
0.741009
It is still not super fast but the reason is that InterpolatingFunction
s are rather slow. As we may use a regular tensor grid for f
, applying it to many points at once could be way faster with a more appropriate binning and parallelization strategy...
Just for comparison: This is the timing of the evalation of the original function:
result2 = ConstantArray[default, Length[x]];
result2[[idx]] = Sin[x[[idx]]] Cos[y[[idx]]]; // AbsoluteTiming // First
0.001445
It is more than 500 times faster. This tells us (i) that the function to interpolate has to be very complex in order to take advantage of FunctionInterpolation
and (ii) that there must be a lot potential to improve the performance of InterpolationFunction
.
Interesting approach. Never seenRandom`Private`PositionsOf
but it looks useful, esp. withUnitStep
for picking indices.
– b3m2a1
2 hours ago
Yeah, Carl Woll used it a couple of times. I really like it. It is much faster thanPosition
for finding integers and it is also faster thanPick[Range[Length[inregionQ]],inregionQ,1]
.
– Henrik Schumacher
2 hours ago
Ah, I see. Yeah. Dunno. It is a black box for me and I only use it for integer lists anyway. I suspect a compiled function behind it, so I do not expect much flexibility from it.
– Henrik Schumacher
2 hours ago
Per your comparison, I have no analytic form for my original thing and probably no hope ever to have an analytic form. I could try some fits but what fit to use it a mystery as it's a high dimensional system. Hence my hope to deal with interpolation really nicely.
– b3m2a1
2 hours ago
1
Yeah. I did not mean to poke you about that. My hope was more towards a random WRI developer stumbling upon this and feeling an itching... ;)
– Henrik Schumacher
1 hour ago
add a comment |
up vote
2
down vote
Setting up the function and the default value. Notice that I force Mathematica to use machine precision numbers in f
.
f = FunctionInterpolation[Sin[θ]*Cos[ϕ], {θ, 0., 2. π}, {ϕ, 0., 1. π}];
default = 0.;
Generating several example points.
n = 100000;
x = RandomReal[{0, 2 Pi}, {n}];
y = RandomReal[{0, Pi}, {n}];
{x, y} = 1/Sqrt[2.] {x + y, x - y};
Now, let's find the points within the domain of f
:
inregionQ = UnitStep[x] UnitStep[2 Pi - x] UnitStep[y] UnitStep[Pi - y];
idx = Random`Private`PositionsOf[inregionQ, 1];
And let's apply f
only to these points:
result = ConstantArray[default, Length[x]];
result[[idx]] = f[x[[idx]], y[[idx]]]; // AbsoluteTiming // First
0.741009
It is still not super fast but the reason is that InterpolatingFunction
s are rather slow. As we may use a regular tensor grid for f
, applying it to many points at once could be way faster with a more appropriate binning and parallelization strategy...
Just for comparison: This is the timing of the evalation of the original function:
result2 = ConstantArray[default, Length[x]];
result2[[idx]] = Sin[x[[idx]]] Cos[y[[idx]]]; // AbsoluteTiming // First
0.001445
It is more than 500 times faster. This tells us (i) that the function to interpolate has to be very complex in order to take advantage of FunctionInterpolation
and (ii) that there must be a lot potential to improve the performance of InterpolationFunction
.
Interesting approach. Never seenRandom`Private`PositionsOf
but it looks useful, esp. withUnitStep
for picking indices.
– b3m2a1
2 hours ago
Yeah, Carl Woll used it a couple of times. I really like it. It is much faster thanPosition
for finding integers and it is also faster thanPick[Range[Length[inregionQ]],inregionQ,1]
.
– Henrik Schumacher
2 hours ago
Ah, I see. Yeah. Dunno. It is a black box for me and I only use it for integer lists anyway. I suspect a compiled function behind it, so I do not expect much flexibility from it.
– Henrik Schumacher
2 hours ago
Per your comparison, I have no analytic form for my original thing and probably no hope ever to have an analytic form. I could try some fits but what fit to use it a mystery as it's a high dimensional system. Hence my hope to deal with interpolation really nicely.
– b3m2a1
2 hours ago
1
Yeah. I did not mean to poke you about that. My hope was more towards a random WRI developer stumbling upon this and feeling an itching... ;)
– Henrik Schumacher
1 hour ago
add a comment |
up vote
2
down vote
up vote
2
down vote
Setting up the function and the default value. Notice that I force Mathematica to use machine precision numbers in f
.
f = FunctionInterpolation[Sin[θ]*Cos[ϕ], {θ, 0., 2. π}, {ϕ, 0., 1. π}];
default = 0.;
Generating several example points.
n = 100000;
x = RandomReal[{0, 2 Pi}, {n}];
y = RandomReal[{0, Pi}, {n}];
{x, y} = 1/Sqrt[2.] {x + y, x - y};
Now, let's find the points within the domain of f
:
inregionQ = UnitStep[x] UnitStep[2 Pi - x] UnitStep[y] UnitStep[Pi - y];
idx = Random`Private`PositionsOf[inregionQ, 1];
And let's apply f
only to these points:
result = ConstantArray[default, Length[x]];
result[[idx]] = f[x[[idx]], y[[idx]]]; // AbsoluteTiming // First
0.741009
It is still not super fast but the reason is that InterpolatingFunction
s are rather slow. As we may use a regular tensor grid for f
, applying it to many points at once could be way faster with a more appropriate binning and parallelization strategy...
Just for comparison: This is the timing of the evalation of the original function:
result2 = ConstantArray[default, Length[x]];
result2[[idx]] = Sin[x[[idx]]] Cos[y[[idx]]]; // AbsoluteTiming // First
0.001445
It is more than 500 times faster. This tells us (i) that the function to interpolate has to be very complex in order to take advantage of FunctionInterpolation
and (ii) that there must be a lot potential to improve the performance of InterpolationFunction
.
Setting up the function and the default value. Notice that I force Mathematica to use machine precision numbers in f
.
f = FunctionInterpolation[Sin[θ]*Cos[ϕ], {θ, 0., 2. π}, {ϕ, 0., 1. π}];
default = 0.;
Generating several example points.
n = 100000;
x = RandomReal[{0, 2 Pi}, {n}];
y = RandomReal[{0, Pi}, {n}];
{x, y} = 1/Sqrt[2.] {x + y, x - y};
Now, let's find the points within the domain of f
:
inregionQ = UnitStep[x] UnitStep[2 Pi - x] UnitStep[y] UnitStep[Pi - y];
idx = Random`Private`PositionsOf[inregionQ, 1];
And let's apply f
only to these points:
result = ConstantArray[default, Length[x]];
result[[idx]] = f[x[[idx]], y[[idx]]]; // AbsoluteTiming // First
0.741009
It is still not super fast but the reason is that InterpolatingFunction
s are rather slow. As we may use a regular tensor grid for f
, applying it to many points at once could be way faster with a more appropriate binning and parallelization strategy...
Just for comparison: This is the timing of the evalation of the original function:
result2 = ConstantArray[default, Length[x]];
result2[[idx]] = Sin[x[[idx]]] Cos[y[[idx]]]; // AbsoluteTiming // First
0.001445
It is more than 500 times faster. This tells us (i) that the function to interpolate has to be very complex in order to take advantage of FunctionInterpolation
and (ii) that there must be a lot potential to improve the performance of InterpolationFunction
.
edited 1 hour ago
answered 3 hours ago
Henrik Schumacher
47.1k466134
47.1k466134
Interesting approach. Never seenRandom`Private`PositionsOf
but it looks useful, esp. withUnitStep
for picking indices.
– b3m2a1
2 hours ago
Yeah, Carl Woll used it a couple of times. I really like it. It is much faster thanPosition
for finding integers and it is also faster thanPick[Range[Length[inregionQ]],inregionQ,1]
.
– Henrik Schumacher
2 hours ago
Ah, I see. Yeah. Dunno. It is a black box for me and I only use it for integer lists anyway. I suspect a compiled function behind it, so I do not expect much flexibility from it.
– Henrik Schumacher
2 hours ago
Per your comparison, I have no analytic form for my original thing and probably no hope ever to have an analytic form. I could try some fits but what fit to use it a mystery as it's a high dimensional system. Hence my hope to deal with interpolation really nicely.
– b3m2a1
2 hours ago
1
Yeah. I did not mean to poke you about that. My hope was more towards a random WRI developer stumbling upon this and feeling an itching... ;)
– Henrik Schumacher
1 hour ago
add a comment |
Interesting approach. Never seenRandom`Private`PositionsOf
but it looks useful, esp. withUnitStep
for picking indices.
– b3m2a1
2 hours ago
Yeah, Carl Woll used it a couple of times. I really like it. It is much faster thanPosition
for finding integers and it is also faster thanPick[Range[Length[inregionQ]],inregionQ,1]
.
– Henrik Schumacher
2 hours ago
Ah, I see. Yeah. Dunno. It is a black box for me and I only use it for integer lists anyway. I suspect a compiled function behind it, so I do not expect much flexibility from it.
– Henrik Schumacher
2 hours ago
Per your comparison, I have no analytic form for my original thing and probably no hope ever to have an analytic form. I could try some fits but what fit to use it a mystery as it's a high dimensional system. Hence my hope to deal with interpolation really nicely.
– b3m2a1
2 hours ago
1
Yeah. I did not mean to poke you about that. My hope was more towards a random WRI developer stumbling upon this and feeling an itching... ;)
– Henrik Schumacher
1 hour ago
Interesting approach. Never seen
Random`Private`PositionsOf
but it looks useful, esp. with UnitStep
for picking indices.– b3m2a1
2 hours ago
Interesting approach. Never seen
Random`Private`PositionsOf
but it looks useful, esp. with UnitStep
for picking indices.– b3m2a1
2 hours ago
Yeah, Carl Woll used it a couple of times. I really like it. It is much faster than
Position
for finding integers and it is also faster than Pick[Range[Length[inregionQ]],inregionQ,1]
.– Henrik Schumacher
2 hours ago
Yeah, Carl Woll used it a couple of times. I really like it. It is much faster than
Position
for finding integers and it is also faster than Pick[Range[Length[inregionQ]],inregionQ,1]
.– Henrik Schumacher
2 hours ago
Ah, I see. Yeah. Dunno. It is a black box for me and I only use it for integer lists anyway. I suspect a compiled function behind it, so I do not expect much flexibility from it.
– Henrik Schumacher
2 hours ago
Ah, I see. Yeah. Dunno. It is a black box for me and I only use it for integer lists anyway. I suspect a compiled function behind it, so I do not expect much flexibility from it.
– Henrik Schumacher
2 hours ago
Per your comparison, I have no analytic form for my original thing and probably no hope ever to have an analytic form. I could try some fits but what fit to use it a mystery as it's a high dimensional system. Hence my hope to deal with interpolation really nicely.
– b3m2a1
2 hours ago
Per your comparison, I have no analytic form for my original thing and probably no hope ever to have an analytic form. I could try some fits but what fit to use it a mystery as it's a high dimensional system. Hence my hope to deal with interpolation really nicely.
– b3m2a1
2 hours ago
1
1
Yeah. I did not mean to poke you about that. My hope was more towards a random WRI developer stumbling upon this and feeling an itching... ;)
– Henrik Schumacher
1 hour ago
Yeah. I did not mean to poke you about that. My hope was more towards a random WRI developer stumbling upon this and feeling an itching... ;)
– Henrik Schumacher
1 hour ago
add a comment |
up vote
1
down vote
Here's my version of this. I use it internally in a discretized function object to provide a nice compiled functional form. One other thing this does is allow you to set some coordinates to a constant value to take slices through the function:
iInterpCompile[interp_, coords_, preProcessor_, def_, min_] :=
Module[{potInterp = interp, dom = interp[[1]], j = 1},
Block[{crds, pt, gps},
Module[
{
getPot,
varBlock,
varBlock2,
preCoords
},
getPot[a_] := Apply[potInterp, a];
preCoords =
Quiet@
preProcessor@
Map[
If[# === Automatic,
Compile`GetElement[crds, j++],
#
] &,
coords
];
j = 1;
(* bounds checking for test *)
With[
{
test =
With[
{
tests =
MapThread[
#[[1]] <=
If[NumericQ[#2],
j++; #2,
Compile`GetElement[pt, j++]
] <= #[[2]] &,
{dom, preCoords}
]
},
If[MemberQ[tests, False],
False,
And @@ DeleteCases[tests, True]
]
],
crdSpec = preCoords,
means = Mean /@ dom,
fn =
Compile[
{{crds, _Real, 1}},
Evaluate@preCoords,
RuntimeAttributes -> {Listable}
]
},
Compile @@
Hold[(* True Compile body but with Hold for code injection *)
{{gps, _Real, 2}},
Module[
{
pts = fn@gps,
ongrid = Table[0, {i, Length@gps}],
intres,
midpt = means,
interpvals,
interpcounter,
interppts,
i = 1,
barrier = def,
minimum = min
},
interppts = Table[midpt, {i, Length@pts}];
(* Find points in domain *)
interpcounter = 0;
Do[
If[test,
ongrid[[i]] = 1;
interppts[[++interpcounter]] = pt
];
i++,
{pt, pts}
];
(* Apply InterpolatingFunction only once (one MainEval call) *)
If[interpcounter > 0,
intres = interppts[[;; interpcounter]];
interpvals = getPot[Transpose@intres] - minimum;
(* Pick points that are in domain *)
interpcounter = 0;
Map[
If[# == 1, interpvals[[++interpcounter]], barrier] &,
ongrid
],
Table[barrier, {i, Length@gps}]
]
],
{{getPot[_], _Real, 1}},
RuntimeOptions -> {
"EvaluateSymbolically" -> False,
"WarningMessages" -> False
},
CompilationOptions -> {"InlineExternalDefinitions" -> True},
RuntimeAttributes -> {Listable}
]
]
]
]
]
Options[InterpCompile] =
{
"CoordinateTransformation" -> Identity,
"Minimum" -> 0.,
"Default" -> 0.,
"Mode" -> "Vector"
};
InterpCompile[
interp_,
coordSpec : {(Automatic | _?NumericQ) ..} | Automatic : Automatic,
ops : OptionsPattern
] :=
If[OptionValue["Mode"] === "Vector",
iInterpCompile[
interp,
Replace[
coordSpec,
Automatic :> ConstantArray[Automatic, Length@interp[[1]]]
],
OptionValue["CoordinateTransformation"],
OptionValue["Default"],
OptionValue["Minimum"]
]
]
Here's a sample usage. First set up the compiled function:
ga =
CoordinateBoundsArray[
{{0., 2. π}, {0., 1. π}},
{π/24., π/24.}
];
fn =
Interpolation@
Flatten[
Join[
ga,
Map[
{Sin[#[[1]]]*Cos[#[[2]]]} &,
ga,
{2}
],
3
],
1
];
cf =
InterpCompile[fn,
"CoordinateTransformation" ->
(1/Sqrt[2.]*
{
#[[2]] + #[[1]], #[[1]] - #[[2]]
}
&
)];
Then test the timing:
cf@testGrid; // RepeatedTiming
{0.47, Null}
And plot the result:
cf@testGrid // ListPlot3D[#, PlotRange -> All] &
It's only barely faster than Henrik's method and multiple orders of magnitude more complex, but on the other hand it's pretty much fully general, which is convenient.
We can also use it to take slices through the interpolation:
With[
{
cf2 =
InterpCompile[fn,
{Automatic, #},
"CoordinateTransformation" ->
(1/Sqrt[2.]*
{
#[[2]] + #[[1]], #[[1]] - #[[2]]
}
&
)]
},
Transpose@{#, cf2@Transpose@{#}} &@Range[-8, 8, .001] //
ListLinePlot[#, ImageSize -> 250] &
] & /@ Range[-3, 3] // Partition[#, 2] & // GraphicsGrid
add a comment |
up vote
1
down vote
Here's my version of this. I use it internally in a discretized function object to provide a nice compiled functional form. One other thing this does is allow you to set some coordinates to a constant value to take slices through the function:
iInterpCompile[interp_, coords_, preProcessor_, def_, min_] :=
Module[{potInterp = interp, dom = interp[[1]], j = 1},
Block[{crds, pt, gps},
Module[
{
getPot,
varBlock,
varBlock2,
preCoords
},
getPot[a_] := Apply[potInterp, a];
preCoords =
Quiet@
preProcessor@
Map[
If[# === Automatic,
Compile`GetElement[crds, j++],
#
] &,
coords
];
j = 1;
(* bounds checking for test *)
With[
{
test =
With[
{
tests =
MapThread[
#[[1]] <=
If[NumericQ[#2],
j++; #2,
Compile`GetElement[pt, j++]
] <= #[[2]] &,
{dom, preCoords}
]
},
If[MemberQ[tests, False],
False,
And @@ DeleteCases[tests, True]
]
],
crdSpec = preCoords,
means = Mean /@ dom,
fn =
Compile[
{{crds, _Real, 1}},
Evaluate@preCoords,
RuntimeAttributes -> {Listable}
]
},
Compile @@
Hold[(* True Compile body but with Hold for code injection *)
{{gps, _Real, 2}},
Module[
{
pts = fn@gps,
ongrid = Table[0, {i, Length@gps}],
intres,
midpt = means,
interpvals,
interpcounter,
interppts,
i = 1,
barrier = def,
minimum = min
},
interppts = Table[midpt, {i, Length@pts}];
(* Find points in domain *)
interpcounter = 0;
Do[
If[test,
ongrid[[i]] = 1;
interppts[[++interpcounter]] = pt
];
i++,
{pt, pts}
];
(* Apply InterpolatingFunction only once (one MainEval call) *)
If[interpcounter > 0,
intres = interppts[[;; interpcounter]];
interpvals = getPot[Transpose@intres] - minimum;
(* Pick points that are in domain *)
interpcounter = 0;
Map[
If[# == 1, interpvals[[++interpcounter]], barrier] &,
ongrid
],
Table[barrier, {i, Length@gps}]
]
],
{{getPot[_], _Real, 1}},
RuntimeOptions -> {
"EvaluateSymbolically" -> False,
"WarningMessages" -> False
},
CompilationOptions -> {"InlineExternalDefinitions" -> True},
RuntimeAttributes -> {Listable}
]
]
]
]
]
Options[InterpCompile] =
{
"CoordinateTransformation" -> Identity,
"Minimum" -> 0.,
"Default" -> 0.,
"Mode" -> "Vector"
};
InterpCompile[
interp_,
coordSpec : {(Automatic | _?NumericQ) ..} | Automatic : Automatic,
ops : OptionsPattern
] :=
If[OptionValue["Mode"] === "Vector",
iInterpCompile[
interp,
Replace[
coordSpec,
Automatic :> ConstantArray[Automatic, Length@interp[[1]]]
],
OptionValue["CoordinateTransformation"],
OptionValue["Default"],
OptionValue["Minimum"]
]
]
Here's a sample usage. First set up the compiled function:
ga =
CoordinateBoundsArray[
{{0., 2. π}, {0., 1. π}},
{π/24., π/24.}
];
fn =
Interpolation@
Flatten[
Join[
ga,
Map[
{Sin[#[[1]]]*Cos[#[[2]]]} &,
ga,
{2}
],
3
],
1
];
cf =
InterpCompile[fn,
"CoordinateTransformation" ->
(1/Sqrt[2.]*
{
#[[2]] + #[[1]], #[[1]] - #[[2]]
}
&
)];
Then test the timing:
cf@testGrid; // RepeatedTiming
{0.47, Null}
And plot the result:
cf@testGrid // ListPlot3D[#, PlotRange -> All] &
It's only barely faster than Henrik's method and multiple orders of magnitude more complex, but on the other hand it's pretty much fully general, which is convenient.
We can also use it to take slices through the interpolation:
With[
{
cf2 =
InterpCompile[fn,
{Automatic, #},
"CoordinateTransformation" ->
(1/Sqrt[2.]*
{
#[[2]] + #[[1]], #[[1]] - #[[2]]
}
&
)]
},
Transpose@{#, cf2@Transpose@{#}} &@Range[-8, 8, .001] //
ListLinePlot[#, ImageSize -> 250] &
] & /@ Range[-3, 3] // Partition[#, 2] & // GraphicsGrid
add a comment |
up vote
1
down vote
up vote
1
down vote
Here's my version of this. I use it internally in a discretized function object to provide a nice compiled functional form. One other thing this does is allow you to set some coordinates to a constant value to take slices through the function:
iInterpCompile[interp_, coords_, preProcessor_, def_, min_] :=
Module[{potInterp = interp, dom = interp[[1]], j = 1},
Block[{crds, pt, gps},
Module[
{
getPot,
varBlock,
varBlock2,
preCoords
},
getPot[a_] := Apply[potInterp, a];
preCoords =
Quiet@
preProcessor@
Map[
If[# === Automatic,
Compile`GetElement[crds, j++],
#
] &,
coords
];
j = 1;
(* bounds checking for test *)
With[
{
test =
With[
{
tests =
MapThread[
#[[1]] <=
If[NumericQ[#2],
j++; #2,
Compile`GetElement[pt, j++]
] <= #[[2]] &,
{dom, preCoords}
]
},
If[MemberQ[tests, False],
False,
And @@ DeleteCases[tests, True]
]
],
crdSpec = preCoords,
means = Mean /@ dom,
fn =
Compile[
{{crds, _Real, 1}},
Evaluate@preCoords,
RuntimeAttributes -> {Listable}
]
},
Compile @@
Hold[(* True Compile body but with Hold for code injection *)
{{gps, _Real, 2}},
Module[
{
pts = fn@gps,
ongrid = Table[0, {i, Length@gps}],
intres,
midpt = means,
interpvals,
interpcounter,
interppts,
i = 1,
barrier = def,
minimum = min
},
interppts = Table[midpt, {i, Length@pts}];
(* Find points in domain *)
interpcounter = 0;
Do[
If[test,
ongrid[[i]] = 1;
interppts[[++interpcounter]] = pt
];
i++,
{pt, pts}
];
(* Apply InterpolatingFunction only once (one MainEval call) *)
If[interpcounter > 0,
intres = interppts[[;; interpcounter]];
interpvals = getPot[Transpose@intres] - minimum;
(* Pick points that are in domain *)
interpcounter = 0;
Map[
If[# == 1, interpvals[[++interpcounter]], barrier] &,
ongrid
],
Table[barrier, {i, Length@gps}]
]
],
{{getPot[_], _Real, 1}},
RuntimeOptions -> {
"EvaluateSymbolically" -> False,
"WarningMessages" -> False
},
CompilationOptions -> {"InlineExternalDefinitions" -> True},
RuntimeAttributes -> {Listable}
]
]
]
]
]
Options[InterpCompile] =
{
"CoordinateTransformation" -> Identity,
"Minimum" -> 0.,
"Default" -> 0.,
"Mode" -> "Vector"
};
InterpCompile[
interp_,
coordSpec : {(Automatic | _?NumericQ) ..} | Automatic : Automatic,
ops : OptionsPattern
] :=
If[OptionValue["Mode"] === "Vector",
iInterpCompile[
interp,
Replace[
coordSpec,
Automatic :> ConstantArray[Automatic, Length@interp[[1]]]
],
OptionValue["CoordinateTransformation"],
OptionValue["Default"],
OptionValue["Minimum"]
]
]
Here's a sample usage. First set up the compiled function:
ga =
CoordinateBoundsArray[
{{0., 2. π}, {0., 1. π}},
{π/24., π/24.}
];
fn =
Interpolation@
Flatten[
Join[
ga,
Map[
{Sin[#[[1]]]*Cos[#[[2]]]} &,
ga,
{2}
],
3
],
1
];
cf =
InterpCompile[fn,
"CoordinateTransformation" ->
(1/Sqrt[2.]*
{
#[[2]] + #[[1]], #[[1]] - #[[2]]
}
&
)];
Then test the timing:
cf@testGrid; // RepeatedTiming
{0.47, Null}
And plot the result:
cf@testGrid // ListPlot3D[#, PlotRange -> All] &
It's only barely faster than Henrik's method and multiple orders of magnitude more complex, but on the other hand it's pretty much fully general, which is convenient.
We can also use it to take slices through the interpolation:
With[
{
cf2 =
InterpCompile[fn,
{Automatic, #},
"CoordinateTransformation" ->
(1/Sqrt[2.]*
{
#[[2]] + #[[1]], #[[1]] - #[[2]]
}
&
)]
},
Transpose@{#, cf2@Transpose@{#}} &@Range[-8, 8, .001] //
ListLinePlot[#, ImageSize -> 250] &
] & /@ Range[-3, 3] // Partition[#, 2] & // GraphicsGrid
Here's my version of this. I use it internally in a discretized function object to provide a nice compiled functional form. One other thing this does is allow you to set some coordinates to a constant value to take slices through the function:
iInterpCompile[interp_, coords_, preProcessor_, def_, min_] :=
Module[{potInterp = interp, dom = interp[[1]], j = 1},
Block[{crds, pt, gps},
Module[
{
getPot,
varBlock,
varBlock2,
preCoords
},
getPot[a_] := Apply[potInterp, a];
preCoords =
Quiet@
preProcessor@
Map[
If[# === Automatic,
Compile`GetElement[crds, j++],
#
] &,
coords
];
j = 1;
(* bounds checking for test *)
With[
{
test =
With[
{
tests =
MapThread[
#[[1]] <=
If[NumericQ[#2],
j++; #2,
Compile`GetElement[pt, j++]
] <= #[[2]] &,
{dom, preCoords}
]
},
If[MemberQ[tests, False],
False,
And @@ DeleteCases[tests, True]
]
],
crdSpec = preCoords,
means = Mean /@ dom,
fn =
Compile[
{{crds, _Real, 1}},
Evaluate@preCoords,
RuntimeAttributes -> {Listable}
]
},
Compile @@
Hold[(* True Compile body but with Hold for code injection *)
{{gps, _Real, 2}},
Module[
{
pts = fn@gps,
ongrid = Table[0, {i, Length@gps}],
intres,
midpt = means,
interpvals,
interpcounter,
interppts,
i = 1,
barrier = def,
minimum = min
},
interppts = Table[midpt, {i, Length@pts}];
(* Find points in domain *)
interpcounter = 0;
Do[
If[test,
ongrid[[i]] = 1;
interppts[[++interpcounter]] = pt
];
i++,
{pt, pts}
];
(* Apply InterpolatingFunction only once (one MainEval call) *)
If[interpcounter > 0,
intres = interppts[[;; interpcounter]];
interpvals = getPot[Transpose@intres] - minimum;
(* Pick points that are in domain *)
interpcounter = 0;
Map[
If[# == 1, interpvals[[++interpcounter]], barrier] &,
ongrid
],
Table[barrier, {i, Length@gps}]
]
],
{{getPot[_], _Real, 1}},
RuntimeOptions -> {
"EvaluateSymbolically" -> False,
"WarningMessages" -> False
},
CompilationOptions -> {"InlineExternalDefinitions" -> True},
RuntimeAttributes -> {Listable}
]
]
]
]
]
Options[InterpCompile] =
{
"CoordinateTransformation" -> Identity,
"Minimum" -> 0.,
"Default" -> 0.,
"Mode" -> "Vector"
};
InterpCompile[
interp_,
coordSpec : {(Automatic | _?NumericQ) ..} | Automatic : Automatic,
ops : OptionsPattern
] :=
If[OptionValue["Mode"] === "Vector",
iInterpCompile[
interp,
Replace[
coordSpec,
Automatic :> ConstantArray[Automatic, Length@interp[[1]]]
],
OptionValue["CoordinateTransformation"],
OptionValue["Default"],
OptionValue["Minimum"]
]
]
Here's a sample usage. First set up the compiled function:
ga =
CoordinateBoundsArray[
{{0., 2. π}, {0., 1. π}},
{π/24., π/24.}
];
fn =
Interpolation@
Flatten[
Join[
ga,
Map[
{Sin[#[[1]]]*Cos[#[[2]]]} &,
ga,
{2}
],
3
],
1
];
cf =
InterpCompile[fn,
"CoordinateTransformation" ->
(1/Sqrt[2.]*
{
#[[2]] + #[[1]], #[[1]] - #[[2]]
}
&
)];
Then test the timing:
cf@testGrid; // RepeatedTiming
{0.47, Null}
And plot the result:
cf@testGrid // ListPlot3D[#, PlotRange -> All] &
It's only barely faster than Henrik's method and multiple orders of magnitude more complex, but on the other hand it's pretty much fully general, which is convenient.
We can also use it to take slices through the interpolation:
With[
{
cf2 =
InterpCompile[fn,
{Automatic, #},
"CoordinateTransformation" ->
(1/Sqrt[2.]*
{
#[[2]] + #[[1]], #[[1]] - #[[2]]
}
&
)]
},
Transpose@{#, cf2@Transpose@{#}} &@Range[-8, 8, .001] //
ListLinePlot[#, ImageSize -> 250] &
] & /@ Range[-3, 3] // Partition[#, 2] & // GraphicsGrid
edited 1 hour ago
answered 1 hour ago
b3m2a1
26k256152
26k256152
add a comment |
add a comment |
Thanks for contributing an answer to Mathematica Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fmathematica.stackexchange.com%2fquestions%2f187747%2ffast-application-of-interpolatingfunction-over-transformed-coordinates%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown