Generazione di tabelle logiche da if condizioni

4

Supponiamo che io abbia una dichiarazione caso estesa su più righe, che controlla diverse variabili prima di restituire un valore finale.

case
  when (foo='bar' OR foo='foo') AND (bar='foo') then 200
  when (foo='jar') AND (bar='glue' OR bar='true') then 212
  else 0
end

Voglio generare una tabella simile alla seguente:

foo  |bar    |value
'bar'|'foo'  |200
'foo'|'foo'  |200
'jar'|'glue' |212
'jar'|'true' |212
 x   |x      |0

Per me, questo mi ricorda una tabella di verità logica booleana, e sarebbe utile per documentare il codice. È possibile generare questo tipo di "tavolo della verità" attraverso un programma o uno strumento automatico, piuttosto che a mano, e come farei per farlo?

    
posta Decimak 11.10.2016 - 20:24
fonte

4 risposte

1

Userò una soluzione rapida e sporca usando i comandi bash di Lunix

Non è completamente programmatico, ma almeno non dovrai scriverlo a mano (con il conseguente rischio di errori umani), e funziona indipendentemente dalla durata della dichiarazione del caso. Gli outpus di esempio sono solo esempi basati nello snippet.

  • Salva l'istruzione case multilinea (comunque lunga) in un file. Chiamiamolo input_data.txt
  • Filtriamo tutti i compiti di foo e bar in un secondo file. Chiamiamolo all_assignments.txt
$ egrep "\b[[:alpha:]]+\b='[[:alpha:]]+'" input_data.txt -o | sort -u > all_assignments.txt

bar='foo'
bar='glue'
bar='true'
foo='bar'
foo='foo'
foo='jar'
  • Ora filtriamo foo assegnazioni e bar assegnazioni a file separati ( foo.txt e bar. txt )

    $ egrep "^bar" all_assignments.txt > bar.txt

    $ egrep "^foo" all_assignments.txt > foo.txt

  • Ora creiamo un prodotto cartesiano di tutti i possibili incarichi di bar e foo:

    $ while read a; do while read b; do echo "$a; $b"; done < bar.txt; done < foo.txt

che darebbe questo:

foo='bar'; bar='foo'
foo='bar'; bar='glue'
foo='bar'; bar='true'
foo='foo'; bar='foo'
foo='foo'; bar='glue'
foo='foo'; bar='true'
foo='jar'; bar='foo'
foo='jar'; bar='glue'
foo='jar'; bar='true'
  • Estrai la struttura del caso a una funzione nella tua lingua
  • Utente a regexp cerca e sostituisce in un editor per aggiungere un'istruzione di stampa formattata con il valore di foo , bar e result .

Pseudocodice generato:

foo='bar'; bar='foo';print foo bar myFunction(foo,bar);
foo='bar'; bar='glue';print foo bar myFunction(foo,bar);
foo='bar'; bar='true';print foo bar myFunction(foo,bar);
foo='foo'; bar='foo';print foo bar myFunction(foo,bar);
foo='foo'; bar='glue';print foo bar myFunction(foo,bar);
foo='foo'; bar='true';print foo bar myFunction(foo,bar);
foo='jar'; bar='foo';print foo bar myFunction(foo,bar);
foo='jar'; bar='glue';print foo bar myFunction(foo,bar);
foo='jar'; bar='true';print foo bar myFunction(foo,bar);

Quando lo esegui, il tuo tavolo della verità sarà pronto per essere importato in un foglio di calcolo

NOTA:

Tecnicamente ciò che si descrive (e la mia soluzione fornisce) non è una tabella di verità. Un tavolo di verità sarebbe qualcosa di solo le linee di questo:

    
risposta data 11.10.2016 - 22:02
fonte
2

È assolutamente possibile generare tale tabella da un'espressione booleana, a condizione che l'espressione non invochi funzioni. In particolare, assumerò che abbiamo operatori per l'uguaglianza =, negazione NOT, congiunzione AND e disgiunzione OR. Data tale espressione, possiamo trasformarla in una forma normale disgiuntiva a mano, o più noiosamente implementando un algoritmo adatto. In DNF, l'espressione è costituita da gruppi AND che sono OR-ed insieme. Questo è interessante, perché ogni riga della tabella implica un AND per tutti i valori di input.

Esempio:

(foo='bar' OR foo='foo') AND (bar='foo')
<=> distributive law
(foo='bar' AND bar='foo') OR (foo='foo' AND bar='foo')

Produce la tabella:

foo bar
--- ---
bar foo
foo foo

Le cose diventano più difficili una volta introdotte le negazioni:

(foo='bar' OR foo='foo') AND NOT (bar='foo') AND NOT (bar='bar')
<=> distributive law
(foo='bar' AND NOT bar='foo' AND NOT bar='bar') OR (foo='foo' AND NOT bar='foo' AND NOT bar='bar')

Questo non può essere rappresentato direttamente nella tabella, poiché ora escludiamo determinati valori. Ogni cella di una tabella dovrebbe avere la capacità di ESCLUDERE un insieme di valori:

foo | bar
----+------------------
bar | EXCLUDE(foo, bar)
foo | EXCLUDE(foo, bar)

Tenendo presenti queste idee, dovrebbe essere possibile generare manualmente le tabelle con un basso tasso di errore. Se è richiesta una soluzione automatizzata, il problema si riduce alla trasformazione automatizzata di un'espressione booleana in DNF, per cui esistono approcci.

    
risposta data 12.10.2016 - 09:41
fonte
1

Is it possible to generate this sort of "truth table" through a program or automated tool, rather than by hand, and how would I go about doing this?

Come già indicato, è possibile, ma mi piacerebbe dare un'altra visione del problema:

Quella "tabella della verità" sembra essere più leggibile per te del codice originale, e poiché la leggibilità è re, suggerisco quindi di creare il codice dalla tabella .

In pratica, mantieni la tabella in un formato adatto (CSV come semplice esempio, XML se lo desideri più complesso) e da ciò generi sia il codice (ad esempio una funzione che implementa sopra case ) sia la documentazione (HTML, markdown, qualunque sia ).

Un vantaggio è che sei responsabile della sintassi della tua tabella, quindi decidi sia la complessità del parser sia quando (se mai) lo cambi. Codice e documentazione possono essere generati usando un motore di template (proprio, open source, ...).

    
risposta data 11.10.2016 - 23:56
fonte
-1

Se i valori nelle istruzioni case sono gli unici valori validi per foo e bar , potresti fare il seguente tipo di costrutto:

['foo', 'bar', 'jar', 'x'].each do |foo|
    ['foo', 'glue', 'true', 'x'].each do |bar|
        case
            when (foo='bar' OR foo='foo') AND (bar='foo') then result = 200
            when (foo='jar') AND (bar='glue' OR bar='true') then result = 212
            else result = 0
        end
        puts "#{foo},#{bar},#{result}"
    end
end

Sostituisci la riga puts con qualcosa con una formattazione appropriata se vuoi più dell'output CSV. L'idea di base è quella di scorrere tutti i valori di ogni input, valutare la tua espressione ed emettere i risultati. È abbastanza facile generare questo codice manualmente per quasi tutte le condizioni. È un po 'più difficile costruirne uno che itera attraverso un numero enorme di input possibili e combina le righe che hanno lo stesso risultato in righe singole per ciascun intervallo contiguo di valori di input (si pensi a una condizione in cui i valori legali sono l'intero insieme di numeri interi e le condizioni abbastanza complesso da non voler elaborare manualmente i raggruppamenti), ma è fattibile.

    
risposta data 11.10.2016 - 22:27
fonte

Leggi altre domande sui tag