2

Consider the following sample:

ie = 200;
ez = ConstantArray[0., {ie + 1}];
hy = ConstantArray[0., {ie}];

fdtd1d = Compile[{{steps}}, 
   Module[{ez = ez, hy = hy}, 
    Do[ez[[2 ;; -2]] += hy[[2 ;; -1]] - hy[[1 ;; -2]];
       ez[[1]] = Sin[n/10];
       hy[[1 ;; -1]] += ez[[2 ;; -1]] - ez[[1 ;; -2]], {n, steps}];
       ez]];

fdtd1d[1000]; // AbsoluteTiming
{0.0100000, Null}

Apparently there're 2 sentences (of course in real situation there can be more) with same structure that can be represented with a function if fdtd1d is built with Function:

ie = 200;
ez = ConstantArray[0., {ie + 1}];
hy = ConstantArray[0., {ie}];

ClearAll[f];
SetAttributes[f, HoldFirst]
f[list1_, list2_, end_] := 
  list1[[end ;; -end]] += (list2[[2 ;; -1]] - list2[[1 ;; -2]]);

fdtd1d = Function[{steps}, 
   Module[{ez = ez, hy = hy}, 
    Do[f[ez, hy, 2]; ez[[1]] = Sin[n/10.]; f[hy, ez, 1], {n, steps}];
    ez]];

fdtd1d[1000]; // AbsoluteTiming
{0.1050000, Null}

But this method isn't available for Compile, even with the trick mentioned here:

ie = 200;
ez = ConstantArray[0., {ie + 1}];
hy = ConstantArray[0., {ie}];

ClearAll[f];
f = Function[{list1, list2, end}, 
   list1[[end ;; -end]] += (list2[[2 ;; -1]] - list2[[1 ;; -2]]), 
   HoldFirst];

fdtd1d = Compile[{steps}, 
   Module[{ez = ez, hy = hy}, 
    Do[f[ez, hy, 2]; ez[[1]] = Sin[n/10.]; f[hy, ez, 1], {n, steps}];
    ez], CompilationOptions -> {"InlineExternalDefinitions" -> True}];

<< CompiledFunctionTools`
CompilePrint@fdtd1d

Compile::argset: The assignment to Compile`FunctionVariable$1571 is illegal; it is not valid to assign a value to an argument. >>

……
1 Return Error

So, as the title said, is there a way to make the code inside Compile conciser without performance decreasing or even compilation failure?

xzczd
  • 65,995
  • 9
  • 163
  • 468

1 Answers1

3

This is your code:

ie = 200;
ez = ConstantArray[0., {ie + 1}];
hy = ConstantArray[0., {ie}];

ClearAll[f];
SetAttributes[f, HoldFirst]
f[list1_, list2_, end_] := 
    list1[[end ;; -end]] += (list2[[2 ;; -1]] - list2[[1 ;; -2]]);

With the help of the withGlobalFunctions macro, defined here, you get simply:

fn=
    withGlobalFunctions[
        Compile[                
            {steps},
            Module[{ez=ez,hy=hy},
                Do[f[ez,hy,2];ez[[1]]=Sin[n /10.];f[hy,ez,1],{n,steps}];ez
            ]
        ]
    ];

which is exactly how you'd like this. The result is the same as if you'd expand the definitions by hand. And of course, the speed is the same too:

fn[1000]; // AbsoluteTiming

(* {0.009366, Null} *)
Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420