Creating a recursive tacit function in J - recursion

I'm a newcomer to J and I've been trying to create a Fibonacci function as an exercise (always the second function I create when learning a language). I just can't figure out what exactly is wrong in my way of doing it. I have tried to define it as tacit, but it gets hung if argument is greater than one.
fib =: [ ` (($: (]-1)) + ($: (]-2))) #. (>&1)
I've also attempted to create it explicitly, and that worked fine.
fib =: 3 : 'if. y>1 do. (fib (y-1)) + (fib (y-2)) else. y end.'
I tried to create a tacit out of that by replacing 3 with 13, but it threw an error.
fib =: 13 : 'if. y>1 do. (fib (y-1)) + (fib (y-2)) else. y end.'
|spelling error
| if. y>1 do. (fib (y-1)) + (fib (y-2)) else. y end.
| ^
| fib=: 13 :'if. y>1 do. (fib (y-1)) + (fib (y-2)) else. y end.'
So, I'm asking for someone to explain what exactly I am doing wrong here.

Here's an alternative that I think is both clearer and more concise:
fibn =: (-&2 +&$: -&1)^:(1&<) M."0
Compare with a more canonical (pseudocode) definition:
fib(n) = fib(n-1) + fib(n-2) if n > 2 else n
First, instead of using [ ` with #. (>&1), which uses a gerund, it's better to use ^:(1&<). For f(n) if cond(n) else n, using the ^: conjunction is more idiomatic; ^:0 means "do nothing" and ^:1 means "do once," so the intent is clear. #. is better suited to nontrivial behavior.
Second, using the & bond/compose conjunction simplifies the train significantly. Repeated uses of [: and ] are rather confusing and opaque. Refactoring using & puts together related operations: first, split n into two, namely n-2 and n-1, and second, add together the fibn of those two numbers.
And, lastly, "0 for list handling and M. for memoizing. M. is rather important from a performance perspective, as a straightforward implementation of the canonical definition will call fib(2) excessively. You can have your cake (a simple definition) and eat it too (good performance) with the built-in memoization adverb.
Source for this particular definition: f0b on this page.

Okay, I found it. I ran only the recursive block through tacit generator and got this block.
13 : '(f y-1) + (f y-2)'
([: f 1 -~ ]) + [: f 2 -~ ]
Then I inserted that to the original piece, getting this.
fib =: [ ` (([: $: 1 -~ ]) + [: $: 2 -~ ]) #. (>&1)
And that works like a charm. I also inserted " 0 to the end to make it accept lists.

Related

Recursive iteration of a function getting stack overflows

I'm trying to write a Maxima function that iterates another function provided as an argument. The goal is basically...
iter(f,0) ........ gives the identity function lambda([x],x)
iter(f,1) ........ gives f
iter(f,2) ........ gives lambda([x],f(f(x))
iter(f,3) ........ gives lambda([x],f(f(f(x)))
The reason is trying to figure out how an iterated polynomial behaves - similar to the Robert May population equation, but a different polynomial.
Anyway, I'm very new to Maxima (at least to things that seem more like simple programming than just asking for a solution) and after some time trying to figure out what I'm doing wrong, I think I've eliminated all silly mistakes and I must have a more fundamental misunderstanding of how Maxima works.
What I have...
iter(f,n) := if is (n=0)
then lambda ([x], x)
else block ([n2: floor (n/2),
nr: is (n2*2#n),
ff: iter (f,n2) ], if nr then lambda ([x],f(ff(ff(x))))
else lambda ([x], ff(ff(x)) ));
Maxima accepts this. Now as a simple example function to iterate...
inc(x):=x+1;
And some tests - first the base case...
iter(inc,0);
That works - it gives lambda([x],x) as expected. Next, "iterating" one time...
iter(inc,1);
I'm expecting something equivalent to inc, but because of the way this is written, more like lambda([x],inc(identity(identity(x))) but with more clutter. What I'm actually getting is a stack overflow...
Maxima encountered a Lisp error:
Control stack exhausted (no more space for function call frames).
This is probably due to heavily nested or infinitely recursive function
calls, or a tail call that SBCL cannot or has not optimized away.
...
I can't see why the is (n=0) base-case check would fail to spot that in the recursive call, so I can't see why this iter function would be entered more than twice for n=1 - it seems pretty extreme for that the exhaust the stack.
Of course once I have the basic idea working I'll probably special-case n=1 as effectively another base case for efficiency (a less cluttered resulting function definition) and add more checks, but I just want something that doesn't stack-overflow in trivial cases for now.
What am I misunderstanding?
Here's what I came up with. It's necessary to substitute into the body of lambda since the body is not evaluated -- I guess you have encountered this important point already.
(%i3) iter(f, n) := if n = 0 then identity elseif n = 1 then f
else subst([ff = iter(f, n - 1),'f = f],
lambda([x], f(ff(x)))) $
(%i4) iter(inc, 0);
(%o4) identity
(%i5) iter(inc, 1);
(%o5) inc
(%i6) iter(inc, 2);
(%o6) lambda([x], inc(inc(x)))
(%i7) iter(inc, 3);
(%o7) lambda([x], inc(inc(inc(x))))
(%i8) iter(inc, 4);
(%o8) lambda([x], inc(inc(inc(inc(x)))))
(%i9) inc(u) := u + 1 $
(%i10) iter(inc, 4);
(%o10) lambda([x], inc(x + 3))
(%i11) %(10);
(%o11) 14
(%i12) makelist (iter(cos, k), k, 0, 10);
(%o12) [identity, cos, lambda([x], cos(cos(x))),
lambda([x], cos(cos(cos(x)))), lambda([x],
cos(cos(cos(cos(x))))), lambda([x], cos(cos(cos(cos(cos(x)))))),
lambda([x], cos(cos(cos(cos(cos(cos(x))))))),
lambda([x], cos(cos(cos(cos(cos(cos(cos(x)))))))),
lambda([x], cos(cos(cos(cos(cos(cos(cos(cos(x))))))))),
lambda([x], cos(cos(cos(cos(cos(cos(cos(cos(cos(x)))))))))),
lambda([x], cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(x)))))))))))]
(%i13) map (lambda([f], f(0.1)), %);
(%o13) [0.1, 0.9950041652780257, 0.5444993958277886,
0.8553867058793604, 0.6559266636704799, 0.7924831019448093,
0.7020792679906703, 0.7635010336918854, 0.7224196362389732,
0.7502080588752906, 0.731547032044224]
Maxima is almost good at stuff like this -- since it is built on top of Lisp, the right conceptual elements are present. However, the lack of lexical scope is a serious problem when working on problems like this, because it means that when you refer to f within a function definition, it is the same f which might exist outside of it. When the solution depends on carefully distinguishing which f you mean, that's a problem.
Anyway as it stands I hope this solution is useful to you in some way.
Earlier, after a moment of inspiration, I tried the following in Maxima...
block([a:1,b:a],b);
This gave me a where I was expecting 1, which suggests that the b:a variable definition cannot see the a:1 variable definition earlier in the same block. I had assumed that later variable definitions in a block would be able to see earlier definitions, and that affects two variable definitions in my iter function - in particular, iter (f,n2) cannot see the definition of n2 which breaks the base-case check in the recursion.
What I have now (WARNING - NOT A WORKING SOLUTION) is...
iter(f,n) := if is (n=0)
then lambda ([x], x)
else block ([n2: floor (n/2)],
block ([g: iter (f,n2)],
if is (n2*2#n) then lambda ([x],f(g(g(x))))
else lambda ([x], g(g(x)) )));
I'm nesting one block inside another so that the later variable definition can see the earlier one. There is no nr (n was rounded?) variable, though TBH keeping that wouldn't have required a third nested block. I replaced ff with g at some point.
This solves the stack overflow issue - the base case of the recursion seems to be handled correctly now.
This still isn't working - it seems like the references to g now cannot see the definition of g for some reason.
iter(inc,0) ................. lambda([x],x)
iter(inc,1) ................. lambda([x],f(g(g(x))))
iter(inc,2) ................. lambda([x],g(g(x)))
...
When the recursive half-size iteration g is needed, for some reason it's not substituted. Also noticable - neither is f substituted.
As a best guess, this is probably due to the function calls being by-name in the generated lambda, and due to nothing forcing them to be substituted in or forcing the overall expression to be simplified.
(update - This SO question suggests I've understood the problem, but the solution doesn't appear to work in my case - what I'm trying to substitute is referenced via a variable no matter what.)
But it's also a different question (it's not a recursion/stack overflow issue) so I'll come back and ask another question if I can't figure it out. I'll also add a working solution here if/when I figure it out.
I tried a few more approaches using subst and the double-quote notation, but Maxima stubbornly kept referring to f and g by name. After a little thought, I switched approach - instead of generating a function, generate an expression. The working result is...
iter(v,e,n) := if is (n=0)
then ''v
else block ([n2: floor (n/2)],
block ([g: iter (v,e,n2)],
block ([gg: subst([''v=g], g)],
if is (n2*2#n) then subst([''v=e], gg)
else gg )));
The three nested block expressions are annoying - I'm probably still missing something that's obvious to anyone with any Maxima experience. Also, this is fragile - it probably needs some parameter checks, but not on every recursive call. Finally, it doesn't simplify result - it just builds an expression by applying direct substitution into itself.
What if you do everything with expressions?
(%i1) iter(e, n):= block([ans: e], thru n - 1 do ans: subst('x = e, ans), ans) $
(%i2) iter(x^2 + x, 1);
2
(%o2) x + x
(%i3) iter(x^2 + x, 2);
2 2 2
(%o3) (x + x) + x + x
(%i4) iter(x^2 + x, 3);
2 2 2 2 2 2 2
(%o4) ((x + x) + x + x) + (x + x) + x + x
You can define a function at the end:
(%i5) define(g(x), iter(x^2 + x, 3));

Functions with the same name but different arguments in functional languages

I see this code in the example of Elixir:
defmodule Recursion do
def print_multiple_times(msg, n) when n <= 1 do
IO.puts msg
end
def print_multiple_times(msg, n) do
IO.puts msg
print_multiple_times(msg, n - 1)
end
end
Recursion.print_multiple_times("Hello!", 3)
I see here the same function defined twice with different arguments, and I want to understand this technique.
Can I look at them as at overloaded functions?
Is it a single function with different behavior or are these two different functions, like print_only_once and print_multiple_times?
Are these functions linked anyhow or not?
Usually in functional languages a function is defined by clauses. For example, one way to implement Fibonacci in an imperative language would be the following code (not the best implementation):
def fibonacci(n):
if n < 0:
return None
if n == 0 or n == 1:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
To define the function in Elixir you would do the following:
defmodule Test do
def fibonacci(0), do: 1
def fibonacci(1), do: 1
def fibonacci(n) when n > 1 do
fibonacci(n-1) + fibonacci(n - 2)
end
def fibonacci(_), do: nil
end
Test.fibonacci/1 is only one function. A function with four clauses and arity of 1.
The first clause matches only when the number is 0.
The second clause matches only when the number is 1.
The third clause matches with any number greater than 1.
The last clause matches anything (_ is used when the value of the variable is not going to be used inside the clause or is not relevant for the match).
The clauses are evaluated in the order they are declared, so for Test.fibonacci(2) will fail in the first 2 clauses and match the third one because 2 > 1.
Think of clauses as a more powerful if statement. The code looks cleaner this way. And is very useful for recursion. For example, a map implementation (the language already provide one in Enum.map/2):
defmodule Test do
def map([], _), do: []
def map([x | xs], f) when is_function(f) do
[f.(x) | map(xs, f)]
end
end
First clause matches an empty list. No need to apply a function.
Second clause matches a list where the first element (head) is x and the rest of the list (tail) is xs and f is a function. It applies the function to the first element and recursively calls map with the rest of the list.
Calling Test.map([1,2,3], fn x -> x * 2 end) will give you the following output [2, 4, 6]
So, a function in Elixir is defined with one or more clauses where every clause have the same arity as the rest.
I hope this answers your question.
In the example you posted both definitions of the function have the same number of arguments: 2, this "when" thing is a guard, but you can also have definitions with many arguments. First, guards -- they are uses to express what cannot be written as a mere matching, like the second line of the following:
def fac(0), do: 1
def fac(n), when n<0 do: "no factorial for negative numbers!"
def fac(n), do: n*fac(n-1)
-- since it's not possible to express being negative number by just equality/matching.
Btw this fac is a single definition, only with three cases. Notice the coolness of using constant "0" in the position of argument :)
You can think of this as it would be nicer way to write:
def fac(n) do
if n==0, do: 1, else: if n<0, do: "no factorial!", else: n*fac(n-1)
end
or a switch case (which even looks pretty close to the above):
def fa(n) do
case n do
0 -> 1
n when n>0 -> n*fa(n-1)
_ -> "no no no"
end
end
only "looks more fancy". Actually it turns out certain definitions (e.g. parsers, small interpreters) look much better in the former than latter style. Nb guard expressions are very limited (I think you can't use your own function in guard).
Now the real thing, varying number of arguments -- check this out!
def mutant(a), do: a*a
def mutant(a,b), do: a*b
def mutant(a,b,c), do: mutant(a,b)+mutant(c)
e.g.
iex(1)> Lol.mutant(2)
4
iex(2)> Lol.mutant(2,3)
6
iex(3)> Lol.mutant(2,3,4)
22
It works a bit similar like (lambda arg ...) in scheme -- think of mutant as taking all its arguments as a list and matching over it. But this time, elixir treats mutant as 3 functions, mutant/1, mutant/2, and mutant/3 and will refer to them as such.
So, to answer your question: these are not like overloaded functions, but rather scattered/fragmented definitions. You see similar ones in functional languages like miranda, haskell or sml.

Multiply without + or *

I'm working my way through How to Design Programs on my own. I haven't quite grasped complex linear recursion, so I need a little help.
The problem:
Define multiply, which consumes two natural numbers, n and x, and produces n * x without using Scheme's *. Eliminate + from this definition, too.
Straightforward with the + sign:
(define (multiply n m)
(cond
[(zero? m) 0]
[else (+ n (multiply n (sub1 m)))]))
(= (multiply 3 3) 9)
I know to use add1, but I can't it the recursion right.
Thanks.
Split the problem in two functions. First, you need a function (add m n) which adds m to n. What is the base case? when n is zero, return m. What is the recursive step? add one to the result of calling add again, but decrementing n. You guessed it, add1 and sub1 will be useful.
The other function, (mul m n) is similar. What is the base case? if either m or n are zero, return 0. What is the recursive step? add (using the previously defined function) m to the result of calling mul again, but decrementing n. And that's it!
Since this is almost certainly a homework-type question, hints only.
How do you add 7 and 2? While most people just come up with 9, is there a more basic way?
How about you increment the first number and decrement the second number until one of them reaches zero?
Then the other one is the answer. Let's try the sample:
7 2
8 1
9 0 <- bingo
This will work fine for natural numbers though you need to be careful if you ever want to apply it to negatives. You can get into the situation (such as with 10 and -2) where both numbers are moving away from zero. Of course, you could check for that before hand and swap the operations.
So now you know can write + in terms of an increment and decrement instruction. It's not fantastic for recursion but, since your multiply-by-recursive-add already suffers the same problem, it's probably acceptable.
Now you just have to find out how to increment and decrement in LISP without using +. I wonder whether there might be some specific instructions for this :-)

lazy sequence depending on previous elements

Learning clojure, trying to create a lazy infinite sequence of all prime numbers.
I'm aware that there are more efficient algorithms; I'm doing the following more as a POC/lesson than as the ideal solution.
I have a function that, given a sequence of primes, tells me what the next prime is:
(next-prime [2 3 5]) ; result: 7
My lazy sequence must therefore pass itself to this function, then take the result and add that to itself.
My first attempt:
(def lazy-primes
(lazy-cat [2 3 5] (find-next-prime lazy-primes)))
..which results in an IllegalArgumentException: Don't know how to create ISeq from: java.lang.Integer
My second attempt:
(def lazy-primes
(lazy-cat [2 3 5] [(find-next-prime lazy-primes)]))
..which gives me [2 3 5 7] when asked for 10 elements.
Attempt 3:
(def lazy-primes
(lazy-cat [2 3 5]
(conj lazy-primes (find-next-prime lazy-primes))))
(take 10 lazy-primes) ; result: (2 3 5 7 2 3 5 7 2 3)
All of these seem like they should work (or at least, should work given that the preceding didn't work). Why am I getting the bogus output for each case?
Reasons why your initial attempts don't work:
(find-next-prime lazy-primes) returns an integer but lazy-cat needs a sequence
[(find-next-prime lazy-primes)] creates a vector (and is hence seqable) but it only gets evaluated once when it is first accessed
conj is adding new primes to the start of the sequence (since lazy-cat and hence lazy-primes returns a sequence)... which is probably not what you want! It's also possibly confusing find-next-prime depending on how that is implemented, and there might be a few subtle issues around chunked sequences as well.....
You might instead want to use something like:
(defn seq-fn [builder-fn num ss]
(cons
(builder-fn (take num ss))
(lazy-seq (seq-fn builder-fn (inc num) ss))))
(def lazy-primes
(lazy-cat [2 3 5] (seq-fn next-prime 3 lazy-primes)))
A bit complicated, but basically what I'm doing is using the higher-order helper function to provide a closure over a set of parameters that includes the number of primes created so far, so that it can generate the next prime incrementally at each step.
p.s. as I'm sure you are aware there are faster algorithms for generating primes! I'm assuming that this is intended primarily as an exercise in Clojure and the use of lazy sequences, in which case all well and good! But if you really care about generating lots of primes I'd recommend taking a look at the Sieve of Atkin
Alternatively, you could use iterate: the built-in function that lazily takes the output of a function and applies that to the function again
clojure.core/iterate
([f x])
Returns a lazy sequence of x, (f x), (f (f x)) etc.
f must be free of side-effects
in order for you to make it work, the next-prime function should concatenate its result to its input, and return the concatenation.
Then you can just call (take 100 (iterate list-primes [1])) to get a list of the first 100
primes.
With your next-prime function you can generate a lazy sequence of all primes with the following snippet of code:
(def primes (map peek (iterate #(conj % (next-prime %)) [2])))
The combination you are looking for is concat + lazy-seq + local fn.
Take a look at the implementation of Erathostenes' Sieve in the Clojure Contrib libraries: https://github.com/richhickey/clojure-contrib/blob/78ee9b3e64c5ac6082fb223fc79292175e8e4f0c/src/main/clojure/clojure/contrib/lazy_seqs.clj#L66
One more word, though: this implementation uses a more sophisticated algorithm for the Sieve in a functional language.
Another implementation for Clojure can be found in Rosetta code. However, I don't like that one as it uses atoms, which you don't need for the solution of this algo in Clojure.

Project Euler #211 - efficiency issue

I've been slowly working my way through the list of Project Euler problems, and I've come to one that I know how to solve, but it seems like I can't (given the way my solution was written).
I am using Common Lisp to do this with and my script has been running for over 24 hours (well over their one minute goal).
For the sake of conciseness, here's my solution (it's a spoiler, but only if you have one hell of a fast processor):
(defun square? (num)
(if (integerp (sqrt num)) T))
(defun factors (num)
(let ((l '()))
(do ((current 1 (1+ current)))
((> current (/ num current)))
(if (= 0 (mod num current))
(if (= current (/ num current))
(setf l (append l (list current)))
(setf l (append l (list current (/ num current)))))))
(sort l #'< )))
(defun o_2 (n)
(reduce #'+ (mapcar (lambda (x) (* x x)) (factors n))))
(defun sum-divisor-squares (limit)
(loop for i from 1 to limit when (square? (o_2 i)) summing i))
(defun euler-211 ()
(sum-divisor-squares 64000000))
The time required to solve the problem using smaller, more friendly, test arguments seems to grow larger than exponentialy... which is a real problem.
It took:
0.007 seconds to solve for 100
0.107 seconds to solve for 1000
2.020 seconds to solve for 10000
56.61 seconds to solve for 100000
1835.385 seconds to solve for 1000000
24+ hours to solve for 64000000
I'm really trying to figure out which part(s) of the script is causing it to take so long. I've put some thought into memoizing the factors function, but I'm at a loss as to how to actually implement that.
For those that want to take a look at the problem itself, here it be.
Any ideas on how to make this thing go faster would be greatly appreciated.
**sorry if this is a spoiler to anyone, it's not meant to be.... but if you have the computing power to run this in a decent amount of time, more power to you.
Here's a solution, keeping in mind the spirit of [Project] Euler. [Warning: spoiler. I've tried to keep the hints slow, so that you can read only part of the answer and think on your own if you want. :)]
When you are confronted with a problem having to do with numbers, one good strategy (as you probably already know from solving 210 Project Euler problems) is to look at small examples, find a pattern, and prove it. [The last part may be optional depending on your attitude to mathematics ;-)]
In this problem, though, looking at small examples -- for n=1,2,3,4,... will probably not give you any hint. But there is another sense of "small examples" when dealing with number-theoretic problems, which you also probably know by now -- primes are the building blocks of the natural numbers, so start with the primes.
For a prime number p, its only divisors are 1 and p, so the sum of the squares of its divisors is 1+p2.
For a prime power pk, its only divisors are 1, p, p2, … pk, so the sum of the squares of its divisors is 1+p+p2+…+pk=(pk+1-1)/(p-1).
That was the simplest case: you've solved the problem for all numbers with only one prime factor.
So far nothing special. Now suppose you have a number n that has two prime factors, say n=pq. Then its factors are 1, p, q, and pq, so the sum of the squares of its divisors is 1+p2+q2+p2q2=(1+p2)(1+q2).
What about n=paqb? What is the sum of the squares of its factors?
[............................Dangerous to read below this line...................]
It is ∑0≤c≤a, 0≤d≤b(pcqd)2 = ((pa+1-1)/(p-1))((qb+1-1)/(q-1)).
That should give you the hint, both on what the answer is and how to prove it: the sum of the divisors of n is simply the product of the (answer) for each of the prime powers in its factorization, so all you need to do is to factorize 64000000 (which is very easy to do even in one's head :-)) and multiply the answer for each (=both, because the only primes are 2 and 5) of its prime powers.
That solves the Project Euler problem; now the moral to take away from it.
The more general fact here is about multiplicative functions -- functions on the natural numbers such that f(mn) = f(m)f(n) whenever gcd(m,n)=1, i.e. m and n have no prime factors in common. If you have such a function, the value of the function at a particular number is completely determined by its values at prime powers (can you prove this?)
The slightly harder fact, which you can try to prove[it's not that hard], is this: if you have a multiplicative function f [here, f(n)=n2] and you define the function F as F(n) = ∑d divides nf(d), (as the problem did here) then F(n) is also a multiplicative function.
[In fact something very beautiful is true, but don't look at it just yet, and you'll probably never need it. :-)]
I think that your algorithm is not the most efficient possible. Hint: you may be starting from the wrong side.
edit: I'd like to add that choosing 64000000 as the upper limit is likely the problem poster's way of telling you to think of something better.
edit: A few efficiency hints:
instead of
(setf l (append l (...)))
you can use
(push (...) l)
which destructively modifies your list by consing a new cell with your value as car and the former l as cdr, then points l to this cell. This is much faster than appending which has to traverse the list once each. If you need the list in the other order, you can nreverse it after it is complete (but that is not needed here).
why do you sort l?
you can make (> current (/ num current)) more efficient by comparing with the square root of num instead (which only needs to be computed once per num).
is it perhaps possible to find the factors of a number more efficiently?
And a style hint: You can put the scope of l into the do declaration:
(do ((l ())
(current 1 (+ current 1)))
((> current (/ num current))
l)
...)
I would attack this by doing the prime factorization of the number (for example: 300 = 2^2 * 3^1 * 5^2), which is relatively fast, especially if you generate this by sieve. From this, it's relatively simple to generate the factors by iterating i=0..2; j=0..1; k=0..2, and doing 2^i * 3^j * 5^k.
5 3 2
-----
0 0 0 = 1
0 0 1 = 2
0 0 2 = 4
0 1 0 = 3
0 1 1 = 6
0 1 2 = 12
1 0 0 = 5
1 0 1 = 10
1 0 2 = 20
1 1 0 = 15
1 1 1 = 30
1 1 2 = 60
2 0 0 = 25
2 0 1 = 50
2 0 2 = 100
2 1 0 = 75
2 1 1 = 150
2 1 2 = 300
This might not be fast enough
The clever trick you are missing is that you don't need to factor the numbers at all
How many numbers from 1..N are multiples of 1? N
How many numbers from 1..N are multiples of 2? N/2
The trick is to sum each number's factors in a list.
For 1, add 1^2 to every number in the list. For 2, add 2^2 to every other number.
For 3, add 3^2 to every 3rd number.
Don't check for divisibility at all.
At the end, you do have to check whether the sum is a perfect square, and that's it.
In C++, this worked in 58 seconds for me.
Sorry, I don't understand LISP well enough to read your answer. But my first impression is that the time cost of the brute force solution should be:
open bracket
sqrt(k) to find the divisors of k (by trial division), square each one (constant time per factor), and sum them (constant time per factor). This is σ2(k), which I will call x.
plus
not sure what the complexity of a good integer square root algorithm is, but certainly no worse than sqrt(x) (dumb trial multiplication). x might well be big-O larger than k, so I reserve judgement here, but x is obviously bounded above by k^3, because k has at most k divisors, each itself no bigger than k and hence its square no bigger than k^2. It's been so long since my maths degree that I have no idea how fast Newton-Raphson converges, but I suspect it's faster than sqrt(x), and if all else fails a binary chop is log(x).
close bracket
multiplied by n (as k ranges 1 .. n).
So if your algorithm is worse than O(n * sqrt(n^3)) = O(n ^ (5/2)), in the dumb-sqrt case, or O(n * (sqrt(n) + log(n^3)) = O(n ^ 3/2) in the clever-sqrt case, I think something has gone wrong which should be identifiable in the algorithm. At this point I'm stuck because I can't debug your LISP.
Oh, I've assumed that arithmetic is constant-time for the numbers in use. It darn well should be for numbers as small as 64 million, and the cube of that fits in a 64bit unsigned integer, barely. But even if your LISP implementation is making arithmetic worse than O(1), it shouldn't be worse than O(log n), so it won't have much affect on the complexity. Certainly won't make it super-polynomial.
This is where someone comes along and tells me just how wrong I am.
Oops, I just looked at your actual timing figures. They aren't worse than exponential. Ignoring the first and last values (because small times aren't accurately measurable and you haven't finished, respectively), multiplying n by 10 multiplies time by no more than 30-ish. 30 is about 10^1.5, which is about right for brute force as described above.
I think you can attack this problem with something like a prime sieve. That's only my first impression though.
I've reworked the program with some notes taken from the comments here. The 'factors' function is now ever so slightly more efficient and I also had to modify the σ_(2)(n) function to accept the new output.
'factors' went from having an output like:
$ (factors 10) => (1 2 5 10)
to having one like
$ (factors 10) => ((2 5) (1 10))
Revised function looks like this:
(defun o_2 (n)
"sum of squares of divisors"
(reduce #'+ (mapcar (lambda (x) (* x x)) (reduce #'append (factors n)))))
After the modest re-writes I did, I only saved about 7 seconds in the calculation for 100,000.
Looks like I'm going to have to get off of my ass and write a more direct approach.

Resources