Recursive Reassignment of Variables in Clojure - recursion

I'm trying to get more acquainted with Clojre so I decided to do my Runge Kutta integrator project in it. However I'm having problems working with the immutable nature of the let statement. I want to evaluate 8 variables in each iteration of the loop and use them to recurse through it until my loop is finished.
The way I understand it, since my recur is inside the let's scope, my k's and l's won't be overwritten with each recursion. I'm looking for a more idiomatic way to recurse through my integrator.
(loop [psin 0 Xin 1 xn dx] ;initial values
(if (> xn 1)
psin
(let [k1 (evalg xn psin) ;define 4 variables to calculate next step of Xi, psi
l1 (evalf xn Xin) ;evalf and evalg evaluate the functions as per Runge Kutta
k2 (evalg (+ (* 0.5 dx) xn) (+ (* 0.5 l1) psin))
l2 (evalf (+ (* 0.5 dx) xn) (+ (* 0.5 k1) Xin))
k3 (evalg (+ (* 0.5 dx) xn) (+ (* 0.5 l2) psin))
l3 (evalf (+ (* 0.5 dx) xn) (+ (* 0.5 k2) Xin))
k4 (evalg (+ dx xn) (+ l3 psin))
l4 (evalf (+ dx xn) (+ k3 Xin))]
(do
(let [Xinew (+ Xin (* (/ dx 6) (+ k1 k4 (* 2 k3) (* 2 k2))) )
psinew (+ psin (* (/ dx 6) (+ l1 l4 (* 2 l2) (* 2 l3) )))]
(println k1)
(recur psinew Xinew (+ dx xn)))))))
Many thanks! Looking forward to getting more acquainted with clojure:)

First, as #Alex has commented, the recur does evaluate your ks and ls afresh on every iteration of the loop. A recur refers to its immediately enclosing function or loop form, in this case the latter.
The (println k1) suggests that what you are looking for is a sequence of k1s as you iterate round the loop.
Clojure has the concept of a lazy sequence: a potentially endless sequence of values that are
calculated when called for
forgotten if/when no longer accessible (garbage collected).
You should
frame the solution as a lazy-sequence of k1s and - while we're at
it -
make your evalg and evalf functions arguments to your runge-kutta
function.
We could build our lazy sequence from scratch, using explicit recursion wrapped in the lazy-seq macro, but there is a whole library of sequence functions to hand, one of which will usually express your intent. These can be faster than what you or I would write, but will still be much slower than your loop.
A handy function here is iterate. We can systematically convert your loop to use it as follows:
Convert the several loop arguments into a single destructured
vector argument to a local function (which I've called step).
Include any result you want, in this case k1 in the argument list.
Rewrite the iteration to return what were the next set of arguments
to the loop as a vector.
Call map on the resulting sequence to get the data you want.
My best guess is the following:
(defn runge-kutta [evalg evalf dx]
(letfn [(step [[k1 psin Xin xn]]
(let [k1 (evalg xn psin)
l1 (evalf xn Xin)
k2 (evalg (+ (* 0.5 dx) xn) (+ (* 0.5 l1) psin))
l2 (evalf (+ (* 0.5 dx) xn) (+ (* 0.5 k1) Xin))
k3 (evalg (+ (* 0.5 dx) xn) (+ (* 0.5 l2) psin))
l3 (evalf (+ (* 0.5 dx) xn) (+ (* 0.5 k2) Xin))
k4 (evalg (+ dx xn) (+ l3 psin))
l4 (evalf (+ dx xn) (+ k3 Xin))
Xinew (+ Xin (* (/ dx 6) (+ k1 k4 (* 2 k3) (* 2 k2))) )
psinew (+ psin (* (/ dx 6) (+ l1 l4 (* 2 l2) (* 2 l3) )))]
[k1 psinew Xinew (+ dx xn)]))]
(map first (iterate step [nil 0 1 dx]))))
There may well be errors in this, as I'm groping in the dark.
The sequence is endless. You can stop it
by returning the xns too, and wrapping the result in a take-while
or
working out how may iterations you want - it looks like (long (/ dx)),
though there may be a one-off error there. Then just use nth
or take to get what you want.
Let us know how you get on.

Related

Recursive call in Scheme language

I am reading sicp, there's a problem (practice 1.29), I write a scheme function to solve the the question, but it seems that the recursive call of the function get the wrong answer. Really strange to me. The code is following:
(define simpson
(lambda (f a b n)
(let ((h (/ (- b a) n))
(k 0))
(letrec
((sum (lambda (term start next end)
(if (> start end)
0
(+ (term start)
(sum term (next start) next end)))))
(next (lambda (x)
(let ()
(set! k (+ k 1))
(+ x h))))
(term (lambda (x)
(cond
((= k 0) (f a))
((= k n) (f b))
((even? k) (* 2
(f x)))
(else (* 4
(f x)))))))
(sum term a next b)))))
I didn't get the right answer.
For example, if I try to call the simpson function like this:
(simpson (lambda (x) x) 0 1 4)
I expected to get the 6, but it returned 10 to me, I am not sure where the error is.It seems to me that the function "sum" defined inside of Simpson function is not right.
If I rewrite the sum function inside of simpson using the iteration instead of recursive, I get the right answer.
You need to multiply the sum with h/3:
(* 1/3 h (sum term a next b))

Why Is This Tail-Recursive Function So Much More Complicated?

So, I'm fiddling with some basic maths, and I wanted a function to convert between bases.
I wrote this function:
(define (convert-base from to n)
(let f ([n n])
(if (zero? n)
n
(+ (modulo n to) (* from (f (quotient n to)))))))
Which works for all my personal tests < base 10 and would as far as I can imagine function perfectly fine for tests > base 10 if I just added support for additional digits.
What's confusing me is that when I tried to make the function tail-recursive, I ended up with this mess (I've added some spacing for SO's benefit, because my code is not often clear or pretty):
;e.g. 10 2 10 should output 1010, 10 8 64 should output 100 etc.
(define (convert-base-tail from to n)
(let f ([n n]
[acc 0]
[zeros 0])
(begin (printf "n is ~a. acc is ~a. zeros are ~a.\n" n acc zeros)
(cond [(zero? n) (let exp
([x acc]
[shft zeros])
(if (zero? shft)
x
(exp (* x 10) (- shft 1))))]
[(zero? (modulo n to))
(if (zero? acc)
(f (quotient n to) (* acc from) (add1 zeros))
(f (quotient n to) (* acc from) zeros))]
[else (f (quotient n to) (+ (* acc from) (modulo n to)) zeros )]))))
My question is, essentially, why is the tail-recursive function so much more complicated? Is it inevitable, due to the nature of the problem, or is it due to an oversight on my part?
It isn't, really:
(define (convert-base from to n)
(let f ([n n] [mul 1] [res 0])
(if (zero? n)
res
(f (quotient n to) (* mul from) (+ res (* mul (modulo n to)))))))
Testing
> (convert-base-y 10 2 10)
1010
> (convert-base-y 10 8 64)
100

Defining a recursive function as iterative?

I have the following recursive function that I need to convert to iterative in Scheme
(define (f n)
(if (< n 3) n
(+
(f (- n 1))
(* 2 (f(- n 2)))
(* 3 (f(- n 3)))
)
))
My issue is that I'm having difficulty converting it to iterative (i.e. make the recursion have linear execution time). I can think of no way to do this, because I just can't figure out how to do this.
The function is defined as follows:
f(n) = n if n<3 else f(n-1) + 2f(n-2) + 3f(n-3)
I have tried to calculate it for 5 linearly, like so
1 + 2 + f(3) + f(4) + f(5)
But in order to calculate say f(5) I'd need to refer back to f(4), f(3), f(2) and for f(4) Id have to refer back to f(3), f(2), f(1)
This is a problem from the SICP book.
In the book, authors have an example of formulating an iterative process for computing the Fibonacci numbers.
(define (fib n)
(fib-iter 1 0 n))
(define (fib-iter a b count)
(if (= count 0)
b
(fib-iter (+ a b) a (- count 1))))
The point here is that use two parameter a and b to memorise f(n+1) and f(n) during computing. The similar could be applied: we need a, b, c to memorise f(n+2), f(n+1) and f(n)
;; an interative process implementation
(define (f-i n)
;; f2 is f(n+2), f1 is f(n+1), f0 is f(n)
(define (interative-f f2 f1 f0 count)
(cond
((= count 0) f0)
(else (interative-f
(+ f2 (* f1 2) (* f0 3))
f2
f1
(- count 1)))))
(interative-f 2 1 0 n))

Trying to understand "let" in scheme

I'm trying to expand a simple fibonacci function, and I need to use the values for each term more than once. So, I figured I'd use let to hold onto the values. But, I'm not getting what I think I should out of the function.
Here is the original fib function:
(define (fib n)
(if (< n 2)
n
(+ (fib (- n 1)) (fib (- n 2)))))
Here is my attempt at doing the same thing, but with let:
(define (fib-with-let n)
(if (< n 2)
0
(let ((f1 (fib-with-let (- n 1)))
(f2 (fib-with-let (- n 2))))
(+ f1 f2))))
Results:
> (fib 10)
55
> (fib-with-let 10)
0
Thanks!
You made a typo:
(if (< n 2)
0
...)
You mean n.
You mistyped your base case. In the first version you had:
(if (< n 2)
n
But then in your latter version you wrote:
(if (< n 2)
0
So just change 0 to n.
Your let is not really doing anything. You are still doing all of the extra calculations. Just because you define f1 as (fib-with-let (- n 1)) doesn't mean you won't compute the fib of n-1 again. f2 does not use f1. If you wanted f2 to see f1 you would use let*. However, even this is not really what you want.
As evidence of this, here are the running times for fib(35) and fib-with-let(35):
(time (fib 35))
cpu time: 6824 real time: 6880 gc time: 0
(time (fib-with-let 35))
cpu time: 6779 real time: 6862 gc time: 0
What you really want to do to avoid extra computations is use dynamic programming and recurse in a bottom-up fashion.
What you want is the following code:
(define (dynprog-fib n)
(if (< n 2)
n
(dynprog-fib-helper 1 1 2 n)))
(define (dynprog-fib-helper n1 n2 current target)
(if (= current target)
n2
(dynprog-fib-helper n2 (+ n1 n2) (add1 current) target)))
(time (dynprog-fib 35))
cpu time: 0 real time: 0 gc time: 0
(time (dynprog-fib 150000))
cpu time: 2336 real time: 2471 gc time: 644
As you can see, you can do the first 150,000 fibs in a third of the time the naive approach takes.
Since it looks like you are confused about what let does let me illustrate better:
When you say:
(let ((a 1)
(b 2))
(+ a b))
What you are saying is, let a be 1, and b be 2, add them together.
If you instead said:
(let ((a 1)
(b (+ a 1))
(+ a b))
Can you guess what you'd get? Not 3. It would be blow up with expand: unbound identifier in module in: a
In simple let, your assignments cannot see each other.
If you wanted to write the above you would have to use let*:
(let* ((a 1)
(b (+ a 1))
(+ a b))
That would give you the 3 you expect. let* essentially expands to:
(let ((a 1))
(let ((b (+ a 1)))
(+ a b)))
What you thought you were doing with the lets is called memoization. It's a technique where you store intermediate values so you don't have to repeat them. Let, however, does not do that for you.
Although your problem is a typo in your fib-with-let function, in its simplest form, let is "syntatic-sugar" for an anonymous lambda followed by the arguments that are then evaluated and passed to the lamba, which is then evaluated and a final value returned. So
(let ((f1 (fib-with-let (- n 1)))
(f2 (fib-with-let (- n 2))))
(+ f1 f2))
would be re-written without let to look like
((lambda (f1 f2) (+ f1 f2))(fib-with-let (- n 1))(fib-with-let (- n 2)))

which programming practice to follow to evaluate expression in scheme

I am solving problems from htdp.org. I would like to know in scheme which is a better practice to evaluate long expressions having a common operator like '+' or '*'.
Example :
> (* 1 10 10 2 4) ; Version A
> (* 1 (* 10 (* 10 (* 2 4)))) ; Version B
Should I follow A or B. Also I please consider the above example for algebraic expressions like surface area of cylinder.
-Abhi
The real question should be, do they produce different results? Let's try in our REPL:
>> (* 1 10 10 2 4)
800
>> (* 1 (* 10 (* 10 (* 2 4))))
800
>>
Since they're essentially the same (using your example), I'd opt for going with lower ceremony / noise in the code. Use the first one.
A bit of a followup on this. (* a b c ...) is not necessarily equivalent to (* (* a b) ...) when you're talking about timing.
Some implementations may recognize the common operation, but try timing these two definitions of factorial:
(define (f1 n)
(let loop ((up 2)
(down n)
(a 1))
(cond ((> up down) a)
((= up down) (* a up))
(else
(loop (+ 1 up) (- 1 down)
(* a up down))))))
(define (f2 n)
(let loop ((up 2)
(down n)
(a 1))
(cond ((> up down) a)
((= up down) (* a up))
(else
(loop (+ 1 up) (- 1 down)
(* a (* up down)))))))
The second procedure is considerably faster than the first for me.

Resources