speeding up programs (was slowness in repeated Maxima evaluations) from Sage



So far as I can tell, the original computation in Maxima was

(fc_all(n):=fc_ab(-1,n,-%pi,(-%pi)/2)+fc_ab(2,n,-%pi/2,0)
       +fc_ab(-1,n,0,%pi/2)+fc_ab(2,n,%pi/2,%pi),
fc_ab(e,n,a,b):=if n = 0 then [integrate(e,x,a,b)/(2*%pi),0]
       else fc1_ab(e,n,a,b),
fc1_ab(e,n,a,b):=[integrate(e*cos(n*x),x,a,b)/%pi,
       integrate(e*sin(n*x),x,a,b)/%pi],
coefs : map (fc_all, makelist (i, i, 0, 15)),
fsum : sum (coefs[1 + n][1] * cos (n*x) + coefs[1 + n][2] * sin (n*x), 
n, 0, 15),
xx : makelist ((i - 1) * 2 * %pi / 100 - %pi,i,1,101),numer,
fsum_xx : makelist (''fsum, x, xx), numer);

which in my (GCL) maxima takes 5 seconds.
There are a number of peculiarities in the way this computation was set 
up, perhaps some because the original author was not concerned with 
efficiency, or aware of the consequences of programming in certain ways. 
or perhaps Sage is itself producing bad stuff from good input. I don't 
know which. Anyway, a few changes to make it into idiomatic Maxima 
results in a program that is over 30X faster.  Usually this kind of 
speedup is an indication that something should have been done another 
way.  Especially when the faster program is also shorter and clearer.

What is being done wrong?   Well, it seems that many computations with 
large expressions are being done with symbols such as %pi in them, and 
then later, %pi is replaced with 3.14159...  at which point the large 
expressions become a single numbers.

If one does the same calculations but using 3.1415... instead of the 
symbol %pi, few of those large expressions are produced. Just numbers.

Another thing.
  If you are computing a symbolic integral  integrate(XXXX,x,a,b),  then 
when you change the limits, you don't have to recompute the symbolic 
integral.  Just change the limits.
Another thing. Using arrays instead of lists is usually a good thing, if 
you are going to access data by array references.

Also, if you are going to define global variables and functions and 
never use them again you should kill them.  In debugging, I usually use 
a "batch" file and kill all the data at the beginning, wiping out all 
previous definitions.

Here's a version of the same computation. Maybe Sagenatics (Sagenicks?)  
in addition to the original author will be able to see some useful 
idioms here. 


(kill(fc_ab,coefs,fsum,xx,fsum_xx,pi),
pi:ev(%pi,numer),
fc_ab[n,e](a,b):= [integrate(e*cos(n*x),x,a,b)/pi,
                   integrate(e*sin(n*x),x,a,b)/pi],
coefs[n]:= fc_ab[n,-1](-pi,-pi/2)  +  fc_ab[n,2](-pi/2,0)
          +fc_ab[n,-1](0,pi/2)  +  fc_ab[n,2](pi/2,pi),
fsum(z) := sum (coefs[n][1] * cos (n*z) + coefs[n][2] * sin (n*z), n, 0, 
15),
xx[i] := pi*(i-51)/50,
fsum_xx:makelist(fsum(xx[i]),i,1,101))