On my machine
function[x_, y_] := If[x < Exp[y], Sqrt[1 - x/Exp[y]], 0];
functionTotal1[x_] := Sum[function[x, 0.02*j], {j, 0, 4*10^5, 1}];
RepeatedTiming[functionTotal1[2]]
{6.631, 399935.}
Here are a few things that I noticed that speed up evaluation.
Each term is real or imaginary
First we see that if $x \leq \exp(y)$, then $\sqrt{1-x e^{-y}}$ is real, and if $x > \exp(y)$, then $\sqrt{1-x e^{-y}}$ is strictly imaginary. Therefore, if we get rid of the If
and ignore all the imaginary terms (effectively setting each term where $x > \exp(y)$ to zero)
f[x_, y_] := Sqrt[1 - x/Exp[y]]
ftot[x_] := Re@Sum[f[x, 0.02*j], {j, 0., 4.*10^5}]
RepeatedTiming[ftot[2]]
{5.3, 399935.}
Vectorization and packed arrays
With the thought of restructuring the Sum
into a Dot
to utilize vectorization, we rewrite the term $\sqrt{1-x e^{-y}}$ into a product of terms as $e^{-y/2} \sqrt{e^y-x}$. Then, skipping the declaration of the "term" function, the sum can be written as
ftotdot[x_] := Dot @@ (Transpose@Table[{Exp[-0.02 y/2], Sqrt[Exp[0.02 y] - x]}, {y, 0., 4.*10^5}]) // Re
ftotdot[2] // RepeatedTiming
{2.91, 399935.}
Then, since Exp
and arithmetic operators are vectorized we can replace the Table
with an evaluation of the packed array in Range
.
ftotdot2[x_] := Exp[-#/2].Sqrt[Exp[#] - x] &[0.02 Range[0., 4.*10^5]]) // Re
ftotdot2[2] // RepeatedTiming
{2.3, 399935.}
Further improvements may include the use of SparseArray
s, Compile
, even just parallelization.
ParallelSum
. $\endgroup$