Scrivi un linguaggio di programmazione di completezza sconosciuta


91

Determinare se una lingua è Turing completa è molto importante quando si progetta una lingua. È anche un compito piuttosto difficile per molti linguaggi di programmazione esoterici per cominciare, ma consente di alzare il livello. Consente di creare alcuni linguaggi di programmazione che sono così difficili da dimostrare Turing Complete che persino i migliori matematici del mondo non riusciranno a dimostrarli in entrambi i modi. Il tuo compito è ideare e implementare un linguaggio la cui Turing Completezza si basa su un grave problema irrisolto in Matematica .

Regole

  • Il problema che scegli deve essere stato posto almeno 10 anni fa e deve essere risolto al momento della pubblicazione di questa domanda. Può essere qualsiasi congettura dimostrabile in matematica, non solo una di quelle elencate nella pagina di Wikipedia .

  • È necessario fornire una specifica della lingua e un'implementazione in una lingua esistente.

  • Il linguaggio di programmazione deve essere Turing completo se e solo se la congettura è valida. (o se e solo se la congettura non regge)

  • È necessario includere una prova del perché sarebbe Turing completo o incompleto in base alla congettura scelta. È possibile assumere l'accesso alla memoria illimitata durante l'esecuzione dell'interprete o del programma compilato.

  • Dato che ci occupiamo della Turing Completeeness I / O non è richiesto, tuttavia l'obiettivo è quello di rendere la lingua più interessante in modo che possa essere d'aiuto.

  • Questo è un quindi la risposta con il maggior numero di voti.

Criteri target

Cosa dovrebbe fare una buona risposta? Ecco alcune cose da cercare quando si vota ma non sono tecnicamente necessarie


Questa conversazione è stata spostata in chat .
Dennis,

13
Nel complesso, sto trovando le risposte qui deludenti. Sono praticamente "Inizia con un linguaggio completo di Turing, quindi verifica se la congettura X è Vero / Falso e, in tal caso, termina o disabilita una funzionalità chiave".
xnor

1
@xnor sono d'accordo con te, speravo che questa generosità avrebbe provocato alcune risposte più interessanti ma sembra che non accadrà.
Wheat Wizard

2
Penso che uno dei problemi sia che la maggior parte delle congetture si sono dimostrate vere per un numero infinito di valori, ma i controesempi sarebbero veri anche per un numero infinito di valori. Di conseguenza, diventa quasi impossibile provare la completezza di Turing se vera.
fəˈnɛtɪk,

1
Penso che il requisito secondo cui la completezza di Turing sia legata uno a uno con una determinata congettura sia un requisito piuttosto forte. Penso che sarebbe facile se dimostrare o smentire la completezza di Turing decidesse, rispettivamente, due diversi problemi aperti. (ovvero dimostrare la completezza di Turing decide il problema aperto A e confutare decide il problema aperto B).
PyRulez,

Risposte:


48

Legendre

Questo linguaggio è completo di Turing solo se e solo se la congettura di Legendre è falsa, cioè esiste un numero intero n> 0 tale che non ci sono numeri primi tra n ^ 2 e (n + 1) ^ 2. Questo linguaggio prende ispirazione da Underload, sebbene per alcuni aspetti sia molto diverso da esso.

I programmi in Legendre sono costituiti da serie di numeri interi positivi (0 è particolarmente vietato, poiché essenzialmente nega l'intero scopo della lingua). Ogni numero intero corrisponde a un comando di base in Legendre o a un potenziale definito dall'utente. A quale comando è assegnato si basa sul numero di numeri primi tra il suo quadrato e il numero intero successivo (equivalente alla sequenza OEIS A014085 ).

I comandi del linguaggio modificano uno stack, che può contenere numeri interi positivi arbitrariamente grandi. Se lo stack contiene sempre 0, lo 0 viene immediatamente rimosso. Nel dettaglio, i comandi sono:

  • 2 (numero intero più piccolo che produce questo comando: 1): Inserire lo stack successivo nel programma nello stack.

  • 3 (numero intero di produzione più piccolo: 4): pop il numero intero superiore nello stack ed esegui il comando ad esso associato.

  • 4 (il più piccolo: 6): pop il numero intero superiore. Se era 1, incrementa il numero intero superiore nello stack.

  • 5 (10): scambia i primi due oggetti in pila.

  • 6 (15): decrementa il numero intero superiore nello stack. Se il risultato è 0, fai apparire lo 0 e scartalo.

  • 7 (16): duplica il numero intero superiore nello stack.

  • 8 (25): interrompe l'esecuzione e stampa il contenuto dello stack.

Questa è la serie di istruzioni di base, che non è in grado di fare nulla di interessante, per non parlare del ciclo. Tuttavia, esiste un altro comando, al quale è possibile accedere solo se la congettura di Legendre risulta falsa.

  • 0 (sconosciuto): rimuove tutti gli oggetti dallo stack e li combina in una nuova funzione, che eseguirà tutti i comandi a partire dal fondo originale dello stack e termina in alto, accessibile come comando il cui "numero comando" è uguale a quello a cui corrisponde il numero intero successivo nella sorgente del programma.

Se questo comando è in qualche modo accessibile, la lingua diventa Turing completa, poiché è possibile simulare una macchina Minsky in essa.

Quando viene eseguito il comando 8 o viene raggiunta la fine del programma, il programma termina e viene stampato il carattere (Unicode) corrispondente a ciascun numero intero nello stack.

Programmi di esempio

1 2 1 3 1 10 4

Questo semplice programma spinge il numero 2, quindi 3 e infine un 10, prima di eseguire un 4 (comando: 3), che fa scattare ed eseguire il 10 (comando: 5), scambiando i 2 e 3.

1 5 3 15 2 1 6 7

Questo programma dimostra l'uso della corrispondenza indiretta da intero a comando. Innanzitutto, viene premuto un 5, quindi un 15 e un 1, utilizzando tre modi diversi di codificare il comando 2. Quindi, 1 viene visualizzato e, di conseguenza, il 15 viene incrementato a 16 e infine eseguito. Il programma termina con due istanze del numero 5 nello stack.

1 1 1 5 ? 24 1 15 1 31 ? 31 24 31

Questo programma dimostra l'uso del comando 0, usando? come numero di segnaposto. Il programma memorizza prima '1 5' nella funzione 9, quindi '15 31 'in 10, prima di eseguire la funzione 9 (usando 24), che spinge 5 sullo stack e lo diminuisce ripetutamente, fino a raggiungere 0 e viene rimosso . Quindi, il programma si interrompe.

Macchina Minsky

Per convertire una macchina Minsky in codice Legendre, è necessario utilizzare il comando 0 . Perché questo comando è inaccessibile a meno che la congettura di Legendre sia falsa, ho usato un segnaposto? anziché.

Notare che tutti i nomi delle righe delle istruzioni della macchina Minsky devono avere numeri interi con diverse corrispondenze A014085 l'uno dall'altro e i comandi di base, nonché 24 (9) e 31 (10).

Inizializzazione:
1 1 1 1 ? 24
x INC (A / B) y:

UN:

1 y 1 24 1 ? 1 6 1 1 16 1 24 ? x

B:

1 y 1 24 1 ? 1 10 1 6 1 1 16 1 10 1 24 ? x
x DEC (A / B) yz:

UN:

1 4 1 10 1 15 1 10 1 31 1 1 1 10 1 z 1 1 1 16 1 24 1 31 1 ? 1 24 1 15 1 y 1 6 16 1 24 16 1 ? 1 1 16 1 10 1 1 16 1 24 ? x

B:

1 4 1 10 1 15 1 10 1 31 1 1 1 10 1 z 1 1 1 16 1 24 1 31 1 ? 1 24 1 15 1 10 1 y 1 6 16 1 24 16 1 ? 1 1 16 1 10 1 1 16 1 10 1 24 ? x
x HALT:
1 25 ? x

Per creare il programma finale, aggiungi tutte le parti (con x, y, z sostituite dalle rispettive controparti) e aggiungi un unico numero intero per avviare la prima istruzione nella catena. Ciò dovrebbe dimostrare la completezza del linguaggio di Turing nel caso in cui la congettura di Legendre sia dimostrata falsa da controesempio.

Interprete

Questo interprete è scritto in Python (3) ed è stato testato su tutti e tre gli esempi precedenti. Utilizzare i flag -a / - allowZero per consentire? da usare, -f / - file per eseguire il codice direttamente da un file e -s / - stackOut per generare invece lo stack come elenco Python. Se non viene fornito alcun file, l'interprete entra in una sorta di modalità REPL, che viene utilizzata al meglio con --stackOut.

import sys
import argparse
import io

class I_need_missing(dict): #used to avoid try/except statements. Essentially a dict
    def __missing__(self,key):
        return None 

def appropriate(integer,prev): #returns number of primes between the square of the integer given and the next

    return_value = 0

    if prev[integer]:
        return prev[integer],prev
    if integer == "?":
        return 0,prev
    for i in range(integer ** 2, (integer + 1) ** 2):
        t = False
        if i > 1:
            t = True
            for j in range(2,int(i ** 0.5)+1):
                t = i/j != round(i/j)
                if not t:
                    break
        return_value += t

    prev[integer] = return_value
    return return_value,prev

def run_command(commandseries,stack,functions,prev): #Runs the appropriate action for each command.

    command,prev = appropriate(commandseries.pop(0),prev)

    halt = False

    if command == 0: #store in given number
        functions[appropriate(commandseries.pop(0),prev)[0]] = stack
        stack = []

    elif command == 2:#push
        stack.append(commandseries.pop(0))

    elif command == 3:#execute top instruction
        commandseries.insert(0,stack.pop())

    elif command == 4:#pop, add 1 to new top if popped value was 1
        if stack.pop() == 1:
            stack[-1] += 1

    elif command == 5:#swap top two integers/?
        stack[-1],stack[-2] = stack[-2],stack[-1]

    elif command == 6:#subtract 1 from top of stack
        stack[-1] -= 1
        if stack[-1] == 0:
            stack.pop()

    elif command == 7:#duplicate top of stack
        stack.append(stack[-1])

    elif command == 8:#halt
        halt = True

    else:#run custom
        try:
            commandseries[0:0] = functions[command]
        except TypeError:
            print("Warning: unassigned function " + str(command) + " is unassigned", file = sys.stderr)

    return commandseries,stack,functions,prev,halt

def main(stack,functions,prev):
    #Parser for command line options
    parser = argparse.ArgumentParser(description = "Interpreter for the Legendre esoteric programming language.")
    parser.add_argument("-a","--allowZero", action = "store_true")
    parser.add_argument("-f","--file")
    parser.add_argument("-s","--stackOut", action = "store_true")

    args = parser.parse_args()
    allow_zero = bool(args.allowZero)

    #Program decoding starts
    pre = ""

    if not args.file:
        pre = input()
        if pre == "":
            return
    else:
        pre = open(args.file).read()

    mid = pre.split()
    final = []

    for i in mid:
        if i == "?" and allow_zero:
            final.append("?")
        elif i != 0 or allow_zero: #and allow_zero)
            final.append(int(i))

    halt = False

    #Functional programming at its best
    while final and not halt:
        final,stack,functions,prev,halt = run_command(final,stack,functions,prev)

    #Halting and output
    else:
        if args.stackOut:
            print(stack)
        else:
            for i in stack:
                print(i == "?" and "?" or chr(i),end = "")
            print("")
        if args.file or halt:
            return
        else:
            main(stack,functions,prev)


if __name__ == '__main__':
    main([],I_need_missing(),I_need_missing())

14

Unione chiusa

Questo linguaggio di programmazione è Turing completo se la congettura dei set chiusi dall'Unione non è corretta.

controlli

Elenco dei comandi:
x ++ Incremento x (INC)
x-- Decremento x (DEC)
j (x, y) Aggiungi set di istruzioni x se y è 0 alla fine della coda di istruzioni

Tutte le variabili sono inizializzate come 0

Sintassi

I programmi sono scritti come una serie di serie di comandi.
Command1 Command2 Command3 ...
Command1 Command2 ...
...

Per determinare se il programma è chiuso dall'unione, ogni set tiene conto solo dell'elenco dei diversi comandi presenti nell'insieme
j (x, y)! = J (a, b)
+ (x)! = + (Y)

Se un tipo di comando (+, -, j) appare in almeno metà degli insiemi, non fa nulla.

I programmi possono terminare se non ci sono istruzioni alla fine della coda di istruzioni

I loop infiniti, incluso il loop vuoto, possono essere raggiunti usando j (x, y)

Interprete

Completezza di Turing

Se tutti e tre i comandi, j (x, y), incrementa, decrementa i comandi sono tutti disponibili, è possibile simulare una macchina Minsky.

Qualsiasi set con solo j (x, y) che viene raggiunto usando j (x, y) è HALT
x ++ è INC
x-- è DEC
j (x, y) è JZ

Se la congettura dei set di unione chiusi è corretta, almeno uno dei tre comandi sarà sempre disabilitato, rendendo così impossibile il completamento di Turing di questa lingua.


Quello che farei invece di avere 3 operatori è avere un numero infinito di valori e prendere il modulo 4 di ciascuno per ottenere una delle tre operazioni più un no-op. All'avvio del programma verifica che l'unione degli insiemi sia chiusa e quindi rimuove tutti gli elementi presenti in più della metà degli insiemi. Quindi ripete questo fino a quando non c'è tale elemento. Se la congettura è vera, tutti i programmi sono uguali al programma vuoto, tuttavia se è falsa puoi esprimere tutti i programmi possibili (ecco perché è inclusa la no-op).
Wheat Wizard

@WheatWizard La determinazione dell'unione chiusa dall'interprete considera diverso lo stesso operatore su variabili diverse. x ++ è considerato diverso da y ++. Di conseguenza, è possibile creare un'infinità di insiemi diversi. Con un numero infinito di insiemi possibili, se nessuno dei tre tipi principali si trova in più della metà degli insiemi, allora è completamente completo.
fəˈnɛtɪk,

È possibile che una prova delle congetture sui set chiusi dell'Unione lascerebbe la conversione a uno dei tre operatori come completa, poiché potrebbe essere possibile lasciare tutti i diversi operatori nel programma, ne occorrerebbero solo 3 su un numero infinito di valori per rimanere.
fəˈnɛtɪk,

13

Numeri primi fermati

La lingua funziona su due nastri potenzialmente infiniti, in cui ogni posizione del nastro può memorizzare un numero intero arbitrario. Entrambi i nastri vengono riempiti -1all'inizio. Esistono anche due testine che iniziano nella posizione 0 su entrambi i nastri.

L'interprete leggerà prima l'input e memorizzerà i valori nel primo nastro (dati), iniziando dalla posizione 0.

Quindi leggerà il programma fornito. Per ogni numero che incontra, controllerà prima se il valore è un numero primo di Fermat o no. Se sì, scriverà sul secondo nastro (istruzione) quale è Fermat prime, altrimenti scriverà -1sul nastro istruzioni.

Quindi controlla il valore nel puntatore dell'istruzione ed esegui una delle seguenti operazioni:

  • -1 o meno: esci dal programma
  • 0: Sposta la posizione del nastro dati di uno a sinistra. Spostare la posizione del nastro istruzioni uno a destra
  • 1: Sposta la posizione del nastro dati di uno a destra. Spostare la posizione del nastro istruzioni uno a destra
  • 2: Aumenta il valore nella posizione del nastro dati. Spostare la posizione del nastro istruzioni uno a destra
  • 3: Ridurre il valore nella posizione del nastro dati. Spostare la posizione del nastro istruzioni uno a destra
  • 4: Se il valore nella posizione corrente del nastro dati è zero, spostare il nastro istruzioni verso destra, fino a raggiungere un valore corrispondente 5(o maggiore) sul nastro istruzioni o qualcosa di più piccolo di 0. Se è un 5(o più grande), sposta di nuovo il puntatore a destra, se è più piccolo di 0allora, esci dal programma. Se il valore della posizione corrente del nastro dati non è zero, spostare semplicemente il nastro istruzioni uno a destra
  • 5o più: sposta il puntatore dell'istruzione verso sinistra, fino a raggiungere il 4valore corrispondente o trova qualcosa di meno 0. Nel caso di quest'ultimo, uscire dal programma.

(abbinando 5(o più) e 4valori significa che durante la ricerca del valore corretto sul nastro delle istruzioni ogni volta che incontra lo stesso valore del comando iniziale (o 5(o più) o 4), dovrà saltare il numero appropriato dell'altro valore ( 4o 5(o più) rispettivamente) nella ricerca)

Ripeti, fino a quando le istruzioni dicono che devi uscire dal programma.

Quando il programma termina, stampare i valori sul nastro dati dalla posizione 0fino alla prima posizione del nastro che contiene un -1valore.

Prova

Si noti che la lingua si associa essenzialmente a un interprete Brainfuck IO-less, dove F_5è necessario essere in grado di eseguire qualsiasi tipo di loop corretto.

Tuttavia, sulla base della congettura di Fermat prime ci sono solo 5 numeri primi di Fermat ( F_0- F_4). Se F_5esiste, la lingua è Turing completa, poiché sappiamo che Brainfuck è Turing completa. Tuttavia, senza di F_5te non sarai in grado di fare né ramificazioni né loop, essenzialmente bloccandoti in programmi molto semplici.

Implementazione

(testato con rubino 2.3.1)

#!/usr/bin/env ruby
require 'prime'

CHEAT_MODE = false
DEBUG_MODE = false
NUM_CACHE = {}

def determine_number(n)
  return n.to_i if CHEAT_MODE
  n = n.to_i
  -1 if n<3

  return NUM_CACHE[n] if NUM_CACHE[n]

  i = 0

  loop do
    num = 2**(2**i) + 1
    if num == n && Prime.prime?(n)
      NUM_CACHE[n] = i
      break
    end
    if num > n
      NUM_CACHE[n] = -1
      break
    end
    i += 1
  end

  NUM_CACHE[n]
end

data_tape = Hash.new(-1)
instruction_tape = Hash.new(-1)

STDIN.read.each_char.with_index { |c,i| data_tape[i] = c.ord }
File.read(ARGV[0]).split.each.with_index do |n,i|
  instruction_tape[i] = determine_number(n)
end

data_pos = 0
instruction_pos = 0

while instruction_tape[instruction_pos] >= 0
  p data_tape, data_pos, instruction_tape, instruction_pos,'------------' if DEBUG_MODE

  case instruction_tape[instruction_pos]
  when 0 then data_pos -= 1; instruction_pos += 1
  when 1 then data_pos += 1; instruction_pos += 1
  when 2 then data_tape[data_pos] += 1; instruction_pos += 1
  when 3 then data_tape[data_pos] -= 1; instruction_pos += 1
  when 4 then
    if data_tape[data_pos] == 0
      count = 1
      instruction_pos += 1
      while count>0 && instruction_tape[instruction_pos] >= 0
        count += 1 if instruction_tape[instruction_pos] == 4
        count -= 1 if instruction_tape[instruction_pos] >= 5
        instruction_pos += 1
      end
      break if count != 0
    else
      instruction_pos += 1
    end
  else
    count = 1
    instruction_pos -= 1
    while count>0 && instruction_tape[instruction_pos] >= 0
      count += 1 if instruction_tape[instruction_pos] >= 5
      count -= 1 if instruction_tape[instruction_pos] == 4
      instruction_pos -= 1 if count>0
    end
    break if count != 0
  end
end

data_pos = 0

while data_tape[data_pos] >= 0
  print data_tape[data_pos].chr
  data_pos += 1
end

Esempi:

Questo scriverà H(abbreviazione di Hello World!) sullo schermo con una nuova riga:

17 17 17 17 17 17 17 17 17 17
17 17 17 17 17 17 17 17 17 17
17 17 17 17 17 17 17 17 17 17
17 17 17 17 17 17 17 17 17 17
17 17 17 17 17 17 17 17 17 17
17 17 17 17 17 17 17 17 17 17
17 17 17 17 17 17 17 17 17 17
17 17 17
5
17 17 17 17 17 17 17 17 17 17
17

Salva come example.fermated eseguilo in questo modo (nota: devi sempre avere un input):

$ echo -n '' | ./fermat.rb example.fermat

Il prossimo esempio farà un semplice cifrario in stile Cesare aumentando di uno il valore dell'input. Ovviamente devi sostituire ?il 5 ° Fermat prime:

17 65537 5 17 ? 257

Puoi provare che funziona abilitando la modalità cheat e usando 2 4 1 2 5 3come codice sorgente:

$ echo 'Hello' | ./fermat.rb example2_cheat.fermat

2
Mi dispiace per il povero programmatore che deve digitare il numero primo corrispondente per arrivare 5. Spero che abbiano una buona tastiera.
AdmBorkBork

2
@AdmBorkBork Non preoccuparti. Ha solo più bit di quanti l'universo abbia particelle elementali.
fəˈnɛtɪk

@LliwTelracs in realtà non ha senso poiché la quantità di particelle elementali nell'universo è Aleph-null (omega) e da omega, inizia a non significare la dimensione effettiva del numero. (A meno che non lo sia: P)
Matthew Roh

1
@MatthewRoh Avevo fatto un errore. Intendevo nell'universo osservabile.
fəˈnɛtɪk

2
@MatthewRoh In realtà, potrebbe essere finito, infinito, non numerabile o addirittura incompatibile con la teoria degli insiemi! Non lo sapremo mai, comunque :(
CalculatorFeline

10

Swallows w / Coconut v2

Poiché la versione precedente presentava errori che lo rendevano non valido per questo concorso e non voglio che i conteggi della versione precedente contino per questa versione che è significativamente diversa, questa versione viene inviata come nuovo post.

Questa lingua non è Turing completa se la congettura di Collatz può essere dimostrata per tutti i numeri interi positivi. Altrimenti, la lingua è Turing completa.

Questa lingua era basata sul cardinale .

Innanzitutto, il contVal del programma viene calcolato utilizzando la formula
contVal = sum (somma (valori ASCII della riga) * 2 ^ (riga numero-1))

Successivamente, vengono creati 2 rondini diretti in direzioni opposte in ogni A o E e tutte le istruzioni di svolta condizionale vengono impostate in attesa dell'inizializzazione.
Le rondini create su una E sono dirette a sinistra / a destra e le rondini create su una A sono dirette su / giù.

Infine, il codice eseguirà i passaggi fino a quando tutti i puntatori non saranno stati rimossi o contVal sarà sceso a uno.

Ad ogni passaggio, se contVal% 2 == 0 verrà diviso per 2, altrimenti verrà moltiplicato per tre e incrementato di uno.

comandi:

0: imposta il valore su 0
+: incrementa il valore di 1
>: cambia direzione a destra
v: cambia direzione a giù
<: cambia direzione a sinistra
^: cambia direzione su su
R: puntatori successivi dopo il primo puntatore confronta con il valore del primo puntatore. Se uguale, vai dritto, altrimenti gira a destra.
L: I puntatori successivi dopo il primo puntatore si confrontano con il valore del primo puntatore. Se uguale, vai dritto, altrimenti gira a sinistra.
E: duplicare il puntatore ma andando nelle direzioni sinistra e destra
A: duplicare il puntatore ma andando nelle direzioni su e giù
? : Rimuove il puntatore se il valore è 0

Spiegazione:

Se la congettura di Collatz può essere dimostrata per tutti i numeri interi positivi, la durata di qualsiasi programma eseguito in questa lingua è limitata, poiché contVal converge sempre a 1, terminando così il programma.

Altrimenti, devo semplicemente dimostrare che questo linguaggio può implementare le seguenti funzioni

Incremento: che è rappresentato da +
Costante 0: che è rappresentato da 0
Accesso variabile: le variabili vengono memorizzate come puntatori mentre viaggiano
Concatenazione delle istruzioni: modificando la distanza percorsa per le operazioni, è possibile modificare l'ordine in cui vengono eseguite le operazioni
Per il ciclo: In questa lingua

E   > V
    ^+R
      +
      A

fungerà da ciclo for> count fino a 1 (è possibile aggiungere ulteriore codice al loop)

Allo stesso modo, il codice

Rv
^<

Agirà come un do finché non sarà uguale al valore condizionale impostato nel ciclo R.


Mi hai battuto anche io, avrei fatto qualcosa con la congettura collatz. Bel lavoro, sull'interessante interpretazione. Stavo per creare una lingua che sarebbe stata in grado di memorizzare solo i numeri se fossero stati convertiti in 1.
Rohan Jhunjhunwala

Non ho capito bene. Dove si inserisce la funzione Collatz in questo? Da un secondo readthrough penso che intendi dire che la funzione è applicata ad contValogni passo (e quindi se la congettura è vera, non ci sono loop infiniti) - ma non vedo che sia esplicitamente indicato da nessuna parte nella risposta. ??
DLosc

Mi dispiace, mentre lo sto facendo penso di averlo accidentalmente tagliato fuori dalla mia descrizione ad un certo punto
fəˈnɛtɪk

10

La perfezione / imperfezione

Accidenti, è stato divertente.

La perfezione / imperfezione è completa solo se ci sono infiniti numeri perfetti. Se ci sono, si chiama perfezione, e se non ci sono, si chiama imperfezione. Fino a quando questo mistero non sarà risolto, contiene entrambi i nomi.

Un numero perfetto è un numero i cui divisori si sommano al numero, quindi sei è un numero perfetto perché 1+2+3=6.

Perfezione / Imperfezione ha le seguenti funzioni:

La perfezione / imperfezione è basata sullo stack, con uno stack a indice zero.

comandi:

p(x, y): spinge x nella pila in posizione yth.

z(x, y): spinge x nella pila in posizione Y, elimina ciò che era in precedenza nella posizione Y.

r(x): rimuove l'elemento xth dalla pila

k(x): restituisce il xo oggetto nello stack

a(x, y): aggiunge xey. Se usato con le stringhe, le mette insieme in ordine xy.

s(x, y): sottrae y da x. con stringhe, rimuove l'ultima len (y) da x

m(x, y): moltiplica xe y. Se utilizzato con le stringhe, moltiplica x volte len y.

d(x, y): divide x per y

o(x): stampa x

i(x, y): se x restituisce true, esegue la funzione y

n(): restituisce il contatore sul quale viene chiamato il blocco di codice.

q(): restituisce la lunghezza della pila

t(): input dell'utente

e(x, y): Se x è un numero intero, se xey hanno lo stesso valore, questo restituisce 1. se y è una stringa, ottiene la lunghezza di y. se x è una stringa, quindi converte y in una stringa e verifica se sono uguali e, se lo sono, restituisce 1. Altrimenti restituisce 0.

l(x, y): se x è maggiore di y, restituisce 1. Se è presente una stringa, utilizza la lunghezza della stringa.

b(): arresta il programma.

c(x, y): esegue x, quindi y.

Per ottenere l'equivalente di un Python and, moltiplica i due valori insieme. Per or, aggiungi i valori e per not, sottrai il valore da 1. Funziona solo se il valore è 1 o 0, che può essere ottenuto dividendo il numero da solo.

Tipi di dati: numeri interi e stringhe. Le stringhe sono indicate da ''e tutti i numeri non interi sono arrotondati.

Sintassi:

Il codice è costituito da funzioni nidificate entro dieci {}secondi. Ad esempio, un programma che otterrebbe agli ingressi e stamparle aggiunto potrebbe essere: {o(a(t(), t()))}. Sullo sfondo del programma c'è un contatore che inizia da 0 e avanza di 1 ogni volta che esegue un blocco di codice. Il primo blocco di codice viene eseguito su 0e così via. Una volta eseguiti i dieci blocchi di codice, il sesto viene eseguito ogni volta che il contatore raggiunge un numero perfetto. Non è necessario disporre di tutti e dieci i blocchi di codice affinché il programma funzioni, ma sono necessari 7 se si desidera creare un ciclo. Per capire meglio come funziona questo linguaggio, eseguire il seguente programma, che stampa il contatore ogni volta che il contatore raggiunge un numero perfetto: {}{}{}{}{}{}{o(n())}.

L'interprete può essere trovato qui: repl.it/GL7S/37 . Seleziona 1 e digita il codice nel terminale oppure incolla il codice nella code.perfectscheda e seleziona 2 quando esegui. Avrà senso quando lo proverai.

Prova della completezza di Turing / mancanza di completezza di Turing.

Secondo questo articolo di scambio di stack di ingegneria del software , un Turing completo deve essere in grado di avere una forma di ripetizione condizionale del salto e avere un modo per leggere o scrivere memoria. Può leggere / scrivere memoria sotto forma di stack e può eseguire il loop a causa del fatto che il sesto blocco di codice viene eseguito ogni volta che il contatore raggiunge un numero perfetto. Se esiste un numero infinito di numeri perfetti, può essere eseguito un ciclo indefinito ed è Turing completo, altrimenti non lo è.

Interprete di tag ciclico bit a bit automatico che richiede 5 caratteri, 1 o 0, come input:

{p(t(),0)}{(p(t(),0)}{p(t(),0)}{p(t(),0)}{p(t(),0)}{p(0,0)}{c(i(e(k(s(q(),k(0))),0),c(r(q()),i(l(k(0),0),z(s(k(0),1),0)))),i(e(k(s(q(),k(0))),1),c(z(a(k(0),1),0),i(e(k(q()),1),p(k(s(q(),k(0))),1)))))}

Può essere espanso per accettare qualsiasi numero di caratteri come input. Potrebbe richiedere un input infinito, ma solo se ci sono infiniti numeri perfetti!


1
Penso che potresti creare solo un nuovo valore per il loop locale poiché non è condiviso con la funzione.
fəˈnɛtɪk

3
Allo stato attuale non hai una prova di TC. L'articolo di ingegneria del software a cui ti colleghi fornisce una serie approssimativa di requisiti, tuttavia TC non è solo un mucchio di caselle da spuntare. Dovrai implementare un automa TC (come una macchina Minsky) o dimostrare che il tuo linguaggio è indecidibile.
Wheat Wizard

2
@WheatWizard Lì ho aggiunto un interprete Tag ciclicamente bit a bit. Può essere modificato per accettare qualsiasi quantità di caratteri come input. Potrebbero essere necessari caratteri infiniti come input, ma solo se ci sono infiniti numeri perfetti!
Compagno SparklePony

2
"Una volta eseguiti i dieci blocchi di codice, il sesto viene eseguito ogni volta che il contatore raggiunge un numero perfetto." Quindi l'interprete conta direttamente i numeri perfetti? Sento che questo va contro lo spirito della sfida. Le specifiche del linguaggio non contano molto, può essere qualsiasi cosa sia Turing-complete più "corri solo per un passo solo quando raggiungi un numero perfetto".
xnor

10

suole

Questo linguaggio di programmazione è Turing completo se la congettura di Scholz è vera.

Ho scritto questa lingua perché @SztupY stava dicendo che non ci sarebbero stati risultati che si basassero sulla congettura per essere veri per essere Turing completi

Elenco dei comandi

+(x)      Increment x (INC)   
-(x)      Decrement x (DEC)  
j(x,y)    Jump to instruction x if y is 0 (JZ)  
x         End program (HALT) 

Con questi comandi, questo linguaggio può simulare una macchina Minsky

Interprete

Consiglio vivamente di non eseguirlo. Utilizza un metodo straordinariamente lento per controllare la catena di addizione.

Completezza di Turing

La lingua utilizza un contatore per il numero di comandi eseguiti che verifica rispetto alla congettura di Scholz per modificare la completezza turing della lingua.

Se la congettura di Scholz è vera, questo programma funziona esattamente come una normale macchina Minsky con
Increment
Decrement
Jump se Zero
Halt

Tuttavia, se la congettura di Scholz è falsa, il contatore alla fine raggiungerà un valore per il quale la congettura di Scholz non è vera. Poiché la lingua è stata progettata per uscire al raggiungimento di un numero in cui la congettura di Scholz è falsa, il programma uscirà ogni volta dopo aver eseguito molti comandi. Pertanto, tutti i programmi avranno una durata limitata. Dato che ciò non concorda con i requisiti per il completamento della lingua di Turing,

"Il nastro non può essere fissato in lunghezza, dal momento che ciò non corrisponderebbe alla definizione data e limiterebbe seriamente la gamma di calcoli che la macchina può eseguire a quelli di un automa lineare limitato",

la lingua non sarebbe completa di Turing se la congettura di Scholz fosse falsa


1
+1, dato che in realtà questo rende difficile il requisito della congettura nella lingua, invece di aggiungere qualcosa di estraneo per uccidere la lingua se la congettura è vera / falsa
Gryphon,

Non capisco I comandi che fornisci sono esattamente quelli di cui hai bisogno per simulare una macchina Minsky, quindi se questo è tutto ciò che devi fare, la tua lingua è Turing completa indipendentemente dalla congettura di Scholz. Devi perdere qualcosa nella tua spiegazione.
Nathaniel,

@Nathaniel Uno dei requisiti per un linguaggio completo di Turing è che il linguaggio può finire in un ciclo infinito (fermare il problema). Il mio codice conta mentre esegue le istruzioni e se la congettura di Scholz è falsa, il programma si fermerà sempre dopo un determinato numero di istruzioni.
fəˈnɛtɪk,

Sì, ma hai dimenticato di spiegare che cosa provoca la sua fermata se la congettura di Scholz è falsa. Dai un'altra occhiata alla tua risposta: non c'è affatto.
Nathaniel,

@Nathaniel Il programma funziona letteralmente controllando ogni singolo numero se funziona nella congettura di scholz. Esce automaticamente quando trova un numero che non è d'accordo con la congettura.
fəˈnɛtɪk,

9

Promessi Sposi

Promessi Sposi Github .

Il file Leggimi e le specifiche sono su github, sotto "README.txt".

Generalmente, un programma Promessi Sposi è composto da coppie di linee, le cui lunghezze sono distinte coppie gemelle prime o coppie fidanzate (non possono verificarsi duplicati). Il programma viene eseguito da "sottoinsiemi flessibili" della prima riga della coppia all'interno della seconda riga. Il numero di tali sottoinsiemi, combinato con la distanza di levenshtein tra la seconda riga originale e la seconda riga senza i sottoinsiemi flessibili, determina il comando da eseguire.

Estrarrò la prova per questo post:

V. PROOF OF TURING COMPLETENESS

Now, no language can be Turing Complete with bounded program size. Therefore, if Betrothed
is Turing Complete, it must have unbounded program size. Since the lengths of the lines of
a Betrothed program must be twin prime pairs or betrothed pairs, and since both sequences
are unproven to be infinite or finite, Betrothed has unbounded program size if and only if
there are infintie betrothed pairs, there are infinite twin prime pairs, or both.

    Next: to prove that if Betrothed has an unbounded program size, then it is Turing
Complete. I will use the op-codes from the above table to demonstrate key factors of a
Turing Complete language; they are of the form  [index]<[ld]> .

  1. Conditional goto: 6<> 5<>, or if-popjump. This can be used to form a loop.
  2. Inequality to a constant K: 10<K> 
  3. Arbitrarily large variable space: you can use some separator constant C.

    With this, I have sufficient reason to believe that Betrothed is Turing Complete.

4
"Ora, nessuna lingua può essere Turing Completa di dimensioni del programma limitate." Sono confuso su questa affermazione ... Da un lato è vero che con una dimensione del programma limitata possiamo scrivere solo un numero finito di programmi diversi, ma d'altra parte una prova comune per Turing Completezza è scrivere un interprete per un altro Turing Linguaggio completo, che non richiede affatto dimensioni illimitate del programma ...
Leo

1
Bene, il programma passato all'interprete non ha bisogno di essere inserito nel codice dell'interprete, dovrebbe essere dato all'interprete come input
Leo

7
@Leo. Devo dire che, in modo che la lingua da TC, deve essere in grado di codificare il programma per essere passato all'interprete (vale a dire, immaginare che questo linguaggio non ha alcun comando in ingresso.) Immaginate una lingua con un solo comando: b. Questo interpreta un programma BF, che viene inserito dopo di esso, come b+++++.. La dimensione del programma, tuttavia, è limitata a 10 caratteri. Mentre può interpretare BF, non può calcolare tutti i programmi che una macchina di Turing può fare.
Conor O'Brien,

3
@EriktheOutgolfer il problema principale con il tuo problema è "può mettere il programma BF che ottiene dall'input ..." Per questo, ti incoraggio fortemente a leggere o rileggere il mio commento precedente, in particolare questa prima frase. Se la lingua è solo Turing completa in base all'input, come può, senza alcun input, essere Turing completa? Cioè, affinché la lingua sia Turing completa, è il programma stesso che deve codificare il programma. Altrimenti, si scopre che stanno codificando il programma nell'input, il che non è un modo valido di programmazione.
Conor O'Brien,

1
Non penso che questo sia un punto fermo. Questo articolo di Esolang discute il problema. (C'è anche la questione se un programma che stampa ogni possibile programma di terminazione in un linguaggio completo di Turing , insieme al suo output, è una dimostrazione di completezza di Turing; che non richiede input e può essere fatto con un programma finitamente lungo .)

5

Parità amichevole

Questa lingua si basa sull'esistenza di numeri amichevoli con parità opposta .

comandi

x : End program if not on top line  
+ : increment stored value  
- : decrement stored value  
{ : set next goto x value to current x value
} : goto previous x value set by {  
j : Go down one line if the special value is an amicable number and the
    parity is opposite to the matching number (loops back to top). If the
    special value is not an amicable number and not on the top line, go up
    one line.  

Flusso di controllo

Il programma scorre ripetutamente da sinistra a destra prima di tornare all'inizio. Se incontra una "j", controlla il valore per determinare se deve cambiare le righe. Se il numero è un numero amichevole con parità opposta alla sua corrispondenza, scende di una riga (ritornando in alto), altrimenti, se il numero è un numero amichevole, sale di una riga se non è già nella riga superiore.

Il programma può terminare solo se il programma raggiunge una x in qualsiasi riga al di fuori della riga superiore.

Completezza di Turing

Questo programma può essere usato per simulare una macchina Minsky supponendo che ci sia una coppia di numeri amichevoli con parità opposta.

j, {e} possono essere usati per simulare JZ (r, x) anche se verificherebbe la presenza di numeri amichevoli anziché zero.
+ è INC (r)
- è DEC (r)
x è HALT

Se non è possibile lasciare la prima riga, i comandi xe} non fanno nulla. Ciò comporta l'impossibilità per il programma di entrare in uno stato HALT a meno che non sia un programma vuoto. Pertanto, sotto la descrizione che la completezza di Turing richiede uno stato HALT , la lingua sarebbe Turing incompleta.

Interprete


2

Nuova linea

Disclaimer: è un po 'un casino e piuttosto semplice. Questa è la prima lingua che abbia mai scritto e la congettura è l'unica che ho capito. So che un altro utente ha avuto una risposta più lunga con lo stesso, ma ho deciso di scriverlo comunque.

Per scrivere in Newline devi avere molto tempo e newline ( \n). Questo funziona al di fuori della congettura di Legendre che è vera. Ogni operatore deve cadere su un numero nella congettura di Legendre che iniziamo con n = 1. Ogni volta che hai un operatore prendi la quantità di \ n e la inserisci nella congettura di Legendre e ottieni l'intervallo che il prossimo importo primo di \ n deve rientrare. Quindi, per iniziare, \n\nsi passa a un operatore, quindi a un \naltro operatore ci troviamo su 3 nuove linee. Ora il prossimo è 5, quindi aggiungi \n\ne sull'operatore assicurandoti che l'ultima riga dell'operatore abbia la giusta quantità di newline che sei su un importo primo che rientra nella congettura di Legendre che abbiamo iniziato.

I numeri (l'array) sono come le variabili. Ogni volta che un operatore esegue (che utilizza numeri) aumenta.

+ adds
- subtracts
/ divide
* multiply 
s sqrt
% mod
a push to vars
g sets stack to numbers
q pushes value of stack to numbers
i increment 
d decrement
r stops subtraction at 0
w turns back on subtraction past 0
[ starts loop
] ends loop runs until stack is 0
{ starts loop
} ends loop and loops until loops[ln] is 0
k increment loops

Finché abbiamo numeri primi illimitati che seguono le regole questa lingua ha un nastro non finito.

Macchina Minsky

\n\ng\nr\n\n[\n\nd\n\n\n\n]

Come funziona:

\n\ng     # the first two newlines are to get to a prime number of newlines (2) then sets the value of stack to the first variable in the array numbers (see code in link)

\nr       # gets to the next number and makes it so subtraction stops at 0

\n\n[     # starts the loop

\n\nd     # decrements stack 

\n\n\n\n] # ends loop

Provalo su KhanAcademy .


@wheat non ha bisogno di loop con memoria non finita
Christopher

Funziona solo se è vero. Non riesco a finire la scrittura in questo momento come sono sul cellulare, ma stasera lo farò
Christopher

Anche se hai una memoria infinita, devi comunque essere in grado di eseguire un ciclo infinito.
Pavel

Ho dei loop. Cercando di renderli infiniti
Christopher

In questo momento si schiantano
Christopher

2

Taggis

Taggis è un linguaggio basato su sistemi di tag .

La completezza turing di Taggis si basa sulla congettura di Collatz

Sintassi

La sintassi di un programma Taggis è semplicemente tre stringhe (regole di produzione) costituite interamente dalle lettere a, b e c, separate da spazi.

Esecuzione

L'unico stato del programma di Taggis è una stringa composta dagli stessi tre caratteri.

Taggis implementa un sistema di tag TS (3, 2), in cui in ogni passaggio vengono rimosse le prime 2 lettere dell'attuale "tag" e la primissima lettera che si trovava in quella porzione rimossa viene aggiunta alla sua regola di produzione corrispondente alla fine di la stringa.

Ad esempio, il programma Taggis bc a aaaimplementa il problema 3n + 1, in cui le iterazioni sono rappresentate da un numero corrispondente di se ail passaggio 3n + 1 viene sostituito con (3n + 1) / 2 [1], portando all'output del programma:

aaa // 3
  abc
    cbc
      caaa
        aaaaa // 5
          aaabc
            abcbc
              cbcbc
                cbcaaa
                  caaaaaa
                    aaaaaaaa // 8
                      aaaaaabc
                        aaaabcbc
                          aabcbcbc
                            bcbcbcbc
                              bcbcbca
                                bcbcaa
                                  bcaaa
                                    aaaa // 4
                                      aabc
                                        bcbc
                                          bca
                                            aa // 2
                                              bc
                                                a // 1 and halt because we then begin an infinite loop
                                                 HALT

Completezza di Turing

Naturalmente, questo semplice sistema può sembrare troppo semplice per emulare la completezza di Turing, ma risulta che qualsiasi macchina di Turing con 2 simboli (una classe che include macchine universali) può essere convertita in un sistema di tag con 2 caratteri rimossi dalla testa, e 32 * m regole di produzione, dove mè il numero di stati nella macchina di Turing.

La macchina Turing universale più piccola conosciuta con solo 2 simboli utilizza 18 stati e quindi il sistema di tag corrispondente contiene ben 576 regole di produzione [2].

Tuttavia, la classe computazionale dell'insieme di tutti i sistemi di tag con 3 produzioni e 2 simboli rimossi è legata alla congettura di Collatz [2]. Se la congettura di Collatz si dimostra falsa, allora Taggis è Turing completo. Altrimenti, si basa su UN ALTRO problema irrisolto in matematica, trovando una macchina di Turing più piccola di

def taggis(inp, a, b, c):
    current = inp
    seen = set()
    while True:
        seen.add(tuple(current))

        yield current

        head = current[0]

        current = current[2:]

        current.extend([a, b, c][head])

        if tuple(current) in seen:
            return

def parse():
    program = input().split(" ")

    assert len(program) == 3, "There has to be exactly 3 production rules!" 

    productions = []

    for production in program:

        production = [{"a": 0, "b": 1, "c": 2}[x] for x in production]
        productions.append(production)  

    program_input = [{"a": 0, "b": 1, "c": 2}[x] for x in input()]

    k = 0   

    for step in taggis(program_input, *productions):
        print(' ' * k +''.join(['abc'[x] for x in step]))

        k += 2
    print(' ' * (k - 1) + 'HALT')

parse()
  1. che equivale alla funzione Collatz originale in quanto 3n + 1 di uno dispari nsarà sempre pari e quindi la divisione può essere applicata automaticamente

  2. Sistemi di tag e funzioni simili a Collatz, Liesbeth De Mol ,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.