Write a procedure rsum that sums the reciprocals of the elements of a list. So rsum( [a,b,c] ) should return 1/a + 1/b + 1/c.
How would i modify my code so that it does this... I know theres a much simpler way (rsum := L -> add( 1/x, x in L ):) but i would like to know how to edit the one ive done.
Heres my code so far...
rsum := proc(L)
local n;
for n in L do
1/n
end do;
end proc;
I think I have to define (for ex), N, as something then have...
for n in L do
N, 1/n.
Any help on this please?
summing
You need to initialize a value to zero and then increment it in the loop.
gc
I wonder if this creates a lot of sums that will need to be garbage collected, like trying to build up a list in a loop.
I would probably use a one-liner to avoid creating garbage:
rsumshort := proc(L)
option inline;
`+`(op(map(`/`,L)));
end proc;
L:=[seq(cat(`a`,i), i=1..10000)]:
time(rsumshort(L));
0.044
time(rsum(L));
10.064
inefficient
Yes, excellent point. I'm embarrassed that I didn't notice this; I wasn't thinking of a symbolic list. If the elements in the list are numeric, then this is not an issue. Of course, the proper method is to use add, but the original poster explicitly ruled that out. Your method is a nifty workaround, but I don't see any practical reasons to prefer it over add.
The reason that the do loop is O(n^2) with symbolic elements is that the k'th pass through the loop creates a partial summation with k distinct elements: a1 + a2 + ... + ak. This summand is stored, at least temporarily, in the Maple simplification table. So n passes creates a total of n objects with sizes from 1 to n, hence the total memory requirement is n*(n+1)/2, which is O(n^2).
Use an Array?
I didn't read the OP carefully enough. If one really wants to do something like this with a do loop, one should build up a mutable object in the loop, then convert it to a sum afterwards. Here it is using an Array, but you could use a table instead.
rsum_array := proc(L::list) local A, i, x; A := Array(1..nops(L)); # this will store the summands i := 1; for x in L do A[i] := 1/x; i := i + 1; end do; return convert(A,`+`); end proc:time(rsum_array(L));
0.080
Using a table is not as straight forward but almost as fast:
rsum_table := proc(L::list) local T, i, x; T := table(); # this will store the summands i := 1; for x in L do T[i] := 1/x; i := i + 1; end do; return convert(map(op,[entries(T)]), `+`); end proc:time(rsum_table(L)); 0.088nolist
Just a note. The entries (indices) command provide a 'nolist' option that returns the results without enclosing each entry in a list, so you can forego the map(op, ...) call:
I prefer, however,
old
convert(...,`+`) is an old technique. I am not 100% sure, but I suspect that it may predate add.
acer
convert/+
I see that one can directly convert from a table to `+`, the call to entries is not needed:
Note that the eval is necessary, otherwise the table itself is returned. This is different than when convert/list is called:
The add and mul functions
The add and mul functions were introduced in Maple V Release 4: see the help page ?updatesR4,language. I'm sure convert(...,`+`) goes way back, long before I became involved with Maple. It's mentioned in the Maple V Library Reference Manual (that's for Maple V Release 1, copyright 1991)
efficiency
I thought convert(...,`+`) might be more efficient than add() but I guess that SUM dag is not just a list with a different label, so convert is probably doing nearly the same computation as 'add' (though it does it without needing a local variable).
add: local variable
I was going to mention that that could be an advantage of convert/+, however, one can safely use a global variable with add (which permits it to be inlined). That is
is, so far as I can ascertain, completely safe and works properly regardless whether x is assigned. Are there exceptions? Note that this is not the case with seq:
This fails with the list [g(x)].
The variable x should be declared as local, which precludes inlining the procedure.