I have to reassign values in a big array many times and it turned out to be the most time consuming in my program. The best way I could figure out is this


mass = ParallelTable[mass[[k, k1]] E^(I*t*(Mod[k - 1, nn, -nnn]^2 + 
   Mod[k1 - 1, nn, -nnn]^2)), {k, 1, nn}, {k1, 1, nn}];

I wonder if there is a faster functional way to change the values in an array with a function depending on their positions.

I tried to use Compile for this function

f = Compile[{{xp, _Complex, 2}}, ParallelTable[xp[[k,k1]] 
E^(I*t*(Mod[k - 1, nn, -nnn]^2 + Mod[k1 - 1, nn, -nnn]^2)), {k, 1, nn}, {k1, 1, nn}],
{{k, _Integer}, {k1, _Integer}, {nn, _Integer}, {nnn, _Integer}, {Mod[_, _, _], _Integer}}]

But I get the answer that Compiled expression should be a mashine-size Complex number. Please tell me what is wrong.

  • $\begingroup$ Is this calculation related to fast Fourier transform? $\endgroup$
    – xzczd
    Jan 19, 2017 at 7:46
  • 2
    $\begingroup$ Am I interpreting this correctly: you are in your code doing the mass=ParallelTable[...] statement repeatedly? If so, why on earth would you recalculate the same factors repeatedly? Simply calculate those once (i.e. remove the mass[[k, k1]] piece, give result a name), and at each iteration to change mass it becomes mass=a_name*mass... $\endgroup$
    – ciao
    Jan 19, 2017 at 9:16
  • $\begingroup$ Yes, it is related to fft. I am doing fft with CUDAFourier and the code above has to change the matrix in the momentum space, then inverse Fourier, and similar change in the coordinate space. $\endgroup$
    – user40532
    Jan 19, 2017 at 10:35
  • $\begingroup$ @ciao, Yes, that is very good, I just was afraid of storing another big array because memory after many iterations becomes a big issue. $\endgroup$
    – user40532
    Jan 19, 2017 at 10:41

1 Answer 1

rotate = l \[Function] RotateLeft[Range[l] - # - 1, #] &@Floor[(l - 1)/2];    
mass3 = (lst \[Function] mass (Exp[I t ( lst^2 + #)] & /@ (lst^2)))@rotate@nn;
(* {0.519567, Null} *)

As to Compile, I don't suggest you to use it now, but if you insist, you can start from here. Here's the compiled version of the code above:

cf = Compile[{{mass, _Complex, 2}, {lst, _Real, 1}, {t, _Real}}, 
   mass (Exp[I t ( lst^2 + #)] & /@ (lst^2))];   
mass4 = cf[mass, rotate@nn, t]; // AbsoluteTiming
(* {0.103073, Null} *)

Or, let's naively compile your implementation:

cf2 = 
  Compile[{{mass, _Complex, 2}, {t, _Real}, {nn, _Integer}, {nnn, _Integer}}, 
   Table[mass[[k, k1]] E^(I t (Mod[k - 1, nn, -nnn]^2 + Mod[k1 - 1, nn, -nnn]^2)), {k, 1,
      nn}, {k1, 1, nn}]];

mass5 = cf2[mass, t, nn, nnn]; // AbsoluteTiming
(* {0.461346, Null} *)

It can be faster if we use some even more advanced technique (related post: Why is CompilationTarget -> C slower than directly writing with C?):

cf3 = 
     Compile[{{mass, _Complex, 2}, {t, _Real}, {nn, _Integer}, {nnn, _Integer}}, 
      Table[mass[[k, k1]] E^(I t (Mod[k - 1, nn, -nnn]^2 + Mod[k1 - 1, nn, -nnn]^2)), {k,
         1, nn}, {k1, 1, nn}], CompilationTarget -> "C", RuntimeOptions -> "Speed"] /. 
    Part -> Compile`GetElement // Last;

mass6 = cf3[mass, t, nn, nnn]; // AbsoluteTiming
(* {0.115824, Null} *)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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