Simula un NFA


15

Un automa finito non deterministico è una macchina a stati finiti in cui una tupla è mappata su più stati. Vale a dire. sostituiamo la solita funzione di transizione δ : Q × Σ Q di un DFA con un'altra funzione Δ : Q × Σ P ( Q ) .(Stun'te,SymBol)δ:Q×ΣQ Δ:Q×ΣP(Q)

Se sai cos'è un NFA, potresti voler saltare la sezione successiva.

Definizione formale

Un NFA è descritto in modo univoco da

  • un insieme finito di statiQ
  • un insieme finito di simboliΣ
  • la funzione di transizioneΔ:Q×ΣP(Q)
  • lo stato inizialeq0Q
  • un insieme di stati finaliFQ

La macchina inizia in e legge una stringa finita di simboli w Σ , per ogni simbolo applicherà simultaneamente la funzione di transizione con uno stato corrente e aggiungerà ogni nuovo set di stati al set di stati correnti.q0wΣ*

Sfida

Per questa sfida ignoreremo per semplificare esso, inoltre l'alfabeto sarà sempre il (minuscole) lettere una per z e l'insieme degli stati sarà { 0 ... N } per qualche intero non negativo N . Lo stato iniziale sarà sempre 0 .F un' z {0...N}N0

Data una parola e una descrizione dell'NFA, il tuo compito è determinare tutti gli stati finali.w{un'...z}*

Esempio

Considera la stringa e la seguente descrizione:abaab

state, symbol, new-states
0, 'a', [1]
1, 'a', [0]
1, 'b', [1,2]

La macchina si avvierà in :q0=0

  1. leggi a : new states { 1 }un'{1}
  2. leggi a : nuovi stati { 1 , 2 }B{1,2}
  3. leggi un : nuovi stati { 0 }un'{0}
  4. leggi a : new states { 1 }un'{1}
  5. leggi a : nuovi stati { 1 , 2 }B{1,2}

Quindi gli stati finali e quindi l'output sarebbero .{1,2}

Nota: nel passaggio (2) la transizione dello stato mappata su poiché la descrizione include solo le transizioni verso insiemi non vuoti.2

Regole

L'input consisterà in una stringa e una sorta di descrizione dell'NFA (senza transizioni ):ε

  • la stringa di input sarà sempre l'elemento di {un'...z}*
  • input validi (non limitati a):
    • lista / matrice di tuple / liste
    • input separato da nuova riga
  • la descrizione dell'NFA conterrà solo transizioni con set non vuoti come risultato
    • puoi abbreviare le regole con gli stessi caratteri se il loro risultato è lo stesso (es. regole 0,'a',[1,2]e 0,'b',[1,2]potrebbe essere abbreviato con0,"ab",[1,2]
    • puoi prendere ciascuna regola separatamente (es. regola 0,'a',[1,2]può essere 0,'a',[1]e 0,'a',[2])
  • puoi scegliere lettere maiuscole se lo desideri
  • puoi prendere il numero di stati come input
  • potresti assumere un qualche tipo di ordinamento degli ingressi (es. ordinato da stato o simboli)

L'output sarà un elenco / set / output separato da nuova riga ecc. Degli stati finali

  • l'ordine non ha importanza
  • nessun duplicato (in quanto è un set)

Casi test

Questi esempi saranno nel formato in description word -> statescui descriptionè presente un elenco di tuple (state,symbol,new-states):

[]  "x" -> []
[]  "" -> [0]
[(0,'a',[1]),(1,'a',[0]),(1,'b',[1,2])]  "abaab" -> [1,2]
[(0,'a',[1]),(1,'a',[0]),(1,'b',[1,2])]  "abc" -> []
[(0,'p',[0,1]),(0,'g',[2]),(1,'c',[1]),(1,'g',[4]),(1,'p',[2]),(2,'c',[0])]  "ppcg" -> [2,4]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])]  "foobar" -> [0,4]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])]  "fooooooobar" -> [0,4]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])]  "fobarfo" -> [1,2]
[(0,'f',[1]),(1,'o',[1,2]),(2,'b',[3]),(3,'a',[4]),(4,'r',[0,4])]  "foobarrf" -> [1]
[(0,'d',[1,2]),(1,'u',[2]),(2,'u',[2,3]),(2,'p',[3]),(3,'p',[3])]  "dup" -> [3]
[(0,'a',[0,2]),(0,'b',[3]),(1,'a',[1]),(1,'b',[1]),(2,'b',[1,4]),(4,'b',[2])]  "aab" -> [3,1,4]
[(0,'a',[0,2]),(0,'b',[3]),(1,'a',[1]),(1,'b',[1]),(2,'b',[1,4]),(4,'b',[2])]  "abb" -> [1,2]


3
Questo riporta ricordi spaventosi dal mio corso di automi.
Don

Possiamo prendere input con linee individuali per ogni nuovo stato, ad esempio questo per un esempio funzionante?
Ovs

@ovs: certo vai avanti!
ბიმო

Risposte:


7

Haskell , 66 byte

import Data.List
f d=foldl(\s c->nub[r|(y,r)<-d,g<-s,(g,c)==y])[0]

Provalo online!


È possibile eliminare l'importazione per nubse si presuppone che gli stati siano [Int], quindi è possibile utilizzare controllare ciascuno [0..]che è finito: 60 byte
ბიმო

@BWO Questo itera su tutti i Ints e su tutti gli stati attuali e quindi ancora produce stati duplicati. Esempio (modificato [0..]a [0..3]scopo di test, ma questo non dovrebbe fare la differenza, giusto?)
ovs

Sì, non sono sicuro di cosa stavo pensando .. Non importa ..
ბიმო

4

Brachylog , 42 byte

,0{hẸ&t|∋₁B∋IhJ&tJ&hhC∧I∋₁C∧It∋S&hb;B,S↰}ᵘ

input come [stringa, nfa] dove nfa è un elenco di transizioni di stato [stato iniziale, lettera, nuovi stati come elenco]

Spiegazione

,0                                              # Append 0 to the input (initial state)
  {                                      }ᵘ     # Find all unique outputs
   h                                            # if first element (string)
    Ẹ                                           #   is empty
     &t                                         #   then: return last element (current state)
       |                                        #   else:
        ∋₁B                                     #       save the state transitions in "B"
           ∋I                                   #       take one of these transitions, save in "I"
             hJ                                 #       take the initial state requirement, store in "J"
               &tJ                              #       make sure "J" is actually the current state
                  &hhC                          #       Save first char of string in C
                      ∧I∋₁C                     #       make sure the char requirement for the state transition is the current char
                           ∧It∋S                #       Make "S" equal to one of the new states
                                &hb             #       Behead the string (remove first char)
                                   ;B,S         #       Add B (the state transitions) and S (the new state)
                                       ↰        #       recur this function

Provalo online!


4

Brachylog v2, 31 byte

{b,Ȯ,Ȯ\c↔,0↔ġ₃kH&hg;Hz{∋ᵈ}ᵐtt}ᵘ

Provalo online! ( o con un esempio più complesso )

Brachylog è davvero bravo in questo tipo di problema, e davvero cattivo in problemi che richiedono due input separati e un output. Quasi tutto questo programma è solo idraulico.

Il formato di input è un elenco contenente due elementi: il primo è l'elenco delle transizioni di stato ([oldState, symbol, newState] ) e il secondo è l'elenco di simboli. Inizialmente avevo programmato che questo programma funzionasse con i codici dei caratteri per i simboli (perché la gestione delle stringhe di Brachylog può essere un po 'strana a volte), ma si scopre che anche i caratteri funzionano (anche se devi scrivere la stringa di input come un elenco di caratteri, non come una stringa). Se una coppia stato-simbolo può passare a più stati diversi, scrivi più transizioni per gestirlo.

Spiegazione

{b,Ȯ,Ȯ\c↔,0↔ġ₃kH&hg;Hz{∋ᵈ}ᵐtt}ᵘ
{                            }ᵘ   Find all distinct outputs that can result from:
 b                                  taking the input minus its first element,
  ,Ȯ                                appending a singleton list (i.e. an element)
    ,Ȯ                              then appending that same element again
      \                             and transposing;
       c                            then concatenating the resulting lists,
        ↔,0↔                        prepending a 0,
            ġ₃                      grouping into blocks of 3 elements
              k                       (and discarding the last, incomplete, block),
               H&                   storing that while we
                 h                  take the first input element,
                  g  z              pair a copy of it with each element of
                   ;H                 the stored value,
                      {  }ᵐ         assert that for each resulting element
                       ∋ᵈ             its first element contains the second,
                        ᵈ ᵐ           returning the list of second elements,
                            t       then taking the last element of
                           t          the last element.

Probabilmente è più facile seguirlo osservando cosa potrebbero produrre alcune versioni parziali del programma. Utilizzando ogni volta il seguente input:

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]

possiamo osservare gli output di alcuni prefissi di questo programma:

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ
[[97,98,97,97,98],L,L]

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ\
[[97,A,A],[98,B,B],[97,C,C],[97,D,D],[98,E,E]]

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ\c↔,0↔
[0,97,A,A,98,B,B,97,C,C,97,D,D,98,E,E]

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ\c↔,0↔ġ₃k
[[0,97,A],[A,98,B],[B,97,C],[C,97,D],[D,98,E]]

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ\c↔,0↔ġ₃kH&hg;Hz
[[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[0,97,A]],
 [[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[A,98,B]],
 [[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[B,97,C]],
 [[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[C,97,D]],
 [[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[D,98,E]]]

[[[0,97,1],[1,97,0],[1,98,1],[1,98,2]],[97,98,97,97,98]]b,Ȯ,Ȯ\c↔,0↔ġ₃kH&hg;Hz{∋ᵈ}ᵐ
e.g. [[0,97,1],[1,98,1],[1,97,0],[0,97,1],[1,98,1]]

Per il primo esempio qui, Linizialmente è un elemento sconosciuto, ma quando lo trasponiamo via\ , Brachylog si rende conto che l'unica possibilità è un elenco con la stessa lunghezza dell'input. L'ultimo esempio qui è non deterministico; stiamo modellando il non determinismo nell'NFA usando il non determinismo nello stesso Brachylog.

Possibili miglioramenti

Una parte della sintassi qui, come ↔,0↔e soprattutto il pasticcio H&hg;Hz{…ᵈ}ᵐ, è piuttosto goffa. Non mi sorprenderebbe se ci fosse un modo più difficile di esprimerlo.

{∋ᵈ}ᵐè di per sé una struttura abbastanza sospetta - ti aspetteresti di poter scrivere ∋ᵈᵐ- ma non analizza per qualche motivo.


∋ᵈᵐnon analizza perché è implementato in modo tale che in teoria potrebbero essere usati nomi con meta-predicato multi-carattere (se esaurissimo le possibilità di simboli singoli). In pratica non è attualmente utilizzato.
Fatalizza il

3

Python 3, 103 80 byte

grazie a @BWO

w=lambda n,f,a={0}:w(n,f[1:],{y for(x,c,y)in n if c==f[0]and{x}&a})if''<f else a

TIO

Comprensione precedente dell'elenco "elegante" (103 byte):

def w(a,b):
    q=[0]
    for c in b:q=[j for s in q for i in a if s in i if i[1]==c for j in i[2]]
    return q

Peccato che Python 3 manchi reduce.. Ma l'uso della ricorsione e dei set effettivi ti porta ancora a 80 byte .
ბიმო

@BWO bello, grazie, ahah, sopra è il mio nuovo codice python di esempio preferito da mostrare ... una comprensione dell'elenco gigante di una riga mi
diverte

Penso che puoi salvare 2 byte sostituendoli if''<fcon if f.
Chas Brown,

@Chas Brown fallisce se f è un valore errato come stringa vuota
Quintec

In realtà, quello che sto dicendo, ignoralo
Quintec,

3

JavaScript (ES6), 99 byte

Accetta input come (nfa)(string). Restituisce un set.

a=>g=([c,...b],s=[0])=>c?g(b,a.reduce((p,[x,y,z])=>s.includes(x)&y==c?[...p,...z]:p,[])):new Set(s)

Provalo online!


3

R , 81 byte

function(a,b,e,s)Reduce(function(A,x)unique(e[a%in%A&b==x]),el(strsplit(s,"")),0)

Provalo online!

Risposta semplice usando Reduce. Prende le regole come tre vettori di state, symbol, new-stateschiamato a,b,e.

Le regole sono separate (es. Rule 0,'a',[1,2]is 0,'a',1e 0,'a',2).



2

Pulito , 68 byte

Questo basato sulla soluzione Haskell di ovs è un po 'più breve del mio approccio iniziale.

ora include un cablaggio di prova

import StdEnv
?d=foldl(\s c=removeDup[r\\(y,r)<-d,g<-s|(g,c)==y])[0]

Provalo online!


1
Aggiunto il cablaggio del test @BWO
Sepurous

1

Carbone , 44 byte

⊞υ⁰Fη«≔υζ≔⟦⟧υFζFθ¿∧⁼§λ⁰κ⁼§λ¹ιF§λ²¿¬№υμ⊞υμ»Iυ

Provalo online! Il collegamento è alla versione dettagliata del codice. Spiegazione:

⊞υ⁰

0{0}

Fη«

Passa sopra l'ingresso.

≔υζ

Copia lo stato.

≔⟦⟧υ

Ripristina lo stato.

Fζ

Passa sopra la copia dello stato.

Fθ

Scorri le voci NFA.

¿∧⁼§λ⁰κ⁼§λ¹ι

Se la voce corrisponde, quindi ...

F§λ²

... passa in rassegna i nuovi stati ...

¿¬№υμ

.... se non sono già nella lista ...

⊞υμ»

... aggiungili all'elenco.

Iυ

Trasmetti l'elenco degli stati su stringa per l'output implicito su righe separate.


1

Perl 6 , 61 54 byte

->\n,\s{set +s&&reduce {n.grep(*[^2]⊆@_)[*;2]},0,|s}

Provalo online!

Prende un elenco di transizioni di stato e una stringa di input come elenco di caratteri.


1

Japt , 31 byte

W=[W]c;Ê?ßUÅVVf!øW føUg)mÌc):Wâ

Provalo!

Salvato 2 byte con un migliore utilizzo della capacità di Japt di formare implicitamente una funzione da alcuni input

Spiegazione:

W=[W]c;                            Initialize the state set to [0] on the first run
       Ê?                   :Wâ    If the input is empty return the unique states; else...
             Vf!øW                 Get the transitions valid for one of the current states
                   føUg)           Of those, get the ones valid for the current character
                        mÌc)       Merge the states of the remaining transitions
         ßUÅV                      Repeat with the remaining characters as input

Il nuovo codice "inizializza stati" potrebbe usare un po 'più di dettaglio. Japt si inizializza Wsu 0 se ci sono meno di 3 input, quindi al primo avvio [W]è [0], e c"appiattisce" un array. [0]è già piatto come diventa, quindi non è cambiato. Nelle esecuzioni successive Wha un valore diverso, ad esempio [1,2]. In tal caso , [W]diventa [[1,2]]un array a elemento singolo in cui quell'elemento è un array. Questa volta lo cscarta e torna a [1,2]. Quindi, al primo giro è W=[0]e alle successive è W=W.

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.