2
$\begingroup$

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?

$\endgroup$
2
  • 1
    $\begingroup$ Another approach you may prefer: write the code programmatically, then compile it. This way it doesn't matter how verbose it is. $\endgroup$ Commented May 8, 2014 at 13:26
  • $\begingroup$ @OleksandrR. You mean what Leonid Shifrin has done below? :) $\endgroup$ Commented May 8, 2014 at 13:44

1 Answer 1

3
$\begingroup$

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.