# How to make the code inside Compile conciser without hurting performance?

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[] = Sin[n/10];
hy[[1 ;; -1]] += ez[[2 ;; -1]] - ez[[1 ;; -2]], {n, steps}];
ez]];

fdtd1d; // 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[] = Sin[n/10.]; f[hy, ez, 1], {n, steps}];
ez]];

fdtd1d; // 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[] = Sin[n/10.]; f[hy, ez, 1], {n, steps}];
ez], CompilationOptions -> {"InlineExternalDefinitions" -> True}];

<< CompiledFunctionTools
CompilePrint@fdtd1d


Compile::argset: The assignment to CompileFunctionVariable\$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?

• Another approach you may prefer: write the code programmatically, then compile it. This way it doesn't matter how verbose it is. – Oleksandr R. May 8 '14 at 13:26
• @OleksandrR. You mean what Leonid Shifrin has done below? :) – xzczd May 8 '14 at 13:44

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[]=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; // AbsoluteTiming

(* {0.009366, Null} *)