October 13, 2025
Learning Objectives for Theoretical Machines
import utils; from utils import rf
from lastDigitIsEven import lastDigitIsEven
def isOddViaReduction(inString):
inStringPlusOne = int(inString) + 1
return lastDigitIsEven(str(inStringPlusOne))
def testisOddViaReduction():
testVals = [('-2', 'no'),
('0', 'no'),
('2', 'no'),
('3742788', 'no'),
('-1', 'yes'),
('1', 'yes'),
('3', 'yes'),
('17', 'yes'),
('3953969', 'yes'),
]
for (inString, solution) in testVals:
val = isOddViaReduction(inString)
utils.tprint(inString, ':', val)
assert val == solutionisOddViaReduction uses lastDigitIsEven to solve the isOdd problemisOddViaReduction solves isOdd by “reducing” it to lastDigitIsEvenlastDigitIsEven functionimport utils; from utils import rf
def lastDigitIsEven(inString):
lastDigit = inString[-1] # ``[-1]'' is Python notation for last element
if lastDigit in '02468':
return 'yes'
else:
return 'no'
def testlastDigitIsEven():
testVals = [('-2', 'yes'),
('0', 'yes'),
('2', 'yes'),
('3742788', 'yes'),
('-1', 'no'),
('1', 'no'),
('3', 'no'),
('17', 'no'),
('3953969', 'no'),
]
for (inString, solution) in testVals:
val = lastDigitIsEven(inString)
utils.tprint(inString, ':', val)
assert val == solutionlastDigitIsEven function can solve the isOdd problemisOddViaReduction behaves the same way as the isOdd functionYesOnString:
ContainsGAGA is uncomputableHaltsOnString is uncomputableYesOnString \(\rightarrow\) ContainsGAGAContainsGAGA is uncomputableYesOnString is uncomputableYesOnString \(\leq_T\) ContainsGAGAYesOnString: Given program \(P\) and input \(I\), does \(P(I)=\) “yes”?ContainsGAGA: Given program \(P\) and input \(I\), does \(P(I)\) contain the string “GAGA”?YesOnString into an instance of ContainsGAGA (i.e., ContainsGAGA will compute YesOnString)ContainsGAGA to solve the YesOnString problemyesViaGAGA programimport utils; from utils import rf
from GAGAOnString import GAGAOnString # oracle function
def yesViaGAGA(progString, inString):
singleString = utils.ESS(progString, inString)
return GAGAOnString(rf('alterYesToGAGA.py'), singleString)
def testYesViaGAGA():
testvals = [
('containsGAGA.py', 'TTTTGAGATT', 'yes'),
('containsGAGA.py', 'TTTTGAGTT', 'no'),
('isEmpty.py', '', 'yes'),
('isEmpty.py', 'x', 'no'),
]
for (filename, inString, solution) in testvals:
val = yesViaGAGA(rf(filename), inString)
utils.tprint(filename + ":", val)
assert val == solutionYesOnString problem using an “oracle” for ContainsGAGA, meaning we will solve known problem with new oneGAGAOnString programimport utils; from utils import rf
from universal import universal
def GAGAOnString(progString, inString):
val = universal(progString, inString)
if val == 'GAGA':
return 'yes'
else:
return 'no'
def testGAGAOnString():
testvals = [('containsGAGA.py', 'GAGAGAGAG', 'no'),
('repeatCAorGA.py', 'CA', 'no'),
('repeatCAorGA.py', 'GA', 'yes') ]
for (progName, inString, solution) in testvals:
val = GAGAOnString(rf(progName), inString)
utils.tprint( (progName, inString), ":", val )
assert val == solutionGAGAOnString function transforms the output of any program to “yes” if standard output equals “GAGA” or “no” otherwisealterYesToGAGA programimport utils; from utils import rf
from universal import universal
def alterYesToGAGA(inString):
(progString, newInString) = utils.DESS(inString)
val = universal(progString, newInString)
if val == 'yes':
return 'GAGA'
else:
return 'no'
def testAlterYesToGAGA():
for (progName, inString, solution) in [('containsGAGA.py', 'GAGAGAGAG', 'GAGA'),
('containsGAGA.py', 'ATATACCC', 'no') ]:
progString = rf(progName)
combinedString = utils.ESS(progString, inString)
val = alterYesToGAGA(combinedString)
utils.tprint( (progName, inString), ":", val )
assert val == solutionalterYesToGAGA function transforms the output of any program to either “GAGA” if output is “yes” or “no” otherwiseYesOnString \(\leq_T\) ContainsGAGAyesViaGAGA: uses the GAGAOnString (i.e., ContainsGAGA) oracle to decide YesOnString by calling the oracle on the transformed program.
yesViaGAGA is functionally equivalent to YesOnStringyesViaGAGA uses GAGAOnString as a key building blockalterYesToGAGA.py: transforms an instance (P, I) so that if P(I) returns "yes" the transformed program prints "GAGA", otherwise prints "no".
GAGAOnString: oracle wrapper that simulates a program and returns "yes" iff the program’s standard output equals GAGA.
Key insights about this proof technique using Turing reductions:
ContainsGAGA’s uncomputabilityYesOnString \(\leq_T\) (“reduces to”) ContainsGAGAYesOnString is no harder than ContainsGAGAContainsGAGA is uncomputable?ContainsGAGA is computableYesOnString is computable, via the reductionYesOnString is uncomputable, which we have previously proven in a separate proof by contradiction!ContainsGAGA was wrongContainsGAGA must be uncomputable via reductionContainsGAGA is uncomputable!YesOnString, previously proven uncomputable
YesOnEmpty (does \(P(\epsilon)=\) “yes”?)YesOnAll (does \(P(I)=\) “yes” for all \(I\)?)YesOnSome (does \(P(I)=\) “yes” for some \(I\)?)ContainsGAGA (does \(P(I)\) output contain “GAGA”?)HaltsOnString, HaltsOnEmpty, HaltsOnAllNumCharsOnString, NumStepsOnStringKey: Importantly, all of these uncomputability proofs start from a single problem, such as YesOnString, that we’ve proven to be uncomputable!
Building hierarchies: Transitivity helps organize problems by hardness
Viewing hierarchies: See the relationships between problems in a tree
Tree Interpretation: Node at the top is the “starting point” of the Turing reduction chain! Okay, let’s see what this uncomputability tree looks like!
YesOnString is no harder than HaltsOnStringHaltsOnString is no harder than HaltsOnEmptyHaltsOnString is no harder than NumStepsOnStringYesOnString is no harder than HaltsOnEmptyYesOnString is no harder than NumStepsOnString
YesOnString to YesOnEmptyimport utils; from utils import rf
from yesOnEmpty import yesOnEmpty # oracle function
def yesViaEmpty(progString, inString):
utils.writeFile('progString.txt', progString)
utils.writeFile('inString.txt', inString)
return yesOnEmpty(rf('ignoreInput.py')) YesOnString \(\leq_T\) YesOnEmptyYesOnString is no harder than YesOnEmptyYesOnEmpty is undecidableHaltsOnString is undecidable?yesViaHalt programimport utils; from utils import rf
from haltsOnString import haltsOnString # oracle function
def yesViaHalts(progString, inString):
singleStr = utils.ESS(progString, inString)
return haltsOnString(rf('alterYesToHalt.py'), singleStr)
def testYesViaHalts():
testvals = [
('containsGAGA.py', 'TTTTGAGATT', 'yes'),
('containsGAGA.py', 'TTTTGAGTT', 'no'),
('isEmpty.py', '', 'yes'),
('isEmpty.py', 'x', 'no'),
]
for (filename, inString, solution) in testvals:
val = yesViaHalts(rf(filename), inString)
utils.tprint(filename + ":", val)
assert val == solutionhaltsOnString “oracle” to solve YesOnString, meaning YesOnString \(\leq_T\) HaltsOnString. Next, what is the implementation of haltsOnString?haltsOnString programimport utils; from utils import rf
from universal import universal
def haltsOnString(progString, inString):
# if it doesn't complete before timing out, assume it is in an infinite loop
# note that this is for demonstration purposes only and not how an
# actual "haltsOnString" oracle would be implemented in the proof
val = utils.runWithTimeout(None, universal, progString, inString)
if val != None:
return 'yes'
else:
return 'no'
def testhaltsOnString():
for (progName, inString, solution) in [
('loopIfContainsGAGA.py', 'GAGAGAGAG', 'no'), \
('loopIfContainsGAGA.py', 'TTTTGGCCGGT', 'yes') ]:
val = haltsOnString(rf(progName), inString)
utils.tprint( (progName, inString), ":", val )
assert val == solutionrunWithTimeout to simulate halting behavior since the universal program may run forever with programs having infinite loopsalterYesToHalt programimport utils; from utils import rf
from universal import universal
def alterYesToHalt(inString):
(progString, newInString) = utils.DESS(inString)
val = universal(progString, newInString)
if val == 'yes':
# return value is irrelevant, since returning any string halts
return 'halted'
else:
# deliberately enter infinite loop
utils.loop()
def testAlterYesToHalt():
for (progName, inString, solution) in [
('containsGAGA.py', 'GAGAGAGAG', 'halted'),
('containsGAGA.py', 'TTTTGGCCGGT', None),
]:
combinedString = utils.ESS(rf(progName), inString)
val = utils.runWithTimeout(None, alterYesToHalt, combinedString)
utils.tprint( (progName, inString), ":", val )
assert val == solutionalterYesToHalt program returns 'halted' if \(P(I)=\)'yes' and otherwise enters an infinite loop using the utility function utils.loop() functionYesOnString \(\leq_T\) HaltsOnStringyesViaHalts: uses the haltsOnString oracle to decide YesOnString by calling the oracle on the transformed program.
yesViaHalts is functionally equivalent to YesOnStringyesViaHalts uses haltsOnString as a key building blockalterYesToHalt.py: transforms an instance (P, I) so that if P(I) returns "yes" the transformed program halts (returns), otherwise it enters an infinite loop.
haltsOnString: oracle “wrapper” that simulates a program with timeout and returns "yes" iff the program halts within the timeout period.
Key insights about this proof technique using Turing reductions:
HaltsOnString’s uncomputabilityYesOnString \(\leq_T\) (“reduces to”) HaltsOnStringYesOnString is no harder than HaltsOnString
YesOnString, many problems are uncomputable!Proofgrammers