Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

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?

share|improve this question
1  
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 at 13:26
    
@OleksandrR. You mean what Leonid Shifrin has done below? :) –  xzczd May 8 at 13:44

1 Answer 1

up vote 3 down vote accepted

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} *)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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