If the order of growth of a process is `log3 a`, can we simplify it to `log a`? - sicp

I'm learning the book SICP, and for the exercise 1.15:
Exercise 1.15. The sine of an angle (specified in radians) can be computed by making use of the approximation sin x x if x is sufficiently small, and the trigonometric identity
to reduce the size of the argument of sin. (For purposes of this exercise an angle is considered ``sufficiently small'' if its magnitude is not greater than 0.1 radians.) These ideas are incorporated in the following procedures:
(define (cube x) (* x x x))
(define (p x) (- (* 3 x) (* 4 (cube x))))
(define (sine angle)
(if (not (> (abs angle) 0.1))
angle
(p (sine (/ angle 3.0)))))
a. How many times is the procedure p applied when (sine 12.15) is evaluated?
b. What is the order of growth in space and number of steps (as a function of a) used by the process generated by the sine procedure when (sine a) is evaluated?
I get the answer of the "order of growth in number of steps" by myself is log3 a. But I found something say, the constants in the expression can be ignored, so it's the same as log a, which looks simpler.
I understand the 2n can be simplified to n, and 2n2 + 1 can be simplified to n2, but not sure if this is applied to log3 a too.

Yes, you can (since we're just interested in the order of the number of steps, not the exact number of steps)
Consider the formula for changing the base of a logarithm:
logb(x) = loga(x) / loga(b)
In other words you can rewrite log3(a) as:
log3(a) = log10(a) / log10(3)
Since log10(3) is just a constant, then for the order of growth we are only interested in the log10(a) term.

Related

Understanding derivatives in Isabelle (meaning of `at .. within`)

This is a question about the notion of derivatives from the Isabelle libraries.
I am trying to understand what (f has_field_derivative D x) (at x within S) means. I know (at x within S) is a filter, but intuitively I was imagining that the following statement is true
lemma DERIV_at_within:
"(∀x ∈ S. (f has_field_derivative D x) (at x))
= (∀x. (f has_field_derivative D x) (at x within S))"
If it is not, how else should I interpret (at x within S) in the context of derivatives?
at x within A is the pointed neighbourhood of x, intersected with A. For instance, at_right is an abbreviation for at x within {x<..}, i.e. the right-neighbourhood of x. This allows you to express one-sided derivatives.
Occasionally, one also sees assumptions like ∀x∈{a..b}. (f has_field_derivative f' x) (at x within {a..b}). This means that f is differentiable with derivative f' between a and b, but the derivatives at the edges (i.e. at a and b) need only be one-sided.
Note also that at x = at x within UNIV. Also, if A is an open set containint x, you simply have at x within A = at x.
Typically, you only really need has_field_derivative with at x within … if you want something like a one-sided limit (or, in higher dimensions, if you somehow want to constrain the direction of approach).

(Scheme) Tail recursive modular exponentiation

I have an assignment to make a tail-recursive function that takes 3 integers(possibly very large), p q and r, and calculates the modulo of the division (p^q)/r. I figured out how to do make a function that achieves the goal, but it is not tail recursive.
(define (mod-exp p q r)
(if (= 0 p)
0
(if (= 0 q)
1
(if (= 0 (remainder r 2))
(remainder (* (mod-exp p (quotient q 2) r)
(mod-exp p (quotient q 2) r))
r)
(remainder (* (remainder p r)
(remainder (mod-exp p (- q 1) r) r))
r)))))
I'm having a hard time wrapping my head around making this tail-recursive, I don't see how I can "accumulate" the remainder.
I'm pretty much restricted to using the basic math operators and quotient and remainder for this task.
I see that you're implementing binary exponentiation, with the extra feature that it's reduced mod r.
What you may want to do is take a normal (tail recursive) binary exponentiation algorithm and simply change the 2-ary functions + and * to your own user defined 3-ary functions +/mod and */mode which also take r and reduce the result mod r before returning it.
Now how do you do binary exponentiation in a tail recursive way? You need the main function to call into a helper function that takes an extra accumulator parameter - initial value 1. This is kind of similar to tail recursive REVERSE using a helper function REVAPPEND - if you're familiar with that.
Hope that helps and feel free to ask if you need more information.

What does squaring a transformation mean?

I am trying to understand a solution that I read for an exercise that defines a logarithmic time procedure for finding the nth digit in the Fibonacci sequence. The problem is 1.19 in Structure and Interpretation of Computer Programs (SICP).
SPOILER ALERT: The solution to this problem is discussed below.
Fib(n) can be calculated in linear time as follows: Start with a = 1 and b = 0. Fib(n) always equals the value of b. So initially, with n = 0, Fib(0) = 0. Each time the following transformation is applied, n is incremented by 1 and Fib(n) equals the value of b.
a <-- a + b
b <-- a
To do this in logarithmic time, the problem description defines a transformation T as the transformation
a' <-- bq + aq + ap
b' <-- bp + aq
where p = 0 and q = 1, initially, so that this transformation is the same as the one above.
Then applying the above transformation twice, the exercise guides us to express the new values a'' and b'' in terms of the original values of a and b.
a'' <-- b'q + a'q + a'p = (2pq + q^2)b + (2pq + q^2)a + (p^2 + q^2)a
b' <-- b'p + a'q = (p^2 + q^2)b + (2pq + q^2)a
The exercise then refers to such application of applying a transformation twice as "squaring a transformation". Am I correct in my understanding?
The solution to this exercise applies the technique of using the value of squared transformations above to produce a solution that runs in logarithmic time. How does the problem run in logarithmic time? It seems to me that every time we use the result of applying a squared transformation, we need to do one transformation instead of two. So how do we successively cut the number of steps in half every time?
The solution from schemewiki.org is posted below:
(define (fib n)
(fib-iter 1 0 0 1 n))
(define (fib-iter a b p q count)
(cond ((= count 0) b)
((even? count)
(fib-iter a
b
(+ (square p) (square q))
(+ (* 2 p q) (square q))
(/ count 2)))
(else (fib-iter (+ (* b q) (* a q) (* a p))
(+ (* b p) (* a q))
p
q
(- count 1)))))
(define (square x) (* x x))
The exercise then refers to such application of applying a transformation twice as "squaring a transformation". Am I correct in my understanding?
Yes, squaring a transformation means applying it twice or (as is the case in the solution to this exercise) finding another transformation that is equivalent to applying it twice.
How does the problem run in logarithmic time? It seems to me that every time we use the result of applying a squared transformation, we need to do one transformation instead of two. So how do we successively cut the number of steps in half every time?
Squaring the given transformation enables us to cut down the number of steps because the values of p and q grow much faster in the squared transformation than they do in the original one. This is analogous to the way you can compute exponents using successive squaring much faster than by repeated multiplication.
So how do we successively cut the number of steps in half every time?
This is in the code given. Whenever count is even, (/ count 2) is passed for count on the next iteration. No matter what value of n is passed in on the initial iteration, it will be even on alternating iterations (worst case).
You can read my blog post on SICP Exercise 1.19: Computing Fibonacci numbers if you want to see a step-by-step derivation of the squared transformation in this exercise.
#Bill-the-Lizard provides a nice proof, but you are allowing yourself to be conflicted by what you think of the word "twice" and the word "square", in relation to transforms.
a) Computing twice the term T--that is, two-times-T--is a case of multiplication. The process of multiplication is simply a process of incrementing T by a constant value at each step, where the constant value is the original term itself.
BUT by contrast:
b) The given fibonacci transform is a process that requires use of the most current state of term T at each step of manipulation (as opposed to the use of a constant value). AND, the formula for manipulation is not a simple increment, but in effect, a quadratic expression (i.e. involves squaring at each successive step).
Like bill says, this successive squaring effect will become very clear if you step through it in your debugger (I prefer to compute a few simple cases by hand whenever I get stuck somewhere).
Think of the process another way:
To reach your destination if you could cover the square of the current distance in the next step, but still somehow manage to take a constant amount of time to complete each step, you're going to get there way faster than if you take constant steps, each in constant time.

How do you find the 6th root using primitive expressions in Scheme?

By primitive expressions, I mean + - * / sqrt, unless there are others that I am missing. I'm wondering how to write a Scheme expression that finds the 6th root using only these functions.
I know that I can find the cube root of the square root, but cube root doesn't appear to be a primitive expression.
Consider expt, passing in a fractional power as its second argument.
But let's say we didn't know about expt. Could we still compute it?
One way to do it is by applying something like Newton's method. For example, let's say we wanted to compute n^(1/4). Of course, we already know we can just take the sqrt twice to do this, but let's see how Newton's method may apply to this problem.
Given n, we'd like to discover roots x of the function:
f(x) = x^4 - n
Concretely, if we wanted to look for 16^(1/4), then we'd look for a root for the function:
f(x) = x^4 - 16
We already know if we plug in x=2 in there, we'll discover that 2 is a root of this function. But say that we didn't know that. How would we discover the x values that make this function zero?
Newton's method says that if we have a guess at x, call it x_0, we can improve that guess by doing the following process:
x_1 = x_0 - f(x_0) / f'(x_0)
where f'(x) is notation for the derivative of f(x). For the case above, the derivative of f(x) is 4x^3.
And we can get better guesses x_2, x_3, ... by repeating the computation:
x_2 = x_1 - f(x_1) / f'(x_1)
x_3 = x_2 - f(x_2) / f'(x_2)
...
until we get tired.
Let's write this all in code now:
(define (f x)
(- (* x x x x) 16))
(define (f-prime x)
(* 4 x x x))
(define (improve guess)
(- guess (/ (f guess)
(f-prime guess))))
(define approx-quad-root-of-16
(improve (improve (improve (improve (improve 1.0))))))
The code above just expresses f(x), f'(x), and the idea of improving an initial guess five times. Let's see what the value of approx-quad-root-of-16 is:
> approx-quad-root-of-16
2.0457437305170534
Hey, cool. It's actually doing something, and it's close to 2. Not bad for starting with such a bad first guess of 1.0.
Of course, it's a little silly to hardcode 16 in there. Let's generalize, and turn it into a function that takes an arbitrary n instead, so we can compute the quad root of anything:
(define (approx-quad-root-of-n n)
(define (f x)
(- (* x x x x) n))
(define (f-prime x)
(* 4 x x x))
(define (improve guess)
(- guess (/ (f guess)
(f-prime guess))))
(improve (improve (improve (improve (improve 1.0))))))
Does this do something effective? Let's see:
> (approx-quad-root-of-n 10)
1.7800226459895
> (expt (approx-quad-root-of-n 10) 4)
10.039269440807693
Cool: it is doing something useful. But note that it's not that precise yet. To get better precision, we should keep calling improve, and not just four or five times. Think loops or recursion: repeat the improvement till the solution is "close enough".
This is a sketch of how to solve these kinds of problems. For a little more detail, look at the section on computing square roots in Structure and Interpretation of Computer Programs.
You may want to try out a numeric way, which may be inefficient for larger numbers, but it works.
Also if you also count pow as a primitive (since you also count sqrt) you could do this:
pow(yournum, 1/6);

Pohlig–Hellman algorithm for computing discrete logarithms

I'm working on coding the Pohlig-Hellman Algorithm but I am having problem understand the steps in the algorithm based on the definition of the algorithm.
Going by the Wiki of the algorithm:
I know the first part 1) is to calculate the prime factor of p-1 - which is fine.
However, I am not sure what I need to do in steps 2) where you calculate the co-efficents:
Let x2 = c0 + c1(2).
125(180/2) = 12590 1 mod (181) so c0 = 0.
125(180/4) = 12545 1 mod (181) so c1 = 0.
Thus, x2 = 0 + 0 = 0.
and 3) put the coefficents together and solve in the chinese remainder theorem.
Can someone help with explaining this in plain english (i) - or pseudocode. I want to code the solution myself obviously but I cannot make any more progress unless i understand the algorithm.
Note: I have done a lot of searching for this and I read S. Pohlig and M. Hellman (1978). "An Improved Algorithm for Computing Logarithms over GF(p) and its Cryptographic Significance but its still not really making sense to me.
Thanks in advance
Update:
how come q(125) stays constant in this example.
Where as in this example is appears like he is calculating a new q each time.
To be more specific I don't understand how the following is computed:
Now divide 7531 by a^c0 to get
7531(a^-2) = 6735 mod p.
Let's start with the main idea behind Pohlig-Hellman. Assume that we are given y, g and p and that we want to find x, such that
y == gx (mod p).
(I'm using == to denote an equivalence relation). To simplify things, I'm also assuming that the order of g is p-1, i.e. the smallest positive k with 1==gk (mod p) is k=p-1.
An inefficient method to find x, would be to simply try all values in the range 1 .. p-1.
Somewhat better is the "Baby-step giant-step" method that requires O(p0.5) arithmetic operations. Both methods are quite slow for large p. Pohlig-Hellman is a significant improvement when p-1 has many factors. I.e. assume that
p-1 = n r
Then what Pohlig and Hellman propose is to solve the equation
yn == (gn)z
(mod p).
If we take logarithms to the basis g on both sides, this is the same as
n logg(y) == logg(yn) == nz (mod p-1).
n can be divided out, giving
logg(y) == z (mod r).
Hence x == z (mod r).
This is an improvement, since we only have to search a range 0 .. r-1 for a solution of z. And again "Baby-step giant-step" can be used to improve the search for z. Obviously, doing this once is not a complete solution yet. I.e. one has to repeat the algorithm above for every prime factor r of p-1 and then to use the Chinese remainder theorem to find x from the partial solutions. This works nicely if p-1 is square free.
If p-1 is divisible by a prime power then a similiar idea can be used. For example let's assume that p-1 = m qk.
In the first step, we compute z such that x == z (mod q) as shown above. Next we want to extend this to a solution x == z' (mod q2). E.g. if p-1 = m q2 then this means that we have to find z' such that
ym == (gm)z' (mod p).
Since we already know that z' == z (mod q), z' must be in the set {z, z+q, z+2q, ..., z+(q-1)q }. Again we could either do an exhaustive search for z' or improve the search with "baby-step giant-step". This step is repeated for every exponent of q, this is from knowing x mod qi we iteratively derive x mod qi+1.
I'm coding it up myself right now (JAVA). I'm using Pollard-Rho to find the small prime factors of p-1. Then using Pohlig-Hellman to solve a DSA private key. y = g^x. I am having the same problem..
UPDATE: "To be more specific I don't understand how the following is computed: Now divide 7531 by a^c0 to get 7531(a^-2) = 6735 mod p."
if you find the modInverse of a^c0 it will make sense
Regards

Resources