Questa macchina Foo si ferma?


43

Determinare se una macchina di Turing si ferma è noto per essere indecidibile, ma ciò non è necessariamente vero per le macchine più semplici.

Una macchina Foo è una macchina con un nastro finito, in cui ogni cella sul nastro ha un numero intero o il simbolo di arresto h, ad es.

2 h 1 -1

Il puntatore dell'istruzione inizia puntando alla prima cella:

2 h 1 -1
^

Ad ogni passo, il puntatore dell'istruzione si sposta in avanti del numero a cui punta, quindi annulla quel numero. Quindi, dopo un passaggio, si sposterebbe in avanti le 2celle e trasformerebbe 2in un -2:

-2 h 1 -1
     ^

La macchina Foo continua a farlo finché il puntatore dell'istruzione non punta al simbolo di arresto ( h). Quindi, ecco la piena esecuzione di questo programma:

2 h 1 -1
^

-2 h 1 -1
     ^

-2 h -1 -1
         ^

-2 h -1 1
      ^

-2 h 1 1
   ^

Anche il nastro è circolare, quindi se il puntatore dell'istruzione si sposta da un lato del nastro, va dall'altro lato, ad esempio:

3 h 1 3
^
-3 h 1 3
       ^
-3 h 1 -3
     ^
-3 h -1 -3
         ^
-3 h -1 3
 ^
3 h -1 3
  ^

Una cosa interessante di queste macchine Foo è che alcune non si fermano, ad esempio:

1 2 h 2
^
-1 2 h 2
   ^
-1 -2 h 2
        ^
-1 -2 h -2
    ^
-1 2 h -2
        ^
-1 2 h 2
   ^

Questo programma continuerà in loop negli ultimi quattro stati per sempre.

Quindi, scrivi un programma che determina se una macchina Foo si ferma o no! Puoi usare qualsiasi formato di input (ragionevole) che ti piace per le macchine Foo e puoi scegliere di usare 0come simbolo di arresto. È possibile utilizzare due uscite distinte per il caso in cui si ferma e per il caso in cui non si ferma. Ovviamente il tuo programma deve fornire una risposta in un tempo limitato per tutti gli input validi.

Questo è , quindi cerca di rendere il tuo programma il più breve possibile!

Casi test

2 h 1 -1
Halts
3 h 1 3
Halts
h
Halts
1 1 1 1 h
Halts
2 1 3 2 1 2 h
Halts
3 2 1 1 4 h
Halts
1 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 h -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36
Halts

2 h
Does not halt
1 2 h 2
Does not halt
8 1 2 3 3 4 8 4 3 2 h
Does not halt
1 2 4 3 h 2 4 5 3
Does not halt
3 1 h 3 1 1
Does not halt
1 2 h 42
Does not halt

5
Proprio per questo sono sicuro dell'algoritmo per risolvere questo problema. Non sono quello di un maestro di algoritmo, quindi preferisco chiedere prima di andare nella direzione sbagliata. Una macchina Foo senza sosta tornerà sempre allo stato originale esatto? O ci sono macchine non-stop "caotiche"?
V. Courtois,

5
@ V.Courtois Tutte le macchine Foo che non si fermano finiranno in un ciclo di stati, perché ci sono solo finitamente molti possibili stati in cui una macchina Foo può trovarsi (ci sono n possibili posti in cui può essere il puntatore alle istruzioni e 2 ^ n possibile configurazioni nastro). Ogni stato ha uno e un solo "stato successivo". Quindi, se una macchina Foo finisce in uno stato in cui è già stata, continuerà a girare in loop. Poiché ci sono solo molti stati finiti, non può continuare a saltare caoticamente tra gli stati perché finirà per andare a uno in cui è già stato.
Leo Tenenbaum

3
Caso di prova suggerito: 1 2 h 42(non si ferma)
Arnauld

6
Banco di prova consigliato: 3 2 1 1 4 h. Questo si ferma ma richiede più iterazioni rispetto al doppio del numero di elementi.
Arnauld,

10
Caso di prova extra lungo suggerito 1 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 h -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36:, che si arresta dopo 786430 passi.
Magma,

Risposte:


11

C # (compilatore interattivo Visual C #) , 71 byte

x=>{for(int i=0,k=0,f=x.Count;i++<1<<f;k%=f)k-=(x[k]*=-1)%f-f;i/=x[k];}

Provalo online!

Non so se quanto segue sia valido, poiché richiede un delegato personalizzato con una firma di unsafe delegate System.Action<int> D(int* a); e deve essere racchiuso in un unsafeblocco per essere utilizzato, ma qui è comunque:

C # (.NET Core) , 64 byte

x=>f=>{for(int i=0,k=0;i++<1<<f;k%=f)k-=(x[k]*=-1)%f-f;k/=x[k];}

Provalo online!

Questa funzione accetta un int * e restituisce un'azione; in altre parole, è una funzione al curry. L'unica ragione per cui utilizzo i puntatori è a causa di codegolf.meta.stackexchange.com/a/13262/84206, che mi consente di salvare i byte avendo già una variabile già definita con la lunghezza dell'array.

Salvataggio di 9 byte grazie a @someone


Golfato il codice di 2 byte: tio.run/…
IQuick 143

@ IQuick143 Bella cattura, grazie
Incarnazione dell'ignoranza il

Non sono sicuro se ci sono casi limite per cui non funziona, ma senza rompere nessuno dei casi di test attuali si potrebbe sostituire 1<<fcon 2*fper salvare un byte.
Kevin Cruijssen,

1
77 byte con orribile magia LINQ e correzione di Arnauld . Non ho idea di come funzioni questa soluzione, quindi potrei averla rotta.
qualcuno il

1
63 byte tramite un normale golf da 1 byte sano e cambiando IO in errore / nessun errore. Link to link
qualcuno

7

Python 3 , 63 89 byte

def f(x):
 for i in range(2**len(x)):a=x[0];x[0]=-a;b=a%len(x);x=x[b:]+x[:b]
 return a==0

Provalo online!

Funziona anche con Python 2; un byte può essere salvato in Python 2 sostituendo return con print e facendo stampare la funzione su stdout invece di return. R giraTrue per fermarsi e Falseper non fermarsi.

Grazie a @Neil e @Arnauld per aver notato che dovevo controllare più a lungo per fermarmi. Grazie a @Jitse per aver segnalato un problema con [2,0]. Grazie a @mypetlion per aver notato che i valori assoluti dei valori del nastro potrebbero superare la lunghezza del nastro.


5
OK, ti mordo: come sai che x+xè abbastanza?
Neil,

4
@Neil In realtà non è abbastanza. Un contro-esempio è [ 3, 2, 1, 1, 4, 0 ], che si interrompe in più di 12 iterazioni.
Arnauld,

1
len(x)*x[8,7,6,5,7,4,0,3,6]92

2
Non è 2**len(x)ancora un po 'inferiore al massimo? Calcolo il numero di stati come n*(2**n)(con n=len(x)-1).
OOBalance

1
@OOBalance Capisco cosa intendi, dal momento che ogni stato può avere un puntatore in ogni cella ... tuttavia, mi sento come se ci fosse qualche altro limite applicato dal fatto che ogni cella può solo passare ad altre due celle. Come nota a margine: nulla nella sfida dice che ci deve essere uno stato di arresto nell'input
Jo King

6

Gelatina , 15 11 byte

N1¦ṙ⁸ḢƊÐLḢẸ

Provalo online!

Un collegamento monadico che accetta l'input come un elenco di numeri interi che usano 0 per indicare l'arresto. Restituisce 0 per arrestare gli input e 1 per quelli che non si arrestano.

Evita il problema della necessità di elaborare il numero di iterazioni a causa dell'uso di ÐLcui verrà eseguito il ciclo fino a quando non viene visualizzato alcun nuovo risultato.

Grazie a @JonathanAllan per aver salvato un byte!

Spiegazione

      ƊÐL   | Loop the following as a monad until the result has been seen before:
N1¦         | - Negate the first element
   ṙ⁸       | - Rotate left by each of the elements
     Ḣ      | - Take just the result of rotating by the first element
         Ḣ  | Finally take the first element
          Ẹ | And check if non-zero

Salvare un byte ruotando di tutte le voci e mantenendo solo il primo risultato:N1¦ṙ⁸ḢƊÐLḢẸ
Jonathan Allan il

5

Python 3 , 91 byte

def f(a):
	s={0,};i=0
	while{(*a,)}-s:s|={(*a,)};a[i]*=-1;i-=a[i];i%=len(a)
	return a[i]==0

Provalo online!

-40 byte grazie a JoKing e Jitse


@JoKing 109 byte eseguendo le assegnazioni delle variabili nella prima riga.
Jitse,

92 byte modificando la conversione della tupla in espansione stellata, non iniziando con un set vuoto e riformulando la whilecondizione.
Jitse,

@JoKing Damn, non imparo mai: p. 93 byte quindi.
Jitse,


@JoKing grazie!
HyperNeutrino,

5

Perl 6 , 46 43 36 byte

{$_.=rotate(.[0]*=-1)xx 2**$_;!.[0]}

Provalo online!

Rappresenta l'arresto da 0e restituisce vero se la macchina si ferma. Questo ripete i 2**(length n)tempi logici , dove se il puntatore finisce sulla cella di arresto, rimane lì, altrimenti si troverà su una cella non ferma. Questo funziona perché ci sono solo 2**nstati possibili (ignorando le celle di arresto) in cui si trova la macchina Foo, poiché ogni cella non di arresto ha solo due stati. Va bene sì, ci sono stati di questo, ma a causa delle limitate possibili transizioni tra puntatori (e quindi stati) ci saranno meno di 2 ** $ _ stati ... Penso

Spiegazione

{                                  }  # Anonymous codeblock
                     xx 2**$_         # Repeat 2**len(n) times
            .[0]*=-1                  # Negate the first element
 $_.=rotate(        )                 # Rotate the list by that value
                             ;!.[0]   # Return if the first element is 0

2
Lo stato della macchina Foo include anche la posizione del puntatore, non solo i segni di ogni cella.
Magma,

1
Schizzo di una prova per una macchina Foo con nastro adesivo a_1 ... a_n 0. Considera un n-cubo dei segni di ogni cella con i bordi diretti (= un'iterazione di Foo) tra i vertici (= stati), visitando lo stesso vertice attraverso qualsiasi ciclo di bordi si tradurrà nell'IP nella stessa posizione con cui è iniziato . Prova: in un ciclo, l'IP viaggia in ogni dimensione un numero pari di volte, cioè l'IP cambia di k × (a_j + (-a_j))% n ≡ 0 per ogni dimensione, quindi ritorna sempre nella stessa posizione, vedendo solo 1 stato su n stati per ogni vertice, ovvero un massimo totale di 2 ^ n stati (= numero di vertici del cubo).
Kritixi Lithos

n2n.log(n)/n

3

05AB1E , 14 13 byte

goFć©(š®._}®_

Provalo online!

Prende l'input come un elenco di numeri interi con 0 come istruzione di arresto. Restituisce 1 per l'arresto e 0 per non arresto.

Grazie a @KevinCruijssen per aver salvato 2 byte!


Oh bello, ecco cosa fa la tua risposta Jelly! Ottimo uso del ruotare e ć! Stavo aspettando una spiegazione nella speranza di trovare la mia risposta, ma tu mi hai battuto, ahah. ; p -1 byte facendo lo stesso golf della mia risposta: g·Fa «v( Provalo online. )
Kevin Cruijssen

E un ulteriore -1 usando ©®invece di DŠs: «vć©(š®._}®_( Provalo online. )
Kevin Cruijssen

Come ha notato Arnauld nella tua risposta Python, fare un loop di due volte la lunghezza non è sufficiente. Quindi puoi cambiare «vin goF.
Kevin Cruijssen,

@KevinCruijssen ringrazia
Nick Kennedy il

3

Java 8, 78 79 73 byte

a->{int k=0,l=a.length,i=0;for(;i++<1<<l;k%=l)k-=(a[k]*=-1)%l-l;k/=a[k];}

Porta diretta della risposta C # .NET di @EmbodimentOfIgnorance , quindi assicurati di votarlo!
Grazie a @Arnauld per aver trovato due bug (che si applica anche ad altre risposte).

Si verifica un java.lang.ArithmeticException: / by zeroerrore quando è in grado di arrestarsi o nessun errore in caso contrario.

Provalo online.

Spiegazione:

a->{                   // Method with integer-array as parameter and no return-type
  int k=0,             //  Index integer, starting at 0
      l=a.length,      //  The length `l` of the input-array
  i=0;for(;i++<1<<l;   //  Loop 2^length amount of times:
          k%=l)        //    After every iteration: take mod `l` of `k`
    k-=                //   Decrease `k` by:
       (a[k]*=-1)      //    Negate the value at index `k` first
                 %l    //    Then take modulo `l` of this
                   -l; //    And then subtract `l` from it
                       //  (NOTE: the modulo `l` and minus `l` are used for wrapping
                       //  and/or converting negative indices to positive ones
  k/=a[k];}            //  After the loop: divide `k` by the `k`'th value,
                       //  which will result in an division by 0 error if are halting

2
Mi chiedo, ti è permesso prendere la lunghezza come argomento aggiuntivo? L'impostazione predefinita per IO post su meta non lo dice, e l'unica ragione per cui la mia seconda risposta prende una lunghezza è perché contiene un int*(da codegolf.meta.stackexchange.com/a/13262/84206 )
Embodiment of Ignorance

@EmbodimentofIgnorance Ah, quando ho visto la tua risposta ho pensato che esistesse una sorta di meta regola che permettesse di prendere la lunghezza come input aggiuntivo, ma questo vale solo per i puntatori. Grazie per avermi fatto sapere. Ho rimosso il parametro length (ma uso ancora l'errore / nessun errore per determinare il risultato).
Kevin Cruijssen il

3

Haskell , 79 byte

s x|m<-length x,let g(n:p)=(drop<>take)(mod n m)(-n:p)=iterate g x!!(2^m)!!0==0

Provalo online!

Restituisce Trueper fermare le macchine, e Falsealtrimenti. Input sotto forma di un elenco, con 0rappresentazione di uno stato di arresto.

Presuppone una versione di GHC successiva alla 8.4 (rilasciata a febbraio 2018).


2

JavaScript (Node.js) , 71 67 byte

x=>{for(p=l=x.length,i=2**l;i--;)p+=l-(x[p%l]*=-1)%l;return!x[p%l]}

Praticamente lo stesso della risposta C # .NET di @EmbodimentOfIgnorance

Risparmio di 4 byte grazie a @Arnaud

Provalo online!

JavaScript (Node.js) , 61 byte

x=>{for(p=l=x.length,i=2**l;i--;p+=l-(x[p%l]*=-1)%l)x[p%l].f}

Questa versione utilizza undefinedcome simbolo di arresto e genera un TypeError: Cannot read property 'f' of undefinedquando la macchina si ferma e termina silenziosamente quando la macchina non si ferma.

Provalo online!


1

Scala , 156 byte

IMO ancora giocabile a golf, ma per ora sto bene. Restituisce 0per Foos senza sosta e 1per fermata Foo. Accetta l'ingresso acome un Array[Int], quindi hviene considerato come 0.

var u=Seq[Array[Int]]()//Keep track of all states
var i=0//Index
while(u.forall(_.deep!=a.deep)){if(a(i)==0)return 1//Check if we are in a previously encountered step ; Halt
u:+=a.clone//Add current state in the tracker
var k=i//Stock temp index
i=(a(i)+i)%a.length//Move index to next step
if(i<0)i+=a.length//Modulus operator in Scala can return a negative value...
a(k)*=(-1)}//Change sign of last seen index
0//Returns 0 if we met a previous step

È piuttosto lungo da eseguire (circa 4 secondi per tutti i casi di test) a causa delle molteplici ricerche full-array che ho fatto, oltre a quelle .deepche creano copie ... Ma puoi ancora provarlo online.



1

Attache , 40 byte

Not@&N@Periodic[{On[0,`-,_]&Rotate!_@0}]

Provalo online!

Spiegazione

{On[0,`-,_]&Rotate!_@0}

Ciò esegue una singola iterazione della macchina Foo; nega il primo membro, quindi ruota l'array dal primo elemento (originale, non negato) dell'array.

Periodicapplicherà questa funzione fino ad accumulare un risultato duplicato. Una macchina si ferma o entra in un banale ciclo infinito. Se si ferma, il primo elemento sarà 0. Altrimenti, sarà diverso da zero.

&Nè un modo da golf per ottenere il primo elemento di un array numerico. Quindi, Notrestituisce true0 (macchine fermatrici) e falsequalsiasi altra cosa (macchine non fermatrici).


1

Carbone , 28 byte

≔⁰ηFX²L諧≔θ籧θη≧⁻§θη绬§θη

Provalo online! Il collegamento è alla versione dettagliata del codice. Output usando l'output booleano predefinito di Charcoal, che è -vero e nulla è falso. Spiegazione:

≔⁰η

Inizializza il puntatore dell'istruzione.

FX²Lθ«

Ripeti ciclicamente quante volte ci sono stati teoricamente possibili.

§≔θ籧θη

Negare il valore nel puntatore dell'istruzione.

≧⁻§θηη

Sottrai il nuovo valore dal puntatore dell'istruzione. Gli accessi all'array di carbone sono ciclici, quindi questo emula automaticamente il nastro circolare di Foo.

»¬§θη

Alla fine del ciclo, emettere se il programma si è fermato.



0

Pyth , 12 byte

!hu.<+_hGtGh

Suite di test!

Utilizza l'approccio diretto. Riprova finché non vediamo l'elenco due volte in uno stato identico. Per i programmi che si arrestano, l'elenco alla fine avrà un vantaggio 0perché è lì che si interrompe la ricorsione. Per i programmi che non si fermano, l'elenco non inizierà con 0, ma piuttosto si troverà in uno stato dal quale il processo sarebbe periodico e quindi la macchina Foo non si fermerebbe.

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.