Fonction McCarthy 91 - McCarthy 91 function

La fonction McCarthy 91 est une fonction récursive , définie par l' informaticien John McCarthy comme un cas test pour la vérification formelle en informatique .

La fonction McCarthy 91 est définie comme

Les résultats de l'évaluation de la fonction sont donnés par M ( n ) = 91 pour tous les arguments entiers n  100, et M ( n ) =  n  − 10 pour n > 100. En effet, le résultat de M(101) est également 91 ( 101 - 10 = 91). Tous les résultats de M(n) après n = 101 augmentent continuellement de 1, par exemple M(102) = 92, M(103) = 93.

Histoire

La fonction 91 a été introduite dans des articles publiés par Zohar Manna , Amir Pnueli et John McCarthy en 1970. Ces articles représentaient les premiers développements vers l'application de méthodes formelles à la vérification de programmes . La fonction 91 a été choisie pour être imbriquée-récursive (contrairement à la récursivité simple , telle que la définition au moyen de ). L'exemple a été popularisé par le livre de Manna, Mathematical Theory of Computation (1974). Au fur et à mesure que le domaine des méthodes formelles avançait, cet exemple est apparu à plusieurs reprises dans la littérature de recherche. En particulier, il est considéré comme un « problème de défi » pour la vérification automatisée des programmes.

Il est plus facile de raisonner sur le flux de contrôle récursif de queue , c'est une définition équivalente ( extensionnellement égale ) :

Comme l'un des exemples utilisés pour démontrer un tel raisonnement, le livre de Manna inclut un algorithme récursif de queue équivalent à la fonction 91 récursive imbriquée. La plupart des articles qui rapportent une « vérification automatisée » (ou une preuve de terminaison ) de la fonction 91 ne traitent que la version récursive de la queue.

Il s'agit d'une définition mutuellement récursive équivalente :

Une dérivation formelle de la version mutuellement récursive de la version imbriquée récursive a été donnée dans un article de 1980 par Mitchell Wand , basé sur l'utilisation de continuations .

Exemples

Exemple A :

M(99) = M(M(110)) since 99 ≤ 100
      = M(100)    since 110 > 100
      = M(M(111)) since 100 ≤ 100
      = M(101)    since 111 > 100
      = 91        since 101 > 100

Exemple B :

M(87) = M(M(98))
      = M(M(M(109)))
      = M(M(99))
      = M(M(M(110)))
      = M(M(100))
      = M(M(M(111)))
      = M(M(101))
      = M(91)
      = M(M(102))
      = M(92)
      = M(M(103))
      = M(93)
   .... Pattern continues increasing till M(99), M(100) and M(101), exactly as we saw on the example A)
      = M(101)    since 111 > 100
      = 91        since 101 > 100

Code

Voici une implémentation de l'algorithme imbriqué-récursif en Lisp :

(defun mc91 (n)
  (cond ((<= n 100) (mc91 (mc91 (+ n 11))))
        (t (- n 10))))

Voici une implémentation de l'algorithme imbriqué-récursif en Haskell :

mc91 n 
  | n > 100   = n - 10
  | otherwise = mc91 $ mc91 $ n + 11

Voici une implémentation de l'algorithme imbriqué-récursif en OCaml :

let rec mc91 n =
  if n > 100 then n - 10
  else mc91 (mc91 (n + 11))

Voici une implémentation de l'algorithme tail-recursive en OCaml :

let mc91 n =
  let rec aux n c =
    if c = 0 then n
    else if n > 100 then aux (n - 10) (c - 1)
    else aux (n + 11) (c + 1)
  in
  aux n 1

Voici une implémentation de l'algorithme imbriqué-récursif en Python :

def mc91(n: int) -> int:
    """McCarthy 91 function."""
    if n > 100:
        return n - 10
    else:
        return mc91(mc91(n + 11))

Voici une implémentation de l'algorithme imbriqué-récursif en C :

int mc91(int n)
{
    if (n > 100) {
        return n - 10;
    } else {
        return mc91(mc91(n + 11));
    }
}

Voici une implémentation de l'algorithme récursif de queue en C :

int mc91(int n)
{
    return mc91taux(n, 1);
}

int mc91taux(int n, int c)
{
    if (c != 0) {
        if (n > 100) {
            return mc91taux(n - 10, c - 1);
        } else {
            return mc91taux(n + 11, c + 1);
        }
    } else {
        return n;
    }
}

Preuve

Voici une preuve que

qui fournit un algorithme non récursif équivalent pour calculer .

Pour n > 100, l'égalité découle de la définition de . Pour n 100, une forte induction descendante à partir de 100 peut être utilisée.

Pour 90 n ≤ 100,

M(n) = M(M(n + 11)), by definition
     = M(n + 11 - 10), since n + 11 > 100
     = M(n + 1)

Donc M ( n ) = M (101) = 91 pour 90 n ≤ 100. Cela peut être utilisé comme cas de base.

Pour l'étape d'induction, soit n 89 et supposons que M ( i ) = 91 pour tout n < i ≤ 100, alors

M(n) = M(M(n + 11)), by definition
     = M(91), by hypothesis, since n < n + 11 ≤ 100
     = 91, by the base case.

Cela prouve que M ( n ) = 91 pour tout n 100, y compris les valeurs négatives.

La généralisation de Knuth

Donald Knuth a généralisé la fonction 91 pour inclure des paramètres supplémentaires. John Cowles a développé une preuve formelle que la fonction généralisée de Knuth était totale, en utilisant le prouveur du théorème ACL2 .

Les références

  • Manne, Zohar ; Pnueli, Amir (juillet 1970). « Formalisation des propriétés des programmes fonctionnels ». Journal de l'ACM . 17 (3) : 555-569. doi : 10.1145/321592.321606 .
  • Manne, Zohar ; McCarthy, John (1970). "Propriétés des programmes et logique de fonction partielle". Intelligence des machines . 5 . OCLC  35422131 .
  • Manne, Zohar (1974). Théorie mathématique du calcul (4e éd.). McGraw-Hill. ISBN 9780070399105.
  • Baguette, Mitchell (janvier 1980). "Stratégies de transformation de programme basées sur la continuité". Journal de l'ACM . 27 (1) : 164-180. doi : 10.1145/322169.322183 .