8
$\begingroup$

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.)

$\endgroup$
  • 4
    $\begingroup$ 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}]} $\endgroup$ – Bob Hanlon Nov 5 '14 at 15:15
9
$\begingroup$

"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}]} *)
$\endgroup$
  • $\begingroup$ 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. $\endgroup$ – Bob Hanlon Nov 5 '14 at 15:21
9
$\begingroup$

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}]} *)
$\endgroup$
2
$\begingroup$

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
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.