# CMPSCI 601: Theory of Computation

### Homework Assignment #3 Solutions

• Question 1 (40):

Three questions concerning Bloop, defined in HW#2 and the resulting questions and answers:

• (a,20) Prove that a function from Nk to N is computable by a Bloop program iff it is primitive recursive.

It's pretty easy to prove one direction, because we have a nice inductive definition of the primitive recursive functions. We write Bloop programs for each initial function, for example pi32 is `define pi32(x,y,z) return y;`. Then closure of Bloop programs under composition is obvious from our definition -- the new program just makes function calls on the programs for the pieces. For closure under primitive recursion we must convert the recursion into a bounded loop. For example if f(n,x,y) is defined by f(0,x,y) = g(x,y) and f(n+1,x,y) = h(f(n,x,y),n,x,y), then we may write:

``````
define f(n,x,y) {
w = g(x,y);
i = 0;
loop n times {
w = h(w,i,x,y);
i++;}
return w;}
``````

For the other direction, the real difficulty is to get the right inductive hypothesis for the proof. How about "for every block B of Bloop code, for every variable v in B, the value of v after B is executed is a primitive recursive function of its inputs", where the inputs to a block are the variable values defined when it starts executing. Now we have to show that this is true

• when B is a single statement
• when B is the concatenation of two blocks C and D, and
• when B is a bounded loop with a block C inside.

If B is a single statement it is either an assignment of an expression to a variable (in which case the new values are sums of products of old values and are p.r. functions of the old ones) or a non-recursive function call, which fits under our inductive hypothesis.

If B is C followed by D then the behavior of B is a composition of the behaviors of C and D, in a way that I would write down if I had more time but should be pretty obvious.

If B is "loop x times {C}", then we use primitive recursion to define B's behavior, where for each variable a fa(n,...) is the value of a after the loop has been executed n times. This can be defined by primitive recursion, where ga is the identity function (since the loop is a no-op if executed zero times, and ha is the p.r. function describing the behavior of C (available by the inductive hypothesis).

Since all Bloop programs are built up by these operations, they all are described by p.r. functions. A correct proof of this half of the problem could differ from mine by quite a bit, depending on how you decide to define Bloop. (I admit I was pretty vague about it, with the intention of letting you grapple with the difficulty of putting a mathematical model to a more real-looking construct like Bloop.)

• (b,5) Prove that every Bloop-computable function is total recursive. Assume that any function definition must end with a return statement.

Well, after (a) we can prove that every p.r. function is total recursive. We explicitly design always-halting TM's that compute each of the basic functions.

Then we show closure under composition: if for example f(y,z) = h(g1(y,z),g2(y,z),g3(y,z)), and there are already known to be always-halting TM's for f and the gi's, then all we need to argue is that there is an always-halting TM computing h. It starts with y and z on its tape, computes g1(y,z), g2(y,z), and g3(y,z) and puts those on another tape, then runs the h-machine as if that second tape were the input.

Finally we show closure under primitive recursion. Here we can actually implement recursion in the usual way, leaving an activation record behind (on a tape reserved for our method stack) for each recursive call. We know that the recursion depth will be only n (the first argument to f), that each invocation of h will call f with first argument one smaller and halt once that call returns, and finally that the last call to g will halt. So the whole TM will halt with the correct answer.

• (c,15) Prove that there is a total recursive function that is not Bloop computable. Hint: Look on the web or elsewhere for a definition of Ackermann's function. Another candidate is the function called "BLUEDIAG" in Hofstadter, where BLUEDIAG(n) is fn(n)+1, where fn is the n'th Bloop computable function in some canonical listing. Here you have to argue that a Turing machine can find and implement this function given n as input.

Let's go with BLUEDIAG. We'll say that if n happens to code a Bloop program with one argument, that the function computed by this program is fn. If n doesn't code such a program, define fn to be the always-zero function. Then, as suggested, we define BLUEDIAG(n) to be fn(n)+1.

It's clear that BLUEDIAG cannot be a Bloop-computable function, because if it had a program, that program would be coded by some number n, and then BLUEDIAG(n) would be fn(n)+1 instead of fn(n). So these two functions would not agree on all inputs and thus would not be the same.

Why is BLUEDIAG a total recursive function? We need to argue that there is an always-halting Turing machine that can compute BLUEDIAG(n) on input n. This machine must interpret n as the code for a Bloop program, and if it can it must see whether this program has one argument. If it is not a valid one-argument program, our machine outputs 1 and halts. If it is valid, our machine must simulate it on input n, add one to the answer, and halt.

The simulation is similar to the simulation of a Floop program by a Turing machine in HW#2, Question 3(e). We set up a tape area (or even a whole tape) for each variable in the program, and then run through the program seeing which variable to update at each step and how to calculate the new value. Because the Bloop program is guaranteed to halt, so is our Turing machine.

• Question 2 (15): Argue that the language EMPTY-CFL, the set of grammars G such that L(G) is empty, can be decided in polynomial time. (For example, in a time that is polynomial in the number of symbols in G, or in the number of rules, or in the length of the string needed to describe G.)

Make an array of boolean flags, one for each nonterminal symbol of G. Each of these flags is originally false, and will be set true if and only if we establish that its nonterminal can generate a string of terminals.

We make a succession of passes over the rules of G. In each pass we look for a rule "A &rightarrow w" where all the letters in w are either terminals or flagged true. Each time we find such a rule we set A's flag to true. If we set the start symbol's flag to true we halt and return "true", and if we go through an entire pass without changing a flag we halt and return "false".

If there are n nonterminals in G, we will make no more than n passes, because in each pass we either increase the number of true flags by at least one or we halt and this number can't exceed n. Each pass takes time proportional to the number of rules times the length of the longest rule, hence clearly polynomial time.

• Question 3 (15): When we proved the Rice-Myhill-Shapiro Theorem in Lecture #7, we assumed that the language EMPTY was disjoint from A. (That is, we assumed that all the Turing machines that never halt were outside of A.) Prove the theorem (that A is not recursive) assuming that EMPTY is a subset of A. Why are these the only two possibilities?

These are the only two possibilities because if A includes a machine, it also by hypothesis includes all other machines that have the same language. So if any machine with empty language is in A, they are all in A.

In this case we begin by choosing a machine M' that is not in A (which we can do because A does not contain all machines). We then reduce K-bar (the complement of K) to A as follows. On input n, design the new machine Mf(n) so that it saves its input x, runs Mn on n, and then (if Mn accepts n) runs M' on x. If Mn accepts n, then the language of Mf(n) is the same as the language of M' and thus f(n) is in A. If Mn does not accept n, M' has an empty language and thus f(n) is not in A. So f reduces K-bar to A, and since K-bar is not recursive neither is A. For that matter, in this case since we know that K-bar is not even r.e., we can conclude that A is not r.e. either.

• Question 4 (30+10):
• (a,10) Show that for any n, the boolean formula

(x1 or x2) and (x3 or x4) and ... and (x2n-1 or x2n)

has a disjunctive normal form with 2n different terms.

We get the formula by applying the distributive law to the given formula and collecting terms. The DNF formula is the OR of the 2n terms that are obtained by choosing one variable from each pair {x2i-1, x2i} in each possible way. We could prove this by induction, or just appeal to our knowledge of algebra and the fact that the same distributive law works in this context.

• (b,10) It can be shown (see (d) below) that no DNF expression without at least this many terms can represent the expression in part (a). Assuming this fact, explain why there is no polynomial time algorithm that inputs a boolean expression and outputs an equivalent DNF expression. (Here "polynomial time" means polynomial in the length of the input expression.)

The length of this expression is O(n) terms, actually O(n log n) bits since the subscripts are O(log n) bits each. The equivalent DNF expression is over 2n bits long since it contains that many terms, and 2n is larger than any polynomial in the input size. Hence no polynomial-time algorithm would have time to write the desired output, even if it were able to figure out what to write.

• (c,10) Describe a polynomial-time algorithm that inputs a DNF expression and determines whether it is satisfiable.

An expression is satisfiable if there is some setting of the variables making it true. Hence a DNF expression is satisfiable if there is any setting making any of its clauses true. A clause is an AND of literals, where literals are variables or negated variables. A clause cannot be made true if it contains two literals that are negations of each other, but otherwise it can be made true by setting each variable to agree with the form it takes in the clause, if any.

The poly-time algorithm for satisfiability thus examines each clause in turn to see whether two of its literals are negations of each other. If it finds a clause where this does not happen, it returns "true", and if it finds eventually that it does happen in each clause, it returns "false". The exact time will depend on the format for presenting the formula, but the number of comparisons between literals is mo more than the sum of the squares of the sizes of the clauses, which is no more than n2 so this is pretty clearly polynomial in the length of the formula.

• (d, 10 extra credit) Prove that fact mentioned in 4(b) above -- that no DNF expression with fewer than 2n terms can represent the boolean expression in 4(a). Hint: You can show that no term with fewer than n literals in it can appear in a correct DNF expression, because it will be true for some setting of the variables where the expression of 4(a) is false. Then you can show that each of the terms in your DNF expression is necessary -- that there are 2n different settings that each require a separate term to be included in the DNF.

My hint can be carried through but works better if it is adjusted slightly. Consider the n pairs of variables {x2i-1, x2i} for i from 1 through n. I claim that

• A clause that doesn't have at least one literal from each pair is either never true or is true in some setting where the statement of 4a is false.
• There exist 2n particular settings such that if a clause contains at least one literal from each pair of variables, it is true for at most one of these settings. Furthermore 4(a) is true in all these settings.
From these two statements it follows that any correct DNF has at least 2n clauses, because it needs at least one for each of these special settings. So it remains to justify the two claims.

Suppose clause C is true in some setting s, but C contains no literal involving either variable x2i-1 or x2i. Make a new setting from s by changing these two variables to false if they weren't false already. Now C is still true, since no variable occurring in it was changed. But 4(a) is false because "x2i-1 OR x2i is false.

Now for the other claim. My 2n settings are those that have exactly one variable true in each pair. Let C be a clause with at least one literal from each pair. In each pair, this literal forces the choice of which variable is to be true, if only one is true. Since the choice in each pair is forced, the choice of setting is forced and all other settings in this group make C false.