15-453 Solutions to Midterm Sample Questions Problem 1: Java Programs

Transcription

15-453 Solutions to Midterm Sample Questions Problem 1: Java Programs
15-453
Solutions to Midterm Sample Questions
Problem 1: Java Programs
A simple answer to this problem is that Java is easily able to get into an infinite loop, so the functions
computed by Java programs are not always total. Since primitive recursive functions are always total, not
every Java program can be simulated using primitive recursion.
Another argument would be to say that Java is able to simulate a Turing Machine. The main obstacle here
is the infinte tape. To simulate an infinite tape, we can have a lazily-created doubly-linked list. That is, if
we ever want to move past the end of the tape, we use new to create a new tape cell, and we assumed that
we will never run out of memory, so this operation will never fail.
Problem 2: Turing Machines
No, checking if a Turing machine state is accessible is an undecidable problem.
Proof. For any Turing machine M , let eM be its corresponding index.
Suppose for a contradiction that there is some Turing machine N that, given a pair (eM , q), determines if q
is an accessible state in the Turing machine M . I claim that using N , we can decide the halting set K (the
set of programs that halt when given their own description as input).
Given a Turing machine M , an algorithm that checks if eM ∈ K is the following:
• Construct M 0 to be the following program:
– Ignore the input to M 0 .
– Write eM to the tape (so that, in effect, the input to M 0 is always eM ).
– Simulate M on the input.
• Let qH refer to the halt state in M 0 . Run N (eM 0 , qH ). If qH is accessible in M 0 , then report that
eM ∈ K. Otherwise, report that eM ∈
/ K.
This algorithm works because M 0 always behaves the same regardless of its input, so the state qH is reached
by a computation in M 0 if and only if M reaches the halt state when computing on input eM .
Problem 3: Wurzelbrunft versus Turing
A. One reasonable way of defining computation is as follows: use the semantics as described in the
problem. That is, the machine is able to duplicate the tape head, with the two duplicates moving to
(possibly) different states. The machine is in a halting configuration when every “thread” is in the
halt state. When the machine as a whole is in a halting configuration, the string on the tape is the
output.
1
For the 3-dimensional variant, we can have the input appear on tape cells with coordinates (n, 0, 0),
where n ∈ N, keep the same halting configuration, and have the output be read from only tape cells
of the form (n, 0, 0), where n ∈ N.
For a more formal definition, we would need to redefine the transition function and the one-step
relation to fit the new semantics. This can be done in a way somewhat analogous to the way given in
the lecture slides, although the details are more complicated.
B. To show that a W-machine cannot solve the halting problem, we can show that it can be simulated
by a Turing Machine.
This can be done in a construction similar to that of a universal Turing machine. Instead of simulating
a single tape head, we simply add the ability to simulate multiple tape heads. Essentially, instead of
being of the form
while (state not halting state) {
perform one step
}
the pseudocode would be
while (states not all halting state) {
for (each tape head i) {
read the input for tape head i
}
for (each tape head i) {
perform one step for tape head i
}
}
So, if a W-machine could solve the halting problem, then a Turing machine could as well.
Note that a W-machine is not the same as a nondeterministic Turing machine. With a nondeterministic
Turing machine, we are only concerned with acceptance of rejection of strings, so no “output” concept
is necessary, and with the computation splits, each computational path works on its own tape, which
is independent of the others.
C. In creating the above simulation, we can keep track of the tape state as a map from integer tape
indices to the tape contents. To modify this to work on a 3-D grid, we can have tape indices instead
be coded triples (x, y, z), and make the appropriate modifications (which are easily computable) based
on which of the 6 directions each tape head wants to go.
Problem 4: Wurzelbrunft Discovers Computability
A. As shown in the “Intermediate Degrees” lecture, there exist incomparable semidecidable Turing degrees, so there are semidecidable sets that are neither decidable nor Turing complete.
2
B. By using the jump construction (where, given a set A, we define the jump of A to be the set of
machines that, given an A oracle, halt on their own description), we can construct infinitely many
Turing degrees. Using a proof similar to the proof that the halting problem is undecidable, we can
show that every set is in a different Turing degree from its jump, so we can easily construct an infinite
sequence of distinct Turing degrees.
Problem 5: Loop Programs
A. P computes the function f , where f (x) = x3 .
B. The following LOOP program also computes x 7→ x3 :
// Q : x --> y
z = 0;
do x:
do x:
z++;
od
od
y = 0;
do x:
do z:
y++;
od
od
It is easy to see that Q computes the same function, and that it has loop depth 2.
Problem 6: A Loop Program
This program computes the Collatz function. That is, it computes the function f : N → N, where
(
n
if n is even
f (n) = 2
3n + 1 if n is odd
Problem 7: Abusing the Recursion Theorem
Intuitively, the recursion theorem says that every computable function is allowed to have access to its
own source code. The idea here is that we will compute multiplication recursively, given that addition is
computable, and will use the recursion theorem in order to actually perform recursive calls.
Using the notation for the second recursion theorem (slide 24 of the Fundamental Results lecture), we define
the computable function f (which is given a program index e as input) to be the following:
3
• We assume that e is a correct multiplication function. So we generate a program index e0 (which is
given a pair of integers (a, b), and should return their product) that does the following:
–
–
–
–
If b = 0, write 0 to the tape and halt.
Subtract 1 from b, so that the tape contains (a, b − 1).
Run e (we simply need to include the Turing machine for e here).
Add a to the value of the result.
If we then invoke the recursion theorem, we have that there is some e0 such that {e0 }(a, b) ' {f (e0 )}(a, b)
for all a, b ∈ N. If e0 is multiplication, then the equation holds and we are done. For a complete proof,
though, we can prove by induction on b that e0 is the multiplication function for all inputs (a, b). For the
base case, we know that e0 and f (e0 ) behave the same, and that f (e0 ) must behave correctly when given
(a, 0). For the inductive step, since we know that e0 behaves correctly on b for some fixed b, we can use the
equivalence to f (e0 ) to show that it behaves correctly on b + 1.
So, e0 is an index for the multiplication function, so multiplication is computable.
Problem 8: Primitive Recursion on Words
A. We can define the Prec operator as follows:
Let n = |Σ|, and let Σ = {σ1 , . . . , σn }. If g : (Σ∗ )k → Σ∗ is primitive recursive on Σ∗ and h1 , . . . , hn
(where hi : (Σ∗ )k+2 → Σ∗ for each i) are all primitive recursive on Σ∗ , then the function f : (Σ∗ )k+1 →
Σ∗ defined by
f (ε, y) = g(y)
f (σ1 x, y) = h1 (x, f (x), y)
..
.
f (σn x, y) = hn (x, f (x), y)
is primitive recursive on Σ∗ . The function f is denoted Prec[g, h1 , . . . , hn ].
In other words, we have the same primitive recursion construction, except we condition over the first
character of the string that we process.
There may be alternative reasonable ways to define the primitive recursion operator.
B. First, I will show that the function Appσi : Σ∗ → Σ∗ is primitive recursive for each i (where 1 ≤ i ≤ n),
where Appi (x) = xσi . That is, Appσi appends character i onto the end of its input. We can define
Appσi (ε) = σi
Appσi (σ1 x) = Sσ1 (Appσi (x))
..
.
Appσi (σn x) = Sσn (Appσi (x))
4
In other words, the base case adds σi , and all other cases keep the string the same. We can then define
the reversal function ρ as follows:
ρ(ε) = ε
ρ(σ1 x) = Appσ1 (ρ(x))
..
.
ρ(σn x) = Appσn (ρ(x))
In other words, we pull off the first character and add the character to the end.
Problem 9: Arithmetical Hierarchy
Recall that We is the set of inputs for which program e halts. Also, notice that only upper bounds are given;
hardness proofs are more difficult.
A. A program index e is in this set if there exists a finite set of inputs S such that We ⊆ S. That is, for
every input x, either x ∈
/ We (meaning that x never halts after any amount of steps), or x ∈ S. This
can be written as
∃S ∀(x, n) ( {e}(x) does not halt after n steps, or x ∈ S )
We can quantify over S because we can always encode a finite set into an integer, so we can loop over
all encodings of finite sets.
Since the problem has two alternating quantifiers before reaching a decidable property, and the quantifiers start with ∃, we know that the problem is Σ2 .
B. Notice that this is the complement of the previous part. Because the Πk classes are defined to be the
set of all complements of sets in Σk , this means that we know that this problem is Π2 . Alternatively,
we could show this by writing it as a formula of the form ∀ ∃.
C. A program index e is in this set if there is some finite set of inputs S such that e halts when given any
input outside of S.
∃S ∀x ∃n ( x ∈ S or {e}(x) halts after n steps )
This has the form ∃ ∀ ∃, with a decidable property at the end, so the set is Σ3 .
D. This is the same problem as in homework 4, problem 2, part A; from that homework, the set is Σ3 .
E. This can be phrased as the program indices e that never halt when given an odd number as input. So,
we can describe the set as
∀(x, n) ( x is even or {e}(x) does not halt after n steps )
So, the problem can be expressed with a single unbounded ∀, so it is Π1 .
5
Problem 10: Selector Functions
A. We can use a table counts counting the number of times we see each equivalence class. We can fill in
the table in the following way:
for (x in A)
counts[R(x)]++;
We then can find the value y ∈ A such that counts[y] is maximized. We can then print out all x such
that R(x) = y. This algorithm prints out all elements in the largest equivalence class, and it consists
of a constant number of operations, each of which takes O(n) time, so the algorithm as a whole takes
O(n) time.
B. This algorithm takes O(n) space, since counts has n elements. It can also be modified so that counts
is a hash table, so that the the space used is O(k), where k is the number of equivalence classes.
Problem 11: Counting Quotients
A. Recall from lecture that the number of quotients in a language is the same as the number of states
in the unique minimal DFA. Also, by changing each reject state to an accept state and vice versa,
we create a DFA for the complement language. So, if we have a minimal DFA D for the language L,
then I need to show that complementing the states gives a minimal DFA E for the language Σ∗ − L.
Suppose, for a contradiction, that there was a DFA E 0 which was smaller than E. When we could
complement E 0 to find a DFA smaller than D that recognizes L, which contradicts minimality of D.
So, it must be the case that E is minimal.
So, µ(L) equals the number of states in D, which equals the number of states in E, which equals
µ(Σ∗ − L).
B. The product machine construction can be used to create a DFA with µ(L)·µ(K) states which recognizes
L ∩ K. To show that this is tight, we can, for any n and m let L be the set of all strings with at least
n copies of the letter a, and let K be the set of all strings with at least m copies of the letter b. It can
be shown that µ(L) = n, that µ(K) = m, and that µ(L ∩ K) = mn.
Problem 12: A Minimal Automaton
6
(bb)∗ aaa
aa
b(bb)∗ aaa
a
∅
∅
(bb)∗ aaa
ε
∅
∅
∅
∅
∅
—
a−1 L1
b−1 L1
a−1 L2
b−1 L2
a−1 L3
b−1 L3
a−1 L4
b−1 L4
a−1 L5
b−1 L5
a−1 L6
b−1 L6
L1
L2
L3
L4
L5
L5
L1
L6
L5
L5
L5
L5
L5
Here is a minimal DFA, where each state corresponds to a quotient, and a state is an accept state if it
contains the empty string:
a
2
4
a
a
b
1
b
6
b
a, b
b
3
a
5
a, b
Problem 13: Union of Finite State Machines
A. N essentially runs the two machines M1 and M2 independently. The definition of acceptance for an
NFA is that it accepts if there is any computational path. So, N will accept a string if either M1 or
M2 accept it, so N ’s acceptance language will be L(M1 ) ∪ L(M2 ), as desired.
B. Notice that when performing the power automaton construction, each state that can actually reached
will be a set of size 2. In particular, it will be a set of the form {qi1 , qj2 }. Notice that after processing a
particular character, the current set will essentially move from qi1 and qj2 in M1 and M2 , respectively.
So, assuming each pair of the form {qi1 , qj2 } is accessible, the resulting machine will the the product
machine M1 × M2 .
Problem 14: Slow State Merging
7
A. Here is a DFA that requires 4 stages:
a, b
0
a, b
1
a, b
2
a, b
3
a, b
4
B. The ability to distinguish states moves from left to right at a speed of one per stage. So, the four
stages are:
E0 = {0, 1, 2, 3}, {4}
E1 = {0, 1, 2}, {3}, {4}
E2 = {0, 1}, {2}, {3}, {4}
E3 = {0}, {1}, {2}, {3}, {4}
Problem 15: Recognizing Simple Patterns
A. Here is a DFA that does this:
b
a, b
a
b
a
a
a
b
b
B. Here is a DFA that does this:
b
b
a
b
a
a
Problem 16: Testing DFA Equivalence
8
a, b
b
a
A. The proof is somewhat tedious, so I will only give an outline.
We can prove for each string x ∈ Σ∗ , δ1 (q01 , x) will be marked as equivalent to δ2 (q02 , x) after the
algorithm has been run. This ben be proven by induction on the length of x.
Once this has been proven, correctness follows easily: if the DFAs are equivalent, then every equivalence
will be valid, since the start states are equivalent and transitioning on the same character maps
equivalent states to equivalent states. If the DFAs are not equivalent, then there is some x ∈ Σ∗ such
that exactly one of δ1 (q01 , x) and δ2 (q02 , x) is an accept state, so the algorithm will recognize the two
DFAs as different for this state.
B. The number of equivalence classes starts at |Q|, and is reduced by 1 every time we do a merge, so the
total number of pairs processed will be linear. We can use a queue for the pairs to get linear time
overall for adding and removing pairs. For merging pairs and testing equivalence, we can use a union
find structure, which is known to take O(n · α−1 (n)) time for n operations, where α is the Ackermann
function. So, the algorithm can be run in essentially linear time.
Problem 17: Rational Relations
A. This is rational. We can simply check that the two strings are the same up until the first string ends,
and have the # symbol count as being equal to everything. If we ever see two characters that are not
equal, we reject.
B. This is not rational. Suppose it was rational. Then the language {x : y | x is a suffix of y } is
regular. The language (0, 1)∗ (#, 0)∗ is also known to be regular, so the intersection, i.e. the language
{(0, 1)n (#, 0)m | m ≥ n} is regular. But this is a language of the form {an bm | m ≥ n}, which is
known to not be regular, so we have a contradiction.
C. This is not rational. Suppose it was rational. Then the language {x : y | x is the reverse of y }
is regular. We can then intersect this with the regular language {x : x | x ∈ {0, 1}∗ } to get that
the language {x ∈ {(0, 0), (1, 1)}∗ | x is a palindrome } is regular. But it is known that nontrivial
palindrome languages are not regular, so we have a contradiction.
D. This is rational. We can simply accept if we ever see a symbol of the form (n, #) for some n ∈ {0, 1},
and reject if we never see such a symbol.
E. This is not rational. Suppose it was rational. Then {x : y | x and y have the same number of 1s} is
regular. So, if we intersect with the language (1, 0)∗ (0, 1)∗ , we get that the language {(1, 0)n (0, 1)n | n ∈
N} is regular. But this language is of the form {an bn | n ∈ N}, so it is known to not be regular, so we
have a contradiction.
F. This is not rational. If it was rational, then the language {x : y | x = yy} would be regular, so if we
intersect with (0, 0)∗ (#, 0)∗ , we would get that {(0, 0)n (#, 0)n | n ∈ N} is regular. But this language
is of the form {an bn | n ∈ N}, so we have a contradiction.
Problem 18: Expressiveness of FOL
9
A. One way of defining a total order is that it is an asymmetric, transitive, and total relation. This can
be expressed in FOL by the following axioms:
∀a (¬(a < a))
∀a∀b∀c (((a < b) ∧ (b < c)) → (a < c))
∀a∀b ((a < b) ∨ (b < a) ∨ (a = b))
B. A rigorous proof of this is probably hard. It can be shown that the well-order property is true if and
only if every set contains a least element. This property is easily expressible in second-order logic (by
quantifying over all sets), but there’s no straightforward way of expressing it in first-order logic.
10