Skip to main content

functional style - About auto-compiling and performance between Do and Fold


I was investigating how Fold could improve performance vs Do. I tested the code


AbsoluteTiming[
sum = 1.0;

inc = 1.0;
Do[inc = inc*Sin[10.5]/i; sum = sum + Tan[inc], {i, 10^5}];
sum]

The output is


Out[] = {2.303896, 0.105747}

I have hoped that using Fold could improve the performance:


AbsoluteTiming@ 
Fold[{#[[1]]*Sin[10.5]/(#2 + 1), #[[2]] + Tan@#[[1]]} &,

{Sin[10.5], 1.0}, N@Range[10^5]]

However, this code is not faster:


Out[] = {2.471189, {-5.537337857006675*10^-462146, 0.105747}}

I have some questions concerning the above example:


(1) [Partially solved. See EDIT] Why the Fold here is not faster? I thought it should have been auto-compiled and thus faster. But it didn't.


(2) [Solved. See EDIT] Here Mathematica is using precision much higher than double precision (by having number as small as 10^{-462146}). Would it be possible to set precision to boost performance? I tried SetPricision and SetAccuracy. The precision changes but it doesn't improve performance.


(3) [Solved. See Mr. Wizard's example in his answer] Another problem of Fold is that one has first to generate a long list (length 10^5 in this example). For much larger list, the Fold method may use too much memory. Is it possible to use functional way (not necessarily Fold) in a more memory-efficient way?


Thank you very much!



PS: I met this question when trying to reproduce Mr.Wizard's answer of the below thread, with some modifications. I can reproduce Wizard's result, where Fold boots the performance greatly compared with Do. But I don't understand why my above example is not as good.


Alternatives to procedural loops and iterating over lists in Mathematica


EDIT:


(a) Rojo's comment is the answer of (2): SetSystemOptions["CatchMachineUnderflow" -> False]


(b) About the performance of Fold: on Mathematica v7 after disabling CatchMachineUnderflow, the Fold code is 10x faster then Do code. However, on Mathematica v9 the Fold code is a bit slower than Do. This seems like a regression in Mathematica. For comparison, this code has 10x improvement than the Do version: Fold[# + Sin[#2] &, 1.0, Range[10^6]] both on v7 and v9.



Answer



In version 7, after setting the option that Rojo described, your Fold code is nearly an order of magnitude faster than Do:


SetSystemOptions["CatchMachineUnderflow" -> False];

AbsoluteTiming[

sum = 1.0;
inc = 1.0;
Do[inc = inc*Sin[10.5]/i; sum = sum + Tan[inc], {i, 10^6}];
sum
]


{2.0100028, 0.105747}

AbsoluteTiming@

Fold[{(#[[1]] Sin[10.5])/(#2 + 1), #[[2]] + Tan[#[[1]]]} &, {Sin[10.5], 1.0},
N@Range[10^6]]


{0.2500003, {0., 0.105747}}

The Fold code can be made faster still with a few optimizations:


sin = Sin[10.5];

AbsoluteTiming[

Fold[
{Divide[#[[1]] sin, #2], #[[2]] + Tan[#[[1]]]} &,
{sin, 1.0},
Range[2, 10^6 + 1]
]
]


{0.1600025, {0., 0.105747}}


In this case splitting the operations and vectorizing Tan yields a greater improvement:


AbsoluteTiming[
1 + Tr @ Tan @ FoldList[Divide[# sin, #2] &, sin, Range[2, 10^6 + 1]]
]


{0.0600001, 0.105747}

This may use additional memory, but trading memory consumption for greater speed is a common programming compromise. If you need to work with longer lists you can split the list into sections and use the output of one Fold as the input for the next:


Fold[

Fold[{Divide[#[[1]] sin, #2], #[[2]] + Tan[#[[1]]]} &, #, Range[#2, #2 + 10000]] &,
{sin, 1.0},
Range[2, 10^7, 10000]
] // AbsoluteTiming


{1.8000025, {0., 0.105747}}

Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

equation solving - Invert and fit implicitly defined curve

I need to fit an implicitly defined curve. I thought I could get some data out of Solve , and then using FindFit . Therefore, I would like to find the relation the parametric curve defined by $F(x,y)=0$: Solve[-(1/2) + 1/2 (0.41202 BesselK[0, 0.1 Sqrt[x^2 + y^2]] + (0.101483 x BesselK[1, 0.1 Sqrt[x^2 + y^2]])/Sqrt[x^2 + y^2]) == 0, y] But I can't get an output: Solve was unable to solve the system with inexact coefficients or the system obtained by direct rationalization of inexact numbers present in the system. Since many of the methods used by Solve require exact input, providing Solve with an exact version of the system may help. >> Edit: In particular, I would like to fit the data coming from the curve with the expression of another curve, and not with a function $f(x)$. In particular, since this clearly looks like a cardioid , I would like it to fit to something like it. What other strategies could I try?

dynamic - How can I make a clickable ArrayPlot that returns input?

I would like to create a dynamic ArrayPlot so that the rectangles, when clicked, provide the input. Can I use ArrayPlot for this? Or is there something else I should have to use? Answer ArrayPlot is much more than just a simple array like Grid : it represents a ranged 2D dataset, and its visualization can be finetuned by options like DataReversed and DataRange . These features make it quite complicated to reproduce the same layout and order with Grid . Here I offer AnnotatedArrayPlot which comes in handy when your dataset is more than just a flat 2D array. The dynamic interface allows highlighting individual cells and possibly interacting with them. AnnotatedArrayPlot works the same way as ArrayPlot and accepts the same options plus Enabled , HighlightCoordinates , HighlightStyle and HighlightElementFunction . data = {{Missing["HasSomeMoreData"], GrayLevel[ 1], {RGBColor[0, 1, 1], RGBColor[0, 0, 1], GrayLevel[1]}, RGBColor[0, 1, 0]}, {GrayLevel[0], GrayLevel...