# Slow performance of ArrayResample

On my system, I had this timing result

tmp = RandomReal[1., {5, 3}];
ListLinePlot[
Table[{i, AbsoluteTiming[ArrayResample[tmp, {1000, i}]][]}, {i, 2,
10}], PlotRange -> All]


it gives What is wrong with {1000,3} sampling? This is exactly the resample I want.

What is more, ArrayResample[tmp,1000] should be gives same result as ArrayResample[tmp, {1000, 3}], while it is also slow

In:= ArrayResample[tmp, 1000]; // AbsoluteTiming

Out= {0.0569425, Null}


How to fix this to make {1000,3} resample as fast as others?

upate

Thanks to halirutan's explanation.

For workaround, I just came up with quick and dirty workaround of this problem.

Notice that

ArrayResample[tmp, {1000, 5}][[;; , {1, 3, 5}]] ==
ArrayResample[tmp, {1000, 3}]


gives True. while

In:= AbsoluteTiming[
ArrayResample[tmp, {1000, 5}][[;; , {1, 3, 5}]];]

Out= {0.00344076, Null}


is much faster than

In:= AbsoluteTiming[ArrayResample[tmp, {1000, 3}];]

Out= {0.379471, Null}

• looks like you get a similar jump in timing for ArrayResample[tmp, {n, Dimensions[tmp][]}] – kglr Mar 15 '18 at 2:20
• @kglr Yeah, though I didn't test it when I made post, but I believe your statement : ) 3 is just an example – matheorem Mar 15 '18 at 2:26

The reason is simple: When you have a 2-dimensional array of dimensions {n,m} and you resample it to dimension {o,p} where both directions are different, then the array is interpolated in each direction. When you resample it to dimensions {o,m}, then a different scheme is used: Only the first direction is interpolated.

Pragmatically speaking, this seems to make sense. However, the 1d resampling is done column by column with FoldList which seems to be slower. If you are interested, I advise you to take a look at

SignalResamplingArrayResample1D


To prove my point, let me show you that it is only called in the situation where one of your dimensions is equal:

tmp = RandomReal[1, {5, 3}];
TracePrint[ArrayResample[tmp, {10, 4}], _SignalResamplingArrayResample1D]


When both dimensions differ, this is not called. However, leaving the second direction alone and you see

TracePrint[ArrayResample[tmp, {10, 3}], _SignalResamplingArrayResample1D]


For educational purpose, you could look at this function, which calls the 2d resampling no matter what (makes only sense on your tmp!):

resample[data_, {n1_, n2_}] := SignalResamplingoArrayResampleM[
data,2, {n1, n2},
{{"Spline", 1}, {"Spline", 1}}, {{1, 5,
4/(n1 - 1)}, {1, 30, 29/(n2 - 1)}},
{"Fixed", "Fixed"}, {False, False}]


Test, if the resampling is close to the standard implementation:

Total[Flatten[ArrayResample[tmp, {1000, 3}] - resample[tmp, {1000, 3}]]]
(* -4.08007*10^-15 *)


Good enough. Let's time it:

ListLinePlot[
Table[{i, AbsoluteTiming[#[tmp, {1000, i}]][]}, {i, 2,
10}] & /@ {ArrayResample, resample}] Especially at m=3 it is several orders of magnitude faster. The rest of the difference comes from the overhead of the high-level implementation.

## Awkward hack around it

If you look carefully at the last If condition in the implementation of

SignalResamplingiArrayResample


and you are sure that you are meeting all conditions, you can to some degree use the following hack with our real-valued data

ArrayResampleSpecial[args___] := Block[{SignalResamplingoArrayResample},
SignalResamplingoArrayResample[data_, _, rank_, _, outDims_, _,
ranges_, resamplings_, paddings_, antiAliasQs_, _] :=
SignalResamplingoArrayResampleM[data, rank, outDims,
ArrayResample[args]
]


Then you have the following ArrayResampleSpecial function available that gives you predictable timings:

tmp = RandomReal[1., {5, 3}];
timings = Table[{i, AbsoluteTiming[f[tmp, {1000, i}]][]},
{f, {ArrayResample, ArrayResampleSpecial}}, {i, 2, 10}];

ListLinePlot[timings] • Hi, halirutan. Thank you so much for taking us to the invisible "core", really interesting. It seems that ArrayResampleSpecial is slower if second dimension is small as I tested. What is more, do you think this can be called a bug for ArrayResample? Because I don't think this is a reasonable behaviour. – matheorem Mar 15 '18 at 5:28
• Well, we have to consider 2 things: (a) Wolfram is aware of the performance behavior and has decided that when looking at all possible calls to ArrayResample, it is better to do it this way. (b) Maybe they haven't profiled it like you did and the decision made was not given much thought. In any case, the thing that triggers the behavior is the condition Apply[And, MapThread[Unequal, {inDims, outDims}]] which checks if all dimensions are unequal. – halirutan Mar 15 '18 at 12:56