David Madore's WebLog: Oracles en calculabilité : degrés de Turing et diverses généralisations

[Index of all entries / Index de toutes les entréesLatest entries / Dernières entréesXML (RSS 1.0) • Recent comments / Commentaires récents]

↓Entry #2764 [older| permalink|newer] / ↓Entrée #2764 [précédente| permalien|suivante] ↓

(mercredi)

Oracles en calculabilité : degrés de Turing et diverses généralisations

Avant-propos et motivation

Avant-propos : J'ai publié il y a quelque temps un billet de vulgarisation sur la notion d'« oracle » en informatique théorique. Ce billet-là (qui se veut grand public) était initialement destiné à être l'introduction à celui-ci (plus technique — mais, j'espère, pas incompréhensible pour autant), mais j'ai décidé de les publier séparément parce qu'ils sont, en fait, à peu près indépendants : on peut donc commencer par lire celui-là si on veut une sorte d'explication introductive et de motivation du sujet, mais ce n'est pas nécessaire non plus.

Ce billet-ci, plus technique mais j'espère pas incompréhensible pour autant (voir le paragraphe suivant pour les prérequis), vise à présenter la notion classique de degré de Turing, et ensuite diverses généralisations de celles-ci dans la recherche contemporaine en logique / calculabilité. Mais je trouve aussi intéressant de vulgariser la notion (classique) de non-déterminisme et celle (pas du tout classique, mais que je trouve très intéressante) de « co-non-déterminisme » (le terme est de moi).

Pour ce qui est des prérequis, ce billet-ci s'adresse à des lecteurs qui savent déjà les bases de la calculabilité : c'est-à-dire en gros, ce qu'est une machine de Turing ou un algorithme (c'est-à-dire au moins approximativement : je n'ai pas l'intention de rentrer dans quelques détails que ce soit sur les état et les bandes), et une fonction calculable (c'est-à-dire, calculable au sens de Church-Turing), ce genre de choses. Je vais essayer de faire en sorte de ne supposer connu (outre des maths générales, du genre ce que c'est qu'une fonction, un ensemble, une partie, une bijection, un ordre, une relation d'équivalence…) que le contenu du chapitre 5 (Introduction à la calculabilité) des notes de mon cours Théorie des langages à Télécom, auquel je peux donc renvoyer pour ces notions de base en calculabilité (en attendant un nouveau cours sur le sujet). • Ajout () : la première partie des transparents de mon nouveau cours est disponible ici.

En tout cas, je ne suppose pas connu la notion de degré de Turing puisque mon but est justement de l'expliquer et de voir comment on peut aller plus loin. (Néanmoins, soyons honnête, les lecteurs déjà un minimum familiers du concept trouveront sans doute mon billet plus facile à suivre que si on le découvre pour la première fois ici.)

Mon but ici est d'abord de définir la notion (tout à fait standard) de réduction de Turing et de degré de Turing, puis de présenter des extensions de ces notions qui me semblent à la fois très importantes et profondément naturelles. J'ai appris l'existence de ces notions en lisant deux articles d'un certain Takayuki Kihara, Lawvere-Tierney topologies for computability theorists et Rethinking the notion of oracle (et dans une moindre mesure Degrees of incomputability, realizability and constructive reverse mathematics, mais je n'ai pas fini celui-là) : je cherche donc à la fois à faire de la pub pour ces articles et pour les notions qu'ils contiennent (parce qu'elles ont vraiment changé la manière dont je pense à la calculabilité), à montrer que ces notions ne sont pas terriblement techniques, et aussi simplement à assurer ma propre compréhension de ces articles en en réexposant certains bouts à ma façon. En outre, j'espère avoir apporté quelques éléments d'intuition utiles derrière certaines des définitions ou des concepts que j'expose. Je trouve particulièrement intéressante la notion de « co-non-déterminisme » (le passage du niveau T2 au niveau T3), donc mon but est notamment de faire de la pub pour ce concept (qui pourrait sans doute s'avérer fécond en-dehors de la calculabilité).

(Notons que j'attribue ces notions à Kihara, qui les a au moins synthétisées, et c'est par lui que je les ai apprises ; mais je ne prétends pas qu'il a tout inventé — il a plutôt réussi à relier, reformuler et réexposer de façon extrêmement convaincante des notions dont certaines figuraient déjà ailleurs : je renvoie aux références de ses papiers pour les citations antérieures, mais je peux par exemple mentionner Basic Subtoposes of the Effective Topos de Lee & van Oosten, ou Instance reducibility and Weihrauch degrees de Bauer, qui sont dignes d'intérêt si on apprécie le sujet.)

Bref, je veux commencer par expliquer ce qu'est un degré de Turing ordinaire (celui d'une fonction — totale, simplement valuée — ℕ→ℕ), puis donner trois extensions successives de cette notion (je vais parler de degrés T1, T2 et T3 faute de meilleure terminologie — Kihara n'en introduit pas vraiment). en expliquant ce qu'elles changent, et si possible pourquoi elles sont naturelles et intéressantes, et ce qu'on peut en dire : d'abord (T1) aux fonctions partielles, puis (T2) aux fonctions multivaluées (ou non-déterministes), et enfin (T3) aux « fonctions avec conseil » (une sorte de « co-non-déterminisme »). Enfin, je veux essayer d'expliquer pourquoi on a fait la « bonne » généralisation, et pour ça, je donne, en guise de dessert, une construction tout à fait différente des degrés (T1, T2 et surtout) T3 qu'on aura définis par des opérateurs effectifs locaux (et évoquer brièvement le lien avec le topos effectif, sur lequel j'ai récemment écrit un billet, mais je ne suppose pas qu'on ici l'a lu).

Conseil de lecture (en guise de leitfaden) : Je sais que j'ai tendance à entrer parfois dans de grandes digressions pas forcément tellement utiles. J'ai essayé de les marquer comme telles (par des petits caractères, ou en disant dès le début d'une section qu'on peut sauter celle-ci) ; je n'ai sans doute pas toujours marqué tout ce qui pouvait être sauté, mais les dépendances entre sections ne sont pas énormes. Même si on n'a pas lu tout ce qui précède, je pense que ça vaut la peine de goûter le dessert (surtout si on n'est pas convaincu par l'intérêt des définitions qui ont précédé, car, après tout, il s'agit plus ou moins de les justifier). Et surtout, je pense que ça vaut la peine de jeter un coup d'œil à la définition des degrés T3 pour la définition du « co-non-déterminisme », ou simplement parce que le jeu à trois joueurs entre Arthur, Nimué et Merlin est vraiment rigolo.

Table des matières

T0 : Degrés de Turing ordinaires (fonctions ℕ→ℕ totales simplement valuées)

Réduction de Turing ordinaire et degrés de Turing

La notion la plus standard est la réduction de Turing ordinaire (j'ajoute ordinaire parce que toutes les notions qui viennent peuvent légitiment être aussi qualifiées de réduction de Turing), et je vais commencer par la définir précisément et dire quelques choses basiques à son sujet. Elle concerne les fonctions ℕ→ℕ (c'est-à-dire, totales, prenant une seule valeur pour chaque entier naturel), ou éventuellement ℕ→{0,1} mais ça ne changera rien à l'histoire.

Une fonction f:ℕ→ℕ est dite réductible au sens de Turing (=Turing-réductible) à une fonction g:ℕ→ℕ, ou bien calculable avec g pour oracle, et on note (disons) f ≼T g, lorsqu'il existe une machine de Turing (i.e., un algorithme) qui calcule f en ayant accès à un oracle calculant g, c'est-à-dire un gadget magique capable de fournir à l'algorithme la valeur de g en tout point souhaité.

Plus précisément, f ≼T g signifie qu'il existe une machine de Turing qui, quand on lui donne un entier n en entrée, termine toujours en temps fini et calcule f(n) comme sortie (peu importent les manières dont n et f(n) sont codés sur la bande de la machine de Turing tant que c'est raisonnable), sachant que la machine dispose de l'accès à un oracle qui peut calculer g(m) pour n'importe quel m donné. (Voici un exemple de protocole d'interrogation de l'oracle : la machine écrit m sur un ruban dédié, entre dans un état spécial interrogation de l'oracle, l'oracle remplace m par g(m) et place la machine dans l'état réponse de l'oracle ; mais les détails sont peu importants tant qu'on parle de calculabilité.) La machine peut interroger l'oracle autant de fois qu'elle le souhaite (y compris pas du tout, mais ça ne changerait d'ailleurs rien si on imposait d'appeler l'oracle puisqu'on peut ignorer sa réponse), et elle l'interroge sur les valeurs qu'elle veut et fait ce qu'elle veut des réponses : la réponse de l'oracle pour une valeur m est toujours exactement g(m), et c'est tout. (Le temps d'interrogation de l'oracle est une étape de calcul, mais ceci est peu important puisqu'on parle de calculabilité et pas de complexité.)

En particulier, toutes les fonctions calculables (c'est-à-dire : sans oracle) sont réductibles à n'importe quelle fonction, tout simplement en utilisant un programme qui ne fait aucun appel à l'oracle (en particulier, elles sont réductibles les unes aux autres, ou par exemple à la fonction constante égale à zéro).

J'insiste bien (parce que c'est ce qui va changer dans la suite) sur le fait que cette réduction de Turing « ordinaire » concerne des fonctions totales. Notamment, l'algorithme réputé calculer f en ayant g pour oracle est censé terminer pour toute valeur n qu'on lui fournit en entrée (du moins tant que n est une représentation légitime d'un entier naturel, et la valeur calculée doit aussi en être une ; mais là non plus, ces subtilités ne changent essentiellement rien). Je réitère aussi le fait que la consultation de l'oracle n'est pas limitée (ou payante) : l'algorithme a le droit de s'en servir aussi souvent qu'il le veut.

La réduction de Turing (ordinaire, mais ça restera vrai pour les généralisations que je vais introduire après) ≼T forme ce qu'on appelle un préordre (relation réflexive et transitive) sur l'ensemble des fonctions ℕ→ℕ, c'est-à-dire que :

  • d'une part, f ≼T f : toute fonction f est Turing-réductible à elle-même (c'est évident) ; et
  • d'autre part, f ≼T g et g ≼T h impliquent f ≼T h : si f est Turing-réductible à g et que g est Turing-réductible à h, alors f est Turing-réductible à h (c'est assez facile à voir : si je sais calculer f en utilisant g et que je sais calculer g en utilisant h, alors pour calculer f en utilisant h je vais utiliser l'algorithme qui me permet f au moyen de g et, à chaque fois que cet algorithme fait appel à l'oracle, j'utilise le programme qui me permet g au moyen de h à la place, en utilisant l'oracle donnant h comme boîte noire).

Ce qui manque à une relation de « préordre » pour être un ordre, c'est l'antisymétrie, et c'est justement ce qui justifie la définition suivante.

On dit que f et g sont Turing-équivalentes ou de même degré de Turing quand chacune est réductible à l'autre (i.e., on peut calculer f en ayant un oracle qui donne g, et réciproquement) : c'est-à-dire qu'on note (disons) f ≡T g lorsque f ≼T g et g ≼T f. Ceci est une relation d'équivalence (c'est la notion de relation d'équivalence associée à un préordre) : les classes d'équivalence sont appelées les degrés de Turing. Autrement dit, le degré de Turing [f]T de f est l'ensemble {g:ℕ→ℕ : g ≡T f} de toutes les fonctions ℕ→ℕ qui sont Turing-équivalentes à f, et notamment, elles sont toutes Turing-réductibles les unes aux autres. C'est-à-dire que deux fonctions sont Turing-équivalentes exactement quand elles ont le même degré de Turing.

Intuitivement, un degré de Turing est la mesure de la puissance d'un oracle. On peut aussi considérer que c'est une forme d'« impossibilité à calculer » la fonction ou bien de « quantité d'information » (totale) contenue dans la fonction f (mais ce n'est pas exactement la même façon de la mesurer que, disons, la complexité de Kolmogorov, pour ceux qui savent ce que c'est que ça : il y a des rapports, bien sûr, mais disons très sommairement que le degré de Turing est une mesure plus grossière que la complexité de Kolmogorov ; comme ce n'est pas mon propos ici, je ne vais pas en dire plus).

Le « préordre » de la réduction de Turing devient un vrai ordre (partiel) sur les degrés de Turing : on dit qu'un degré de Turing f est inférieur ou égal à un degré de Turing g, et on note fg, lorsque une (ou, ce qui revient au même, toute) fonction du degré f est Turing-réductible à une (ou, ce qui revient au même, toute) fonction du degré g. (Autrement dit, [f]T ≤ [g]T signifie par définition exactement la même chose que f ≼T g.)

Parmi les degrés de Turing, il en est un plus petit, qu'on note 0, c'est celui des fonctions calculables (c'est notamment celui de la fonction constante égale à 0, c'est-à-dire un oracle qui ne répond rien d'intéressant, et on peut voir ça comme une raison de cette notation ; si on préfère, c'est la puissance des oracles qui n'ont aucun intérêt comme oracles parce qu'on peut les calculer directement sans oracle).

Le problème de l'arrêt, et le saut de Turing

Un autre degré de Turing particulièrement intéressant est celui noté 0′ : c'est le degré du problème de l'arrêt. Le problème de l'arrêt est la fonction qui, sur le codage ⟨e,n⟩ d'un couple d'entiers naturels, vaut 1 si la valeur de la e-ième fonction calculable partielle en n est définie (notation : φe(n)↓), et 0 sinon, i.e., le problème de l'arrêt vaut 1 si l'algorithme codé par l'entier e termine quand on lui fournit n en entrée, et 0 s'il ne termine pas. (Bref, le problème de l'arrêt consiste à savoir si un algorithme donné s'arrête sur une entrée donnée ; ou, considéré comme un oracle, il permet justement de répondre à cette question.) Le problème de l'arrêt est notoirement non calculable, c'est-à-dire que 0′ > 0 dans l'ordre qu'on vient de définir sur les degrés de Turing. (Je vais dire dans un instant qu'il y a des choses strictement entre 0 et 0′, il y en a même plein.)

☞ Note en passant : Le fait de définir le problème de l'arrêt comme l'ensemble des ⟨e,n⟩, codant à la fois une machine de Turing et une entrée à celle-ci, tels que φe(n)↓, est sans importance : on pourrait se contenter de e et prendre, disons, n=0 (ou n=e, ce qui est peut-être moins intuitif mais c'est essentiellement ce que fait la démonstration), i.e., définir le problème de l'arrêt comme l'ensemble des e tels que φe(0)↓ ou φe(e)↓, cela ne changerait rien du tout. La même chose vaudra relativement à un oracle, et pour la machine universelle dont je parlerai plus bas, et toutes sortes de variations sur le même thème : à chaque fois, le fait de prendre des (codages de) couples ⟨e,n⟩ est une sorte de tradition plus qu'autre chose (même si ça peut simplifier certains énoncés). Néanmoins, comme cette convention est fréquente, il peut être intéressant d'avoir un nom pour désigner, dans une phrase, (le codage d')un couple formé d'une machine de Turing (éventuellement avec oracle) et d'une entrée à fournir à celle-ci : sans en faire une définition formelle ou une convention rigide, je vais avoir tendance à appeler ça un plan (d'exécution) dans ce qui suit.

Plus généralement, on peut définir une version « relative » du problème de l'arrêt, c'est-à-dire le problème de l'arrêt pour les machines disposant de g comme oracle (autrement dit, la fonction qui, sur le codage ⟨e,n⟩ d'un couple d'entiers naturels, vaut 1 ou 0 selon que la machine de Turing codée par l'entier e termine sur l'entrée n lorsqu'elle a accès à g comme oracle ; notation : φeg(n)↓). Il n'est pas difficile de vérifier que ce problème de l'arrêt relativisé permet de recalculer g, et aussi que si on remplace g par une fonction qui lui est Turing-équivalente, cela fournit un problème de l'arrêt Turing-équivalent : ceci définit une opération sur les degrés de Turing qu'on appelle le saut de Turing : le saut de Turing d'un degré d, noté d′, c'est le degré de Turing du problème de l'arrêt pour les machines disposant comme oracle d'une fonction de d (fixée, peu importe laquelle). De même qu'un machine de Turing ne peut pas calculer le problème de l'arrêt, une machine de Turing ayant g pour oracle ne peut pas calculer le problème de l'arrêt des machines de Turing ayant g pour oracle, ce qui dit que d′ > d pour tout degré de Turing d.

Je peux peut-être mentionner brièvement au passage le concept de degré de Turing bas, qui est un degré d ayant le même saut de Turing que 0, c'est-à-dire d′=0′, ce qui n'implique pas d=0 comme on pourrait peut-être le croire, en revanche, ça implique évidemment que d<0′. (Symétriquement, il y a le concept de degré haut, qui est un degré d0′ tel que d′=0′′, ce qui n'implique pas d=0′ comme on pourrait le croire.) Un théorème important de la calculabilité est le théorème de la base basse de Jockusch et Soare, qui affirme que tout sous-arbre infini et calculable de l'arbre binaire infini (représenté, disons, comme l'ensemble {0,1}* des mots finis sur l'alphabet {0,1} et qu'on peut coder par des entiers naturels) a une branche basse, c'est-à-dire une branche infinie qui, considérée comme un ensemble d'entiers naturels, a un degré de Turing bas.

Toutes ces notions sont classiques. Il y a énormément de questions qu'on peut ensuite se poser sur les degrés de Turing, et énormément de résultats à leur sujet. Je vais mentionner quelques faits (peut-être un peu rapidement) juste pour donner une idée, mais ce n'est pas vraiment mon propos : on peut lire ce qui suit en diagonale.

Degrés de Turing calculablement énumérables

Il faut sans doute que je mentionne au moins la notion de degré de Turing calculablement énumérable (même si ce n'est pas vraiment de ça que je vais parler dans la suite, donc ceci est une sorte de digression).

Rappelons qu'un ensemble D⊆ℕ d'entiers naturels est dit semi-décidable ou calculablement énumérable (c.e.) lorsqu'il existe une machine de Turing qui, donné un élément de D, termine en temps fini et répond oui et qui, donné un élément qui n'est pas dans D, ne termine pas (elle a aussi le droit de terminer et répondre non, ça ne change rien) : on dit parfois qu'une telle machine semi-décide D ; il revient au même de demander que D soit l'image d'une fonction ℕ→ℕ. calculable (du moins pour D≠∅ ; ou disons plutôt que D soit l'ensemble des éléments >−1 de l'image d'une fonction calculable ℕ → ℕ∪{−1}). À titre d'exemple (fondamental !), le problème de l'arrêt est calculablement énumérable mais non calculable. (Voir mes notes à Télécom liées ci-dessus pour ces différentes affirmations.)

On dit qu'un degré de Turing est calculablement énumérable ou c.e. (ou semi-décidable ou semi-calculable) lorsqu'il est le degré de Turing d'(au moins) une fonction indicatrice d'un ensemble calculablement énumérable ; on notera bien qu'un degré de Turing calculablement énumérable contient plein de fonctions qui ne sont pas de cette forme, on demande juste qu'il y en ait une dans le tas.

Un degré de Turing c.e. est forcément compris au sens large entre 0 (le degré des fonctions calculables) et 0′ (le degré du problème de l'arrêt) : en effet, il s'agit simplement de montrer que si D est calculablement énumérable, alors la fonction indicatrice de D peut être calculable en ayant accès à un oracle du problème de l'arrêt, mais c'est facile car, donné une machine qui « semi-décide » D, l'oracle de l'arrêt permet justement de savoir si cette machine s'arrête, donc si un élément proposé est dans D. Bref, 0 est le plus petit degré de Turing c.e. et 0′ est le plus grand. Mais il ne faut pas s'imaginer que tout degré de Turing entre 0 et 0′ est forcément c.e.

Un problème qui a longtemps été ouvert (problème de Post) a été celui de savoir s'il existe d'autres degrés de Turing c.e. que 0 et 0′, i.e., strictement intermédiaires entre les deux. Autrement dit, des ensembles calculablement énumérables qui ne soient pas calculables, mais auxquels on ne puisse pas non plus ramener le problème de l'arrêt. La réponse est positive (c'est le théorème de Friedberg-Mučnik en réponse au problème de Post), et la démonstration est d'ailleurs explicite (on construit explicitement un programme qui énumère un certain ensemble D auquel on ne puisse pas décider algorithmiquement l'appartenance, mais qui ne permet pas pour autant de décider le problème de l'arrêt), mais cette construction fait appel à une technique (la méthode de priorité) qui dépend fortement des détails de la machine de Turing, et on ignore toujours s'il existe des problèmes de décision « naturels » qui sont ainsi de difficulté strictement intermédiaire entre 0 et 0′ (car dans la pratique, à chaque fois qu'on montre qu'un problème est algorithmiquement indécidable, c'est en lui ramenant le problème de l'arrêt).

Évocation de quelques questions sur les degrés de Turing

Il y a énormément de questions subtiles (et que j'ai d'ailleurs énormément de mal à retenir) sur les degrés de Turing et leur ordre, ou sur les degrés de Turing c.e. et leur ordre. Les deux théories (celle des degrés de Turing en général et celles des degrés de Turing c.e.) sont d'ailleurs tout à fait différentes.

À titre d'exemple, il existe des degrés de Turing non-calculables minimaux, c'est-à-dire tels que 0 < d mais qu'il n'y ait pas de degré strictement intermédiaire entre les deux ; en revanche, il n'y a pas de tel degré qui soit c.e. : au contraire, entre deux degrés de Turing c.e. comparables il y en a toujours un troisième qui soit strictement intermédiaire entre eux. Mais je ne veux pas parler de toutes ces choses.

On peut aussi chercher à itérer le saut de Turing à travers les ordinaux : c'est-à-dire qu'après les degrés 0, 0′, 0′′, 0′′′, etc., on peut construire un degré 0(ω) (c'est, par exemple, le degré de Turing de l'oracle qui dit si un énoncé arithmétique quelconque est vrai ou faux), et plus généralement, des degrés 0(α) pour « plein » d'ordinaux α (au moins jusqu'à l'ordinal de Church-Kleene, voire l'ordinal de l'analyse ramifiée, voire le ω₁ constructible, voyez ce billet passé poru des explications de ces termes), mais il y a plein de subtilités (par exemple, 0(ω) n'est pas la borne supérieure de 0, 0′, 0′′0(i) pour i∈ℕ ; et en outre, 0(α) va dépendre non seulement de l'ordinal α mais de sa notation ordinale, ce qui est la raison pour laquelle on ne peut pas itérer transfiniment sans se poser de question). Je ne veux pas non plus parler de toutes ces choses, je les évoque juste pour dire que ce sont des questions abondamment étudiées.

Bornes sup et inf binaires sur les degrés de Turing

Mentionnons quand même un point important : l'existence d'une borne supérieure et l'inexistence (en général) d'une borne inférieur pour deux degrés de Turing.

Donnés deux degrés de Turing a et b il y a un degré de Turing noté ab (ou parfois ab) qui est leur borne supérieure, c'est-à-dire le plus petit degré de Turing supérieur ou égal à a et b.

C'est même assez intuitif : si a est représenté par une fonction a (rappelons que ça signifie notamment qu'une fonction est de degré ≤a exactement quand on peut la calculer avec a pour oracle) et b par une fonction b, alors ab devrait correspondre aux fonctions calculables avec accès à la fois à a et b pour oracles. Mais comment réaliser cette notion d'avoir accès à la fois à a et b pour oracles ? C'est facile : il suffit de construire un oracle c qu'on interroge en demandant soit je voudrais la réponse de a sur la question suivante soit je voudrais la réponse de b sur la question suivante : précisément, on pose c(⟨0,m⟩) = a(m) et c(⟨1,m⟩) = b(m) (et pour toute autre valeur, c vaut 0, disons), le 0 en premier argument servant à dire je souhaite interroger a et le 1 en premier argument servant à dire je souhaite interroger b. (Il revient au même, si on préfère, et c'est peut-être plus courant, d'alterner valeurs de a et de b sur les entiers pairs et impairs, c'est-à-dire de poser c(2m)=a(m) et c(2m+1)=b(m) : la seule chose qui importe est qu'en interrogeant c on puisse, dans les faits, interroger a et b comme on le souhaite et que les éventuelles autres valeurs soient sans objet.) Alors cette fonction c (parfois notée ab) sert à encoder l'information de a et b à la fois, et ab est précisément le degré de Turing de la fonction c ainsi construite (notamment, il ne dépend pas du choix de a et b dans a et b respectivement), et c'est bien la borne supérieure au sens de l'ordre sur les degrés de Turing.

Intuitivement, le paragraphe précédent signifie qu'on a une façon naturelle et assez évidente de combiner la puissance de deux oracles en un seul, leur borne supérieure.

En revanche, il n'y a pas de façon de former la borne inférieure de deux degrés de Turing en général : ce degré de Turing ab qui n'existe pas en général (mais il existe parfois) serait tel que les fonctions de degré ≤ab sont exactement celles qui sont calculables avec un oracle dans a et avec un oracle dans b : le problème est qu'il n'y a pas moyen de faire une fonction qui reflète les choses qu'on peut calculer au moyen de a et aussi (peut-être différemment) au moyen de b, une sorte d'information commune, comme on l'a fait pour fabriquer ab ci-dessus en réunissant l'information qu'elles apportent. On peut considérer que c'est là une limitation des degrés de Turing, et le signe qu'il peut être intéressant de les généraliser.

Notons aussi qu'il n'y a pas non plus, en général, de borne supérieure d'une infinité de degrés de Turing : même pour une suite a0, a1, a2… de degrés de Turing, la construction qui semble pourtant évidente c(⟨i,m⟩)=ai(m) ne fournit pas une borne supérieure, et d'ailleurs ne fournit même pas un degré de Turing bien-défini, car elle dépend de la manière dont les ai ont été choisis et indexés dans les degrés ai. (Ce qui n'empêche que cette construction a un intérêt : par exemple, 0(ω) est effectivement défini de la sorte à partir des degrés 0, 0′, 0′′, 0′′′, etc.)

Digression : les degrés de Mučnik

Une possible généralisation des degrés de Turing est celle apportée par les degrés de Mučnik, que j'évoque brièvement même si ce n'est pas le sujet de ce billet. On peut complètement ignorer cette section.

Un degré de Mučnik peut être défini (même si ce n'est pas la définition la plus standard) comme un cône supérieur pour la réductibilité de Turing, c'est-à-dire un ensemble de fonctions ℕ→ℕ tel que si f est dans l'ensemble et que f est Turing-réductible à g alors g est aussi dans l'ensemble (si fD et f ≼T g alors gD). Ou, ce qui revient au même, un cône supérieur de degrés de Turing, i.e., un ensemble de degrés de Turing qui, quand il contient un degré f, contient aussi tout degré gf.

Les degrés de Mučnik sont ordonnés par l'inclusion réciproque, c'est-à-dire que plus il y a de fonctions dedans plus le degré de Mučnik est petit (D₁≤D₂ signifie D₁⊇D₂), ceci pour que l'ordre ‘≤’ continue à vouloir dire a moins de puissance/information que : intuitivement, il faut imaginer que le degré de Mučnik représente la puissance d'une fonction avec tout ce qui permet de calculer cette fonction.

Tout degré de Turing d définit un degré de Mučnik, à savoir son cône supérieur : ce sont les degrés ≥d ou, si on préfère la présentation en termes de fonctions, les fonctions qui permettent de calculer une — et donc toute — fonction de d ; l'ordre et la borne supérieure des degrés de Turing sont préservés quand on les voit comme des degrés de Mučnik.

L'avantage des degrés de Mučnik par rapport à ceux de Turing est que, cette fois, deux degrés ont une borne supérieure et une borne inférieure : elles sont données par l'intersection et la réunion respectivement ; dans les degrés de Mučnik, on a même les bornes inférieures et supérieures quelconques, données par les intersections et réunions respectives.

En fait, c'est là une construction standard qui fabrique un treillis complet complètement distributif à partir d'un demi-treillis (cf. le lemme C.1.1.3 du livre de Johnstone, Sketches of an Elephant pour des détails). Mais peut-être justement parce que cette construction prendre des cônes est trop facile et formelle, on peut douter que les degrés de Mučnik capturent vraiment les subtilités de la notion d'oracle.

T1 : Degrés de Turing de fonctions partielles ℕ⇢ℕ

Réduction des fonctions partielles

Comme expliqué dans l'introduction, je veux maintenant évoquer différentes généralisations de la notion de réduction de Turing, et d'oracle au sens de celle-ci. Plus exactement, on va généraliser les fonctions auxquelles on applique la réduction de Turing, tout en cherchant à garder autant que possible la même notion de réduction. La première généralisation, assez évidente, consiste à autoriser les fonctions partielles. (Je vais noter ℕ⇢ℕ, avec une flèche en pointillés, pour une fonction partielle de ℕ vers ℕ, c'est-à-dire une fonction définie sur un sous-ensemble de ℕ et à valeurs dans ℕ. Par ailleurs, faute de terminologie standard ou adéquate, je vais appeler degrés T1 les degrés définis ici quand il s'agit de lever une ambiguïté, même s'il peut être légitime de les appeler degrés de Turing des fonctions partielles.)

En fait, il y a plein de notions subtilement différentes qu'on peut imaginer utiliser pour dire qu'une fonction partielle f:ℕ⇢ℕ est calculablement réductible à une autre g:ℕ⇢ℕ : voir cette question MathOverflow où je définis six notions subtilement différentes (notées S, N, W, S*, N* et W*). Mais je vais me contenter ici d'une seule de ces notions, parce que c'est elle qui va se prêter aux généralisations ultérieures que je vais introduire après (dans la terminologie de la question que je viens de lier, la réductibilité T1 est la notion S*, ou sous-réductibilité de Sasso) : je vais juste dire réductible pour simplifier, mais on prendra garde au fait que, comme je viens de le dire, ce n'est pas la seule notion possible, et il est même plausible que ce ne soit pas la plus standard.

L'idée intuitive, quand l'oracle est une fonction partielle g:ℕ⇢ℕ, est qu'il y a des questions interdites : si on interroge l'oracle sur une question interdite, c'est-à-dire qu'on lui demande la valeur g(m) alors que g(m) n'est pas défini, on n'obtient jamais de réponse et le calcul dans son ensemble ne termine pas. De façon encore plus frappante : si on pose une question interdite à l'oracle, alors l'oracle vous tue pour votre impudence. En contrepartie, la fonction f qu'on est censée calculer ne sera elle-même interrogée que sur des valeurs où elle est définie : c'est-à-dire que si f(n) n'est pas définie, on ne place aucune contrainte sur ce que le calcul fera (peu importe s'il ne termine pas, peu importe s'il pose des questions interdites à l'oracle, mais peu importe aussi s'il termine alors que la valeur demandée n'est pas définie), tout ce qu'on demande c'est que f(n) soit calculée correctement quand f(n) est définie. Autrement dit :

Une fonction partielle f:ℕ⇢ℕ est dite réductible (au sens T1 s'il y a besoin de préciser) à une fonction partielle g:ℕ⇢ℕ, ou bien calculable avec g pour oracle lorsqu'il existe une machine de Turing (i.e., un algorithme) qui, quand on lui fournit un entier n en entrée tel que f(n) soit définie, termine toujours en temps fini et calcule f(n) comme sortie, sachant que la machine dispose de l'accès à un oracle qui peut calculer g(m) pour n'importe quel m tel que g(m) soit défini, mais n'a pas le droit d'interroger g(m) sur une valeur non définie. La machine peut interroger l'oracle autant de fois qu'elle le souhaite (y compris pas du tout) tant que les valeurs interrogées sont toutes définies et elle fait ce qu'elle veut des réponses : la réponse de l'oracle pour une valeur m est toujours exactement g(m), et c'est tout.

Je ne sais pas bien quelle terminologie ou quelle notation utiliser. On peut considérer que c'est toujours la réduction de Turing (pour les fonctions totales c'est la même), elle a simplement été généralisée à un ensemble plus grand. Pour faire quand même la différence, mettons que je vais noter f ≼T1 g pour la réductibilité définie au paragraphe précédent.

Pour être bien clair, cette définition fait notamment que toute restriction de g à un domaine de définition plus petit est réductible à g (la réductibilité ≼T1 dont je parle est la composition de la réductibilité de Sasso et de la restriction des fonctions). Symboliquement : si g étend f en tant que fonction partielle, alors en particulier f ≼T1 g. Intuitivement, si vous interdisez bêtement certaines questions, cela rend toujours votre oracle moins puissant.

Comme précédemment, la notion définit un préordre. Lorsque f et g sont totales, évidemment, il s'agit du même préordre qu'on a déjà défini (on l'a étendu à un ensemble de fonctions plus large, mais pour f et g totales, les relations f ≼T g et f ≼T1 g disent exactement la même chose). Comme précédemment, on peut définir une relation d'équivalence f ≡T1 g lorsque f ≼T1 g et g ≼T1 f (et je répète que, lorsque f et g sont totales, les relations f ≡T g et f ≡T1 g sont équivalentes).

Les classes d'équivalence pour cette relation ≡T1 peuvent s'appeler degrés de Turing des fonctions partielles ou quelque chose de ce genre (mais attention, j'ai signalé plus haut en petits caractères que ce n'est pas la seule notion qui peut être appelée ainsi) : disons degrés T1 si j'ai besoin d'un terme.

Vu que f ≡T g et f ≡T1 g sont équivalentes lorsque f et g sont totales, on peut identifier un degré de Turing ordinaire (i.e., une classe d'équivalence pour ‘≡T’) avec un degré T1 en identifiant la classe d'équivalence [f]T d'une fonction f:ℕ→ℕ totale pour l'équivalence de Turing ordinaire ‘≡T’ avec la classe d'équivalence [f]T1 de la même fonction pour ‘≡T1’ (même si cette dernière classe d'équivalence est, en fait, plus grande et contient toujours des fonctions partielles). Cette injection [f]T ↦ [f]T1 permet de considérer, et on le fera toujours, les degrés de Turing ordinaires comme un sous-ensemble des degrés T1. Précisément, les degrés de Turing ordinaires s'identifient au sous-ensemble des degrés T1 qui contiennent (au moins) une fonction totale. C'est un sous-ensemble strict (i.e., il y a des degrés T1 qui ne contiennent aucune fonction totale), même si ce n'est pas tout à fait évident à montrer.

Bornes sup et inf binaires sur les degrés T1 ; la construction ‘⌘’

On dispose toujours d'une opération ab sur deux degrés au sens définis ici (deux degrés T1) : l'idée intuitive est la même (on autorise à interroger librement les deux oracles). Formellement, si a et b sont deux fonctions partielles ℕ⇢ℕ, on peut définir une fonction partielle c:ℕ⇢ℕ par c(⟨0,m⟩) = a(m) lorsque celle-ci est définie et c(⟨1,m⟩) = b(m) lorsque celle-ci est définie, et toute autre valeur indéfinie. Il est facile de voir, comme pour les degrés de Turing ordinaires, que le degré de c ne dépend que des degrés a et b de a et b respectivement, et que ceci constitue la borne supérieure de a et b, et aussi qu'elle coïncide avec celle des degrés de Turing ordinaires lorsque a et b sont des degrés de Turing ordinaires (i.e., représentables par a et b totales). Bref, tout se passe comme avant.

Mais une différence importante, et peut-être surprenante, avec les degrés de Turing ordinaires, est que cette fois on a aussi une borne inférieure de deux degrés (T1, donc) quelconques : pour deux degrés a et b on peut définir un degré ab tel que x≤(ab) si et seulement si xa et cb. Ou, ce qui revient au même, données a et b sont deux fonctions partielles ℕ⇢ℕ, on peut définir une fonction partielle c:ℕ⇢ℕ telle que les fonctions réductibles à c soient exactement celles réductibles à la fois à a et à b. Pourquoi peut-on faire cela alors qu'on ne le peut pas (en général) pour des fonctions totales ? Ça vaut la peine d'y réfléchir un moment. Avant d'y répondre, il faut que je donne l'idée-clé qui fait que les fonctions partielles se comportent mieux que les fonctions totales ici :

Rappelons ce qu'est la machine de Turing universelle : c'est une fonction qui, sur le codage ⟨e,n⟩ d'un couple d'entiers naturels, a la même valeur (généralement notée φe(n)) que la e-ième fonction calculable partielle en n si elle est définie (et sinon, n'est pas définie) ; autrement dit, c'est un algorithme qui prend en entrée un autre algorithme e et une entrée n à fournir à cet algorithme (appelons ça un plan d'exécution), et qui exécute le plan en question et renvoie la même valeur si l'algorithme termine lui-même (et ne termine pas sinon). Ça n'a rien de magique : il s'agit juste de dire qu'on peut exécuter un algorithme fourni en entrée, i.e., on peut écrire, par exemple, un interpréteur de machine de Turing en machine de Turing.

La machine de Turing universelle fonctionne aussi bien avec oracle que sans oracle : donné un oracle g (fonction totale ou même partielle), on peut considérer la machine de Turing universelle avec cet oracle : donné le codage ⟨e,n⟩ d'un couple d'entiers naturels, elle fait la même chose que la machine de Turing codée par l'entier e sur l'entrée n lorsqu'elle a accès à g comme oracle. Ceci définit une nouvelle fonction partielle qu'on pourrait appeler, euh, disons, ⌘g : ℕ⇢ℕ (formellement, ⌘g est la fonction ⟨e,n⟩ ↦ φeg(n)). Intuitivement, il faut imaginer ça comme un « oracle g programmable » : au lieu de répondre bêtement à une question comme le fait g, cette fonction ⌘g prend en entrée tout un plan d'interrogation de g (c'est le couple ⟨e,n⟩), l'exécute et renvoie le résultat. Remarquez que la fonction ⌘g est partielle même si g était totale, parce qu'il y a toujours des machines de Turing qui ne terminent pas.

Pour qu'il n'y ait pas de doute que les définitions sont cohérentes entre elles, la réduction f ≼T1 g définie au-dessus signifie exactement, et par définition, qu'il existe e∈ℕ tel que pour tout n du domaine de définition de f on ait ⌘g(⟨e,n⟩) défini et égal à f(n).

Bref, ⌘g doit se comprendre intuitivement comme une version de l'oracle g avec programmation intégrée, une version plus flexible de celui-ci.

Néanmoins, au niveau calculabilité, ce ⌘g vaut exactement autant que g : d'une part il est évident que g ≼T1 ⌘g (pour calculer g(m) il suffit de construire le programme qui appelle l'oracle sur son argument, et de l'exécuter), mais d'autre part il est aussi vrai que ⌘g ≼T1 g justement parce qu'on peut réaliser une machine universelle. Donc ⌘g a le même degré (T1) que g. (Ceci ne serait plus vrai si nos oracles étaient limités à un unique appel, parce qu'un unique appel à ⌘g permet de faire n'importe que plan d'appels à g ; donc il est crucial ici que je parle depuis le début de réduction de Turing et pas de « réduction de Weihrauch » : pour la réduction de Turing, g ou ⌘g sont équivalentes.) Néanmoins, la construction g ↦ ⌘g a un intérêt parce qu'elle remplace une fonction g quelconque par une fonction qui se comporte de façon bien plus « robuste ». Et notamment, c'est ça qui nous permet de construire ab.

Justement, supposons données a et b sont deux fonctions partielles ℕ⇢ℕ, et on veut définir une fonction partielle c:ℕ⇢ℕ telle que les fonctions réductibles à c soient exactement celles réductibles à la fois à a et à b. On va la définir comme ceci : c(⟨m₁,m₂⟩) est égale à la valeur commune de ⌘a(m₁) et de ⌘b(m₂) si ces deux valeurs sont toutes les deux définies et sont égales, et n'est pas définie sinon. Pour dire les choses autrement, pour interroger l'oracle c, vous devez fournir un plan m₁=⟨e₁,n₁⟩ d'interrogation de a et un plan m₂=⟨e₂,n₂⟩ d'interrogation de b, et si ces plans calculent une même valeur bien définie, alors, et seulement alors, c vous renvoie cette valeur.

Il n'est pas difficile de voir que cette construction donne bien la borne inférieure recherchée : d'une part on a bien c ≼T1 a (il suffit d'ignorer le second argument et de passer le premier à ⌘a ; je rappelle que ma définition de la réduction T1 autorise à calculer plus de valeurs que ce qui était demandé), et bien sûr, symétriquement, c ≼T1 b ; d'autre part, si on a f ≼T1 a et f ≼T1 b, c'est qu'il existe un programme permettant de calculer f(n) en fonction de n donné l'accès à un oracle qui renvoie a, et symétriquement pour b : si on fournit ces deux programmes à c (avec la même entrée n), il calculera f(n) puisque, justement, nos deux programmes calculent la même valeur.

Voici donc les degrés de Turing ordinaires (ceux des fonctions totales ℕ→ℕ) inclus dans l'ensemble plus gros des degrés T1 (degrés « de Turing » des fonctions partielles ℕ⇢ℕ) en préservant l'ordre et la borne supérieure binaire mais en ajoutant les bornes inférieures. Il y a sans doute beaucoup plus de choses intéressantes à dire sur cet ensemble des degrés T1, mais je veux passer à la généralisation suivante.

T2 : Degrés de Turing de fonctions non-déterministes (partielles multivaluées)

Réduction des fonctions non-déterministes

La généralisation suivante consiste à ce que les fonctions (celle qu'on cherche à calculer, et les oracles auxquels on a accès) soient non-déterministes : elles renvoient possiblement plusieurs valeurs. (Faute de terminologie standard ou adéquate, je vais parler ici de degrés T2.)

Autrement dit, on s'intéresse maintenant à des fonctions ℕ⇢𝒫(ℕ), c'est-à-dire que non seulement g(m) n'est pas forcément définie, mais elle renvoie un ensemble de valeurs (il sera utile de distinguer le cas où g(m) est non défini et le cas où g(m) est défini mais vide, c'est-à-dire ne renvoie aucune valeur : même si on peut vouloir interdire cette dernière situation, le fait de l'autoriser semble plus satisfaisant).

L'idée intuitive est que g(m) est l'ensemble des réponses à votre question, i.e., des valeurs que l'oracle pourra vous renvoyer : quand vous faites appel à l'oracle, il vous renverra une valeur de l'ensemble, mais vous ne contrôlez pas laquelle (et il faut plus ou moins s'imaginer qu'il va renvoyer celle qui vous arrange le moins ; ou en tout cas, on doit se vous préparer à cette possibilité, c'est-à-dire que quand on fait un calcul utilisant l'oracle g, le calcul doit fonctionner quelle que soit la valeur retournée à chaque étape). Symétriquement, quand on vous demande de calculer f et que f(n) a plusieurs éléments, vous pouvez renvoyer celui qui vous arrange, votre but est d'en produire un (et celui que vous produisez peut dépendre de ce que l'oracle vous aura donné quand vous avez fait appel à lui).

Et si un ensemble est vide, alors ? Si la fonction f que vous devez calculer est (définie et) vide pour une certaine valeur n, alors vous n'avez aucun moyen d'y arriver (sauf de mettre en échec l'oracle comme je vais le dire), donc vous ne pouvez pas la calculer (sauf…). Mais symétriquement, quand vous appelez l'oracle sur une valeur m (pour laquelle g(m) est défini), il doit choisir une des valeurs dans l'ensemble g(m) : donc si g(m)=∅, vous venez de mettre l'oracle en échec, et vous avez gagné la partie (il vous donne les clés du royaume des cieux, quelque chose comme ça), quelle que soit la fonction que vous aviez comme mission de calculer (même si elle comporte elle-même des ensembles vides).

Mon explication intuitive peut sembler assez vaseuse, donc voici une version précisément formalisée :

Une fonction partielle multivaluée, c'est-à-dire une fonction f:ℕ⇢𝒫(ℕ), est dite réductible (au sens T2 s'il y a besoin de préciser) à une autre telle fonction g:ℕ⇢𝒫(ℕ), ou bien calculable avec g pour oracle, et on notera ça f ≼T2 g, lorsqu'il existe une machine de Turing (i.e., un algorithme) qui, quand on lui fournit un entier n en entrée tel que f(n) soit définie, termine toujours en temps fini et calcule un certain élément de f(n) comme sortie, sachant que la machine dispose de l'accès à un oracle qu'on peut interroger pour n'importe quel m tel que g(m) soit défini (mais on n'a pas le droit d'interroger g(m) sur une valeur non définie) et qui, dans ce cas, renvoie un élément quelconque de g(m). La machine peut interroger l'oracle autant de fois qu'elle le souhaite (y compris pas du tout) tant que les valeurs interrogées sont toutes définies et elle fait ce qu'elle veut des réponses : la réponse de l'oracle pour une valeur m est un élément quelconque de g(m). Le calcul est valable quand chaque interrogation de l'oracle porte sur une valeur pour laquelle g(m) est définie, et que, quel que soit l'élément de g(m) que l'oracle répond à chaque valeur pour laquelle on l'interroge, l'algorithme termine et renvoie un élément de f(n) (qui a le droit d'être différent selon les choix effectués par l'oracle).

Pour être parfaitement clair sur les cas « non défini » et « vide » :

  • peu importe ce que fait l'algorithme sur l'entrée n lorsque f(n) n'est pas défini, ces valeurs ne seront pas consultées ni interrogées,
  • l'algorithme n'a pas le droit d'interroger g(m) si g(m) n'est pas défini (le faire cause son plantage immédiat, i.e., c'est une forme de non-terminaison comme une boucle infinie),
  • si g(m)=∅, alors l'algorithme est considéré comme ayant gagné son calcul (quel que soit la fonction à calculer, arriver à mettre en défaut l'oracle est une façon d'y arriver),
  • si f(n)=∅, alors il n'y a pas moyen de mener le calcul (autrement qu'en mettant en défaut l'oracle, comme au point précédent).

On voit à cette description que la relation entre l'algorithme et l'oracle commence à devenir adversariale, et voici une façon de le redire :

Chercher une réduction de f à g revient à faire gagner Arthur à un jeu à deux joueurs, dont les joueurs s'appellent Arthur (l'algorithme) et Merlin (l'oracle) :

  • au premier tour, Merlin (qui commence) joue un élément n∈ℕ ; Merlin perd dès le premier tour (i.e., Arthur gagne) si f(n) n'est pas défini ;
  • à chaque tour suivant, Arthur a deux types de coups possibles : il peut soit « déclarer la fin du calcul » avec une valeur k∈ℕ, soit « lancer une interrogation de l'oracle » avec une valeur m∈ℕ ;
  • lorsque Arthur déclare la fin du calcul avec une valeur k, le jeu prend fin ; Arthur gagne si k ∈ f(n), sinon Merlin gagne ;
  • lorsque Arthur lance une interrogation de l'oracle avec une valeur m, Merlin joue ensuite un élément ∈ℕ ; Merlin perd à ce stade (i.e., Arthur gagne) si g(m), sinon le jeu continue (avec un coup d'Arthur).

Le jeu prend fin dès qu'un des joueurs a gagné, c'est-à-dire soit lorsque Arthur a déclaré la fin du calcul soit lorsqu'un des joueurs a violé une contrainte sur le coup. Si le jeu dure indéfiniment (Arthur ne déclare jamais la fin du calcul), alors Arthur a perdu (i.e., Merlin a gagné).

Par ailleurs, Arthur (simple mortel !) joue conformément à un algorithme, c'est-à-dire qu'il suit une stratégie qui calcule le coup qu'il fait (soit la valeur k sur laquelle il déclare la fin du calcul, soit la valeur m sur laquelle il lance une interrogation) en fonction de tous les coups joués précédemment, tandis que Merlin joue arbitrairement. Plus exactement, ce que je veux dire, c'est que la définition de f ≼T2 g (f est réductible à g) pour deux fonctions f et g partielles multivaluées (i.e., ℕ⇢𝒫(ℕ)) est : il existe un algorithme (prenant en entrée les coups joués précédemment et renvoyant le coup d'Arthur) constituant une stratégie gagnante d'Arthur, contre n'importe quelle stratégie de Merlin, dans le jeu qui vient d'être décrit. La stratégie de Merlin, elle, n'a pas à être calculable : l'intérêt de la réduction réside justement dans le fait qu'une stratégie calculable d'Arthur gagne contre Merlin quoi que fasse Merlin.

Comme dans le cas T1 (celui des fonctions partielles simplement valuées), toute restriction de g à un domaine de définition plus petit est réductible à g. C'est aussi, maintenant, le cas de toute fonction qui élargit l'ensemble g(m) pour tout m.

De nouveau, la notion définit un préordre. Lorsque f et g sont simplement valuées (chaque f(n) qui est défini est un singleton, et pareil pour g, et en identifiant ça à des fonctions ℕ⇢ℕ), il s'agit du même préordre T1 qu'on a déjà défini (et qui généralise lui-même la réduction de Turing ordinaire). De nouveau, on peut définir une relation d'équivalence f ≡T2 g lorsque f ≼T2 g et g ≼T2 f (et je répète que, lorsque f et g sont simplement valuées, les relations f ≡T1 g et f ≡T2 g sont équivalentes, et en particulier si f et g sont totales et simplement valuées c'est exactement la réduction de Turing ordinaire).

On a donc de nouveau un ensemble de degrés, qu'on peut appeler les degrés T2, ou degrés de Turing des fonctions partielles multivaluées.

Comme précédemment, vu que f ≡T1 g et f ≡T2 g sont équivalentes lorsque f et g sont simplement valuées, on obtient une injection [f]T1 ↦ [f]T2 des degrés T1 dans les degrés T2 en envoyant la classe d'équivalence pour ‘≡T1’ de f vers la classe d'équivalence pour ‘≡T2’ de cette même fonction. Ceci permet de considérer, et on le fera toujours, les degrés T1 (et a fortiori les degrés de Turing ordinaires) et comme un sous-ensemble des degrés T2. Précisément, les degrés T1 s'identifient au sous-ensemble des degrés T2 qui contiennent (au moins) une fonction simplement valuée. C'est un sous-ensemble strict pour la raison évidente qui va être dite dans deux paragraphes.

Comme précédemment, ces degrés ont des bornes supérieures et inférieures binaires : et elles sont données, mutatis mutandis par les mêmes constructions que pour les degrés T1… enfin, si le mutare mutanda est assez évident pour la borne supérieure, il l'est un peu moins pour la borne supérieure qui ne semble pas coïncider avec celle sur les degrés T1, donc je vais en parler un peu plus précisément dans la section suivante, qu'on peut sauter ainsi que celle d'après si on veut passer rapidement aux degrés T3.

Dans les degrés T2, cette fois, il y a un plus grand degré (on pourrait le noter ) : dès que g(m)=∅ pour au moins un entier m, toute fonction f est réductible à g : il suffit d'interroger l'oracle sur la valeur de g(m) (i.e., pour Arthur d'appliquer la stratégie consistant à lancer l'interrogation pour m, à laquelle Merlin ne peut pas répondre). Inversement, les seules fonctions auxquelles se ramènent une telle fonction g sont les fonctions qui vérifient la même propriété, car si Merlin joue m au permier coup, la seule stratégie permettant à Arthur de gagner est de lancer une interrogation à laquelle Merlin ne peut pas répondre. Plus loin, j'appellerai degré omnipotent ce plus grand degré.

Bornes sup et inf binaires sur les degrés T2

Comme pour les degrés de Turing ordinaires et T1, la borne supérieure de deux degrés T2 ne pose pas de problème à définir : données deux fonctions partielles multivaluées a et b, on en définit une qui consiste à permettre à Arthur de choisir s'il veut interroger a ou b : précisément, si a,b : ℕ⇢𝒫(ℕ), on définit simplement c : ℕ⇢𝒫(ℕ) par c(⟨0,m⟩) = a(m) lorsque celle-ci est définie et c(⟨1,m⟩) = b(m) lorsque celle-ci est définie, et toute autre valeur indéfinie. Ceci définit bien la borne supérieure des degrés T2 comme on l'attend, et il n'y a pas de surprise particulière.

La construction étant exactement la même, la borne supérieure binaires de degrés de Turing ordinaires, ou de degrés T1, est toujours la même dans les degrés T2 (i.e., le plongement de ces différents ensembles de degrés préserve l'opération de borne supérieure binaire : on peut noter ab sans avoir à dire dans quel ensemble de degrés on se place).

Pour la borne inférieure, il faut modifier un petit peu la construction qu'on a utilisée pour les degrés T1.

Je rappelle que, pour une fonction g : ℕ⇢ℕ (partielle déterministe, c'est-à-dire du niveau T1), j'ai défini une fonction ⌘g : ℕ⇢ℕ (ma notation !) qui consiste à faire tourner la machine de Turing universelle ayant accès à g comme oracle ; cette fonction est de même degré T1 que g mais permet de construire sur les degrés T1 la borne inférieure binaire (qui n'existe généralement pas pour les degrés de Turing ordinaires).

Au niveau T2, la construction ⌘g est définie ainsi : donné un plan ⟨e,n⟩ (c'est-à-dire le code e d'une machine de Turing avec oracle et une entrée n à lui passer), alors ⌘g(⟨e,n⟩) est définie lorsque l'exécution du plan termine quelle que soit la valeur renvoyée par g à chaque interrogation de l'oracle, et, si c'est bien le cas, l'ensemble des valeurs ⌘g(⟨e,n⟩) est l'ensemble de toutes les valeurs possibles renvoyées par la machine. (C'est donc ce qu'on attend raisonnablement de la fonction non-déterministe définie par un calcul faisant appel à un oracle non-déterministe g, mais je souligne une fois de plus que s'il y a une possibilité quelconque que le calcul ne termine pas — que ce soit parce qu'il fait appel à une valeur non-définie de g ou parce que la machine part en boucle infinie — alors ⌘g(⟨e,n⟩) n'est pas définie.)

Pour qu'il n'y ait pas de doute que les définitions sont cohérentes entre elles, la réduction f ≼T2 g définie au-dessus signifie exactement, et par définition, qu'il existe e∈ℕ tel que pour tout n du domaine de définition de f on ait ⌘g(⟨e,n⟩) défini et ⊆ f(n).

Comme dans le cas T1, on a g ≡T2 ⌘g.

On peut alors définir la borne inférieure binaire des degrés T2 : supposons données a et b sont deux fonctions partielles multivaluées ℕ⇢𝒫(ℕ), et on veut définir une fonction partielle c : ℕ⇢𝒫(ℕ) telle que les fonctions réductibles à c soient exactement celles réductibles à la fois à a et à b. On va la définir comme ceci : c(⟨m₁,m₂⟩) est égale à la réunion disjointe étiquetée (je vais définir ça tout de suite) ⌘a(m₁) ⊔ ⌘b(m₂) de ⌘a(m₁) et de ⌘b(m₂) si ces deux valeurs sont toutes les deux définies, et n'est pas définie sinon.

Si P et Q sont deux parties de ℕ, la réunion disjointe étiquetée PQ, désigne ici l'ensemble des ⟨0,p⟩ pour pP et des ⟨1,q⟩ pour qQ.

Pour dire les choses autrement, pour interroger l'oracle c, vous devez fournir un plan m₁=⟨e₁,n₁⟩ d'interrogation de a et un plan m₂=⟨e₂,n₂⟩ d'interrogation de b, ces deux plans doivent tous les deux terminer correctement (si l'un des deux échoue, l'oracle vous tue) ; et si c'est le cas, l'oracle c vous renvoie une valeur de l'un ou de l'autre plan, en vous disant lequel.

Comme au niveau T1, il n'est pas difficile de voir que cette construction donne bien la borne inférieure recherchée. La construction est presque la même, mais ça vaut la peine de souligner la différence : dans la construction au niveau T1, l'oracle c exige que les deux plans d'exécution (à a et à b) soient valables et donnent exactement le même résultat, alors que dans la construction au niveau T2, l'oracle c exige que les deux plans d'exécution (à a et à b) soient valables, et il renvoie non-déterministement une valeur renvoyée par l'un des deux (avec l'information de laquelle il a choisi).

Notons que lorsque a et b se trouvent être toutes les deux des fonctions partielles simplement valuées (ℕ⇢ℕ), les deux constructions ont un sens : on a alors c₁ : ℕ⇢ℕ qui est donnée par la première, et c₂ : ℕ⇢𝒫(ℕ) donnée par la seconde. Il est clair que c₁ ≼T2 c₂, et, en fait, le degré de c₁ est le plus grand degré T1 qui est ≤ au degré de c₂. J'ignore, cependant, si ces degrés peuvent vraiment être différents (j'imagine que oui, mais je n'ai pas de preuve) : si c'est bien le cas, cela signifie que le plongement des degrés T1 dans les degrés T2, bien qu'il préserve l'ordre et les bornes supérieures binaires, ne préserve pas les bornes inférieures binaires. Bref, quand on parle de ab pour a et b deux degrés T1, il faut préciser si cette borne est prise dans les degrés T1 ou dans les degrés T2.

J'en profite d'ailleurs pour réfuter une erreur possible : on aurait pu croire que la borne inférieure dans les degrés T2 entre le degré de a et le degré de b s'obtient plus simplement en prenant la réunion a(m)∪b(m) des valeurs possibles des deux fonctions, ou, de façon un chouïa moins naïve, la réunion disjointe étiquetée a(m)⊔b(m) : la fonction c ainsi définie vérifie certes c ≼T2 a et c ≼T2 b (de façon évidente), mais ce n'est pas parce qu'une fonction est réductible à a et à b à la fois qu'elle sera réductible à cette fonction c (même si on a pris l'opération ‘⊔’), essentiellement parce que la construction en question insiste trop naïvement pour combiner a et b prises à la même valeur m. Pour illustrer le problème, si on définit a comme valant 0 en 2m et Halting(m) en 2m+1 (où Halting désigne le problème de l'arrêt), et b comme valant Halting(m) en 2m et 0 en 2m+1, alors manifestement a ≡T2 b donc la borne inférieure de leurs degrés est leur degré commun ; pourtant, si on les combine comme je viens de dire, alors c est de degré trivial (0) car Merlin peut choisir de renvoyer a quand on l'interroge sur une valeur paire et b quand on l'interroge sur une valeur impaire, et il ne fournit donc aucune information.

Un degré T2 intermédiaire naturel

Il y a autre chose qui mérite d'être noté au niveau T2 : j'ai mentionné plus haut qu'on ne connaît pas de degré de Turing ordinaire « naturel » (calculablement énumérable, mais peu importe ici) qui soit strictement intermédiaire entre 0 (degré de ce qui est calculable) et 0′ (degré du problème de l'arrêt). Quand on passe aux fonctions non-déterministes, en revanche il y a un tel degré (enfin, il y en a plein mais celui-ci semble raisonnablement intéressant, et en tout cas me semble mériter le qualificatif de naturel). Je vais en parler un petit peu : tout ceci est essentiellement une digression, donc on peut sauter la fin de cette section, mais je pense que c'est quand même pertinent d'en dire un mot, à la fois parce que ça remet en perspective le problème de Post, et aussi parce que ça donne un exemple de la manière dont fonctionne la réduction T2.

Je vais décrire trois fonctions non-déterministes (i.e., ℕ⇢𝒫(ℕ)) différentes, toutes les trois du même degré T2 (je vais expliquer pourquoi), pour définir le degré en question (l'une de ces descriptions, ainsi que la preuve de l'équivalence, suppose quelques connaissances en logique ; on peut sauter ce passage, mais sinon je pense que ce billet passé explique assez pour suivre) :

  • Première fonction, appelons-la LLPO pour des raisons en lien avec les maths constructives mais je n'ai pas envie d'en dire plus ici. La fonction LLPO prend en entrée les codes ⟨⟨e₁,n₁⟩, ⟨e₂,n₂⟩⟩ de deux machines de Turing ordinaires e₁, e₂ avec des entrées n₁,n₂ à leur fournir. La fonction LLPO est définie lorsque au moins une des deux machines fournies ne termine pas, c'est-à-dire lorsque φe(n₁)↑ ou bien φe(n₂)↑ (la notation φe(n)↑ signifiant que l'algorithme codé par l'entier e ne termine pas quand on lui fournit n en entrée ; le ou bien est évidemment un ou inclusif). Si les deux machines terminent, la valeur de LLPO est non-définie (c'est une « question interdite »). Si au moins une des deux machines ne termine pas, alors LLPO renvoie, de façon non-déterministe, une des machines qui ne termine pas. Pour être tout à fait clair, la fonction LLPO : ℕ⇢𝒫(ℕ) dont je parle est la suivante : son domaine de définition est l'ensemble des ⟨⟨e₁,n₁⟩, ⟨e₂,n₂⟩⟩ tels que φe(n₁)↑ ou bien φe(n₂)↑ ; et, sur le codage d'un tel couple, la fonction LLPO vaut {⟨ei,ni⟩ : i∈{0,1} et φei(ni)↑}, c'est-à-dire que ses valeurs possibles sont les ⟨ei,ni⟩ pour lesquelles φei(ni)↑.
  • La seconde fonction, appelons-la LLPO, est presque identique à la précédente, mais la différence est que, quand les deux machines terminent, au lieu que la question soit interdite, la fonction vous renvoie n'importe laquelle des deux (toujours de façon non-déterministe). Autrement dit, LLPO⁺ est définie sur tous les ⟨⟨e₁,n₁⟩, ⟨e₂,n₂⟩⟩ ; mais cette fois l'ensemble des valeurs possibles est {⟨ei,ni⟩ : i∈{0,1} et (si (φe(n₁)↑ ou bien φe(n₂)↑) alors φei(ni)↑)}.
  • La troisième fonction, appelons-la Consist, prend en entrée un énoncé logique P dans le langage de l'arithmétique (du premier ordre), et elle peut renvoyer P si P est cohérent avec l'arithmétique de Peano (c'est-à-dire : si sa négation ¬P n'est pas un théorème), ou bien ¬P si ¬P est cohérent avec (c'est-à-dire, si P n'est pas un théorème). En clair, l'ensemble des valeurs possibles est Consist(P) = {Q∈{PP} : Peano ⊬ ¬Q}, où le symbole ‘⊬’ signifie ne démontre pas. Comme l'arithmétique de Peano est cohérente, il y a forcément l'un de P et de ¬P qui est cohérent avec Peano, donc Consist peut toujours renvoyer quelque chose (l'ensemble n'est jamais vide). Peut-être que c'est plus clair si je le dis ainsi : Consist(P) va renvoyer P si P est un théorème de l'arithmétique de Peano, ¬P si ¬P est un théorème, et l'un quelconque des deux de façon non-déterministe si P est indécidable dans l'arithmétique de Peano.

Notons de plus Halting le problème de l'arrêt (dont le degré est 0′ par définition de ce dernier).

Il est facile de voir ConsistLLPOLLPO⁺ ≼ Halting (en notant ‘≼’ pour ‘≼T2’) :

  • Si on disposant de l'accès à un oracle LLPO, pour calculer Consist, donné un énoncé arithmétique P, on considère ⟨e₁,n₁⟩ qui recherche une preuve de ¬P dans l'arithmétique de Peano et ⟨e₂,n₂⟩ qui recherche une preuve de P dans l'arithmétique de Peano. L'une des deux doit forcément ne pas terminer (parce que Peano est cohérent), si bien que ⟨⟨e₁,n₁⟩, ⟨e₂,n₂⟩⟩ est une question autorisée à LLPO (il est défini dessus). Si notre oracle LLPO répond 1 (i.e., ⟨e₁,n₁⟩ ne termine pas), on renvoie P, et s'il répond 2 on renvoie ¬P.
  • Il est trivial que LLPO se réduit à LLPO⁺ puisque c'est une restriction de ce dernier.
  • Si on dispose de l'accès à un oracle du problème de l'arrêt, il est évident de calculer LLPO⁺ : on utilise l'oracle pour décider si ⟨e₁,n₁⟩ s'arrête et si ⟨e₂,n₂⟩ s'arrête, et on renvoie ⟨e₁,n₁⟩ sauf lorsque φe(n₁)↓ et φe(n₂)↑ auquel cas on renvoie ⟨e₂,n₂⟩.

La chose qui est un petit peu subtile, c'est que LLPO⁺ ≼ Consist (du coup, ConsistLLPOLLPO⁺ comme annoncé). Pour ça, il y a une astuce due à Rosser : donnés ⟨e₁,n₁⟩ et ⟨e₂,n₂⟩, on appelle P l'énoncé l'algorithme e₂ sur n₂ s'arrête avant l'algorithme e₁ sur n (c'est-à-dire précisément : il existe une trace d'exécution de e₂ sur n₂ qui a une longueur strictement plus courte que toute trace d'exécution de e₁ sur n). L'intérêt de cet énoncé est que si φe(n₁)↑ et φe(n₂)↓ alors P est prouvable dans Peano (il suffit d'écrire la trace d'exécution complète de φe(n₂) et le début de la trace d'exécution de φe(n₁) de cette longueur, ceci constitue une preuve de P), et symétriquement, si φe(n₁)↓ et φe(n₂)↑ alors ¬P est prouvable dans Peano (il suffit d'écrire la trace d'exécution complète de φe(n₁) et le début de la trace d'exécution de φe(n₁) de cette longueur). Donc on interroge l'oracle Consist sur l'énoncé P, et s'il répond P on renvoie ⟨e₁,n₁⟩ tandis que s'il répond ¬P on renvoie ⟨e₂,n₂⟩ : ceci constitue une implémentation de LLPO⁺.

Le fait que le degré de ConsistLLPOLLPO⁺ est > 0, c'est-à-dire qu'on ne peut pas implémenter ces oracles algorithmiquement, est expliqué ici. Le fait que ce degré T2 est < 0′ est plus subtil : je le démontrerai plus bas en comparant à un degré T3 (Error1/3), mais mentionnons que c'est, par exemple, une conséquence du théorème de la base basse (que j'ai brièvement évoqué ci-dessus en petits caractères ; cf. ici pour une discussion sur la question) : grosso modo, le théorème de la base basse assure qu'il existe une fonction d:ℕ→{0,1} (totale et déterministe) qui pour chaque P choisit P ou ¬P pour être cohérent avec Peano et même, si on veut, pour être cohérent avec les choix faits par cette même fonction (ce qui donne donc une extension cohérente et complète de l'arithmétique de Peano) et dont le degré de Turing d est bas, c'est-à-dire qu'il vérifie d′=0′, et en particulier d<0′. On a alors Consist ≼ d (précisément parce que d fait des choix de réponses valables pour Consist), et notamment, comme le degré (ordinaire, donc aussi T2) de d est <0′, il en va de même de celui de Consist. Donc le degré de ConsistLLPOLLPO⁺ est strictement intermédiaire entre 0 et 0′ comme annoncé.

Mais par ailleurs, même si je n'ai pas défini le concept pour un degré T2 et je ne sais pas exactement ce qu'il devrait être, il est plausible que le degré en question mérite d'être qualifié de calculablement énumérable (on peut énumérer les ⟨⟨e₁,n₁⟩, ⟨e₂,n₂⟩⟩ pour lesquels φe(n₁)↓ ou bien φe(n₂)↓, ce qui oblige à répondre ⟨e₂,n₂⟩ ou ⟨e₁,n₁⟩ respectivement, et pour les autres, on peut faire n'importe quelle réponse). Donc on peut dire qu'au niveau T2 on a une réponse satisfaisante et naturelle au problème de Post.

T3 : Degrés de Turing des « fonctions avec conseil » (non-déterministes et co-non-déterministes)

Réduction des fonctions avec conseil

Pour récapituler, pour l'instant, on a défini la réduction de Turing ordinaire (celle des fonctions ℕ→ℕ totales simplement valuées), puis on a généralisé d'abord (réduction T1) aux fonctions partielles, et ensuite (réduction T2) aux fonctions partielles multivaluées, c'est-à-dire pouvant prendre plusieurs valeurs (quand vous l'appelez, la fonction vous renvoie une valeur que vous ne contrôlez pas, c'est-à-dire choisie par votre adversaire, Merlin).

Quelle est la généralisation suivante ? C'est là que je trouve ça très intéressant : on va introduire une sorte de non-déterminisme « dual » (co-non-déterminisme ? le terme est de moi), où la valeur choisie est non pas celle qui vous arrange le moins (choisie par votre adversaire, Merlin) mais celle qui vous arrange le plus (choisie par votre fée protectrice, Nimué) ! C'est un peu subtil, et il y a diverses façons de présenter la chose. Je vais décrire deux points de vue différents légèrement différents pour la même chose (ci-après, le point de vue parties et le point de vue bicouche), au risque de compliquer la présentation mais dans l'espoir de plaire à tout le monde. (Je conseille de lire une première fois en diagonale pour essayer de trouver quelle présentation semble la plus claire, et une deuxième fois plus précisément une fois qu'on a cette idée.)

La présentation la plus économique et peut-être la plus élégante est d'appeler fonction avec conseil (« point de vue parties ») une fonction (totale) g : ℕ→𝒫(𝒫(ℕ)) de l'ensemble ℕ des entiers naturels vers l'ensemble 𝒫(𝒫(ℕ)) des ensembles d'ensembles d'entiers naturels. Je vais expliquer plus précisément quel est le jeu auquel on va jouer et qui sont ses joueurs, mais pour donner déjà une idée de quoi il s'agit, si m est choisi par Arthur, alors Nimué (qui est alliée d'Arthur) choisit un élément de g(m), et Merlin (qui est adversaire d'Arthur) choisit un élément de l'élément que Nimué aura choisi (et c'est ça qu'Arthur verra). Une fonction partielle multivaluée (cas T2) g : ℕ⇢𝒫(ℕ) est identifiée à la fonction avec conseil ℕ→𝒫(𝒫(ℕ)) valant {g(m)} lorsque g(m) est défini (c'est lui-même un ensemble d'entiers naturels), et valant ∅ lorsque g(m) n'est pas défini (autrement dit, Nimué a un seul choix dans le premier cas, et aucun choix dans le second) ; en particulier, une fonction partielle simplement valuée (cas T1) g : ℕ⇢ℕ est identifiée à la fonction avec conseil ℕ→𝒫(𝒫(ℕ)) valant {{g(m)}} lorsque g(m) est défini (c'est un entier naturel), et ∅ lorsque g(m) n'est pas défini. Bref, les cas que nous avons précédemment considérés sont les cas des fonctions avec conseil où chaque élément de 𝒫(𝒫(ℕ)) pris par la fonction est de cardinal ≤1.

Un autre point de vue (« point de vue bicouche »), peut-être moins élégant mais éventuellement plus pratique et peut-être plus intuitif, sur le cas T3 qu'on cherche à définir, consiste à regarder des fonctions ℕ×Λ ⇢ 𝒫(ℕ), c'est-à-dire partielles multivaluées, mais prenant maintenant deux entrées, un entier naturel et un élément d'un ensemble Λ non spécifié dépendant de la fonction, ce deuxième élément étant appelé l'entrée secrète ou (lorsque la fonction est utilisée comme oracle) le choix de Nimué. Pour distinguer notationnellement ces deux arguments, on notera g(n|c) la valeur de la fonction sur le couple formé d'un élément n∈ℕ et cΛ. Avec ce point de vue, si m est choisi par Arthur, alors Nimué choisit un élément cΛ tel que g(m|c) soit défini, et Merlin choisit un élément de g(m|c).

J'utiliserai le terme de fonction avec conseil pour désigner l'un ou l'autre de ces deux points de vue (fonction ℕ→𝒫(𝒫(ℕ)) ou ℕ×Λ ⇢ 𝒫(ℕ)) : je vais de toute façon dire qu'ils sont équivalents et définiront les mêmes degrés T3. Si je dois les distinguer, j'ajouterai point de vue parties pour une fonction ℕ→𝒫(𝒫(ℕ)) ou point de vue bicouche pour une fonction ℕ×Λ ⇢ 𝒫(ℕ).

Je ne sais pas si ça éclaircit les choses où si ça les embrouille de donner ces deux points de vue à la fois (fonction ℕ→𝒫(𝒫(ℕ)) ou ℕ×Λ ⇢ 𝒫(ℕ)), mais en tout cas, la conversion entre les deux points de vue est la suivante : donnée une fonction avec conseil point de vue parties g : ℕ→𝒫(𝒫(ℕ)), on appelle Λ = 𝒫(ℕ), et on définit une fonction avec conseil point de vue bicouche gˆ : ℕ×Λ ⇢ 𝒫(ℕ) ainsi : si n∈ℕ et cΛ=𝒫(ℕ), alors la fonction gˆ est définie en (n|c) exactement lorsque cg(n) et dans ce cas elle vaut c ; inversement, donnée une fonction avec conseil point de vue bicouche g : ℕ×Λ ⇢ 𝒫(ℕ), on définit une fonction avec conseil point de vue parties gˇ : ℕ→𝒫(𝒫(ℕ)) ainsi : gˇ(n) est l'ensemble de toutes les valeurs g(n|c) qui sont définies lorsque c parcourt Λ. Ces opérations ne sont pas inverses l'une de l'autre (on a bien gˆˇ=g mais dans l'autre sens ce n'est pas vrai), mais pour ce qui nous concerne ce sera tout comme (la fonction gˇˆ sera T3-équivalente à g).

Avant de passer à une description plus formelle, l'idée intuitive de notre niveau T3 peut être décrite très informellement comme suit. Arthur est en train de mener un calcul algorithmique et dispose d'un oracle de nature ℕ→𝒫(𝒫(ℕ)) ou ℕ×Λ ⇢ 𝒫(ℕ) selon le point de vue par lequel on préfère le représenter : il (Arthur) va choisir une valeur m sur laquelle interroger l'oracle. L'oracle est, en quelque sorte, formé de deux personnes : Nimué, qui est l'alliée d'Arthur, et Merlin, qui est son adversaire. Nimué cherche à aider Arthur mais ne peut pas communiquer directement avec lui. Merlin cherche à l'emmerder. Dans le point de vue parties g : ℕ→𝒫(𝒫(ℕ)), Arthur choisit m pour interroger l'oracle, Nimué choisit un élément de g(m), et Merlin choisit un élément de cet élément-là (c'est donc un entier naturel) et c'est là la valeur qu'Arthur voit comme réponse de l'oracle, et avec laquelle il continue son calcul. (Si g(m) est vide, Nimué ne peut pas jouer et Arthur/Nimué a perdu ; en revanche, si l'élément de g(m) choisi par Nimué est vide, Merlin ne peut pas jouer, et Arthur a gagné.) Dans le point de vue bicouche g : ℕ×Λ ⇢ 𝒫(ℕ), Arthur choisit m pour interroger l'oracle, Nimué choisit un élément cΛ tel que g(m|c) soit défini, et Merlin choisit un élément de cet ensemble-là (c'est donc un entier naturel) et c'est là la valeur qu'Arthur voit comme réponse de l'oracle, et avec laquelle il continue son calcul. Dans les deux points de vue, il est crucial de noter qu'Arthur ne voit pas la valeur choisie par Nimué, il voit uniquement la valeur choisie par Merlin. (De toute façon, Arthur joue selon un algorithme donc ça n'a même pas de sens de lui permettre de voir un élément d'un ensemble Λ abstrait.)

Inversement, quand c'est Arthur (aidé de Nimué) qui doit calculer une fonction f, il faut « inverser les rôles » mais comme il y a trois rôles il faut être un peu précis sur ce qu'inverser signifie. Il se passe les choses suivantes. Dans le point de vue parties f : ℕ→𝒫(𝒫(ℕ)), Merlin choisit à la fois n (sur lequel Arthur est interrogé) et un élément de f(n), mais le premier est montré à Arthur et Nimué tandis que le second n'est montré qu'à Nimué, et le but d'Arthur est de fabriquer un élément de cet ensemble. Dans le point de vue bicouche f : ℕ×Λ ⇢ 𝒫(ℕ), Merlin choisit à la fois n∈ℕ et cΛ tels que f(n|c) soit défini, mais n est montré à Arthur et Nimué tandis que c n'est montré qu'à Nimué, et le but d'Arthur est de fabriquer un élément de l'ensemble f(n|c).

Bon, tout ceci était peut-être désespérément vague, donc voici une définition précise. Je vais prendre le point de vue bicouche ℕ×Λ ⇢ 𝒫(ℕ) et ensuite dire ce qu'il faut changer pour le point de vue parties ℕ→𝒫(𝒫(ℕ)).

Données deux fonctions f : ℕ×Θ ⇢ 𝒫(ℕ) et g : ℕ×Λ ⇢ 𝒫(ℕ), on dit que f est réductible à g (réductible au sens T3 s'il y a besoin de préciser, mais je pourrais aussi l'appeller réductible au sens de Turing-Kihara) lorsqu'il existe une stratégie calculable pour Arthur et une stratégie pour Nimué qui leur assurent de gagner au jeu suivant.

Le jeu : se joue entre trois joueurs, Arthur+Nimué (qui font équipe) et Merlin (leur adversaire) : Arthur voit uniquement les coups qui seront indiqués visibles ci-dessous, tandis que Nimué et Merlin voient tous les coups passés ; les coups se font dans l'ordre suivant : Merlin, Arthur, Nimué, Merlin, Arthur, Nimué, etc.

  • au premier tour, Merlin joue un élément n∈ℕ, qui sera visible d'Arthur, et un élément dΘ qui ne sera pas visible d'Arthur ; Merlin perd dès le premier tour (i.e., Arthur+Nimué gagnent) si f(n|d) n'est pas défini ;
  • à chaque tour suivant, Arthur a deux types de coups possibles : il peut soit « déclarer la fin du calcul » avec une valeur k∈ℕ, soit « lancer une interrogation de l'oracle » avec une valeur m∈ℕ ;
  • lorsque Arthur déclare la fin du calcul avec une valeur k, le jeu prend fin ; Arthur+Nimué gagnent si k ∈ f(n|d), sinon Merlin gagne ;
  • lorsque Arthur lance une interrogation de l'oracle avec une valeur m :
    • Nimué joue ensuite un élément cΛ, qui ne sera pas visible d'Arthur ; Arthur+Nimué perdent à ce stade (i.e., Merlin gagne) si g(m|c) n'est pas défini, sinon le jeu continue ;
    • puis Merlin joue un élément ∈ℕ, qui sera visible d'Arthur ; Merlin perd à ce stade (i.e., Arthur+Nimué gagnent) si g(m|c), sinon le jeu continue (avec un coup d'Arthur).

Le jeu prend fin dès qu'un des joueurs a gagné, c'est-à-dire soit lorsque Arthur a déclaré la fin du calcul soit lorsqu'un des joueurs a violé une contrainte sur le coup. Si le jeu dure indéfiniment (Arthur ne déclare jamais la fin du calcul), alors Arthur+Nimué ont perdu (i.e., Merlin a gagné).

Arthur (simple mortel !) joue selon une stratégie calculable, c'est-à-dire qu'on exige qu'il existe une fonction calculable qui, données toutes les informations dont il dispose à ce stade (et qui sont toutes des entiers naturels) renvoie le coup qu'il joue. Nimué et Merlin, en revanche, ne sont pas ainsi limités : la condition de réduction est donc qu'il existe une stratégie calculable pour Arthur et une stratégie pour Nimué telles que pour toute stratégie de Merlin, Arthur+Nimué gagnent au jeu qui vient d'être décrit.

Pour ce qui est du point de vue parties ℕ→𝒫(𝒫(ℕ)), données deux fonctions f : ℕ→𝒫(𝒫(ℕ)) et g : ℕ→𝒫(𝒫(ℕ)), on dit que f est réductible à g (réductible au sens T3, je ne ferai pas de différence avec la notion précédente, parce que c'est vraiment interconvertible) lorsqu'il existe une stratégie calculable pour Arthur et une stratégie pour Nimué qui leur assurent de gagner au jeu suivant.

Le jeu ne comporte que de petites variations par rapport à la description précédente.

  • au premier tour, Merlin joue un élément n∈ℕ, qui sera visible d'Arthur, et un élément D∈𝒫(ℕ) qui ne sera pas visible d'Arthur ; Merlin perd dès le premier tour (i.e., Arthur+Nimué gagnent) si Df(n) ;
  • à chaque tour suivant, Arthur a deux types de coups possibles : il peut soit « déclarer la fin du calcul » avec une valeur k∈ℕ, soit « lancer une interrogation de l'oracle » avec une valeur m∈ℕ ;
  • lorsque Arthur déclare la fin du calcul avec une valeur k, le jeu prend fin ; Arthur+Nimué gagnent si k ∈ D, sinon Merlin gagne ;
  • lorsque Arthur lance une interrogation de l'oracle avec une valeur m :
    • Nimué joue ensuite un élément C∈𝒫(ℕ), qui ne sera pas visible d'Arthur ; Arthur+Nimué perdent à ce stade (i.e., Merlin gagne) si Cg(m) n'est pas défini, sinon le jeu continue ;
    • puis Merlin joue un élément ∈ℕ, qui sera visible d'Arthur ; Merlin perd à ce stade (i.e., Arthur+Nimué gagnent) si C, sinon le jeu continue (avec un coup d'Arthur).

Les autres remarques s'appliquent à l'identique.

Quel que soit le point de vue que l'on choisit, la relation de réduction qu'on vient de définir, et qu'on notera f ≼T3 g est, comme dans les cas précédents (réduction de Turing ordinaire, T1 et T2) un préordre. C'est un tout petit peu plus compliqué à voir que dans les cas précédents parce qu'on a un jeu à trois joueurs, mais il n'y a pas de difficulté majeure (en gros : si on suppose f ≼T3 g et g ≼T3 h et qu'on veut prouver f ≼T3 h, Arthur et Nimué appliquent chacun la stratégie qui montre que f ≼T3 g sauf que, à chaque fois que celle-ci préconise à Arthur de lancer une interrogation de l'oracle, celle-ci est remplacée par une application des stratégies qui montrent g ≼T3 h en faisant semblant que Merlin a fait le coup que les stratégies précédentes auraient préconisé pour Arthur et Nimué).

Lorsque f et g sont « sans conseil » (i.e., que Nimué n'a aucun choix à faire, c'est-à-dire, dans le point de vue parties ℕ→𝒫(𝒫(ℕ)), que leurs valeurs sont soit ∅ soit un singleton, ou, dans le point de vue bicouche ℕ×Λ ⇢ 𝒫(ℕ) que Λ est un singleton), il s'agit du même préordre T2 qu'on a déjà défini (et qui généralise lui-même la réduction T1 et la réduction de Turing ordinaire). De nouveau, on peut définir une relation d'équivalence f ≡T3 g lorsque f ≼T3 g et g ≼T3 f (et je répète que, lorsque f et g sont « sans conseil », les relations f ≡T2 g et f ≡T3 g sont équivalentes).

On a donc de nouveau un ensemble de degrés, qu'on peut appeler les degrés T3, ou degrés de Turing des fonctions avec conseil.

Comme précédemment, vu que f ≡T2 g et f ≡T3 g sont équivalentes lorsque f et g sont « sans conseil », on obtient une injection [f]T2 ↦ [f]T3 des degrés T2 dans les degrés T3 en envoyant la classe d'équivalence pour ‘≡T2’ de f vers la classe d'équivalence pour ‘≡T3’ de cette même fonction. Ceci permet de considérer, et on le fera toujours, les degrés T2 (et a fortiori les degrés de Turing ordinaires et T1) et comme un sous-ensemble des degrés T3. On va maintenant dire un mot des degrés « basiques » qui sont une sorte de supplémentaire des degrés T2 dans les degrés T3.

Les degrés « basiques », les fonctions Error1/

La notion de degré T3 est sans doute plus délicate à visualiser intuitivement que celle de degré de Turing ordinaire, T1 ou T2. Quelques commentaires et exemples sont sans doute bienvenus.

La première chose à comprendre, c'est que Nimué est extrêmement puissante : le point crucial des règles du jeu définies ci-dessus est qu'elles ne permettent pas à Nimué de communiquer directement en direction d'Arthur (je vais dire ci-dessous que si elle le peut, on peut tout calculer), elle peut juste restreindre les coups de Merlin pour aider Arthur.

Si Nimué ne joue pas (i.e., si elle n'a pas de choix), on obtient exactement les degrés T2 définis précédemment (et si Merlin lui non plus n'a pas de choix, on obtient les degrés T1, peut-être avec une petite discussion sur ce que pas de choix signifie exactement entre ≤1 option ou =1 option, mais ne pinaillons pas ici).

Mais on peut aussi considérer la situation symétrique où c'est Arthur qui ne joue pas (disons, par exemple, que le nombre qu'il joue est ignoré, ou bien que s'il est ≠0 alors Nimué n'a aucun coup ce qui force Arthur à jouer 0). On parlera d'oracle basique pour cette situation : un oracle basique est donc juste un élément de 𝒫(𝒫(ℕ)), ou une fonction Λ ⇢ 𝒫(ℕ), selon le point de vue qu'on préfère (parties ou bicouche : je rappelle que l'élément de 𝒫(𝒫(ℕ)) donné par le point de vue parties est juste l'image de la fonction Λ ⇢ 𝒫(ℕ) du point de vue bicouche) ; et on parlera de degré basique pour le degré T3 d'une telle fonction.

Commençons par examiner la situation la plus simple qui ne soit pas triviale : l'oracle basique, appelons-le provisoirement q (plus bas il sera aussi nommé Error½), donné par {{0},{1}} ∈ 𝒫(𝒫(ℕ)), ou, dans le point de vue bicouche, la fonction {0,1} ⇢ 𝒫(ℕ) donnée par 0↦{0}, 1↦{1}. Autrement dit : Arthur n'a pa de choix à faire (c'est un oracle basique), Nimué a le choix entre deux options que nous avons notées “0” et “1”, et Merlin n'a pas de choix derrière, il doit juste reprendre la valeur choisie par Nimué parmi 0 et 1 ; concrètement, cet oracle consiste donc pour Nimué à communiquer un bit à Arthur, en forçant Merlin à le lui donner. (Enfin, un bit par appel de l'oracle !, mais comme les appels à l'oracle sont illimités, on devine bien que ça va être très puissant.) On peut se convaincre que toute fonction partielle f:ℕ⇢ℕ est réductible à l'oracle q en question (i.e., f ≼T3 q) : en effet, voici une stratégie possible d'Arthur et Nimué : en réponse à un coup n∈ℕ de Merlin, Nimué calcule f(n)∈ℕ et, au k-ième coup (compté à partir de 0), elle répond 1 si f(n)=k et 0 sinon ; Arthur va donc interroger l'oracle de façon répétée jusqu'à ce que l'oracle réponde 1, et si ça se produit à la k-ième interrogation (comptée à partir de 0), il déclare la fin du calcul avec la valeur en question ; clairement, cette stratégie est calculable, et gagnante pour Arthur+Nimué, prouvant que f ≼T3 q lorsque f est une fonction partielle ; le même argument fonctionne pour une fonction non-déterministe ℕ⇢𝒫(ℕ), tant que celle-ci ne prend pas la valeur ∅. Encore plus généralement, le même argument montre que pour toute fonction f : ℕ×Θ ⇢ 𝒫(ℕ) on a f ≼T3 q dès lors que f(n|d)≠∅ pour tout n∈ℕ et tout dΘ (si on préfère le point de vue parties ℕ→𝒫(𝒫(ℕ)), on a f ≼T3 q dès lors que tous les éléments de f(n) sont non vides) : en effet, donnés n∈ℕ et dΘ, Nimué va utiliser q pour communiquer à Arthur, disons, la valeur du plus petit élément de f(n|d), ce qui constitue une stratégie gagnante pour eux deux.

J'appellerai degré omniscient, et je noterai (oui, c'est une blague, mais je ne sais pas quel symbole utiliser) le degré T3 de l'oracle (q ou Error½) défini au paragraphe précédent, c'est-à-dire celui permettant à Nimué de communiquer directement un bit à Arthur. En fait, en gros, dès que Nimué peut communiquer avec Arthur, on tombe sur ce degré  (notamment, si un oracle basique, dans le point de vue parties, c'est-à-dire élément de 𝒫(𝒫(ℕ)), contient deux parties disjointes et calculables — ou même simplement disjointes et calculablement énumérables, ou même simplement calculablement séparables — alors son degré est , parce que Nimué va pouvoir jouer l'une de ces parties pour communiquer un bit à Arthur et Arthur saura décoder la réponse de Merlin pour savoir ce que Nimué cherche à lui dire). Comme montré au paragraphe précédent, ce degré omniscient  majore tout degré T3 à la seule exception du plus grand de tous. Ce dernier (le plus grand degré T3) sera appelé degré omnipotent, c'est le degré d'une fonction met Merlin en échec (par exemple, représenté par l'oracle basique {∅}∈𝒫(𝒫(ℕ)) dans le point de vue parties : Nimué joue ∅ et Merlin ne peut pas répondre, donc Arthur+Nimué ont gagné). Je noterai pour ce degré omnipotent, qui est, je répète, le seul strictement plus grand que  (et encore moins intéressant que lui).

(Les notations sont assez pourries, j'en conviens. Déjà, ça n'aide pas qu'on veuille parfois parler des fonctions, parfois de leur degré. Il est standard de noter 0 pour le plus petit degré — celui des fonctions calculables — comme degré de Turing ordinaire, donc comme degré T1, T2 ou T3. Pour les degrés de Turing ordinaires ou les degrés T1, il n'y a pas de plus grand degré. Dans les degrés T2 et T3 apparaît ce plus grand degré, que je note  parce que c'est une notation standard pour le plus grand élément d'un treillis. Mais comment noter le deuxième plus grand élément ? J'ai écrit  parce que c'est une blague sur OMniscient, mais aussi parce que c'est sûr que ce symbole n'est pas utilisé ailleurs en maths. Il peut être légitime de le noter ¬¬ parce qu'il correspondra à la topologie du non-non au sens de Lawvere-Tierney, mais je pense que ce serait confusant de le noter ainsi à ce stade. C'est le degré de la fonction Error½ introduite ci-dessous, mais c'est un petit peu long pour un objet aussi fondamental.)

J'ai défini le degré omniscient  par l'oracle basique {{0},{1}} ∈ 𝒫(𝒫(ℕ)) qui permet à Nimué de communiquer un bit à Arthur. Plus généralement, on peut considérer l'oracle basique suivant : Errorm/k est défini comme l'ensemble des parties à km éléments de {0,…,k−1}, c'est-à-dire qu'on peut voir l'utilisation de cet oracle de la manière suivant : parmi k possibilités, Nimué en exclut secrètement m, et Merlin montre une des km restantes à Arthur. (Si on préfère le point de vue bicouche, il peut être préférable d'appeler Λ l'ensemble des parties à m éléments de {0,…,k−1}, et alors Errorm/k : ℕ×Λ ⇢ 𝒫(ℕ) renvoie le complémentaire de son deuxième argument dans {0,…,k−1}.) Le cas précédemment considéré était Error½ (qui définit, je répète, le degré omniscient  qui est le plus grand après le degré omnipotent).

Du point de vue calculatoire, on peut dire que Errorm/k est un gadget qui vous permet de lancer k fils d'exécution en parallèle, dont (au plus) m d'entre eux ont le droit de se tromper : si au moins km donnent un bon résultat, vous avez réussi votre calcul.

La question de si Errorm′/kT3 Errorm/k peut être tournée de façon un peu ludique comme suit : un aventurier (Arthur) est dans un donjon, il est face à k′ portes identiques dont m′ conduisent à la mort, mais il ignore lesquelles. Son but est d'ouvrir une porte non-mortelle. Son ange gardien (Nimué, qui connaît notamment les bonnes et mauvaises portes) peut l'aider dans cette tâche, mais Nimué ne peut pas communiquer directement d'information à Arthur : tout ce qu'elle peut faire c'est, parmi un ensemble de m possibilités (choisies par Arthur), en exclure k, après quoi Merlin (le concepteur du donjon, qui cherche à nuire à Arthur) va en sélectionner une et la communiquer à Arthur. L'énigme que j'avais posée à la fin du billet précédent était le cas (k,m,k′,m′) = (5,2,3,1), c'est-à-dire, sous une formulation un peu différente, demandait de montrer Error1/3T3 Error2/5 (sachant que Error2/5T3 Error1/3 est évident, donc, en fait, on a Error1/3T3 Error2/5).

Kihara donne, en fait (en adaptant la preuve d'un article de Cenzer et Hinman dans un contexte un petit peu différent), le rapport précis entre les degrés T3 des oracles Errorm/k : il montre que Errorm/kT3 Error1/ := ⌈k/m⌉, la notation ⌈z⌉ désignant la partie entière supérieure de z (c'est-à-dire le plus petit entier supérieur ou égal à z), et que les Error1/ sont de degrés distincts (or est évident que Error1/T3 Error1/ si ′ ≤ ). Bref, finalement, Errorm′/kT3 Errorm/k se produit si et seulement si ⌈k′/m′⌉ ≤ ⌈k/m⌉.

Ce résultat est peut-être un peu décevant au sens où on pouvait espérer une structure plus riche et plus complexe. On peut se demander s'il existe des degrés T3 de nature complètement « combinatoire » (disons, des oracles basiques définies par un élément de 𝒫fin(𝒫fin(ℕ)) où 𝒫fin désigne l'ensemble des parties finies, c'est-à-dire que Nimué et Merlin ont chacun un nombre fini de choix) autres que ceux des Error1/ : je ne sais pas quelle est la réponse.

(Je me suis notamment demandé quel était le degré de l'oracle suivant : parmi les k éléments {0,…,k−1}, Nimué en exclut secrètement p, et Merlin montre q parmi les des kp restants à Arthur. Mais en fait, il est assez facile de voir que c'est le même que Errorp/(kq+1), donc finalement Error1/⌈(kq+1)/p : donc la généralité supplémentaire donnée par q n'apporte en fait rien de nouveau.)

Comme je l'ai expliqué ci-dessus, Error½ est du degré omniscient , donc permet d'implémenter n'importe quelle fonction ℕ⇢ℕ. D'après ce que j'ai dit, le plus puissant des Errorm/k après Error½ est Error1/3. Celui-ci n'apporte rien quand il s'agit de calculer une fonction déterministe ℕ⇢ℕ. En effet :

Proposition : si f:ℕ⇢ℕ (déterministe !) est telle que f ≼T3 Error1/3 (et, en particulier, si f ≼T3 Error1/ pour ≥3) alors f est, en fait, calculable. Autrement dit l'ensemble des degrés T1 majorés par le degré T3 de Error1/3 est réduit à {0}.

(Je fais la preuve de façon un peu précise parce que Kihara ne l'écrit pas. Voir le paragraphe suivant si on en veut juste un résumé.)

Preuve. Considérons une stratégie σ (calculable !) d'Arthur témoignant du fait que f ≼T3 Error1/3. On souhaite implémenter f algorithmiquement (sans oracle). Donnée une entrée n∈ℕ, considérons l'arbre ternaire 𝒯 suivant : Arthur joue selon σ en supposant que Merlin a joué n au coup initial, et, à chaque fois que (selon cette stratégie σ) Arthur fait appel à l'oracle, on crée un nœud dans l'arbre avec trois descendants en imaginant que la réponse de Merlin (visible d'Arthur) vaut 0, 1 ou 2, en continuant la construction de chaque sous-arbre d'après la réponse que σ préconise pour Arthur à ce coup de Merlin ; en revanche, si (toujours selon σ) Arthur déclare la fin du calcul avec une valeur v, on arrête la construction du sous-arbre en créant une feuille étiquetée par v. (Notons qu'il est possible que certains bouts de la construction de l'arbre ne terminent jamais, parce que certains coups de Merlin auraient été écartés par Nimué, mais comme on ignore les coups de Nimué on ne peut pas le savoir. Ce n'est pas grave.) L'hypothèse que σ est gagnante signifie qu'il y a un sous-arbre binaire 𝒯₂ de l'arbre 𝒯 que nous avons construit (sous-arbre correspondant à l'élimination d'une branche par Nimué à chaque nœud) qui soit fini et terminé par des feuilles étiquetées toutes par la même valeur f(n) — c'est là qu'on utilise le fait que f est déterministe. Ne voyant pas les coups de Nimué, on ne sait pas quel est ce sous-arbre 𝒯₂, mais on peut quand même calculer f(n) selon l'algorithme suivant : on lance la construction algorithmique de l'arbre 𝒯 qu'on vient de décrire (en simulant en parallèle toutes les branches possibles du calcul ; tout ceci est possible algorithmiquement car σ est calculable) et, dès qu'un nœud a deux de ses trois fils étiquetés par la même valeur, on étiquette ce nœud lui-même par cette valeur (et on arrête l'exécution de l'éventuel troisième sous-arbre). Par l'existence du sous-arbre binaire 𝒯₂ qui a été décrit, la racine de 𝒯 va finir par être étiquetée par une certaine valeur, et ceci est la valeur de f(n) recherchée. ∎

Résumé de la démonstration : on lance en parallèle tous les fils de calcul possibles en simulant les réponses de l'oracle Error1/3 et, comme à chaque appel, il y a deux des trois fils qui doivent terminer avec la même réponse, on peut se considérer comme satisfait à ce point.

En particulier, le problème de l'arrêt ne se réduit pas à Error1/3. En revanche, si on a lu la section plus haut sur le degré intermédiaire (ConsistLLPOLLPO⁺) entre 0 et le degré du problème de l'arrêt, il est intéressant de noter que ce degré-là se réduit bien à Error1/3 (en effet, mettons que je veuille réduire Consist à Error1/3 : donné un énoncé P, je demande à Error1/3 d'éliminer une des trois possibilités : ① P est un théorème, ② ¬P est un théorème, ou bien ③ P n'est ni l'un ni l'autre, i.e., est indécidable : si l'oracle élimine ① je réponds que ¬P est cohérent, si l'oracle élimine ② je réponds que P est cohérent, et si l'oracle élimine ③, je recherche en parallèle une démonstration de P et de ¬P avec la certitude que l'une des deux va terminer, et je renvoie l'énoncé en question). Ceci montre en particulier que le problème de l'arrêt ne se réduit pas à ConsistLLPOLLPO⁺ puisque ces derniers se réduisent à Error1/3 et que ce n'est pas le cas du problème de l'arrêt d'après la proposition précédente.

La proposition ci-dessus affirme que Error1/3 ne présente aucun intérêt pour calculer une fonction déterministe (niveau T1). Mais inversement, Error1/3 n'est pas non plus calculable par une fonction de niveau T1 (déterministe partielle ℕ⇢ℕ) ou même T2 (non-déterministe ℕ⇢𝒫(ℕ), en supposant bien sûr que cette dernière ne prend jamais la valeur ∅) : il n'existe pas de telle g tel que Error1/3T3 g. C'est facile à montrer, mais je pense que ça vaut la peine de faire l'exercice pour comprendre le sens qu'a cette affirmation : une telle réduction pour g déterministe voudrait dire qu'Arthur arriverait à éviter de façon certaine une valeur d∈{0,1,2} que Merlin lui a cachée, or Arthur ne peut pas voir d, et le fait d'avoir accès à une fonction g qui n'a aucun rapport avec le schmilblick ne l'aide pas à éviter d : il devra de toute façon renvoyer une valeur indépendante de d, et Merlin peut mettre en échec sa stratégie en choisissant justement cette valeur pour d ; et même si g n'est pas déterministe, ça n'aide pas Arthur, parce que si on avait Error1/3T3 g avec g non-déterministe alors on aurait à plus forte raison Error1/3T3 g₀ en appelant g₀ une fonction déterministe quelconque qui choisit une valeur particulière pour chaque ensemble de valeurs de g (que je rappelle que j'ai supposé ≠∅, parce que sinon la fonction est de degré , c'est-à-dire qu'Arthur gagne pour une raison idiote à savoir que Merlin ne peut pas jouer).

Plus généralement, un argument combinant les idées simples du paragraphe précédent avec celles de la démonstration de la proposition précédente (pour les détails, voir la preuve de la proposition 4.6 dans Lawvere-Tierney topologies for computability theorists) montre que Error1/ n'est pas réductible à la borne supérieure entre Error1/(+1) et une fonction non-déterministe g quelconque (supposée bien sûr avoir un ensemble ≠∅ de valeurs, comme ci-dessus). Je vais y revenir, mais comme dans les cas des degrés de Turing ordinaires, T1 et T2, la borne supérieure signifie en pratique qu'on a librement accès aux deux oracles considérés. Donc, concrètement, le fait d'avoir accès à Error1/(+1) et à g fonction non-déterministe quelconque ne permet pas d'implémenter Error1/.

L'oracle de Pitts

J'ai introduit ci-dessus l'oracle basique Error1/ qui permet à Arthur de demander d'écarter une possibilité parmi . Plus est grand, moins cet oracle est puissant. Je peux aussi mentionner Error1/ℕ qui est défini par l'élément 𝒫(𝒫(ℕ)) donné par l'ensemble des complémentaires de tous les singletons, i.e., Arthur demande à l'oracle d'éliminer un entier naturel : cet Error1/ℕ est intéressant parce qu'on peut montrer que son degré est le plus petit degré basique qui soit >0 (pour la preuve, voir Basic Subtoposes of the Effective Topos, proposition 5.5). Comme je l'ai montré plus haut, à part Error½ qui confère l'omniscience, aucun de ces oracles ne présente le moindre intérêt pour calculer une fonction déterministe.

On peut être tenté de penser que, plus généralement, aucun oracle basique ne présente d'intérêt pour calculer une fonction déterministe (niveau T1) sauf à être carrément omniscient. Il n'en est rien ! L'exemple qui suit montre qu'on peut avoir un oracle basique qui soit très puissant pour calculer les fonctions déterministes sans pour autant être omniscient.

L'oracle de Pitts est l'oracle basique Cofinite défini par l'élément de 𝒫(𝒫(ℕ)) donné par l'ensemble {{∈ℕ : c} : c∈ℕ} des demi-droites {∈ℕ : c} (dans le point de vue bicouche, c'est la fonction ℕ ⇢ 𝒫(ℕ) qui à c associe la demi-droite {∈ℕ : c}). Autrement dit : quand Arthur fait appel à cet oracle Cofinite, Nimué choisit un entier c∈ℕ, et Merlin montre à Arthur un entier c. Pourquoi cet oracle est-il très puissant ?

Pour l'illustrer (et montrer comment on se sert de Cofinite), expliquons pourquoi le problème de l'arrêt Halting est (T3-)réductible à Cofinite. Pour montrer HaltingT3 Cofinite, on doit donner une stratégie d'Arthur+Nimué (calculable de la part d'Arthur) permettant à Arthur d'annoncer, donné ⟨e,n⟩ choisi par Merlin, si φe(n)↓. La stratégie de Nimué est la suivante : donnés ⟨e,n⟩, elle regarde si φe(n)↓ (rappelons que Nimué peut jouer n'importe quelle stratégie, elle n'est pas tenue par une quelconque exigence de calculabilité) : si c'est le cas, elle joue pour c le nombre d'étapes d'exécution du calcul avant terminaison, tandis que si ce n'est pas le cas elle joue 0. La stratégie d'Arthur est la suivante : il prend note des valeurs ⟨e,n⟩ jouées par Merlin au premier coup, et il commence par interroger l'oracle (c'est un oracle basique, donc il n'a rien à dire) : Merlin lui renvoie une valeur  qui, par définition de Cofinite, est supérieure ou égale à la valeur c jouée par Nimué (et qu'Arthur ne peut pas voir) ; Arthur lance alors l'exécution de φe(n) pour étapes : si le calcul est fini après ce nombre d'étapes, alors Arthur répond que φe(n) termine (i.e., il déclare la fin du calcul avec la valeur de retour 1), tandis que si l'exécution n'a pas fini, il répond que φe(n) ne termine pas. Il est clair que cette stratégie fonctionne : tout ce dont Arthur a besoin pour savoir si φe(n)↓, c'est un majorant du nombre d'étapes sur lequel l'exécuter pour décider si le calcul termine, et c'est ce que Nimué lui fournit, via Merlin : tout ce que Merlin peut faire, c'est augmenter ce majorant, donc forcer Arthur à faire des calculs inutiles, mais sans impacter la justesse du résultat final. Ceci montre bien que HaltingT3 Cofinite, i.e., le degré T3 de Cofinite vaut au moins 0′.

Mais il n'y a pas de raison de s'arrêter là : puisque Arthur peut effectivement utiliser Cofinite pour simuler une machine de Turing ayant accès à l'oracle de l'arrêt, on peut refaire le même argument sur ce type de machines (en comptant la consultation de l'oracle comme une seule « étape » : Nimué ne peut pas savoir combien ça en prendra vraiment à simuler parce que ça dépend du coup de Merlin, mais ce n'est pas important), et ceci montre que le degré T3 de Cofinite vaut au moins 0′′, et en refaisant ce raisonnement, 0′′′ « et ainsi de suite ». Bien sûr, le ainsi de suite finit par s'arrêter, mais l'analyse de comment il s'arrête exactement dépasse le cadre de ce billet de blog : disons juste que les fonctions calculables (totales, déterministes) ℕ→ℕ calculables avec Cofinite (c'est-à-dire, réductibles à lui) sont les fonctions dites hyperarithmétiques, un concept que j'avais tenté d'expliquer il y a quelques années. Mais peut-être que la présentation en question (les fonctions calculables au moyen de l'oracle de Pitts) est en fait la façon la meilleure ou la plus élégante d'expliquer ce qu'est une fonction hyperarithmétique !

Les oracles Error1/ (pour ≥3 fixé) et Cofinite ne sont pas comparables : d'un côté, Cofinite n'est certainement pas réductible à Error1/3 (et a foriori Error1/ pour ≥3) car on a vu que Error1/3 ne permet pas de calculer le problème de l'arrêt ; de l'autre côté (en considérant un analogue de LLPO pour les machines hyperarithmétiques, cf. le corollaire 5.13 dans Lawvere-Tierney topologies for computability theorists) on peut montrer que Error1/ n'est pas non plus réductible à Cofinite. Ceci montre qu'il existe au moins deux degrés basiques incomparables.

Kihara définit encore d'autres oracles basiques, par exemple celui qu'il note DenErrorε pour ε≥0, et qui peut se décrire brièvement ainsi : Nimué choisit une partie de ℕ de densité asymptotique inférieure ≥ 1−ε, et Merlin choisit un entier dans cette partie (donc même pour ε, qui est le plus faible de tous, c'est déjà au moins aussi fort que l'oracle de Pitts Cofinite). Mais je pense que j'en ai ai assez dit, donc je m'arrête ici.

Bornes sup et inf binaires sur les degrés T3

Comme pour les degrés de Turing ordinaires, T1 et T2, la borne supérieure de deux degrés T3 ne pose pas de problème : données deux fonctions avec conseil a et b, on en définit une qui consiste à permettre à Arthur de choisir s'il veut interroger a ou b (dans le point de vue parties ℕ→𝒫(𝒫(ℕ)), on posera simplement c(⟨0,m⟩)=a(m) et c(⟨1,m⟩)=b(m), et, disons, c(n)=∅ pour toute autre valeur ; dans le point de vue bicouche ℕ×Λ ⇢ 𝒫(ℕ), on peut d'abord passer à un Λ commun et ensuite définir c(⟨0,m⟩|c) = a(m|c) lorsque celle-ci est définie et c(⟨1,m⟩|c) = b(m|c) lorsque celle-ci est définie, et toute autre valeur indéfinie). Ceci définit bien la borne supérieure des degrés comme on l'attend, et il n'y a pas de surprise particulière ; l'opération de borne supérieure binaire est la même entre les degrés de Turing ordinaires, T1, T2 et T3.

Pour la borne inférieure, la même construction que pour les degrés T2 (qui est elle-même une variation de celle pour les degrés T1) va fonctionner, mais elle mérite un petit peu plus de soin dans l'exposition.

Je rappelle que, pour une fonction g : ℕ⇢ℕ (partielle déterministe, c'est-à-dire du niveau T1), j'ai défini plus haut une fonction ⌘g : ℕ⇢ℕ (ma notation !) qui consiste à faire tourner la machine de Turing universelle ayant accès à g comme oracle ; cette fonction est de même degré T1, mais la construction a un certain nombre d'intérêts, notamment de permettre de définir la borne inférieure des degrés T1 (je rappelle : c(⟨m₁,m₂⟩) est égale à la valeur commune de ⌘a(m₁) et de ⌘b(m₂) si ces deux valeurs sont toutes les deux définies et sont égales, et n'est pas définie sinon). Au niveau T2, la construction ⌘g fonctionne en gros pareil (elle va renvoyer de façon non-déterministe une valeur possible renvoyée par le plan d'exécution passé en argument, selon les différentes valeurs possibles de g à chaque appel — bref, « ce qu'on attend » de l'exécution d'une machine faisant appel à un oracle non-déterministe).

Mais si g est une fonction avec conseil, quel sens donner à ⌘g (Kihara note ça g) ? Ici, le point de vue bicouche sera plus agréable, donc supposons donnée g : ℕ×Λ ⇢ 𝒫(ℕ), et on veut définir une fonction ⌘g : ℕ×Λ′ ⇢ 𝒫(ℕ).

Pour la définir, on va considérer le jeu (explicité plus haut) qui a servi à définir la notion de réduction f ≼T3 g, à une petite modification près : il n'y a pas de fonction f dans la variante considérée maintenant ; du coup, au premier coup, Merlin peut jouer n'importe quel (n|d) (il n'y a pas de contrainte que f(n|d) soit définie puisque la fonction f n'existe pas), et, quand Arthur déclare la fin du calcul avec une valeur k, il a gagné (il n'y a pas la contrainte que k ∈ f(n|d)), et cette valeur k sera appelée la sortie du jeu (i.e., de la partie considérée). (Si on préfère, il revient au même de considérer le jeu d'origine pour la fonction f qui prend toutes les valeurs entières en toute valeur. Manifestement, Arthur a toujours une stratégie gagnante au jeu ainsi modifié puisqu'il peut juste immédiatement déclarer la fin du calcul avec la valeur 42.)

Bref, les entrées de la fonction ⌘g seront les suivantes : (⟨e,n⟩ | (σ,d)) où :

  • e est le code d'une stratégie calculable d'Arthur, c'est-à-dire un programme qui prend en entrée (le codage de) la liste des coups antérieurs visibles par Arthur, et qui renvoie un coup d'Arthur en réponse (si le programme ne termine pas, bien sûr, Arthur est considéré comme ayant perdu par forfait) ;
  • n est un entier naturel qui sera la partie visible du premier coup joué par Merlin (ce paramètre ne sert à rien, on aurait pu décider que Merlin ne joue pas initialement, ou joue forcément 0, ou quelque chose comme ça, mais je l'inclus par cohérence avec le fait que mes machines universelles prennent le codage d'un couple ⟨e,n⟩ en entrée : si ce n vous embrouille, oubliez-le) ;
  • σ est une stratégie de Nimué, c'est-à-dire une fonction (pas forcément calculable !) qui, en fonction de la liste de tous les coups antérieurs, et qui renvoie un coup de Nimué en réponse ;
  • d est un élément d'un certain ensemble Θ qui sera la partie secrète du premier coup joué par Merlin (ce paramètre ne sert à rien non plus, il est juste là pour la cohérence des définitions, et on me pardonnera d'ignorer le petit tracas que Θ devrait être explicité dans la notation ⌘g : ça n'aura aucune importance ; comme pour n, si ce d vous embrouille, oubliez-le).

La fonction ⌘g est définie en (⟨e,n⟩ | (σ,d)) lorsque Arthur+Nimué gagnent le jeu (modifié !, c'est-à-dire sans fonction f) en jouant selon e et σ dès que Merlin commence par jouer (n|d), autrement dit, quels que soient les coups de Merlin après le premier coup (n|d), si Arthur joue selon e et Nimué joue selon σ, alors Arthur+Nimué gagnent (au jeu modifié !), c'est-à-dire qu'Arthur finit par déclarer la fin du calcul. Lorsque c'est le cas, l'ensemble des valeurs de ⌘g est l'ensemble de toutes les sorties possibles du jeu (c'est-à-dire, en considérant tous les coups possibles de Merlin).

Si on n'aime pas les paramètres n et d, on peut les supprimer et décider que dans le jeu modifié, Merlin ne joue pas son premier tour (le jeu commence avec alors un coup d'Arthur). J'ai mis n et d dans l'histoire surtout pour éviter d'avoir à changer le jeu plus que nécessaire, et pour pouvoir faire l'affirmation assez simple qui se situe deux paragraphes plus bas.

Bref, l'idée est toujours la même : ⌘g prend en argument un « plan d'interrogation de l'oracle », mais cette fois le plan d'interrogation, au lieu de concerner le seul Arthur, implique aussi Nimué, c'est-à-dire qu'il s'agit d'une stratégie pour chacun des deux, avec les contraintes le concernant (et, pour des raisons de cohérence avec ce qui précède, j'ai aussi inclus un coup initial de Merlin, mais je répète que ce n'est pas ce qui est important dans l'histoire).

Pour qu'il n'y ait pas de doute que les définitions sont cohérentes entre elles, la réduction f ≼T3 g définie plus haut signifie exactement, et par définition, qu'il existe e et σ tels que pour tout (n|d) du domaine de définition de f on ait ⌘g(⟨e,n⟩|(σ,d)) défini et ⊆ f(n|d).

Comme dans le cas T1 ou T2, on a g ≡T3 ⌘g : le fait que g ≼T3 ⌘g est évident (Arthur et Nimué construisent chacun la stratégie consistant à lancer une unique interrogation de l'oracle sur la valeur en laquelle ils cherchent à évaluer g, et soumettent cette stratégie à ⌘g). Mais pour voir que ⌘g ≼T3 g, en fait, c'est évident aussi : dans le jeu de réduction, la définition de ⌘g fait que Merlin soumet, au premier tour, une stratégie gagnante pour Arthur et (de façon non visible d'Arthur) une stratégie gagnante pour Nimué : les joueurs ont donc simplement à appliquer la stratégie gagnante que leur adversaire leur fournit obligeamment !

Une fois qu'on a cette construction ⌘g, on peut définir la borne inférieure de deux degrés comme précédemment : c(⟨m₁,m₂⟩|(ϑ₁,ϑ₂)) est égale à la réunion disjointe étiquetée de ⌘a(m₁|ϑ₁) et de ⌘b(m₂|ϑ₂) si ces deux valeurs sont toutes les deux définies. Pour dire les choses de façon plus intuitive : pour jouer au jeu correspondant à c, Arthur soumet une stratégie (calculable) d'interrogation de a et une stratégie (calculable) d'interrogation de b, et Nimué soumet des stratégies secrètes correspondantes, et Merlin choisit entre les deux, et renvoie une valeur correspondant soit à a soit à b, avec l'indication de laquelle il a choisi, où Arthur et Nimué ont joué selon les stratégies fournies. C'est exactement l'analogue de ce qu'on a fait au niveau T2 mais avec la complication qu'il faut ajouter les stratégies de Nimué partout.

Négation et opération de Heyting

Je mets cette section en petits caractères parce que je n'ai pas eu le temps d'y réfléchir correctement, et on peut la sauter.

L'ensemble des degrés T3 n'est pas juste un treillis (ensemble partiellement ordonné munis de bornes sup et inf binaires) mais une algèbre de Heyting : je n'ai pas envie d'expliquer exactement de quoi il s'agit (voyez Wikipédia si vous voulez une définition), néanmoins, il est intéressant de noter l'existence de l'opération de Heyting et d'expliciter sa construction.

Commençons par le cas de la négation (pseudocomplément) : si a est un degré T3, il y a un plus grand degré T3 c tel que ac=0, où ‘∧’ désigne la borne inférieure binaire évoquée à la section précédente ; on peut le noter ¬a. Je vais tâcher de décrire comment ce degré ¬a. Supposons a représentée par une fonction bicouche a : ℕ×Λ ⇢ 𝒫(ℕ) ; pour commencer, on va remplacer a par la version « universelle » ⌘a : ℕ×Λ ⇢ 𝒫(ℕ) (ce n'est plus le même Λ mais peu importe), dont je rappelle qu'elle a le même degré (a) que a mais qu'elle prend en entrée une stratégie calculable d'Arthur et une stratégie de Nimué (telles que quoi que fasse Merlin, Arthur finit en temps fini par déclarer la fin du calcul), et renvoie l'ensemble des valeurs renvoyées possibles (selon ce que fait Merlin). J'avoue ne pas avoir bien réfléchi à la question de savoir si on a vraiment besoin de remplacer a par ⌘a dans ce que je vais dire.

On va appeler simulateur (partiel) de ⌘a un programme qui prend en entrée un entier m et doit renvoyer soit échec soit réussite accompagné d'un entier qui appartienne à ⌘a(m|ϑ) quel que soit ϑ (autrement dit, le simulateur cherche à calculer une valeur ∈ ⋂ϑ ⌘a(m|ϑ), c'est-à-dire une valeur que Merlin peut toujours faire donner au calcul quel que soit le jeu de Nimué pour la stratégie m d'Arthur passée en argment). Mais peut-être qu'il vaut mieux penser aux niveaux intermédiaires avant de passer à T3. Au niveau T1, le simulateur prend en entrée un plan d'interrogation de l'oracle a (valable, c'est-à-dire ne posant jamais de question interdite et terminant en temps fini), c'est-à-dire, je rappelle, un programme ayant accès à a comme oracle (ainsi qu'une valeur à passer en entrée à ce programme, mais peu importe), et le simulateur doit renvoyer la valeur que renverrait le plan avec le vrai oracle, s'il le peut (ou bien avouer son échec). Au niveau T2 (non-déterministe), le simulateur doit renvoyer une valeur que donnerait le vrai oracle (ou bien déclarer son échec). Au niveau T3 (avec conseil), le simulateur a la tâche essentiellement impossible de simuler l'action de Nimué (qui ne lui est même pas fournie en paramètre, et on voit mal comment elle pourrait l'être), donc sa seule façon de réussir est de renvoyer une valeur compatible avec n'importe action possible de Nimué. Bref, évidemment, dès que a>0 un simulateur devra parfois avouer son échec. Pour être bien clair, notons qu'un simulateur n'a pas le droit de se tromper : il doit soit déclarer la réussite avec une bonne valeur au sens que je viens d'expliquer, soit déclarer son échec.

Maintenant la fonction c : ℕ ⇢ 𝒫(ℕ) (de niveau T2, c'est-à-dire sans conseil de Nimué) définissant le pseudocomplément ¬a de a est la suivante : elle prend en entrée un simulateur de ⌘a comme je viens de le définir, et elle renvoie un échec du simulateur, c'est-à-dire une valeur m pour laquelle le simulateur déclare un échec. (Lorsque a=0, c'est-à-dire que a est calculable, ce n'est pas possible, il y a des simulateurs sans échecs, et dans ce cas bien sûr c est le degré omnipotent , seul capable de renvoyer un élément de l'ensemble vide.)

Expliquons pourquoi ac=0, c'est-à-dire que le degré en question est calculable. Je rappelle que pour interroger ac on doit fournir un plan d'interrogation de a et un plan d'interrogation de c. Pour réaliser l'oracle de façon calculable, on va suivre le plan d'interrogation de c : à chaque appel qu'il fait à l'oracle, il doit fournir un simulateur de ⌘a, qu'on peut justement appliquer au plan d'ingerrogation de a : soit le simulateur réussit, soit il échoue ; si l'un quelconque réussit, on est capable de fournir la réponse au plan d'interrogation de a (justement par ce simulateur), et si tous échouent, ceci fournit une réponse au plan d'interrogation de c. Mais a contrario, si un degré c₁ est tel que ac₁=0, alors on peut se convaincre que c₁≼c : en effet, d'un moyen de calculer ac₁, on peut en déduire (algorithmiquement) un simulateur partiel de ⌘a, consistant à utiliser ce moyen de calcul pour simuler soit ⌘a soit ⌘c₁, et dans le second cas déclarer un échec : alors on a une réduction de c₁ à c consistant à chercher un échec de ce simulateur (je laisse les détails en exercice). Bref, le c =: ¬a qu'on a défini est bien le plus grand degré tel que ac soit calculable.

Malheureusement, si la construction est intéressante (et, je trouve, assez élégante), je ne suis pas sûr que le résultat le soit vraiment. En effet, dans beaucoup de cas, on a tout simplement c=0, c'est-à-dire qu'on peut algorithmiquement trouver un échec d'un simulateur proposé. Notamment, si a est une fonction ℕ→ℕ (totale !) qui n'est pas calculable, c'est facile : il suffit de demander au simulateur de simuler les appels simples a(0), a(1), a(2), successivement, jusqu'à en trouver un qui soit un échec, et renvoyer celui-là (il y a forcément un échec, sinon a serait calculable) : ceci montre que dès que a>0 est représentée par une fonction ℕ→ℕ totale, il a pour pseudocomplément ¬a = 0. Plus généralement, si je ne m'abuse, ça montre la même chose pour une fonction a : ℕ → 𝒫(ℕ) (c'est-à-dire non-déterministe mais totale — sans question interdite), ou même ℕ×Λ ⇢ 𝒫(ℕ) telle que pour tout m il existe ϑ tel que a(m|ϑ) soit définie (et tout ça toujours sous l'hypothèse que le degré de a est >0). En particulier, qu'il s'agisse de l'oracle de l'arrêt, de l'oracle Error1/ (ou même Error1/ℕ), leur pseudocomplément est simplement 0. Je soupçonne qu'il existe des oracles (représentés par des fonctions partielles ℕ⇢ℕ) non calculables et dont le pseudocomplément ne l'est pas non plus, mais je ne sais pas le prouver, et je ne sais pas non plus s'il en existe qui soient intéressants.

Quant à l'opération de Heyting, c'est un pseudocomplément relatif à un autre degré b : si a et b sont deux degrés T3, il existe un grand degré T3 c tel que ac ≤ b ; on peut le noter ab. La description explicite est en gros la même que ce que je viens de faire pour le pseudocomplément, à ceci près qu'on considère des simulateurs (partiels) de ⌘a relativement à b, c'est-à-dire qu'ils disposent de l'oracle b (représentant le degré b) ; il y a juste une petite chose à changer : en cas d'échec, le simulateur renvoie une valeur d'échec (pas juste le mot échec), et l'oracle c fournit non pas juste une valeur d'entrée du simulateur qui conduit à un échec, mais la valeur de sortie (enfin, une valeur de sortie possible compatible avec cette valeur d'entrée) aussi : dans le cas b=0 décrit ci-dessus ceci n'a pas d'importance, mais dans le cas relatif c'est important pour assurer que c permet au moins tous les calculs que b permet (il suffit d'écrire un simulateur qui échoue toujours, fait le calcul qu'il a envie de faire, et déclare un échec avec le résultat du calcul), bref, on a bien cb. Je n'ai pas réfléchi plus que ça à cette opération de Heyting.

Dessert : une autre présentation : les opérateurs effectifs locaux

Bon, j'ai défini des degrés T1, T2 et T3 généralisant les degrés de Turing, mais en quoi sont-ce des « bonnes » généralisations ? Si les fonctions partielles et le non-déterminisme sont sans doute assez naturelles, c'est déjà moins clair que tout le jeu Arthur-Nimué-Merlin soit raisonnable, et rien que pour les fonctions partielles il y a au moins six généralisations des degrés de Turing à leur niveau, alors pourquoi prendre précisément celle que j'ai décrite pour les degrés T1 ?

Une justification convaincante qu'on a fait « la bonne chose » vient, il me semble, de la description par opérateurs effectifs locaux.

Avant de définir ce que ce sont, je dois introduire la notation suivante : si P,Q∈𝒫(ℕ) sont deux ensembles d'entiers naturels, alors PQ (avec une flèche triple ; la notation est de moi) désignera l'ensemble des codes des programmes qui, si on leur fournit un élément de P en entrée terminent en temps fini et renvoient un élément de Q (c'est-à-dire { e∈ℕ : ∀nP. (φe(n)↓ et φe(n)∈Q) } = { e∈ℕ : φe définit une fonction (totale) PQ }).

Un opérateur effectif local (ce terme n'est pas franchement standard) est une application J : 𝒫(ℕ) → 𝒫(ℕ) vérifiant les trois propriétés suivantes :

  • il existe un élément dans ⋂P,Q∈𝒫(ℕ) ((PQ) ⇛ (J(P)⇛J(Q))) (condition de monotonie pour ‘⇛’),
  • il existe un élément dans ⋂P∈𝒫(ℕ) (PJ(P)) (condition d'inflation),
  • il existe un élément dans ⋂P∈𝒫(ℕ) (J(J(P)) ⇛ J(P)) (condition d'idempotence) ;

et de plus, si J₁ et J₂ sont deux tels opérateurs, on note J₁ ≼ J₂ lorsqu'il existe un élément dans ⋂P∈𝒫(ℕ) (J₁(P) ⇛ J₂(P)), et J₁ ≡ J₂ lorsque J₁ ≼ J₂ et J₂ ≼ J₁.

On pourrait vouloir ajouter la condition que si PQ alors J(P)⊆J(Q), i.e., que J est monotone pour l'inclusion : on va voir que cette condition ne change rien d'important (les opérateurs effectifs locaux qu'on fabriquera à partir d'oracles seront automatiquement monotones pour l'inclusion, et tout opérateur effectif local sera équivalent à un autre qui est monotone pour l'inclusion).

Je dois maintenant expliquer pourquoi cette définition est intéressante et quel est le rapport avec ce que j'ai raconté avant ! (Divulgâchis : les classes d'équivalence pour ≡ des opérateurs effectifs locaux vont être exactement les degrés T3, avec le même ordre.)

Donnons trois exemples vraiment idiots avant d'aller plus loin : l'identité PP est un opérateur effectif local (c'est le plus petit au sens de ‘≼’, et il correspondra à un oracle trivial, c'est-à-dire au degré 0) ; l'application P↦ℕ est un opérateur effectif local (c'est le plus grand au sens de ‘≼’, et il correspondra au degré « omnipotent », c'est-à-dire celui que j'ai noté ) ; et, de façon un petit peu moins inintéressante, l'application ‘¬¬’ donnée par ∅↦∅ et P↦ℕ pour P≠∅ est aussi un opérateur effectif local (sa classe est la plus grande après le précédent, et il correspondra au degré « omniscient », c'est-à-dire celui que j'ai noté ).

L'idée intuitive d'un opérateur effectif local est la suivante : vous disposez d'un certain moyen de calcul et vous devez résoudre un problème dont l'ensemble des solutions est P⊆ℕ (i.e., votre but est de produire un élément quelconque de P) : l'ensemble J(P) est l'ensemble des programmes pour ce moyen de calcul qui résolvent ce problème, i.e., produisent un élément de P. La première condition demande essentiellement qu'une transformation réalisable par une machine de Turing soit réalisable par notre moyen de calcul (si je sais algorithmiquement transformer un élément de P en élément de Q, alors je sais — algorithmiquement et uniformément en P et Q — transformer une façon de produire un élément de P avec le moyen de calcul considéré en une façon de produire un élément de Q). La seconde demande que le moyen de calcul permette de calculer n'importe quoi dont on ait déjà la réponse, i.e., une solution permet de produire une solution (je sais algorithmiquement et uniformément en P transformer un élément de P en une façon de produire un élément de P avec le moyen de calcul considéré). La troisième demande qu'une façon de produire une façon de produire une solution soit une façon de produire une solution (je sais algorithmiquement et uniformément en P transformer une façon de produire une façon de produire un élément de P en une façon de produire un élément de P avec le moyen de calcul considéré).

Je vais donner des exemples d'opérateurs effectifs locaux qui convaincront, j'espère, que c'est une notion naturelle, mais je peux aussi signaler que la définition est fortement évocatrice de diverses notions standard en mathématiques. Si on c'est ce qu'est une topologie de Lawvere-Tierney et ce que c'est que le topos effectif (p.ex., si on a lu mon billet à son sujet), les classes d'équivalence (pour ‘≡’) des opérateurs effectifs locaux sont exactement les topologies de Lawvere-Tierney sur le topos effectif (et du coup, le théorème plus bas va dire que les degrés T3 peuvent s'identifier aux topologies de L-T sur le topos effectif, ce qui est la punchline de Kihara).

Mais on peut aussi, pour les gens qui savent ce que c'est, justifier les trois conditions ci-dessus en évoquant la notion de monade en théorie des catégories ou en informatique (c'est bien la même notion, mais dans un contexte différent). Par exemple, si on est familier avec Haskell, les trois éléments dont l'exigence est demandé ci-dessus sont à rapprocher respectivement primo de fmap = \f -> \x -> (do z <- x ; return (f z)) :: (p -> q) -> m p -> m q pour le témoin de la monotonie, secundo de return :: p -> m p pour le témoin de l'inflation, et tertio de \x -> (do z <- x ; z) :: m (m p) -> m p pour le témoin de l'idempotence ; tandis que si on préfère les monades au sens des catégories, on doit rapprocher nos opérations de la fonctorialité, de l'unité et de la multiplication d'une monade. (Normalement il y aurait des contraintes de compatibilité à demander entre ces différents objets, mais en fait, ici, les contraintes de compatibilité n'apporteront rien de plus. Je précise que mes explications relatives aux monades sont plus une analogie qu'une explication précise, parce que je n'ai pas envie d'expliquer exactement — et je ne suis d'ailleurs pas sûr de savoir au juste — sur quoi on a affaire à une monade. L'idée est juste de dire que ces trois conditions sont naturelles, et reviennent souvent sous différentes variations.)

Bon, mais quel rapport avec les oracles ?

Plaçons-nous d'abord au niveau des degrés de Turing ordinaires, pour que ce soit un peu plus simple : si a:ℕ→ℕ est une fonction quelconque, je peux définir un opérateur effectif local Ja : 𝒫(ℕ) → 𝒫(ℕ) (que Kihara note a⅁→, pour moi ce serait plutôt (⌘a) ou quelque chose comme ça du coup) : à savoir, Ja(P) est l'ensemble des m = ⟨e,n⟩ tels que φea(n)), c'est-à-dire le résultat de l'exécution du e-ième programme sur l'entrée n pour une machine de Turing ayant accès à a comme oracle, ou avec ma notation précédente, ⌘a(m), soit défini et appartienne à P. C'est donc bien ce qu'on peut qualifier d'une façon de produire un élément de P avec a comme oracle. Et il est facile de voir que les trois conditions demandées sont bien satisfaites pour ce Ja : primo, donné un élément de PQ et un de Ja(P) je peux fabriquer la machine avec oracle qui exécute d'abord le second argument puis lui applique le premier (qui n'a pas besoin de l'oracle mais peu importe) ; secundo, donné un élément de P je peux fabriquer la machine avec oracle qui renvoie précisément cette valeur ; et tertio, donné une machine avec oracle qui calcule une machine avec oracle, je peux faire une machine avec oracle qui exécute ce calcul et l'exécute ensuite sur la machine universelle. Bref, toute fonction a:ℕ→ℕ donne naissance à un opérateur effectif local Ja. Et il est également facile de voir que si a₁ ≼ a₂ pour la réduction de Turing (i.e. ‘≼T’), alors JaJa (si on peut calculer a₁ avec a₂, on peut algorithmiquement convertir un programme utilisant a₁ en un programme utilisant a₂).

Au niveau T1, c'est exactement la même chose. Au niveau T2 (l'oracle a est non-déterministe), il faut modifier la définition de Ja ainsi : Ja(P) est l'ensemble des m tels que ⌘a(m) soit défini et inclus dans P, i.e., l'ensemble des valeurs que le calcul peut renvoyer (selon les choix faits par le non-déterminisme, par Merlin si on veut) est inclus dans P ; bref, l'ensemble des plans d'interrogation de l'oracle qui garantissent de tomber sur une réponse dans P. Et au niveau T3, si je pars d'une fonction bicouche a : ℕ×Λ ⇢ 𝒫(ℕ), on définit Ja comme ceci : Ja(P) est l'ensemble des m tels qu'il existe ϑ tel que ⌘a(m|ϑ) soit défini et inclus dans P. Autrement dit, Ja(P) est l'ensemble des stratégies d'Arthur telles qu'il existe une stratégie de Nimué pour l'aider et qui assurent ensemble que, quoi que fasse Merlin, Arthur déclarera la fin du calcul sur une valeur dans P. Comme dans le cas des degrés de Turing ordinaires, pour les degrés T1, T2 et T3, ce Ja vérifie les trois conditions définissant un opérateur effectif local, et de plus si a₁ ≼ a₂ (où ‘≼’ signifie ‘≼T3’) alors JaJa.

Une chose qui diffère selon qu'on était parti du niveau T1, T2 ou T3, c'est qu'au niveau T1 la fonction Ja définie ci-dessus (et qui est essentiellement juste l'image réciproque par ⌘a) préserve les réunions et intersections quelconques ; au niveau T2, elle préserve les intersections quelconques mais pas forcément les réunions ; au niveau T3, en revanche, elle ne préserve pas forcément ni l'un ni l'autre. (Par ailleurs, à n'importe quel niveau, le Ja fabriqué est monotone pour l'inclusion en plus d'être monotone pour ‘⇛’, mais peu importe.)

Maintenant, ce qui rend la construction aJa intéressante, c'est qu'il y a une réciproque, au moins à équivalence près : donné un opérateur effectif local J, on définit une fonction aJ : ℕ×Λ ⇢ 𝒫(ℕ) (que Kihara note J), avec Λ := 𝒫(ℕ), de la façon suivante : la fonction aJ est définie en (m|c) exactement lorsque m ∈ J(c) et dans ce cas elle vaut c (c'est-à-dire que c est l'ensemble des valeurs possibles). Autrement dit : pour interroger cet oracle, Arthur choisit un entier m, Nimué choisit une partie c⊆ℕ vérifiant la condition m ∈ J(c), et Merlin choisit un élément de cette partie c (qui est la valeur renvoyée par l'oracle). Notons que si J préserve les intersections quelconques, alors Nimué a un choix évident (si tant est qu'elle en ait un), qui est de prendre le plus petit c possible : on peut alors directement au niveau T2 définir aJ : ℕ ⇢ 𝒫(ℕ) qui à m associe l'intersection de tous les c tels que m ∈ J(c) (s'il y en a au moins un, et non défini sinon) ; et si J préserve aussi les réunions quelconques, alors on peut directement au niveau T1 définir aJ : ℕ⇢ℕ qui à m associe le ∈ℕ tel que m ∈ J({}) s'il existe. Il est facile de voir que si J₁ ≼ J₂ alors aJaJ (où ‘≼’ signifie ‘≼T3’ dans la conclusion).

Les deux opérations aJa et JaJ sont essentiellement réciproques l'une de l'autre au sens suivant. Partant de a : ℕ×Λ ⇢ 𝒫(ℕ), si on construit le J := Ja qui lui correspond et qu'on refait l'autre opération pour fabriquer b := aJ, on tombe sur ⌘a à un reparamétrage près sur le second argument qui est de toute façon sans importance (je crois qu'on tombe sur (⌘a)ˇˆ avec les notations que j'ai introduites plus haut, mais peu importe), en tout cas c'est Turing-équivalent (enfin, T3-équivalent) à a. Dans l'autre sens, partant de J : 𝒫(ℕ) → 𝒫(ℕ), si on construit le a := aJ qui lui correspond et qu'on refait l'autre opération pour fabriquer K := Ja, on obtient K(P) = ⋃P₀⊆P J(P₀) (si on veut, K est le plus petit opérateur effectif local qui soit monotone pour l'inclusion et qui contienne J). Or KJ : le fait que JK est clair (un programme codant la fonction identité est dans ⋂P∈𝒫(ℕ) (J(P) ⇛ K(P))) ; pour voir qu'on a KJ, on utilise un élément de ⋂P₀,P∈𝒫(ℕ) ((P₀⇛P) ⇛ (J(P₀)⇛J(P))) dont l'existence est garantie par la première condition (monotonie en ‘⇛’) de la définition de J et on l'applique à un programme codant la fonction identité qui est donc dans (P₀⇛P) pour tous P₀⊆P : ceci fournit un élément de ⋂P₀⊆P (J(P₀) ⇛ J(P)) donc de ⋂P∈𝒫(ℕ) (K(P) ⇛ J(P)).

Pour résumer :

Théorème (Kihara) : Les applications aJa et JaJ définissent des bijections réciproques croissantes entre l'ensemble des degrés T3 et l'ensemble des classes d'équivalence (pour ‘≡’) des opérateurs effectifs locaux, et celles-ci préservent l'ordre partiel. De plus, les degrés T2 correspondent par cette bijection aux classes des opérateurs effectifs locaux qui préservent ⋂, et les degrés T1 correspondent aux classes de ceux qui préservent à la fois ⋂ et ⋃.

Pour défendre l'idée que les degrés T3 sont un objet d'étude intéressant et naturel, je peux donc invoquer cette présentation par les opérateurs effectifs locaux : d'une part ces opérateurs effectifs locaux sont quelque chose qui a été étudié pour d'autres raisons (ce sont les topologies de Lawvere-Tierney sur le topos effectif, c'est-à-dire les sous-topos de ce dernier, si on sait ce que tout ça veut dire), d'autre part leur définition est de toute façon assez naturelle (cf. ce que j'ai dit plus haut sur les monades), et enfin, si on convient que les degrés T1 et T2 sont des objets d'étude assez naturels, les degrés T3 apparaissent comme leur généralisation la plus évidente à travers le point de vue des opérateurs effectifs locaux (retirer la condition de préserver l'intersection).

En revanche, les degrés de Turing ordinaire ne semblent pas pouvoir se traduire par une condition facile sur les opérateurs effectifs locaux. (C'est, du moins, une question que pose Kihara dans son article d'arriver à les caractériser à ce niveau.)

Normalement je devrais écrire une section ici, s'adressant aux gens qui savent déjà ce qu'est un topos (élémentaire) et une topologie de Lawvere-Tierney, et/ou qui ont lu mon billet sur le topos effectif, pour expliquer comment voir le topos défini par un opérateur effectif local J : c'est le topos des faisceaux pour J vu comme une topologie de Lawvere-Tierney sur le topos effectif, qu'on peut décrire de diverses manières, notamment directement en reprenant la définition du topos effectif et en saupoudrant des J aux bons endroits, ou, je pense, en reprenant la définition et en remplaçant calculable par calculable avec l'oracle a un peu partout. Mais j'avoue ne pas avoir la patience d'écrire tout ça, de trouver les bons endroits où mettre les J ni de faire toutes les vérifications pour savoir si ça marche de remplacer calculable par calculable avec l'oracle a quasi aveuglément. Il reste certain que pour chaque J on a un analogue naturel du topos effectif (mais qui est un sous-topos de celui-ci) défini par J : notamment, lorsque J est ‘¬¬’, défini par ∅↦∅ et P↦ℕ pour P≠∅, ou, ce qui revient au même, JError½, le topos en question est simplement le topos des ensembles ; mais en général, on obtient un topos intermédiaire entre le topos effectif et le topos des ensembles (sauf bien sûr le cas idiot où on obtient le topos trivial).

En guise de prolongement : quelques choses que je n'ai pas abordées

Réduction de Weihrauch

J'ai raconté tout ce qui précède en mettant au centre de mon propos la réduction de Turing : c'est-à-dire (cf. mon autre billet à ce sujet) que les oracles peuvent être interrogés de façon illimitée. Mais on peut aussi faire le même genre de jeu avec la réduction de Weihrauch, c'est-à-dire avec des oracles qu'on a le droit d'interroger une et une seule fois (et même qu'on doit interroger une fois, ce qui n'est pas anecdotique parce que si l'oracle a des questions interdites ce n'est pas forcément évident de trouver une question qui n'est pas interdite ! notamment, interroger un oracle qui vous tue quelle que soit la question que vous posez n'est pas un cadeau).

Si on s'intéresse à la réduction de Weihrauch au lieu de Turing, les fonctions auxquelles on a affaire aux niveaux T1, T2 et T3, qu'il faudrait du coup peut-être plutôt appeler W1, W2 et W3, sont les mêmes, mais la réduction est différente : dans le jeu entre Arthur+Nimué et Merlin, le nombre de coups sera limité : Merlin joue d'abord (pour lancer le défi à calculer), puis Arthur puis Nimué (pour poser une question à l'oracle), puis Merlin (qui fournit la réponse de l'oracle) et enfin Arthur (qui doit déclarer la fin du calcul exactement à ce coup-là). Essentiellement tout ce qui concerne l'opération ‘⌘’ disparaît de l'histoire, et les choses sont globalement plus simples mais aussi, à mon avis, moins intéressante (l'équivalence de Weihrauch étendue W1, W2 ou W3 est beaucoup plus fine que l'équivalence de Turing T1, T2 ou T3, mais il me semble qu'elle est trop fine pour que les problèmes soient vraiment intéressants).

On peut trouver une correspondance avec des fonctions 𝒫(ℕ) → 𝒫(ℕ) analogues aux opérateurs effectifs locaux que j'ai décrits dans le cas de la réduction de Turing. Cette fois ce seront les opérateurs effectifs monotones qui sont définis en retranchant la 2e et la 3e condition de la définition des opérateurs effectifs locaux donnée plus haut (i.e., on demande juste que ⋂P,Q∈𝒫(ℕ) ((PQ) ⇛ (J(P)⇛J(Q))) soit habité). La définition de l'opérateur effectif monotone associé à un oracle (à usage unique !) est la même que celle que j'ai donnée pour Ja ci-dessus mais en oubliant le ‘⌘’ ; dans l'autre sens, la définition est la même : si je n'ai pas merdé mes définitions, ceci doit donner des bijections entre l'ensemble des degrés W3 (Weihrauch pour les fonctions avec conseil) et l'ensemble des classes d'équivalence (pour ‘≡’) des opérateurs effectifs monotones, et celles-ci préservent l'ordre partiel, les niveaux W2 resp. W1 correspondant aux cas où on préserve ⋂ resp. ⋂ et ⋃.

L'opération que j'ai notée ‘⌘’, que Kihara note ‘⅁’, que d'autres gens notent ‘◇’, correspond à prendre le plus petit degré de Turing (ici, T1, T2, T3) au-dessus d'un degré de Weihrauch (ici, W1, W2, W3) donné : les degrés de Turing se voient donc comme une rétraction des degrés de Weihrauch.

Fonctions sur ℕ

Si on a lu mon billet sur le topos effectif, à la fin je parle de deux sortes de calculabilité sur l'espace de Baire ℕ des suites d'entiers. (Cette section-là est relativement indépendante du reste, donc même si on n'a pas lu l'ensemble du billet sur le topos effectif, on peut la lire en sautant les bouts qui concernent la définition des topoi.) D'une part, il y a la seconde algèbre de Kleene, qui est une façon de définir des fonctions Φε : ℕ ⇢ ℕ pour ε∈ℕ (et énumérant toutes les fonctions continues sur un Gδ), qui se comporte de façon très analogue à la définition des fonctions calculables partielles φe(n) : ℕ⇢ℕ pour e∈ℕ. D'autre part, on peut utiliser les machines de Turing pour définir des fonctions Φe : ℕ ⇢ ℕ pour e∈ℕ, par exemple on peut dire que c'est juste Φφe (lorsque φe est totale, et non définie sinon) ou quelque chose comme ça (ou bien on peut dire que Φe(g) : ℕ→ℕ est la fonction calculée par la e-ième machine de Turing quand on lui fournit g:ℕ→ℕ comme oracle, si cette fonction est totale, et non définie sinon ; je crois bien que ça revient essentiellement au même).

Bref, il y a trois situations classiques à étudier :

  • la calculabilité de Church-Turing des fonctions ℕ⇢ℕ (« première algèbre de Kleene »),
  • la continuité des fonctions ℕ ⇢ ℕ (« seconde algèbre de Kleene »),
  • la situation hybride, c'est-à-dire la calculabilité de Church-Turing des fonctions ℕ ⇢ ℕ (partie calculable de la seconde algèbre de Kleene).

(Et à la fin de mon billet sur le topos effectif, j'évoque trois topos correspondants : ce sont respectivement le topos effectif, le topos de la réalisabilité fonctionnelle, et le topos de Kleene-Vesley.)

Ces trois situations sont unifiées par la notion d'algèbre combinatoire partielle (relative), mais je pense que ça n'éclaircira rien que j'en dise plus à ce sujet.

Le fait est que beaucoup de ce ce que j'ai raconté ici en partant de la calculabilité de Church-Turing des fonctions ℕ⇢ℕ (en gros tout ce qui est complètement général, mais pas la description de tel ou tel oracle précis) peut se faire aussi aux deux autres niveaux : donc on a aussi des degrés T1, T2 et T3 pour les fonctions ℕ ⇢ ℕ pour la continuité et pour la calculabilité, et on a la correspondance avec les opérateurs effectifs locaux correspondants, et cela correspond à des topologies de Lawvere-Tierney sur le topos de la réalisabilité fonctionnelle et le topos de Kleene-Vesley respectivement. (Et, pour combiner les choses dont je n'ai pas parlé, on peut aussi faire des degrés de Weihrauch.)

Par exemple, pour la situation « seconde algèbre de Kleene », un opérateur effectif local J : 𝒫(ℕ) → 𝒫(ℕ) est une application telle qu'il existe un élément dans chacun des trois ensembles primo ⋂P,Q∈𝒫(ℕ) ((PQ) ⇛ (J(P)⇛J(Q))), secundo ⋂P∈𝒫(ℕ) (PJ(P)), et tertio ⋂P∈𝒫(ℕ) (J(J(P)) ⇛ J(P)), et on note J₁ ≼ J₂ lorsqu'il existe un élément dans ⋂P∈𝒫(ℕ) (J₁(P) ⇛ J₂(P)), mais où cette fois ‘⇛’ désigne { ε∈ℕ : ∀αP. (Φε(α)↓ et Φε(α)∈Q) } = { e∈ℕ : Φε définit une fonction (totale) PQ }. Tandis que dans la situation « hybride » on demande que les trois éléments exigés par la définition de J soient calculables (en tant que fonctions ℕ→ℕ, calculables au sens usuel), et de façon analogue pour la définition de ‘≼’ entre ces opérateurs.

J'avoue ne pas être très sûr de comment il faut modifier la définition côté oracles (par exemple comment se déroule le jeu Arthur-Nimué-Merlin) sur ℕ, mais la description avec les opérateurs effectifs locaux assure au moins une définition robuste des degrés T3.

Les degrés T3 pour la situation hybride, c'est-à-dire la calculabilité des fonctions ℕ ⇢ ℕ (ou, ce qui revient au même, les topologies de Lawvere-Tierney sur le topos de Kleene-Vesley), bien que plus complexes à définir, sont peut-être un objet d'étude finalement plus satisfaisant que pour les fonctions ℕ ⇢ ℕ (ou, ce qui revient au même, les topologies de Lawvere-Tierney sur le topos effectif) : car dans ce dernier cas (celui dont j'ai parlé tout au long de ce billet), il semble qu'on n'ait pas vraiment d'autre exemple intéressant que les exemples déjà évoqués (les degrés de Turing ordinaires, les Error1/, l'oracle de Pitts Cofinite et quelques autres), tandis que dans la situation ℕ ⇢ ℕ les exemples abondent : on a une structure extrêmement riche, qui inclut le treillis de Medvedev des degrés de difficulté (en fait, deux fois : une fois à l'endroit et une fois à l'envers) mais aussi toutes sortes de choses qui peuvent servir à fabriquer des modèles intéressants des maths constructives.

Sur ce, ce billet a vraiment atteint une taille trop délirante, et j'en ai marre de le traîner, donc je m'arrête ici.

↑Entry #2764 [older| permalink|newer] / ↑Entrée #2764 [précédente| permalien|suivante] ↑

[Index of all entries / Index de toutes les entréesLatest entries / Dernières entréesXML (RSS 1.0) • Recent comments / Commentaires récents]