9

I am pleased to have MovingMap in Mathematica 10. But, today, I encountered the problem that needs MovingMap with a periodic boundary condition.

To be specific, Consider the following example.

MovingMap[ f, Range[3], {2} ]

will gives the result {f[{1, 2}], f[{2, 3}], f[{3, 4}]}. However, what I want to get is {f[{1, 2}], f[{2, 3}], f[{3, 4}], f[{4,1}]}.

One of the easiest and straightforward way would be calculating the last one and then join the lists together. But I want to know if there is more elegant way to do it. (I checked the optional arguments of MovingMap but I couldn't find a solution.)

Sungmin
  • 2,285
  • 15
  • 23
  • 4
    Use Map with Partition: f /@ Partition[Range[4], 2, 1, {1, 1}] gives {f[{1, 2}], f[{2, 3}], f[{3, 4}], f[{4, 1}]} – Bob Hanlon Nov 05 '14 at 15:15

3 Answers3

9

Here is one way:

movingMapCircular[f_, l_List] := MapThread[f@* List, {l, RotateLeft[l]}];

For example:

movingMapCircular[f, {1, 2, 3, 4}]

(* {f[{1, 2}], f[{2, 3}], f[{3, 4}], f[{4, 1}]} *)

A generalization of this approach for arbitrary window size may look like:

ClearAll[movingMapCircular];
movingMapCircular[f_, l_List, {n_Integer}] :=
  MapThread[
    f@* List,
    MapThread[RotateLeft, {ConstantArray[l, n], Range[0, n - 1]}]
  ];

for example:

movingMapCircular[f, Range[5], {3}]

(* {f[{1, 2, 3}], f[{2, 3, 4}], f[{3, 4, 5}], f[{4, 5, 1}], f[{5, 1, 2}]} *)
Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
9

"Reflected" padding works as desired but "Periodic" padding is missed. There is corresponding definition for "Reflected"

RandomProcesses`TemporalDataUtilitiesDump`toCannonicalPadding[
  RandomProcesses`TemporalDataUtilitiesDump`td_, "Reflected", 
  RandomProcesses`TemporalDataUtilitiesDump`w_, 
  RandomProcesses`TemporalDataUtilitiesDump`Caller_] := 
 Reverse[Rest[
   TemporalData`Utilities`TDResample[
     RandomProcesses`TemporalDataUtilitiesDump`td,
     RandomProcesses`TemporalDataUtilitiesDump`w, {}, 
     RandomProcesses`TemporalDataUtilitiesDump`Caller]["Values"]]]

So we can add a similar definition for "Periodic"

RandomProcesses`TemporalDataUtilitiesDump`toCannonicalPadding[
  RandomProcesses`TemporalDataUtilitiesDump`td_, "Periodic", 
  RandomProcesses`TemporalDataUtilitiesDump`w_, 
  RandomProcesses`TemporalDataUtilitiesDump`Caller_] := 
 TemporalData`Utilities`TDResample[
   RandomProcesses`TemporalDataUtilitiesDump`td, 
   RandomProcesses`TemporalDataUtilitiesDump`w, {}, 
   RandomProcesses`TemporalDataUtilitiesDump`Caller]["Values"]

Verification:

MovingMap[f, Range[3], {2}, "Periodic"]
(* {f[{3, 1}], f[{1, 2}], f[{2, 3}]} *)
ybeltukov
  • 43,673
  • 5
  • 108
  • 212
  • You can get this result with MovingMap[f, Range[3], {2}, Range[3]]. With either approach a RotateLeft is required to put in order that OP requested. – Bob Hanlon Nov 05 '14 at 15:21
3

With versions 10.4.1 and 11.0.1 "Periodic" works:

MovingMap[f, Range[5], 1, "Periodic"]
MovingMap[f, Range[5], {1, Left}, "Periodic"]
MovingMap[f, Range[5], 2, "Periodic"]
MovingMap[f, Range[5], {2, Center}, "Periodic"]
{f[{5, 1}], f[{1, 2}], f[{2, 3}], f[{3, 4}], f[{4, 5}]}

{f[{1, 2}], f[{2, 3}], f[{3, 4}], f[{4, 5}], f[{5, 1}]}

{f[{4, 5, 1}], f[{5, 1, 2}], f[{1, 2, 3}], f[{2, 3, 4}], f[{3, 4, 5}]}

{f[{5, 1, 2}], f[{1, 2, 3}], f[{2, 3, 4}], f[{3, 4, 5}], f[{4, 5, 1}]}

But MovingMap is still one order of magnitude slower than Map + Partition:

ClearSystemCache[]
m1 = MovingMap[f, Range[10^6], {2, Center}, "Periodic"]; // RepeatedTiming
ClearSystemCache[]
m2 = f /@ Partition[ArrayPad[Range[10^6], {1, 1}, "Periodic"], 3, 1]; // RepeatedTiming
ClearSystemCache[]
m3 = f /@ Partition[Range[10^6], 3, 1, {2, 2}]; // RepeatedTiming
ClearSystemCache[]
m4 = Developer`PartitionMap[f, Range[10^6], 3, 1, {2, 2}]; // RepeatedTiming
m1 === m2 === m3 === m4
{6.60, Null}

{0.950, Null}

{0.987, Null}

{1.07, Null}

True

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368