SICP 2.16 interval-arithmetic (scheme) - algorithm

This isn't a homework question, I'm just left unsatisfied with my understanding of interval arithmetic and the implications of exercise 2.16.
The interval arithmetic defined by section 2.14 does not exhibit the properties of normal arithmetic. Two should be equivalent operations, (r1*r2)/(r1 + r2) and 1/(1/r1 + 1/r2),
give different results. The exercise asks why this is the case, and if it is possible to construct an interval-arithmetic system in which this is not the case.
The section is addressing the calculation of error margins of resistance of electrical components. I'm not sure I understand what it would mean, in these terms, to multiply and divide intervals. What is the application to multiplying two intervals together?
Is it possible to construct an interval-arithmetic system without the problem in this example?
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1.4
(define (make-interval a b)
(cons a b))
(define (make-center-width c w)
(make-interval (- c w) (+ c w)))
(define (make-center-percent c p)
(make-center-width c (* c (/ p 100.0))))
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
(define (center i)
(/ (+ (upper-bound i) (lower-bound i)) 2))
(define (width i)
(/ (- (upper-bound i) (lower-bound i)) 2))
(define (percent i)
(* 100.0 (/ (width i) (center i))))
(define (add-interval x y)
(make-interval (+ (lower-bound x) (lower-bound y))
(+ (upper-bound x) (upper-bound y))))
(define (sub-interval x y)
(make-interval (- (lower-bound x) (lower-bound y))
(- (upper-bound x) (upper-bound y))))
(define (mul-interval x y)
(let ((p1 (* (lower-bound x) (lower-bound y)))
(p2 (* (lower-bound x) (lower-bound y)))
(p3 (* (lower-bound x) (lower-bound y)))
(p4 (* (lower-bound x) (lower-bound y))))
(make-interval (min p1 p2 p3 p4)
(max p1 p2 p3 p4))))
(define (div-interval x y)
(if (= (width y ) 0)
(error "division by interval with width 0")
(mul-interval x
(make-interval (/ 1.0 (upper-bound y))
(/ 1.0 (lower-bound y))))))
(define (parl1 r1 r2)
(div-interval (mul-interval r1 r2)
(add-interval r1 r2)))
(define (parl2 r1 r2)
(let ((one (make-interval 1 1)))
(div-interval one
(add-interval (div-interval one r1)
(div-interval one r2))))
(define (r1 (make-interval 4.0 3.2)))
(define (r2 (make-interval 3.0 7.2)))
(center (parl1 r1 r2))
(width (parl1 r1 r2))
(newline)
(center (parl2 r1 r2))
(width (parl2 r1 r2))

This happens because the operations in the interval arithmetic do not have the arithmetic structure of a field.
As Sussman says, the exercise is difficult -- you need to check each of the operations of the field structure, and see which one is not satisfied.
The exercise asks us to show that the interval arithmetic is not the arithmetic of the ranges of functions.
A function like f (x) = x^2 defined on a domain [-1, 1] has the
range [0,1], which is included in [-1,1] * [-1,1] = [-1,1], obtained by replacing the symbol x by the domain of the symbol x.
If we define a similar function that uses a different variable for each dimension, like in f(x,y) = x * y, then the range of this function, when defined on the domain [-1,1] * [-1,1], is the same as the interval [-1,1] * [-1,1] = [-1, 1], because x is used once, and so with y.
It happens that all the time when the function f(.., x, ..) is continous in each variable x we have the range arithmetics to be identical with interval arithmetics if each symbol is used only once in definition of f.
In the first formula of Alice, parallel resistor is computed
repeating 2 times the variable R1, and 2 times the variable R2,
and using the same argument the range of this function is included
in the product of the corresponding intervals obtained from the
formula of the function, by replacing each name by corresponding
domain interval, but it is not strictly the same.
We are asked either to rewrite any function such that the range of the rewritten function be the same as the interval obtained by applying the rewritten function's formula, wih names replaced by intervals equal to the domain of the corresponding name from the rewritten function, or to show that this is not possible for each possible function.
This problem is called dependency problem, and it is a large
problem, whose understanding is out of the purpose of SICP, and requires differential equations in multiple variables to solve it.
The purpose of this exercise is , as Sussman himself said, just to show that data can be encoded in multiple ways. The focus is not on mathematics , but on data abstraction.

The easiest way to understand the problem is looking at the very simple expression e = x/x where x is in [2,3]. If we use interval arithmetic, we get that e is in [2/3, 3/2], however second grade arithmetic shows that e=x/x=1. So what gives?
Well it is actually very simple: when using interval arithmetic I made the mistake of assuming x can have two different values at the same time.
the maximum value of e is given when the numerator is 3 and the denominator is 2, however since both should always be the same this is not possible.
So, is it ever possible to use interval arithmetic? Yes, when all intervals appear only once, since then you would not have the problem of different values for the same variable in different interval calculations.
Is it possible to create an arithmetic package which does not have this problem? No, since not every function can be written where every variable appears only once. This problem is known as the dependency problem.

Related

Define a procedure that takes three numbers as arguments and returns the sum of the squares of the two larger numbers

I'm having trouble figuring out how to sort out the 2 biggest numbers and return them into the sum of squares procedure. I am struggling to write the code out in Scheme's syntax. I'm trying to write it as cleanly as possible, and I keep running circles in my head and on paper trying to do so. the book describes thinking "procedurally" and I think I'm having trouble with that aspect.
The book provides code for the sum-of-squares and square procedures. I would include my pseudo code but I'm severely lost. Here is the code the book provides:
(define (square x) (* x x))
(define (sum-of-squares x y)
(+ (square x) (square y)))
How to define a procedure that takes three numbers as arguments and returns the sum of the squares of the two larger numbers?
How to define a procedure that takes three numbers as arguments and returns the sum of the squares of the two larger numbers?
First you need a name for the procedure. Let's called it sum-of-squares-two-largest.
(define (sum-of-squares-two-largest x y z)
...)
It can make use of the sum-of-squares function, but it needs to find the two largest numbers out of x,y,z first.
One way to do this would be to get rid of the smallest number. You could define a helper procedure smallest? a b c that checks that a is the smallest of the 3 numbers by doing (and (<= a b) (<= a c)).
(define (sum-of-squares-two-largest x y z)
(if (smallest? x y z)
(sum-of-squares y z)
(if (smallest? y x z)
...]
Write the code for min-of-three. Its negative (as in photography) is what you need:
(define (negative-min-of-three a b c)
(if (<= a b)
(if (<= a c)
(..... b ... c .....)
(..... a ... b .....))
(if (<=
..........
You can complete the code, and rename it. The clock is ticking!
I created two methods to get the largest and the one in the middle for the time being.
(define (largest x y z)
(cond ((and (> x y) (> x z)) x)
((and (> y x) (> y z)) y)
(else z))
)
(define (mid x y z)
(cond ((and (> x y) (< x z)) x)
((and (> y x) (< y z)) y)
(else z))
)
(define (square a)
(* a a)
)
(define (sum-of-two-largest x y z)
(+ (square (largest x y z)) (square (mid x y z)))
)
(sum-of-two-largest -12 -4 1)
The hard part of this is, if you're reading SICP book, finding the 2nd largest number of the three. You can observe, if we let c < b < a, that:
a = max(a, b) gives the largest of the two numbers
b = max(c, b) gives the largest of the two smaller numbers
But how do we get the variable b on the second line. It can so happen that a is the smaller of the two? We can observe that:
b = min(a, b)
If we substitute min(a, b) for b in the max function on the third line, we get:
b = max(c, min(a, b))
This strategy is implemented in the following code, using only the constructs introduced in the book so far:
(define (square x) (* x x))
(define (max a b) (if (> a b) a b))
(define (min a b) (if (< a b) a b))
(define (sum-of-squares-two-largest a b c)
(+ (square (max a b)) (square (max c (min a b)))))
(sum-of-squares-two-largest 1 2 3)
(sum-of-squares-two-largest 1 2 1)

SICP 1.45 - Why are these two higher order functions not equivalent?

I'm going through the exercises in [SICP][1] and am wondering if someone can explain the difference between these two seemingly equivalent functions that are giving different results! Is this because of rounding?? I'm thinking the order of functions shouldn't matter here but somehow it does? Can someone explain what's going on here and why it's different?
Details:
Exercise 1.45: ..saw that finding a fixed point of y => x/y does not
converge, and that this can be fixed by average damping. The same
method works for finding cube roots as fixed points of the
average-damped y => x/y^2. Unfortunately, the process does not work
for fourth roots—a single average damp is not enough to make a
fixed-point search for y => x/y^3 converge.
On the other hand, if we
average damp twice (i.e., use the average damp of the average damp of
y => x/y^3) the fixed-point search does converge. Do some experiments
to determine how many average damps are required to compute nth roots
as a fixed-point search based upon repeated average damping of y => x/y^(n-1).
Use this to implement a simple procedure for computing the roots
using fixed-point, average-damp, and the repeated procedure
of Exercise 1.43. Assume that any arithmetic operations you need are
available as primitives.
My answer (note order of repeat and average-damping):
(define (nth-root-me x n num-repetitions)
(fixed-point (repeat (average-damping (lambda (y)
(/ x (expt y (- n 1)))))
num-repetitions)
1.0))
I see an alternate web solution where repeat is called directly on average damp and then that function is called with the argument
(define (nth-root-web-solution x n num-repetitions)
(fixed-point
((repeat average-damping num-repetition)
(lambda (y) (/ x (expt y (- n 1)))))
1.0))
Now calling both of these, there seems to be a difference in the answers and I can't understand why! My understanding is the order of the functions shouldn't affect the output (they're associative right?), but clearly it is!
> (nth-root-me 10000 4 2)
>
> 10.050110705350287
>
> (nth-root-web-solution 10000 4 2)
>
> 10.0
I did more tests and it's always like this, my answer is close, but the other answer is almost always closer! Can someone explain what's going on? Why aren't these equivalent? My guess is the order of calling these functions is messing with it but they seem associative to me.
For example:
(repeat (average-damping (lambda (y) (/ x (expt y (- n 1)))))
num-repetitions)
vs
((repeat average-damping num-repetition)
(lambda (y) (/ x (expt y (- n 1)))))
Other Helper functions:
(define (fixed-point f first-guess)
(define (close-enough? v1 v2)
(< (abs (- v1 v2))
tolerance))
(let ((next-guess (f first-guess)))
(if (close-enough? next-guess first-guess)
next-guess
(fixed-point f next-guess))))
(define (average-damping f)
(lambda (x) (average x (f x))))
(define (repeat f k)
(define (repeat-helper f k acc)
(if (<= k 1)
acc
;; compose the original function with the modified one
(repeat-helper f (- k 1) (compose f acc))))
(repeat-helper f k f))
(define (compose f g)
(lambda (x)
(f (g x))))
You are asking why “two seemingly equivalent functions” produce a different result, but the two functions are in effect very different.
Let’s try to simplify the problem to see why they are different. The only difference between the two functions are the two expressions:
(repeat (average-damping (lambda (y) (/ x (expt y (- n 1)))))
num-repetitions)
((repeat average-damping num-repetition)
(lambda (y) (/ x (expt y (- n 1)))))
In order to simplify our discussion, we assume num-repetition equal to 2, and a simpler function then that lambda, for instance the following function:
(define (succ x) (+ x 1))
So the two different parts are now:
(repeat (average-damping succ) 2)
and
((repeat average-damping 2) succ)
Now, for the first expression, (average-damping succ) returns a numeric function that calculates the average between a parameter and its successor:
(define h (average-damping succ))
(h 3) ; => (3 + succ(3))/2 = (3 + 4)/2 = 3.5
So, the expression (repeat (average-damping succ) 2) is equivalent to:
(lambda (x) ((compose h h) x)
which is equivalent to:
(lambda (x) (h (h x))
Again, this is a numeric function and if we apply this function to 3, we have:
((lambda (x) (h (h x)) 3) ; => (h 3.5) => (3.5 + 4.5)/2 = 4
In the second case, instead, we have (repeat average-damping 2) that produces a completely different function:
(lambda (x) ((compose average-damping average-damping) x)
which is equivalent to:
(lambda (x) (average-damping (average-damping x)))
You can see that the result this time is a high-level function, not an integer one, that takes a function x and applies two times the average-damping function to it. Let’s verify this by applying this function to succ and then applying the result to the number 3:
(define g ((lambda (x) (average-damping (average-damping x))) succ))
(g 3) ; => 3.25
The difference in the result is not due to numeric approximation, but to a different computation: first (average-damping succ) returns the function h, which computes the average between the parameter and its successor; then (average-damping h) returns a new function that computes the average between the parameter and the result of the function h. Such a function, if passed a number like 3, first calculates the average between 3 and 4, which is 3.5, then calculates the average between 3 (again the parameter), and 3.5 (the previous result), producing 3.25.
The definition of repeat entails
((repeat f k) x) = (f (f (f (... (f x) ...))))
; 1 2 3 k
with k nested calls to f in total. Let's write this as
= ((f^k) x)
and also define
(define (foo n) (lambda (y) (/ x (expt y (- n 1)))))
; ((foo n) y) = (/ x (expt y (- n 1)))
Then we have
(nth-root-you x n k) = (fixed-point ((average-damping (foo n))^k) 1.0)
(nth-root-web x n k) = (fixed-point ((average-damping^k) (foo n)) 1.0)
So your version makes k steps with the once-average-damped (foo n) function on each iteration step performed by fixed-point; the web's uses the k-times-average-damped (foo n) as its iteration step. Notice that no matter how many times it is used, a once-average-damped function is still average-damped only once, and using it several times is probably only going to exacerbate a problem, not solve it.
For k == 1 the two resulting iteration step functions are of course equivalent.
In your case k == 2, and so
(your-step y) = ((average-damping (foo n))
((average-damping (foo n)) y)) ; and,
(web-step y) = ((average-damping (average-damping (foo n))) y)
Since
((average-damping f) y) = (average y (f y))
we have
(your-step y) = ((average-damping (foo n))
(average y ((foo n) y)))
= (let ((z (average y ((foo n) y))))
(average z ((foo n) z)))
(web-step y) = (average y ((average-damping (foo n)) y))
= (average y (average y ((foo n) y)))
= (+ (* 0.5 y) (* 0.5 (average y ((foo n) y))))
= (+ (* 0.75 y) (* 0.25 ((foo n) y)))
;; and in general:
;; = (2^k-1)/2^k * y + 1/2^k * ((foo n) y)
The difference is clear. Average damping is used to dampen the possibly erratic jumps of (foo n) at certain ys, and the higher the k the stronger the damping effect, as is clearly seen from the last formula.

How to calculate the degree of a polynomial in scheme?

I need to create a scheme code that allows me to calculate the degree of a polynomial and show it, is there a special function in scheme that allows me to treat them?
pd: What is the way to raise these types of problems?
There is no such function just like there are no functions for guns in games in the standard libraries. There isn't even one data structure for a polynomial.
As with all user defined extensions you have the power to model your data as you wish and you make an interface to work with that data. This is how you extend the language to support the data you want to play with.
;; this is not part of the interface
(define tag-point (list 'point))
;; these are the interface
(define (point x y)
(list tag-point x y))
(define point-x cadr)
(define point-y caddr)
(define (point? p)
(and (pair? p)
(eq? (car p) tag-point)))
;; implemented distance that uses the interface
(define (distance p1 p2)
;; (assert (and (point? p1) (point? p2)))
(sqrt (+ (square (- (point-x p1) (point-x p2)))
(square (- (point-y p1) (point-y p2))))))
(distance (point 3 0 ) (point 0 4)) ; ==> 5
Now you can change your data structure as long as the interface stays intact:
;; implement points using complex numbers
(define (point x y) (make-rectangular x y))
(define (point-x p) (real-part p))
(define (point-y p) (imag-part p))
(define (point? p) (complex? p))
One could just do (define point make-rectangular) but then the interface documentation would be vague.
In the SICP videos I remember they did a polynomial type. It's in part 4B. It explains pretty much the same as I do here and they actually implement polynomials as a type you can do arithmetic on. Thus it might not be what you are looking for, but their data structure can give you an idea.

Scheme error when programming point-distance formula - attempt to apply non-procedure

I am attempting to program the point distance formula using Scheme. I am very close to getting it, except I am getting an error.
The exact error is:
Traceback (most recent call last):
File "In [54]", line 5, col 11, in 'application'
File "In [54]", line 5, col 11
RunTimeError: attempt to apply non-procedure '4'
Here is my code:
; code for the distance procedure
(define (distance p1 p2) (sqrt (+ (* (- (car(p2)) (car(p1))) (- (car(p2)) (car(p1)))) (* (- (car(cdr(p2))) (car(cdr(p1)))) (- (car(cdr(p2))) (car(cdr(p1))))))))
(distance (4 5) (3 2))
For reference, the point distance formula is:
√((x2 - x1)^2 + (y2 - y1)^2)
It is generally better to format Scheme code correctly instead of putting everything in just one line.
And it is useful to name intermediate values. If your formula contains x1, x2, y1 and y2, create Scheme variables with those names. This makes it easier to understand the solution.
Scheme hast several abbreviations for nested car and cdr functions. If you need the car of a cdr, you can use cadr.
Scheme allows you to use mathematic symbols in variable names. If a variable contains the difference of x2 and x1, you can name it x2-x1. This enhances the readability of Scheme's Polish notation.
(define (distance p1 p2)
(let ((x1 (car p1))
(y1 (cadr p1))
(x2 (car p2))
(y2 (cadr p2)))
(let ((x2-x1 (- x2 x1))
(y2-y1 (- y2 y1)))
(sqrt (+ (* x2-x1 x2-x1)
(* y2-y1 y2-y1))))))
If you want to pass list literals to functions, you have to quote them in order to prevent evaluation.
(distance '(4 5) '(3 2))
Or use evaluation correctly:
(distance (list 4 5) (list 3 2))

SICP exercise 1.16, where is my bug, because it looks right to me

I've just started working through this book for fun; I wish it were homework, but I could never afford to attend MIT, and there are tons of people smarter than me anyway. :p
fast-exp is supposed to find b^n, i.e. 4^2 = 16, 3^3 = 27
(define (fast-exp b n)
(define (fast-exp-iter n-prime a)
(cond ((= n-prime 1) a)
((= (remainder n-prime 2) 1) (fast-exp-iter (- n-prime 1) (* a b)))
(else (fast-exp-iter (/ n-prime 2) (* a b b)))))
(fast-exp-iter n 1))
fast-exp 4 2; Expected 16, Actual 2
You forgot to call fast-exp. Instead, you evaluated three separate atoms. To actually evaluate the fast-exp of 4 to the 2, you'd have to write
(fast-exp 4 2)
The solution you have written here is also incorrect. e.g. Check out (fast-exp 2 6). Expected: 64, actual: 32.
Your solution is calculating wrong answers. (See http://ideone.com/quT6A) In fact, how you in principle can write a tail-recursive fast exponentiation passing only two numbers as arguments? I don't think it's even possible, because in the middle of computation you don't know what multiplier to use if you encounter odd exponent.
But I can give an example of working solution that is exactly what is expected by SICP authors (iterative process using "invariant quantity" (a * b^n), where a is initially 1)
(define (pow x y)
(define (powi acc x y)
(cond
((= y 0) acc)
((odd? y) (powi (* acc x) x (- y 1)))
(else (powi acc (* x x) (/ y 2)))))
(powi 1 x y))

Resources