I need to speed up a large program that repeatedly calls the module below (I've not trimmed the code for this question to ensure there is enough calculation to show a speed improvement.) The obvious way of making a step change in speed seemed to be use of Compile, so I create the second version show below, however, there is very marginal speed improvement. Am I doing something wrong?
ZrootsAnalytic[A_Real, B_Real] :=
Module[
{ Zroot1, Zroot2, Zroot3, term1, term2},
term1 = (-1. + 3. A - 4. B - 10. B^2.);
term2 = (2. - 9. A + 12. B + 36. A B - 12. B^2. -
56. B^3. + \[Sqrt](4. term1^3. + (2. - 9. A + 12. B + 36. A B -
12. B^2. - 56. B^3.)^2.))^(1./3.);
Zroot1 = (1. - B)/3. - (2.^(1./3.) term1)/(3. term2) +
1./(3. 2.^(1./3.)) term2;
Zroot2 = (1. - B)/
3. + ((1. + I Sqrt[3.]) term1)/(3. 2.^(2./3.) term2) -
1./(6. 2.^(1./3.)) (1. - I Sqrt[3.]) term2;
Zroot3 = (1. - B)/
3. + ((1. - I Sqrt[3.]) term1)/(3. 2.^(2./3.) term2) -
1./(6. 2.^(1./3.)) (1. + I Sqrt[3.]) term2;
{Zroot1, Zroot2, Zroot3 }
]
Compiled version of the code.
ZrootsAnalyticCC = Compile[
{{A, _Real}, {B, _Real}},
term1 = (-1. + 3. A - 4. B - 10. B^2.);
term2 = (2. - 9. A + 12. B + 36. A B - 12. B^2. -
56. B^3. + \[Sqrt](4. term1^3. + (2. - 9. A + 12. B + 36. A B -
12. B^2. - 56. B^3.)^2.))^(1./3.);
Zroot1 = (1. - B)/3. - (2.^(1./3.) term1)/(3. term2) +
1./(3. 2.^(1./3.)) term2;
Zroot2 = (1. - B)/
3. + ((1. + I Sqrt[3.]) term1)/(3. 2.^(2./3.) term2) -
1./(6. 2.^(1./3.)) (1. - I Sqrt[3.]) term2;
Zroot3 = (1. - B)/
3. + ((1. - I Sqrt[3.]) term1)/(3. 2.^(2./3.) term2) -
1./(6. 2.^(1./3.)) (1. + I Sqrt[3.]) term2;
{Zroot1, Zroot2, Zroot3 }
,
{{ Zroot1, _Complex, 0}, {Zroot2, _Complex, 0}, {Zroot3, _Complex,
0}, {term1, _Complex, 0}, { term2, _Complex, 0}},
CompilationTarget -> "C",
RuntimeAttributes -> {Listable},
RuntimeOptions -> "Speed",
CompilationOptions -> {"InlineCompiledFunctions" -> True}
]
Is it the use of imaginary no.'s that prevents speedup?
================== Here is a modified version of the code as suggested by Mark
ZrootsAnalyticCC =
Compile[
{{A, _Real}, {B, _Real}},
Module[{term1, term2, Zroot1, Zroot2, Zroot3},
term1 = (-1. + 3. A - 4. B - 10. B^2.);
term2 = (2. - 9. A + 12. B + 36. A B - 12. B^2. -
56. B^3. + \[Sqrt](4. term1^3. + (2. - 9. A + 12. B + 36. A B -
12. B^2. - 56. B^3.)^2.))^(1./3.);
Zroot1 = (1. - B)/3. - (2.^(1./3.) term1)/(3. term2) +
1./(3. 2.^(1./3.)) term2;
Zroot2 = (1. - B)/
3. + ((1. + I Sqrt[3.]) term1)/(3. 2.^(2./3.) term2) -
1./(6. 2.^(1./3.)) (1. - I Sqrt[3.]) term2;
Zroot3 = (1. - B)/
3. + ((1. - I Sqrt[3.]) term1)/(3. 2.^(2./3.) term2) -
1./(6. 2.^(1./3.)) (1. + I Sqrt[3.]) term2;
{Zroot1, Zroot2, Zroot3 }
]
,
{{ Zroot1, _Complex, 0}, {Zroot2, _Complex, 0}, {Zroot3, _Complex,
0}, { term1, _Complex, 0}, { term2, _Complex, 0}},
CompilationTarget -> "C"
]
I get no speed up and an error message:
ZrootsAnalyticCC[1., 1.] // AbsoluteTiming
CompiledFunction::cfne: Numerical error encountered; proceeding with uncompiled evaluation. >>
{0.046061, {1.86081 - 2.22045*10^-16 I, -2.11491 - 4.44089*10^-16 I,
0.254102 + 4.44089*10^-16 I}}
However, the problem goes away when I specify {{A, _Complex}, {B, _Complex}}
, the AbsoluteTiming for a single evaluation of ZrootsAnalyticCC is still about the same as the uncompiled version, but there is a 25x speed up when I evaluate it many times in table:
Table[ ZrootsAnalyticCC[1., 1.], {100000}]; // AbsoluteTiming