This page currently contains interesting questions I have received from students in CMPSCI 601 about Homework #3, together with my answers. Questions about the current homework are here.
Questions are in black, answers in blue. Most recently answered questions are listed first.
The values of Questions 1 and 4 don't match the total values of their subparts, what gives?
Thanks, this is now fixed. Question 1 is 40 total points, and Question 4 is 30 plus 10 extra credit. The values of the subproblems are all unchanged.
This question is probably not all that relevant to answering 1C, but I wanted to confirm my thinking about BLUEDIAG. When you say f_n is the nth Bloop-computable function in some canonical listing, is this a listing of Bloop programs that take only a single argument.
Actually it is relevant to 1(c) if you use BLUEDIAG because the proof
that BLUEDIAG is not Bloop-computable will probably refer to Bloop programs
that take exactly one argument (since only such a program would have any
hope of computing BLUEDIAG).
You could, as you suggest, create a listing that only contains
one-argument Bloop functions. (You might have to explain why interpreting
this listing, e.g., running the n'th program in this listing, is computable --
you don't even need it to be Bloop-computable.)
Another approach is to have the listing include all
Bloop programs, and
define BLUEDIAG(n) so that it takes some default value if n is not the number
of a one-argument Bloop function. After all, you're defining BLUEDIAG so
that it meets the two specifications of being total recursive but not Bloop
computable.
The same holds for Ackermann's function, by the way. Someone mentioned
that there are several conflicting definitions of Ackermann's function on
the net. You are free to pick any
of them, or even something else entirely,
as long as you prove the function you pick to be total recursive but not
primitive recursive.
I am trying to implement primitive recursion in Bloop to do Question 1(a), but you said that recursive function calls are not allowed in Bloop.
That's right, they aren't. "Implementing primitive recursion in Bloop" means that if the functions g and h in the definition of primitive recursion can each be simulated by Bloop programs, then so can f. So you need to take the code for g and h and use it to build code for f, using only the Bloop programming constructs (bounded loops, and whatever you have previously shown to be buildable from bounded loops).
I'm confused about Question 3 -- if A is the empty language, doesn't it have to be recursive?
The language EMPTY referred to in Question 3 is not the empty language, it's the set of all numbers of Turing machines that don't accept any strings. In the proof in the lecture notes, we assumed that none of these numbers were in A, now we must assume that all of them are in A.
For question 4(c), what should we consider to be the input size of the expression? The number of terms, or the number of variables? If it is the number of variables, wouldn't the possible number of terms in the expression be the power set of the number of variables, in which case it would impossible to create a P-time DNF SAT algorithm?
When in doubt, the "input size" is _always_ the number of bits
needed to indicate the input unambiguously. So here we would say
that the input is given as a string of n bits, and we would later
be able to say that there are "no more than n variables" and "no
more than n terms". There couldn't be both n variables and n terms,
of course, and still have only n bits in the input string, but these
claims about the number of variable and the number of terms are good
enough to show what we want to show.
I agree that it would be impossible to solve the problem if I meant
"polynomial in the number of variables", because the input might be
much longer than that in length and I might need to look at the entire
input to determine the right answer.
We are given that the function zeta(), which returns zero given no arguments, is primitive recursive. I have occasion to use the function z_1(y), which takes one argument but still always returns 0, in one of my constructions. May I assume that this is also primitive recursive?
Technically, no, things are only primitive recursive
if they are proved to be so using the rules. In this case you use primitive
recursion, with k=0:
This defines z_1(0) = 0 and z_1(n+1) = z_1(n) for all n, which is what
you want. If you've done one or two proofs like this I'm willing to be
casual about your claiming that more proofs of the same kind are "obvious".
If we were developing p.r. functions in full detail we'd prove lemmas like
"if f is p.r., and g is made from f by reordering the inputs, g is p.r." --
that and the construction above tells you that you can always insert new
input variables that are never read, for example.
z_1(0) = zeta() /*function g has k=0 arguments
z_1(n+1) = pi_1^2(z_1(n), n) /*function h has k+2=2 arguments
Isn't "Ackermann's function" spelled with two "n"'s?
Yes, I've fixed it on the assignment. Google gets several relevant hits with either spelling.
When writing Bloop code, what is the preferred syntax to define a function? You haven't really specified it.
You're right that I haven't specified it, so anything
that is clear is ok. If you'd like a model, the clearest thing for me is
something that mimics C or Java:
Officially I should probably call x and y "input(0)" and "input(1)"
respectively, but the more familiar-looking names are fine. Note that
we may leave off C/Java references to types of variables, since all our
variables are of type "non-negative integer".
define add(x, y) {
z = x;
loop y times {z++};
return z;}
On Question 1(a), are we really just trying to show that any Bloop program can be converted to Primative Recursive and vice versa? If so, then what does the "N^k to N" have to do with Bloop?
Yes, that's exactly what you're being asked to do. A Bloop function that takes k arguments is computing a function from N^k to N, rather than from N to N as a one-argument function would do.
On Question 2, Is it sufficient to come up with an algorithm that is polynomial in terms of the production rules instead of the number of symbols in G?
If the grammar G is input as a string of n bits, you may assume that G has at most n symbols, at most n production rules, etc. -- so "poly in the number of production rules" implies "poly in n" because the number of rules is at most n. So, yes, "poly in the number of rules" is fine.
In the extra credit question 4(d), don't you mean to refer to 4(a) and 4(b) rather than 3(a) and 3(b)?
Yes, thanks, this has been corrected on the assignment page.
On Question 3 we are to assume that the language EMPTY is a subset of A. Is it possible that EMPTY is equal to A?
Yes, whenever we say "subset" we include this possibility, unless we say something like "strict subset".
I think that one of the questions becomes very easy if I make the following assumption -- that a Turing machine that outputs a string of length f(n) must take at least f(n) steps. Is this valid?
Yes, that is a valid assumption and yes, that question is rather easy.
Question 2 asks us to argue that EmptyCFL can be computed in polynomial time. Can we assume the input is a grammar in Chomsky Normal Form? I'm not sure it changes much, but I think it will make things a little easier to explain.
Go ahead and assume Chomsky Normal Form if you want, though it actually makes little difference in the proof.
Answers to Questions during HW#2 (through 3 Mar 2003)
Answers to Questions during HW#1 (through 12 Feb 2003)
Last modified 18 March 2003