Home/Blog/Programming/Beyond P vs. NP: Finding Harder Problems
Home/Blog/Programming/Beyond P vs. NP: Finding Harder Problems

Beyond P vs. NP: Finding Harder Problems

12 min read
Jan 22, 2024
content
The P vs. NP problem
The Hardest of Them All
Setting up the Framework
Time Hierarchy Theorem
The Statement of the Theorem
Defining the Problem in Terms of the Solution
Designing DDD: The High-Level Idea
The program DDD
Just Defining DDD Is Enough
Concluding Thoughts

Become a Software Engineer in Months, Not Years

From your first line of code, to your first day on the job — Educative has you covered. Join 2M+ developers learning in-demand programming skills.

The P vs. NP problem#

The discussion on hard programming problems is mostly centered around the famous P\text{P} vs. NP\text{NP} problem. Where P\text{P} is the collection of problems that are efficiently solvableWe consider a problem to be efficiently solvable if its running time is bounded by some polynomial., and NP\text{NP} is the collection of problems that are efficiently verifiableA problem is efficiently verifiable if there’s a way to verify that a given solution is a valid solution of a given problem instance in polynomial time..

The P\text{P} vs. NP\text{NP} problem asks whether these two collections are the same!

The answer to this problem is unknown, as of now. If the answer turns out to be in the affirmative, the two notions (efficient verifiability and efficient search for solutions) would be provably the same. This does not seem very likely, and most researchers believe that it is not the case. There are some exceptions, however, Donald Knuth being the most notableSee the answer to question 17 at https://www.informit.com/articles/article.aspx?p=2213858.. Settling this question might be one way to earn your first million dollars“P vs NP.” n.d. Clay Mathematics Institute.

We can easily establish that any problem in NP\text{NP} can be solved in exponential time.

We’ll prove in this blog that there are even harder problems than the ones in NP\text{NP}.

The Hardest of Them All#

Have you ever wondered which of the known problems is the hardest of them all?

We’re not talking about problems that cannot be solved (like the halting problem). We’d like to know which problem, from among the solvable ones (that is, for which some algorithm is known), is the hardest—in the sense that it would require the most time to solve.

We’ll answer this question in this blog. As a sneak peek, our answer will be “There’s no such problem.” That is, given any hard problem, we can always find a harder problem—so there’s no hardest problem! This is where we will need to go beyond the the P vs. NP question into the realm of the time hierarchy theorem.

Setting up the Framework#

We’ll limit ourselves to the standard framework of computability theory, conveniently adapted for the general computer science audience we laid down in an earlier blog about the halting problem.

In summary:

  • All of our problems will be decision problems. That is, we’ll be interested in deciding whether a given input satisfies certain conditions or not. For instance, the problem of determining whether a given number is prime, or the problem of determining whether a given graph has a HamiltonianA cycle that contains all vertices of the graph. cycle.

  • All of our programs will take only one input and return a boolean value. We can easily modify every program to receive only one input by using, for instance, some aggregate data type.

Justifications for why these assumptions do not affect the generality are given in the above mentioned blog.

We’d also assume that we have access to a program UU that can simulate a given program for a specified number of steps. Think of it as a modified interpreter that increments a counter after executing each step. We can build it, or modify one, without too much difficulty.

Time Hierarchy Theorem#

We’ll start by introducing the time hierarchy theorem, that’s the key to answering the questions we’ve set out to answer. It basically formalizes and justifies the intuitive notion that given more time, more complex problems can be solved!

We’ll state and prove a weak version of the time hierarchy theorem since it’s easier to prove, and can serve as the foundation of studying the stronger version for interested learners.

The Statement of the Theorem#

In order to avoid weird functions, let’s restrict ourselves to increasing functions f(n)f(n) on natural numbers1, 2, 3, … that are computable—that is, there is a program that takes nn as input, and outputs f(n)f(n). Note that the functions we commonly see in computer science, like lgn,n,nlgn,n2,5n3+2n3,2n\lg n, n, n\lg{n}, n^2, 5n^3+2n-3, 2^n, etc., satisfy this condition.

We’ll show that for any such function ff, there is a problem AA that cannot be solved in f(n)f(n) time.

This would immediately imply that no matter how much time is given, there’d still be problems that can’t be solved in that time!

There’s a stronger version of this theorem of a more applied flavor that measures the time complexity of the program that solves AA. However, we’ll restrict ourselves to this weaker version, as it’s more suitable to the blog format.

Defining the Problem in Terms of the Solution#

The approach we’ve taken for coming up with this problem AA is a little unusual—instead of defining AA directly, we’ll define it in terms of a program DD that solves it.

AA is the set of all inputs on which DD would return TRUE.

Don’t be put off by it as it’s a perfectly legitimate way of defining a problem. For example, we can legitimately define even numbers by first providing a program that tests if a number is a multiple of two, and then say even numbers are all those numbers on which this program returns TRUE.

Designing DDD: The High-Level Idea#

Recall that we’re dealing with decision problems in computability theory where problems are sets. We’ll design DD so that it differs from any program that runs in f(n)f(n) time on at least one input. This would establish that AA, the problem solved by DD, is different from any problem that can be solved in f(n)f(n) time.

To be more precise, let’s assume Q1,Q2,Q3,Q_1, Q_2, Q_3, \ldots are all the programs that halt and return an answer in f(n)f(n) time. If AA could be solved in f(n)f(n) time, then surely one of the QiQ_i from this list would solve it.

We’ll design DD in such a way that for any program QkQ_k from this list, there’s an input ww on which Qk(w)D(w)Q_k(w) \neq D(w).

While designing DD, we’ll choose ww to be the program QkQ_k itself!

As AA is defined using DD, this would prove that AA can’t be the same as any of the problems solved by the QiQ_i. This would immediately imply that the problem AA can’t be solved in f(n)f(n) time, as the list of QiQ_i contains all problems solvable in f(n)f(n) time.

This is diagonalization in action that we used to show that the halting problem is unsolvable.

The program DDD#

We’ll define DD as follows: DD takes an input ww and returns TRUE or FALSE. Recall that our problem AA is the set of all inputs on which DD returns TRUE.

DD performs the following steps on the input ww:

  1. DD verifies whether ww is a valid program. If it isn’t, DD returns FALSE. This can easily be done by embedding a compiler of whichever language is chosen in DD as a subroutine and calling it on ww. Let’s refer to the program that ww corresponds to as QQ.

  2. DD now runs QQ on ww for f(n)f(n) steps, using the program UU described earlier. DD returns FALSE if the program UU does not produce a valid return value (TRUE or FALSE) in this much time.

    Do note that DD runs the program QQ on itself, as w=Qw = Q.

  3. When QQ halts with a valid return value in f(n)f(n) steps, DD returns the opposite of what QQ has returned. That is, if QQ returns TRUE, DD returns FALSE, and if QQ returns FALSE, DD returns TRUE.

    Note that by differing with QQ on input ww, DD has made sure that AA is different from the problem solved by QQ.

This completes the construction of DD.

The problem A is defined to be the collection of problems on which D returns TRUE.
The problem A is defined to be the collection of problems on which D returns TRUE.

In the above figure, each entry of the table represents the result of running the program QkQ_k on input QkQ_k for f(n)f(n) steps inside DD. The problem AA is then defined to be the set of all programs QjQ_j that return FALSE on input QjQ_j, as these are the only inputs on which DD returns TRUE.

Just Defining DDD Is Enough#

As the input to DD can be any string, it could be given any program whatsoever as an input. In particular, all programs in the chosen language that run in f(n)f(n) times can be given as inputs to DD.

Keep in mind that we are not going to run DD to do anything, our job is done by just writing DD, as this gives us the definition of AA.

To reiterate, by ensuring that DD is different on at least one input from any program that runs and produces a valid result in f(n)f(n) time, we have established that AA can’t be solved in f(n)f(n) time. This is precisely what we set out to do!

We can use this version of the time hierarchy theorem to show that there are problems that can’t be solved in even 2n,22n,222n,2^n, 2^{2^n}, 2^{2^{2^n}}, or 222n2^{2^{\cdot^{\cdot^{\cdot^{2^n}}}}} time, for example!

Concluding Thoughts#

A stronger version of the time hierarchy theorem can be proven if we measure the complexity of the program DD more precisely. We can do so if we make certain assumptions, like the following:

  • f(n)f(n) is at least nn. DD needs at least this much time to determine nn from the input ww, as n=wn = |w|.

  • Each step of the simulation takes some constant time. This is a reasonable assumption, as a simulation of one step of the program should not depend on input length.

  • Each increment to the counter in UU (to check if we have not exceeded f(n)f(n) steps) does not take more than O(lgf(n))O(\lg f(n)) time. This is also a fair assumption, as we do not require more than lgf(n)\lg f(n) bits to write down f(n)f(n).

The time complexity of DD then turns out to be O(f(n)lgf(n))O(f(n) \lg f(n)) (simulation of f(n)f(n) steps each requiring O(lgf(n))O(\lg f(n)) time). This is under the assumption that the compiler does not need more than this much time to verify if the input ww is a valid program.

Once we have this, we can make stronger claims like the following:

There’s a problem that can be solved in O(f(n)lgf(n))O(f(n) \lg f(n)) time that can’t be solved in f(n)f(n) time.

An obvious and immediate consequence is that

PEXPTIME\text{P} \neq \text{EXPTIME}

where P\text{P} is the collection of efficiently solvable problems discussed earlier, and EXPTIME\text{EXPTIME} is the collection of all problems that can be solved in exponential time.

This won’t earn us a million dollars, but it’s no less valuable since there’s a severe dearth of specific results like this in complexity theory. Understanding the nuances of time complexity and the time hierarchy theorem gives you a foundational basis for grappling with the complexities of the ‘P vs NP’ problem.

Want to learn more? Feel free to check out the following resources available on Educative:

Frequently Asked Questions

Has P vs NP been solved?

The core challenge lies in the inability to identify an NP-complete problem that also falls under P, a discovery that would imply the potential for rapid and straightforward solutions to all NP problems. For several decades, computer scientists have been diligently working to resolve this issue, yet a conclusive answer remains elusive.


Written By:
Imran Farid Khan

Free Resources