2
$\begingroup$

How can I make compilation to go through with a module inside module? I tried this, failed, a few other ways failed too.

f = Compile[
     {{σt, _Real, 1}, {sρ, _Complex, 1}, {dt, _Real, 1}, {x, _Real}, {nnt, _Integer}, 
      {dqt, _Real}, {divt, _Integer}},
  Module[{temp, dq = dqt, div = divt, j, h},
   temp[x_] := 
    Module[{kz = 1/2 x, σ = σt, d = dt, i, kp, c, β, r, k, ρ = sρ * 10^-6, nn = nnt},
     kp = kz + 0. I;
     k = Sqrt[kz^2 - 4 π (ρ[[2]] - ρ[[1]])];
      r = (kp - k)/(kp + k) E^(-2 kp k σ[[1]]^2);
     c = {{1 + 0. I, r }, {r , 1}};
     kp = k;
     For[i = 2, i < 2 nn + 2, i++,
      If[EvenQ[i],
       k = Sqrt[kz^2 - 4 π (ρ[[3]] - ρ[[1]])];
       r = (kp - k)/(kp + k) E^(-2 kp k σ[[2]]^2); 
       β = I kp d[[1]],
       k = Sqrt[kz^2 - 4 π (ρ[[2]] - ρ[[1]])];
       r = (kp - k)/(kp + k) E^(-2 kp k σ[[3]]^2); 
       β = I kp d[[2]] 
      ];

      c = c.{{E^β, r E^β}, {r E^-β, E^-β}};
      (*previous k*)
      kp = k
      ];
     Abs[c[[2, 1]]/c[[1, 1]]]^2];
   h = 0.0;
   For[j = 1, j < div + 1, j++,
    h = h + temp[x - dq/2 + dq/div*j]
   ];
   h/div
   ]
  , CompilationTarget -> "C"]
$\endgroup$
  • 1
    $\begingroup$ You should probably compile the more computation-intensive temp function on its own. You will also want to look at more efficient and idiomatic Mathematica alternatives to explicit For loops. $\endgroup$ – MarcoB Aug 26 '15 at 23:52
  • 3
    $\begingroup$ On that note, you'll be interested in the "InlineCompiledFunctions" and "InlineExternalDefinitions" suboptions of CompilationOptions. $\endgroup$ – J. M. will be back soon Aug 27 '15 at 1:52
6
$\begingroup$

There are two issues with your code. The first is that you have a variable name clash when using x as the argument in the definition of temp. Changing it to something else, e.g. q, will work in an uncompiled version of your code.

fff[σt : {__Real}, sρ : {__?NumericQ}, dt : {__Real}, 
  x_Real, nnt_Integer, dqt_Real, divt_Integer] := 
 Module[{temp, dq = dqt, div = divt, j, h}, 
  temp[q_] := 
   Module[{kz = 1/2 q, σ = σt, d = dt, i, kp, 
     c, β, r, k, ρ = sρ*10^-6, nn = nnt}, 
    kp = kz + 0. I; 
    k = Sqrt[kz^2 - 4 π (ρ[[2]] - ρ[[1]])]; 
    r = (kp - k)/(kp + k) E^(-2 kp k σ[[1]]^2); 
    c = {{1 + 0. I, r}, {r, 1}}; kp = k; 
    For[i = 2, i < 2 nn + 2, i++, 
     If[EvenQ[i], 
      k = Sqrt[kz^2 - 4 π (ρ[[3]] - ρ[[1]])]; 
      r = (kp - k)/(kp + k) E^(-2 kp k σ[[2]]^2); 
      β =  I kp d[[1]], 
      k = Sqrt[kz^2 - 4 π (ρ[[2]] - ρ[[1]])]; 
      r = (kp - k)/(kp + k) E^(-2 kp k σ[[3]]^2); 
      β =  I kp d[[2]]]; 
     c = c.{{E^β, r E^β}, {r E^-β, E^-β}};
    (*previous k*)kp = k]; 
    Abs[c[[2, 1]]/c[[1, 1]]]^2]; h = 0.0; 
  For[j = 1, j < div + 1, j++, h = h + temp[x - dq/2 + dq/div*j]]; 
  h/div]

fff[{0.1, 0.2, 0.3}, {0.3 + 0.4 I, 0.4 - I, 1.2 + 0.6 I},
 {0.2, 0.4,  0.6}, 0.3, 5, 0.8, 3]

(* 7.65573*10^-8 *)

The second is that SetDelayed doesn't work inside Compile. This error message comes up once you make the above change to the compiled version. You will need to find a different way to write the code (probably shuffling it so that the function defined by temp is part of the code rather than being defined as a separate sub-function). Alternatively create the temp function outside the main function. There is a good example in the documentation (under "Neat Examples") of a function that involves many sub-functions.

As a small side note, you have defined β twice in your function but don't call it in between. This looks unintentional. There might be other problems with your code. I would strongly suggest testing an uncompiled version for correctness before moving to compilation.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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