Python Development, memoized functions.

Antti Karttunen antti.karttunen at gmail.com
Fri Jan 5 02:17:21 CET 2007


Alec Mihailovs wrote:

> From: "Antti Karttunen" <antti.karttunen at gmail.com>
>
>> @M
>> def A000045(n):  if(n < 2): return(n) else: 
>> return(A000045(n-1)+A000045(n-2))
>
>
> Another way of doing this is to define A000045_list first (that saves 
> all the calculated values in a list), and then define A000045 as the 
> last element of the list. Such as
>
> def A000045_list(n):
> result=[0]
> a,b=0,1
> for i in range(n):
>     result.append(b)
>     a,b=b,a+b
> return result
>
> def A000045(n): return A000045_list(n)[-1]
>
> That should calculate values faster than the recursive procedure with 
> memoization because that avoids multiple function calls.  


What is the ratio of speedwise improvement of the latter list-version 
vs. the former memoized version,
compared to the ratio of speedwise improvent of the version written in 
assembly language vs. the above Python list-version?
 And compare similar ratios for the legibility and the ease of use.
(My point: in any case, Python is slow compared to assembly, C or even 
Scheme compiled into native code.)

Point against my view ("Advocatus Diaboli"): An one-liner like:

  def A000045(n):  if(n < 2): return(n) else: 
return(A000045(n-1)+A000045(n-2))

is not anymore "program", it's a formula/definition, which does not give 
any more information
than the %F-line itself: a(0)=0, a(1)=1, a(n) = a(n-1)+a(n-2).

"Promotor Fidei": On the other hand, if it can be computed efficiently, 
then it's a very good proram.
(Brief and very legible at the same time.) Why should we specify/need 
some ancillary
information concerning allocation of lists et cetera, when that doesn't 
affect the mathematical
definition of the function, just makes the implementation more error-prone?

> Alec Mihailovs wrote:
> From: "Alec Mihailovs" <alec at mihailovs.com>
> To: "Antti Karttunen" <antti.karttunen at gmail.com>
>
>>> What will happen when you call A000045 multiple times, with varying 
>>> n (increasing and decreasing
>>> at times)?
>>
>>
>> In this case, certainly, memoization has an advantage.
>
>> From other point of view, that also can be done as assigning 
>
> A000045=A000045_list(1000)
> or with other than 1000 number, greater than the indices needed, and then
> using A000045[n] instead of A000045(n) - that would be the same as 
> with memoization.

How do you know what will be the maximum index one needs?
E.g. if somebody wants to calculate something like 
http://www.research.att.com/~njas/sequences/A001605 ?
Or http://www.research.att.com/~njas/sequences/A003714
which itself might be called from yet another function?
In the latter case the calls to A000045 doesn't need to occur
in order A000045(i), A000045(i+1), A000045(i+2), ...
but could happen in any order. (With Fibonacci's we know that
the "memo-vector" will not contain "holes", but this is not case
in general, with functions that involve recursions like
a(n) = a(floor(n/2)) + ... )


>
> Alec
>

Antti






More information about the SeqFan mailing list