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$
    – xzczd
    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$

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.