Come trasformare la tabella di verità nel blocco if / else più piccolo possibile


20

Come posso prendere una tabella della verità e trasformarla in un blocco if compattato?

Ad esempio, supponiamo di avere questa tabella di verità in cui A e B sono condizioni e x, ye z sono azioni possibili:

A B | x y z
-------------
0 0 | 0 0 1
0 1 | 0 0 1
1 0 | 0 1 0
1 1 | 1 0 0

Questo potrebbe trasformarsi in sotto se blocco:

if(A)
{
    if(B)
    {
        do(x)
    }
    else
    {
        do(y)
    }
}
else
{
    do(z)
}

Questo è un semplice esempio, ma spesso ho diverse condizioni che combinate in modi diversi dovrebbero produrre output diversi e diventa difficile capire il modo più compatto ed elegante di rappresentare la loro logica in un blocco if.


10
intendi trasformare una mappa di Karnaugh in una cascata ifelse?
maniaco del cricchetto,

@Ratchet: sembra che non lo faccia? Non li conoscevo prima. Dovrà fare qualche lettura, ma comunque e un'app che lo farebbe per me sarebbe bello, se non altro, per verificare i miei risultati fatti a mano.
Juan,

1
@jalayn la maggior parte degli strumenti karnaugh sono per i circuiti digitali; quelli hanno un'euristica diversa da quella di cui si tratta
maniaco del cricchetto il

1
@jsoldi: le risposte che ricevi dipenderanno dal sito che chiedi. Se stai cercando commenti su un particolare frammento di codice contenente alcuni blocchi if-then-else, appartiene sicuramente alla revisione del codice (beta) . Stackoverflow ti insegnerà gli strumenti e le tecniche. Su programmers.SE, le persone ti diranno se dovresti / non dovresti preoccuparti di riscrivere le dichiarazioni logiche per la comprensione umana o per un'esecuzione più rapida.
rwong,

2
Raccomandazioni utensili sono off-topic, ma se si cambia la domanda in "Come possono io fare questo?" sarà in tema. Se vuoi una raccomandazione sul software, dovresti andare su softwarerecs.stackexchange.com.
Kilian Foth,

Risposte:


14

Se stai progettando da una mappa di Karnaugh, anche il codice potrebbe apparire così:

//                   a      b
def actionMap = [ false: [false: { z() },
                          true:  { z() }],
                  true:  [false: { x() },
                          true:  { y() }]]

actionMap[a][b]()

Che lingua è questa? Javascript? Pitone?
TheLQ

TheLQ, non è python, potrebbe essere javascript. Ma sarebbe molto simile se scritto in pitone
grizwako il

@TheLQ: è Groovy, perché è quello che sto facendo in questi giorni, e probabilmente anche Ruby. Il codice per Javascript o Python o LUA o Perl sarebbe molto simile.
Kevin Cline,

2
Questo, ovviamente, ha l'effetto di valutare b anche quando la valutazione non è necessaria. Forse è un problema, forse no.
Pseudonimo,

@kevincline per favore, abbastanza per favore, "Lua", non "LUA". :)
Machado,

4

In C # .NET, puoi utilizzare una classe di dizionario per ottenere il risultato senza IF ELSE come segue: La cosa bella di questo è:

  1. È leggibile
  2. Le nuove chiavi saranno univoche (altrimenti, otterrai un errore)
  3. La sequenza non ha importanza
  4. Facile da aggiungere o rimuovere voci

Se non disponi di un equivalente della classe del dizionario, puoi fare lo stesso in una funzione di ricerca / ricerca binaria.

//A B | x y z
//-------------
//0 0 | 0 0 1
//0 1 | 0 0 1
//1 0 | 0 1 0
//1 1 | 1 0 0
// Create a Dictionary object and populate it
Dictionary<string, string> _decisionTable = new Dictionary<string, string>() { 
    { "0,0", "0,0,1" }, 
    { "0,1", "0,0,1" }, 
    { "1,0", "0,1,0" }, 
    { "1,1", "1,0,0"} 
};

//usage example: Find the values of X,Y,Z for A=1,B=0
Console.WriteLine(_decisionTable["1,0"]);
Console.Read();

1
Mi piace questa soluzione, l'unica modifica che vorrei fare sarebbe usare un dizionario <Tuple <bool, bool>, Tuple <bool, bool, bool> invece di un dizionario <string, string>. Quindi non è necessario creare una stringa per cercare e decostruire il risultato in seguito poiché Tuples lo farà per te.
Lyise,

@Lyise, grazie per la tua osservazione. Hai assolutamente ragione. Dovrei includere il tuo buon punto quando ne avrò la possibilità.
NoChance,

2

Quello che vuoi è un algoritmo di Rete . Questo combina automaticamente un insieme di regole e le priorità in un albero come descritto.

Esistono numerosi sistemi commerciali di "motore delle regole" che lo fanno su larga scala (milioni di regole) in cui la velocità di esecuzione è essenziale.


2

Ecco la tua libreria :) E non è necessario passare la tabella K completa, solo i campi che ti interessano :) Si presume che il suo operatore AND nella tabella di verità. Se vuoi usare più operatori, dovresti essere in grado di riscriverlo. Puoi avere qualsiasi numero di argomenti. Scritto pythone testato.

def x():
    print "xxxx"

def y():
    print "yyyyy"

def z(): #this is default function
    print "zzzzz"

def A():
    return 3 == 1

def B():
    return 2 == 2


def insert(statements,function):
    rows.append({ "statements":statements, "function":function })

def execute():
    for row in rows:
        print "==============="
        flag = 1

        for index, val in enumerate(row["statements"]):
            #for first pass of lopp, index is 0, for second its 1....
            #if any function returns result different than one in our row, 
            # we wont execute funtion of that row (mark row as not executable)
            if funcs[index]() != val:
                flag = 0

        if flag == 1:
            #we execute function 
            row["function"]()
        else: z() #we call default function


funcs = [A,B]  #so we can access functions by index key
rows = []

insert( (0,0), y)
insert( (0,1), y)
insert( (1,0), x)
insert( (1,1), x)
insert( (0,1), x)

execute()

1

Mappare gli input in un singolo valore e quindi accenderlo:

#define X(a, b) (!!(a) * 2 + !!(b))
switch(X(A, B)) {
case X(0, 0):
    ...
    break;
case X(0, 1):
    ...
    break;
case X(1, 0):
    ...
    break;
case X(1, 1):
    ...
    break;
}
#undef X

1

Una tabella di ricerca contenente i puntatori a funzioni può funzionare bene in alcune situazioni. In C, ad esempio, puoi fare qualcosa del genere:

typedef void(*VoidFunc)(void);

void do(int a, int b)
{
    static VoidFunc myFunctions[4] = {z, z, y, x}; // the lookup table

    VoidFunc theFunction = myFunctions[ a * 2 + b ];
    theFunction();
}

Questa è una buona soluzione quando il numero di input è relativamente piccolo, poiché il numero di voci nella tabella deve essere 2 ^^ n dove n è il numero di input. 7 o 8 ingressi potrebbero essere gestibili, 10 o 12 iniziano a diventare brutti. Se hai così tanti input, prova prima a semplificare con altri mezzi (come le mappe di Karnaugh).


0

Guarda il software "Gorgeous Karnaugh": può accettare tabelle di verità abbastanza esatte come il tuo campione, accettare definizioni di formule booleane analitiche, accettare script Lua per costruire tabelle di verità. Successivamente, il software "Gorgeous Karnaugh" disegna le K-Maps per l'input preso, che puoi minimizzare manualmente o usando il minimizer logico "Espresso", e produce output per C / C ++ e alcuni linguaggi hardware. Guarda la pagina delle caratteristiche di riepilogo per "Gorgeous Karnaugh" - http://purefractalsolutions.com/show.php?a=xgk/gkm


Assomiglia molto a quello di cui ho bisogno, ma non è stato possibile ottenere il codice C / C ++ per mostrare qualcosa di diverso dai vuoti ifdopo aver inserito una tabella di verità.
Juan

Sì, quello strumento progettato per minimizzare le funzioni logiche - dopo aver inserito la tabella di verità è necessario minimizzare la funzione logica (PoS / SoP - di 0 / per 1). Il codice C ++ si trova nella finestra "Risultati della minimizzazione" dopo la minimizzazione.
Petruchio,
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.