Prouver 2 + 2 = 2 * 2 (et similaire)

12

Produire un poof formel complet de telles déclarations telles que 1+2=3, 2+2=2*(1+1)etc.

Introuction

Si vous connaissez Peano Arithmetic, vous pouvez probablement ignorer cette section.

Voici comment nous définissons les nombres naturels:

(Axiom 1) 0 is a number
(Axiom 2) If `x` is a number, the `S(x)`, the successor of `x`, is a number.

Par conséquent, par exemple, S(S(S(0)))est un nombre.

Vous pouvez utiliser n'importe quelle représentation équivalente dans votre code. Par exemple, tous ces éléments sont valides:

0    ""    0           ()       !
1    "#"   S(0)        (())     !'
2    "##"  S(S(0))     ((()))   !''
3    "###" S(S(S(0)))  (((()))) !'''
...
etc

Nous pouvons étendre les règles pour définir l'addition comme suit.

(Rule 1) X+0 = X
(Rule 2) X+S(Y)=S(X)+Y

Avec cela, nous pouvons prouver 2 + 2 = 4 comme suit

         S(S(0)) + S(S(0)) = 2 + 2
[Rule 2 with X=S(S(0)), Y=S(0)]
         S(S(S(0))) + S(0) = 3 + 1
[Rule 2 with X=S(S(S(0))), Y=0]
         S(S(S(S(0)))) + 0 = 4 + 0
[Rule 1 with X=S(S(S(S(0))))
         S(S(S(S(0))))     = 4

Nous pouvons étendre ces règles pour définir la multiplication comme suit

(Rule 3) X*0 = 0
(Rule 4) X*S(Y) = (X*Y) + X

Bien que pour permettre cela, nous devons définir le rôle structurel des parenthèses.

(Axiom 3) If X is a number, (X) is the same number.

Les opérateurs d'addition et de multiplication sont strictement binaires et les parenthèses doivent toujours être explicites. A+B+Cn'est pas bien défini, mais (A+B)+Cet le A+(B+C)sont.

Exemple

Nous avons maintenant assez pour prouver un théorème sur la multiplication: 2 + 2 = 2 * 2

2 + 2
(2) + 2
(0 + 2) + 2
((0*2) + 2) + 2
(1*2) + 2
2*2

Exigences

Une preuve quiA=B est une liste d'expressions telles que:

  • le premier est A,
  • le dernier est B, et
  • chaque expression de la liste en dehors de la première peut être obtenue à partir de la précédente en la transformant selon l'une des règles.

Votre programme prendra en entrée deux expressions valides , chaque expression contient des nombres, des ajouts, des multiplications et des parenthèses comme défini ci-dessus.

Votre programme affichera une preuve, une liste telle que définie ci-dessus, que les deux expressions sont égales, si une telle preuve existe.

Si les deux expressions ne sont pas égales, votre programme ne sortira rien.

La preuve ou la réfutation est toujours possible en un nombre fini d'étapes, car chaque expression peut être réduite à un seul nombre et ces nombres peuvent être testés de manière triviale pour l'égalité.

Si les expressions d'entrée ne sont pas valides (par exemple, des parenthèses non équilibrées, contiennent des opérateurs non numériques ou non binaires), votre programme doit se terminer avec une erreur, lever une exception, imprimer une erreur ou autrement produire un comportement observable qui est distinct du cas dans lequel les entrées sont valides mais non égales .

En résumé, la sortie normale pour les entrées admissibles est une liste de nombres égaux, y compris les entrées, qui est produite par les règles suivantes.

(Axiom 1) 0 is a number
(Axiom 2) If `x` is a number, the `S(x)`, the successor of `x`, is a number.
(Axiom 3) If X is a number, (X) is the same number

(Rule 1) X+0 = X
(Rule 2) X+S(Y)=S(X)+Y
(Rule 3) X*0 = 0
(Rule 4) X*S(Y) = (X*Y) + X
(Rule 5) X = (X)              (Axiom 3 expressed as a transformation rule.)

Toute représentation appropriée des nombres dans l'entrée et la sortie est autorisée, par exemple 0=""=(), 3="###"=(((())))etc. est hors de propos Whitespace.

Bien entendu, les règles peuvent être appliquées dans les deux sens. Votre programme n'a pas besoin de sortir quelle règle est utilisée, juste l'expression produite par son action sur l'expression précédente.

Le code le plus court gagne.

vaporiser
la source

Réponses:

5

Perl, 166 + 1 octets

Exécutez avec -p(1 octet de pénalité).

$r='\((S*)';(@b,@a)=@a;push@a,$_ while+s/\+S/S+/||s/$r\+\)/$1/||s/$r\*\)//||s/$r\*S(S*)/(($1*$2)+$1/||s/$r\)/$1/;$\.=/[^S]./s;$_=$b[-1]eq$a[-1]?join'',@b,reverse@a:""

Plus lisible:

                           # implicite: lit une ligne d'entrée dans $ _
                           # nous laissons la nouvelle ligne activée
$ r = '\ ((S *)'; # nous utilisons beaucoup ce fragment d'expression régulière, factorisons-le
(@b, @a) = @a; # définissez @b sur @a, @a sur vide
appuyez sur @a, $ _ tandis que # à chaque tour de boucle, ajoutez $ _ à @a
+ s / \ + S / S + / || # règle 2: remplacez "+ S" par "S +"
s / $ r \ + \) / $ 1 / || # règle 1: changer "(X + 0)" en "X"
s / $ r \ * \) // || # règle 3: remplacez "(X * 0)" par ""
s / $ r \ * S (S *) / (($ 1 * $ 2) + $ 1 / || # règle 4: changer "(X * Y" en "((X * Y) + X"
s / $ r \) / $ 1 /; # règle 5: changer "(X) en" X "
$ \. = / [^ S] ./ s; # ajoutez un 1 au caractère de nouvelle ligne si nous
                           # voir tout non-S suivi de quoi que ce soit
$ _ = $ b [-1] eq $ a [-1]? # si @b et @a se terminent de la même manière
  rejoindre '', @ b, inverser @ a # puis $ _ devient @b suivi de (@a en arrière)
  : "" # sinon vide $ _
                           # implicite: sortie $ _

Le format d'entrée exprime les nombres en unaire sous forme de chaînes de S, et nécessite les deux entrées sur des lignes distinctes (chacune suivie d'un retour à la ligne et d'un EOF après que les deux sont visibles). J'ai interprété la question comme exigeant que les parenthèses devraient être littéralement ( )et l'addition / multiplication devrait être littéralement + *; Je peux économiser quelques octets grâce à moins d'échappement si je suis autorisé à faire des choix différents.

L'algorithme compare en fait la première ligne d'entrée avec une ligne vide, la seconde avec la première, la troisième avec la seconde, etc. Cela répond aux exigences de la question. Voici un exemple d'exécution:

Ma contribution:

(SS + SS)
(SS * SS)

Sortie du programme:

(SSS + S)
(SSSS +)
SSSS
SSSS
(SSSS +)
((SS +) SS +)
(((SS *) SS +) SS +)
(((SS *) S + S) SS +)
(((SS *) + SS) SS +)
((SS * S) SS +)
((SS * S) S + S)
((SS * S) + SS)

Le doublon SSSSau milieu est ennuyeux mais j'ai décidé qu'il ne violait pas les spécifications, et c'est moins d'octets pour le laisser.

Sur une entrée non valide, j'ajoute 1au caractère de nouvelle ligne, de sorte que vous obtenez des 1s parasites saupoudrés à la fin de la sortie.


la source
echo -e "((SS+)+(S+S))\nSS*SS" | perl -p /tmp/x.plsorties 1.
pulvérisation
C'est exact, vous manquez les crochets sur la deuxième ligne (ce qui devrait dire (SS*SS)). "Les opérateurs d'addition et de multiplication sont strictement binaires et les parenthèses doivent toujours être explicites."