web-dev-qa-db-fra.com

Essayer de comprendre P vs NP vs NP Complete vs NP Hard

J'essaie de comprendre ces classifications et pourquoi elles existent. Ma compréhension est-elle correcte? Sinon, quoi?

  1. P est la complexité polynomiale, ou O(nk) pour un certain nombre réel non négatif k, comme O(1), O(n1/2), O(n2), O(n3), etc. Si un problème appartient à P, alors il existe à au moins un algorithme qui peut le résoudre à partir de zéro en temps polynomial. Par exemple, je peux toujours déterminer si un entier n est premier en faisant une boucle sur 2 <= k <= sqrt(n) et en vérifiant à chaque étape si k divise n.

  2. NP est une complexité polynomiale non déterministe. Je ne sais pas vraiment ce que cela signifie pour elle d'être non déterministe. Je pense que cela signifie qu'il est facile de vérifier en temps polynomial, mais peut ou non être un temps polynomial à résoudre à partir de zéro si nous ne connaissions pas déjà la réponse. Puisqu'il peut être résoluble en temps polynomial, tous les problèmes P sont également NP problèmes. La factorisation entière est citée comme exemple de NP, mais je ne comprends pas pourquoi ce n'est pas P, personnellement, car la factorisation d'essai prend O(sqrt(n)) temps.

  3. NP-Complete Je ne comprends pas du tout, mais le problème des vendeurs ambulants est cité en exemple. Mais à mon avis, le problème TSP pourrait simplement être NP, car il faut quelque chose comme O(2n n2) time to solve, but O(n) pour vérifier si vous avez le chemin d'accès à l'avant.

  4. NP-Hard, je suppose, est juste plein d'inconnues. Difficile à vérifier, difficile à résoudre.

48
Nakano

Vous avez fondamentalement raison pour P et NP, mais pas pour NP-hard et NP-complete.

Pour commencer, voici les définitions super concises des quatre classes de complexité en question:

  • P est la classe de problèmes de décision qui peuvent être résolus en temps polynomial par une machine de Turing déterministe.

  • NP est la classe de problèmes de décision qui peuvent être résolus en temps polynomial par une machine de Turing non déterministe. De manière équivalente, c'est la classe de problèmes qui peut être vérifiée en temps polynomial par une machine de Turing déterministe.

  • NP-hard est la classe de problèmes de décision à laquelle tous les problèmes en NP peuvent être réduits en temps polynomial par une machine de Turing déterministe.

  • NP-complete est l'intersection de NP-hard et NP. De manière équivalente, NP-complet est la classe de problèmes de décision en NP à laquelle tous les autres problèmes en NP peuvent être réduits en temps polynomial par une machine de Turing déterministe) .

Et voici un diagramme d'Euler de Wikipedia montrant les relations entre ces quatre classes (en supposant que P n'est pas égal à NP):

enter image description here

La partie avec laquelle je suppose que vous n'êtes pas familier ou que vous confondez le plus est la notion de "réduction du temps polynomial" du problème X au problème Y. Une réduction de X à Y est simplement un algorithme A qui résout X en utilisant certains autre algorithme B qui résout le problème Y. Cette réduction est appelée "réduction de temps polynomiale" si toutes les parties de A autres que B ont une complexité de temps polynomiale. À titre d'exemple trivial, le problème de trouver le plus petit élément dans un tableau est réductible en temps constant au problème de tri, car vous pouvez trier le tableau puis renvoyer le premier élément du tableau trié.

Une chose qu'il est facile de manquer à propos de la définition NP-dur est que la réduction passe des problèmes NP au problème NP-dur, mais pas nécessairement l'inverse . Cela signifie que les problèmes NP-difficiles peuvent être dans NP, ou dans une classe de complexité beaucoup plus élevée (comme vous pouvez le voir sur le diagramme d'Euler), ou ils peuvent même ne pas être des problèmes décidables. pourquoi les gens disent souvent quelque chose comme "NP-dur signifie au moins aussi dur que NP" lorsqu'ils essaient d'expliquer ces choses de manière informelle.

Le problème d'arrêt est un bon exemple d'un problème NP-difficile qui n'est clairement pas dans NP, comme Wikipedia explique :

Il est facile de prouver que le problème d'arrêt est NP-difficile mais pas NP-complet. Par exemple, le problème de satisfiabilité booléenne peut être réduit au problème d'arrêt en le transformant en la description d'une machine de Turing qui essaie toutes les affectations de valeur de vérité et quand il en trouve une qui satisfait la formule, il s'arrête et sinon il va dans une boucle infinie. Il est également facile de voir que le problème d'arrêt n'est pas dans NP puisque tous les problèmes dans NP sont décidables dans un nombre fini d'opérations, tandis que le problème d'arrêt) , en général, est indécidable.

52
Ixrec

La factorisation entière est citée comme un exemple de NP, mais je ne comprends pas pourquoi ce n'est pas P, personnellement, car la factorisation d'essai prend O(sqrt(n)) temps.

Aux fins des classes de complexité, n est la longueur de l'entrée. Donc, si vous voulez factoriser l'entier k, n n'est pas k mais log k, Le nombre de bits (ou autre) qu'il faut pour écrire le nombre. La factorisation entière est donc O(sqrt(k)) comme vous dites, mais c'est O(sqrt(2n)) qui est O(2(n/2)).

NP-Hard, je suppose, est juste plein d'inconnues. Difficile à vérifier, difficile à résoudre.

Non. NP-Hard est simplement la difficulté de résoudre un problème.

Les problèmes NP-Hard sont au moins aussi difficiles que le problème le plus difficile dans NP. Nous savons qu'ils sont au moins aussi difficiles, car si nous avions un algorithme polynomial pour un problème NP-Hard, nous pourrions adapter cet algorithme à n'importe quel problème dans NP.

NP-Complete Je ne comprends pas du tout

NP-Complete signifie qu'un problème est à la fois NP et NP-Hard. Cela signifie que nous pouvons vérifier une solution rapidement (NP), mais c'est au moins aussi difficile que le problème le plus difficile dans NP (NP-Hard).

Je ne sais pas vraiment ce que cela signifie pour elle d'être non déterministe.

Le non-déterminisme est une autre définition du NP. Une machine de turing non déterministe est effectivement capable de se dupliquer à tout moment et de faire en sorte que chaque doublon prenne un chemin d'exécution différent. Sous cette définition, NP est l'ensemble des problèmes qui peuvent être résolus en temps polynomial par un ordinateur et qui peuvent se dupliquer librement. Il s'avère que c'est exactement le même ensemble de problèmes qui peuvent être vérifiés en temps polynomial.

9
Winston Ewert

La première chose à comprendre est que P et NP classifier langues, pas problèmes. Pour comprendre ce que cela signifie, nous avons d'abord besoin d'autres définitions.

Un alphabet est un ensemble fini non vide de symboles.

{_0_, _1_} est un alphabet tout comme le jeu de caractères ASCII. {} N'est pas un alphabet car il est vide. N (les entiers) n'est pas un alphabet car il n'est pas fini.

Laisser Σ être un alphabet. Une concaténation ordonnée d'un nombre fini de symboles de Σ est appelé un mot sur Σ.

La chaîne _101_ est un mot sur l'alphabet {_0_, _1_}. Le mot vide (souvent écrit comme ε) est un mot sur n'importe quel alphabet. La chaîne penguin est un mot sur l'alphabet contenant les caractères ASCII. La notation décimale du nombre π n'est pas un mot sur l'alphabet {_._, _0_, _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_} car il n'est pas fini.

La longueur d'un mot w, écrit comme |w|, est le nombre de symboles qu'il contient.

Par exemple, | hello | = 5 et |ε| = 0. Pour tout mot w, |w| ∈ N et donc fini.

Laisser Σ être un alphabet. L'ensemble Σ contient tous les mots Σ, comprenant ε. L'ensemble Σ+ contient tous les mots Σ, à l'exclusion ε. Pour n ∈ NΣn est l'ensemble des mots de longueur n.

Pour chaque alphabet ΣΣ et Σ+ sont infinis ensembles dénombrables . Pour le jeu de caractères ASCII ΣASCII, les expressions régulières _.*_ et _.+_ désignent ΣASCII et ΣASCII+ respectivement.

{_0_, _1_}7 est l'ensemble de 7 bits ASCII {_0000000_, _0000001_,…, _1111111_}. {_0_, _1_}32 est l'ensemble des valeurs entières de 32 bits.

Laisser Σ être un alphabet et L ⊆ ΣL est appelé une langue sur Σ.

Pour un alphabet Σ, l'ensemble vide et Σ sont des langues triviales sur Σ. Le premier est souvent appelé langue vide. La langue vide {} et la langue ne contenant que le mot vide {ε} sont différents.

Le sous-ensemble de {_0_, _1_}32 qui correspond aux valeurs à virgule flottante non NaN IEEE 754 est un langage fini.

Les langues peuvent avoir un nombre infini de mots mais chaque langue est dénombrable. L'ensemble de chaînes {_1_, _2_,…} désignant les entiers en notation décimale est une langue infinie sur l'alphabet {_0_, _1_, _2_ , _3_, _4_, _5_, _6_, _7_, _8_, _9_}. L'ensemble infini de chaînes {_2_, _3_, _5_, _7_, _11_, _13_,…} désignant les nombres premiers en décimal la notation en est un sous-ensemble approprié. La langue contenant tous les mots correspondant à l'expression régulière [+-]?\d+\.\d*([eE][+-]?\d+)? est une langue sur le jeu de caractères ASCII (désignant un sous-ensemble des expressions à virgule flottante valides définies par la programmation C Langue).

Il n'y a pas de langue contenant tous les nombres réels (dans n'importe quelle notation) car l'ensemble des nombres réels n'est pas dénombrable.

Laisser Σ être un alphabet et L ⊆ Σ. Une machine   décide  L si pour chaque entrée w ∈ Σ il calcule la fonction caractéristique  χL(w) en temps fini. La fonction caractéristique est définie comme

χLΣ → {0, 1} 
 w  ↦ 1, w ∈ L
 0, sinon.

Une telle machine est appelée décideur pour L. Nous écrivons "(w) = x"Pour" donné w les sorties x".

Il existe de nombreux modèles de machines. Le plus général actuellement utilisé est le modèle d'une Turing machine . Une machine Turing a un stockage linéaire illimité regroupé en cellules. Chaque cellule peut contenir exactement un symbole d'un alphabet à tout moment. La machine de Turing effectue son calcul comme une séquence d'étapes de calcul. À chaque étape, il peut lire une cellule, éventuellement écraser sa valeur et déplacer la tête de lecture/écriture d'une position vers la cellule gauche ou droite. L'action que la machine exécutera est contrôlée par un automate à états finis.

Une machine à accès aléatoire avec un ensemble fini d'instructions et un stockage illimité est un autre modèle de machine aussi puissant que le modèle de machine de Turing.

Pour les besoins de cette discussion, nous ne nous soucierons pas du modèle de machine précis que nous utilisons, mais il suffit de dire que la machine a une unité de contrôle déterministe finie, un stockage illimité et effectue un calcul comme une séquence d'étapes qui peuvent être comptées.

Puisque vous l'avez utilisé dans votre question, je suppose que vous êtes déjà familier avec notation "big-O" alors voici seulement un petit rappel.

Laisser fN → être une fonction. L'ensemble O(f) contient toutes les fonctions gN → N pour lesquels il existe des constantes n ∈ N et c ∈ N de telle sorte que pour chaque n ∈ N avec n > n c'est vrai que g(n) ≤ cf(n).

Nous sommes maintenant prêts à aborder la vraie question.

La classe P contient toutes les langues L pour lequel il existe une machine de Turing  qui décide L et une constante k ∈ N de telle sorte que pour chaque entrée w s'arrête après au plus T(|w|) étapes pour une fonction T ∈ O(n ↦ nk).

Depuis O(n ↦ nk), bien que mathématiquement correct, n'est pas pratique à écrire et à lire, la plupart des gens - pour être honnête, tout le monde sauf moi - écrit généralement simplement O(nk).

Notez que la limite dépend de la longueur de w. Par conséquent, l'argument que vous faites pour la langue des nombres premiers n'est correct que pour les nombres en encodages unaray , où pour l'encodage w d'un certain nombre n, la longueur de l'encodage |w| est proportionnel à n. Personne n'utiliserait jamais un tel encodage dans la pratique. En utilisant un algorithme plus avancé que d'essayer simplement tous les facteurs possibles, on peut montrer, cependant, que la langue des nombres premiers reste P si les entrées sont codées en binaire (ou vers toute autre base). (Malgré un intérêt massif, cela n'a pu être prouvé que par Manindra Agrawal, Neeraj Kayal et Nitin Saxena dans un article primé en 2004, vous pouvez donc deviner que l'algorithme n'est pas très simple.)

Les langues triviales {} et Σ et le langage non trivial {ε} sont évidemment P (pour tout alphabet Σ). Pouvez-vous écrire des fonctions dans votre langage de programmation préféré qui prennent une chaîne en entrée et retournent un booléen indiquant si la chaîne est un mot du langage pour chacune d'entre elles et prouver que votre fonction a une complexité d'exécution polynomiale?

Chaque régulière langue (une langue décrite par une expression régulière) est en P.

Laisser Σ être un alphabet et L ⊆ Σ. Une machine V qui prend un Tuple codé de deux mots wc ∈ Σ et sort 0 ou 1 après un nombre fini d'étapes est un vérificateur pour L s'il a les propriétés suivantes.

  • Donné (wc), V ne sort 1 que si w ∈ L.
  • Pour chaque w ∈ L, il existe un c ∈ Σ tel que V(wc) = 1.

Le c dans la définition ci-dessus est appelé un témoin (ou certificat).

Un vérificateur est autorisé à donner de faux négatifs pour le mauvais témoin même si w est en fait L. Il n'est cependant pas permis de donner de faux positifs. Il est également requis que pour chaque mot de la langue, il existe au moins un témoin.

Pour le langage COMPOSITE, qui contient les codages décimaux de tous les entiers qui sont pas premier, un témoin pourrait être une factorisation. Par exemple, _(659, 709)_ est un témoin de _467231_ ∈ COMPOSITE. Vous pouvez facilement vérifier que sur une feuille de papier sans que le témoin ne soit donné, il serait difficile de prouver que 467231 n'est pas premier sans utiliser un ordinateur.

Nous n'avons pas dit comment trouver un témoin approprié. Ceci est la partie non déterministe.

La classe NP contient toutes les langues L pour lequel il existe une machine de Turing V qui vérifie L et une constante k ∈ N de telle sorte que pour chaque entrée (wc), V s'arrête après au plus T(|w|) étapes pour une fonction T ∈ O(n ↦ nk).

Notez que la définition ci-dessus implique que pour chaque w ∈ L il existe un témoin c avec |c| ≤ T(|w|). (La machine Turing ne peut pas regarder plus de symboles du témoin.)

NP est un surensemble de P (Pourquoi?). On ne sait pas s'il existe des langues qui sont en NP mais pas dans P.

La factorisation entière n'est pas une langue en soi. Cependant, nous pouvons construire un langage qui représente le problème de décision qui lui est associé. Autrement dit, une langue qui contient tous les tuples (nm) tel que n a un facteur  avec  ≤ m. Appelons ce langage FACTEUR. Si vous avez un algorithme pour décider du FACTEUR, il peut être utilisé pour calculer une factorisation complète avec uniquement une surcharge polynomiale en effectuant une recherche binaire récursive pour chaque facteur premier.

Il est facile de montrer que FACTOR est NP. Un témoin approprié serait simplement le facteur  lui-même et tout ce que le vérificateur aurait à faire est de vérifier que  ≤ m et n mod  = 0. Tout cela peut se faire en temps polynomial. (Rappelez-vous, encore une fois, que c'est la longueur de l'encodage qui compte et qui est logarithmique in n.)

Si vous pouvez montrer que FACTOR est également P, vous pouvez être sûr d'obtenir de nombreuses récompenses intéressantes. (Et vous avez cassé une partie importante de la cryptographie d'aujourd'hui.)

Pour chaque langue en NP, il existe un algorithme de force brute qui décide de manière déterministe. Il effectue simplement une recherche exhaustive sur tous les témoins. (Notez que la longueur maximale d'un témoin est limitée par un polynôme.) Donc, votre algorithme pour décider PRIMES était en fait un algorithme de force brute pour décider COMPOSITE.

Pour répondre à votre dernière question, nous devons introduire réduction. Les réductions sont un concept très puissant de l'informatique théorique. Réduire un problème à un autre signifie essentiellement résoudre un problème en résolvant un autre problème.

Laisser Σ être un alphabet et UNE et B être plus de langues ΣUNE est plusieurs fois polynomial réductible à B s'il existe une fonction fΣ → Σ avec les propriétés suivantes.

  • w ∈ UNE ⇔ f(w) ∈ B pour tous w ∈ Σ.
  • La fonction f peut être calculé par une machine de Turing pour chaque entrée w en plusieurs étapes délimitées par un polynôme en |w|.

Dans ce cas, nous écrivons UNE ≤pB.

Par exemple, laissez UNE être le langage qui contient tous les graphiques (codés comme matrice d'adjacence) qui contiennent un triangle. (Un triangle est un cycle de longueur 3.) B être le langage qui contient toutes les matrices avec une trace non nulle. (La trace d'une matrice est la somme de ses principaux éléments diagonaux.) Alors UNE est plusieurs fois polynomiale réductible à B. Pour le prouver, nous devons trouver une fonction de transformation appropriée f. Dans ce cas, nous pouvons définir f pour calculer le 3rd puissance de la matrice d'adjacence. Cela nécessite deux produits matrice-matrice, chacun ayant une complexité polynomiale.

Il est trivialement vrai que L ≤pL. (Pouvez-vous le prouver formellement?)

Nous l'appliquerons à NP maintenant.

Une langue L est NP-hard si et seulement si L"≤pL pour chaque langue L"∈ NP.

Une NP-une langue dure peut ou non être en NP lui-même.

Une langue L est NP-complet si et seulement si

  • L ∈ NP et
  • L est NP-difficile.

Le plus connu NP-la langue complète est SAT. Il contient toutes les formules booléennes qui peuvent être satisfaites. Par exemple, (une ∨ b) ∧ (¬une ∨ ¬b) ∈ SAT. Un témoin valide est {une = 1, b = 0}. La formule (une ∨ b) ∧ (¬une ∨ b) ∧ ¬b ∉ SAT. (Comment prouvez-vous cela?)

Il n'est pas difficile de montrer que SAT ∈ NP. Pour montrer le NP-la dureté de SAT est un travail mais cela a été fait en 1971 par Stephen Cook .

Une fois celui-là NP- une langue complète était connue, il était relativement simple de montrer NP-complétude d'autres langues via la réduction. Si la langue UNE est connu pour être NP-Dur, montrant ensuite que UNE ≤pB montre que B est NP- dur aussi (via la transitivité de "≤p”). En 1972 Richard Karp a publié une liste de 21 langues qu'il pouvait montrer étaient NP-complète via la réduction (transitive) de la SAT. (C'est le seul article de cette réponse que je vous recommande de lire. Contrairement aux autres, il n'est pas difficile à comprendre et donne une très bonne idée de la façon dont NP-complétude via des travaux de réduction.)

Enfin, un bref résumé. Nous utiliserons les symboles NPH et NPC pour désigner les classes de NP-dur et NP-les langues complètes respectivement.

  • P ⊆ NP
  • NPC ⊂ NP et NPC ⊂ NPH, réellement NPC = NP ∩ NPH par définition
  • (UNE ∈ NP) ∧ (B ∈ NPH) ⇒ UNE ≤pB

Notez que l'inclusion NPC ⊂ NP est approprié même dans le cas où P = NP. Pour voir cela, indiquez clairement qu'aucun langage non trivial ne peut être réduit à un langage trivial et qu'il existe des langages triviaux dans P ainsi que des langues non triviales dans NP. C'est un cas d'angle (pas très intéressant).

Addenda

Votre principale source de confusion semble être que vous pensiez au "n" dans "O(n ↦ f(n)) ”Comme interprétation de l'entrée d'un algorithme quand il se réfère en fait à la longueur de l'entrée. Il s'agit d'une distinction importante car elle signifie que la complexité asymptotique d'un algorithme dépend du codage utilisé pour l'entrée.

Cette semaine, un nouveau record pour le plus grand connu Mersenne prime a été atteint. Le plus grand nombre premier connu actuellement est 274207281 - 1. Ce nombre est si énorme qu'il me donne mal à la tête, je vais donc en utiliser un plus petit dans l'exemple suivant: 231 - 1 = 2147483647. Il peut être codé de différentes manières.

  • par son exposant de Mersenne sous forme de nombre décimal: _31_ (2 octets)
  • comme nombre décimal: _2147483647_ (10 octets)
  • comme numéro unaire: _11111…11_ où le __ doit être remplacé par 2147483640 plus _1_ s (presque 2 Gio)

Toutes ces chaînes codent le même nombre et étant donné l'une d'entre elles, nous pouvons facilement construire n'importe quel autre codage du même nombre. (Vous pouvez remplacer le codage décimal par un binaire, un octal ou un hexadécimal si vous le souhaitez. Il ne modifie la longueur que par un facteur constant.)

L'algorithme naïf pour tester la primalité n'est qu'un polynôme pour les codages unaires. Le test de primalité AKS est polynomial pour décimal (ou toute autre base b ≥ 2). Le test de primalité de Lucas-Lehmer est l'algorithme le plus connu pour les nombres premiers de Mersenne Mp avec p un nombre impair premier, mais il est toujours exponentiel dans la longueur du codage binaire de l'exposant de Mersenne p (polynôme en p).

Si nous voulons parler de la complexité d'un algorithme, il est très important que nous soyons très clairs sur la représentation que nous utilisons. En général, on peut supposer que l'encodage le plus efficace est utilisé. Autrement dit, binaire pour les entiers. (Notez que tous les nombres premiers ne sont pas des nombres premiers de Mersenne, donc l'utilisation de l'exposant de Mersenne n'est pas un schéma de codage général.)

En cryptographie théorique, de nombreux algorithmes passent officiellement une chaîne complètement inutile de k _1_ s comme premier paramètre. L'algorithme ne regarde jamais ce paramètre mais il lui permet d'être formellement polynomial dans k, qui est le paramètre de sécurité utilisé pour régler la sécurité de la procédure.

Pour certains problèmes pour lesquels le langage de décision dans le codage binaire est NP-complet, le langage de décision n'est plus NP-complet si le codage des nombres intégrés est basculé sur unaire. Les langues de décision pour les autres problèmes restent NP-complète même alors. Ces derniers sont appelés fortement NP-complet. L'exemple le plus connu est emballage bin .

Il est également (et peut-être plus) intéressant de voir comment la complexité d'un algorithme change si l'entrée est compressée. Pour l'exemple des nombres premiers de Mersenne, nous avons vu trois encodages, chacun étant logarithmiquement plus compressé que son prédécesseur.

En 1983, Hana Galperin et Avi Wigderson ont écrit un article intéressant sur la complexité des algorithmes de graphe courants lorsque l'encodage d'entrée du graphe est compressé logarithmiquement. Pour ces entrées, le langage des graphiques contenant un triangle d'en haut (où il était clairement P) devient soudainement NP-Achevée.

Et c'est parce que des cours de langue comme P et NP sont définis pour langues, pas pour problèmes.

8
5gon12eder

Je vais essayer de vous donner une définition moins informelle de la même chose.

Problèmes P: problèmes qui peuvent être résolus en temps polynomial. Contient des problèmes qui peuvent être résolus efficacement.

Problème NP: problèmes vérifiables en temps polynomial. Par exemple: Vendeur itinérant, conception de circuits. NP les problèmes sont un peu comme des puzzles (comme sudoku). Étant donné une solution correcte pour le problème, nous pouvons vérifier notre solution très rapidement, mais si nous essayons de le résoudre, cela pourrait prendre une éternité.

Maintenant, P vs NP demande en fait si un problème dont la solution peut être rapidement vérifiée pour être correcte, existe-t-il toujours un moyen rapide de le résoudre. Ainsi, écrire en termes mathématiques: est NP un sous-ensemble de P ou non?

Revenons maintenant à NP complet: ce sont les problèmes vraiment difficiles des problèmes NP. Par conséquent, s'il existe un moyen plus rapide de résoudre NP complete puis NP complete devient P et NP les problèmes se réduisent en P.

NP hard: les problèmes qui ne peuvent même pas être vérifiés dans le temps polynomial sont np hard. Par exemple, choisir le meilleur coup aux échecs en fait partie.

Si quelque chose n'est pas clair, essayez de regarder cette vidéo: https://www.youtube.com/watch?v=YX40hbAHx3s

J'espère que cela fournira un contour flou.

8
kanishk verma