2012-09-17 18 views
6

Sto provando a creare un programma, che usa sympy per prendere un set di variabili e valutare un'espressione logica simbolica sul dominio di quelle variabili. Il problema è che non riesco a ottenere Python per valutare l'espressione dopo che sputa la tabella della verità.Tabelle di verità in python usando sympy

Ecco il codice:

from sympy import * 
from sympy.abc import p, q, r 

def get_vars(): 
    vars = [] 
     print "Please enter the number of variables to use in the equation" 
     numVars = int(raw_input()) 
    print "please enter each of the variables on a newline" 
     for i in xrange(numVars): 
     vars.append(raw_input()) 
    return vars 

def get_expr(): 
    print "Please enter the expression to use" 
    return str(raw_input()) 

def convert_to_expr(inputStr): 
    return eval(inputStr) 

def main(): 
    vars = get_vars() 
    expr = get_expr() 

    print("recieved input: " + str(vars) + " expr " + str(expr)) 

    print "Truth table for " + str(len(vars)) + "variable(s)" 
    for i in enumerate(truth_table(vars, expr)): 
     print i 

def fixed_table(numvars): 
    """ 
    Generate true/false permutations for the given number of variables. 
    So if numvars=2 
    Returns (not necessarily in this order): 
     True, True 
     True, False 
     False, False 
     False, True 
    """ 
    if numvars is 1: 
     yield [True] 
     yield [False] 
    else: 
     for i in fixed_table(numvars-1): 
      yield i + [True] 
      yield i + [False] 


def truth_table(vars, expr): 
    """ 
    Takes an array of variables, vars, and displays a truth table 
    for each possible value combination of vars. 
    """ 
    for cond in fixed_table(len(vars)): 
     values=dict(zip(vars,cond)) 
     yield cond + [eval(expr)] 

if __name__ == "__main__": 
    main() 

Se faccio seguito, ecco l'output:

Please enter the number of variables to use in the equation 
3 
please enter each of the variables on a newline 
p 
q 
r 
Please enter the expression to use 
p&q&r 
recieved input: ['p', 'q', 'r'] expr p&q&r 
Truth table for 3variable(s) 
(0, [True, True, True, And(p, q, r)]) 
(1, [True, True, False, And(p, q, r)]) 
(2, [True, False, True, And(p, q, r)]) 
(3, [True, False, False, And(p, q, r)]) 
(4, [False, True, True, And(p, q, r)]) 
(5, [False, True, False, And(p, q, r)]) 
(6, [False, False, True, And(p, q, r)]) 
(7, [False, False, False, And(p, q, r)]) 

Se alcuni software esiste per eseguire questa operazione, mi piacerebbe davvero sapere a questo proposito :-)

Grazie in anticipo.

risposta

7

Sei davvero vicino! Una volta che hai And(p, q, r) e le tabelle di verità, è possibile utilizzare il metodo subs di spingere il vostro values dict nell'espressione: cioè

yield cond + [eval(expr).subs(values)] 

p&q&r 
recieved input: ['p', 'q', 'r'] expr p&q&r 
Truth table for 3variable(s) 
(0, [True, True, True, True]) 
(1, [True, True, False, False]) 
(2, [True, False, True, False]) 
(3, [True, False, False, False]) 
(4, [False, True, True, False]) 
(5, [False, True, False, False]) 
(6, [False, False, True, False]) 
(7, [False, False, False, False]) 

Ma penso che ci sia un modo più semplice per Fai questo. La funzione sympify lavora già per generare espressioni dalle stringhe:

In [7]: expr = sympify("x & y | z") 

In [8]: expr 
Out[8]: Or(z, And(x, y)) 

e possiamo ottenere le variabili troppo:

In [9]: expr.free_symbols 
Out[9]: set([x, z, y]) 

più itertools.product in grado di generare i valori (e cartes è un alias per esso in sympy) :

In [12]: cartes([False, True], repeat=3) 
Out[12]: <itertools.product at 0xa24889c> 

In [13]: list(cartes([False, True], repeat=3)) 
Out[13]: 
[(False, False, False), 
(False, False, True), 
(False, True, False), 
(False, True, True), 
(True, False, False), 
(True, False, True), 
(True, True, False), 
(True, True, True)] 

combinazione di questi, che è fondamentalmente solo utilizzando sympify per ottenere il espressione e di evitare eval, utilizzando il built-in prodotto cartesiano, e l'aggiunta di .subs() di utilizzare il dizionario values, otteniamo:

def explore(): 
    expr_string = raw_input("Enter an expression: ") 
    expr = sympify(expr_string) 
    variables = sorted(expr.free_symbols) 
    for truth_values in cartes([False, True], repeat=len(variables)): 
     values = dict(zip(variables, truth_values)) 
     print sorted(values.items()), expr.subs(values) 

che dà

In [22]: explore() 
Enter an expression: a & (b | c) 
[(a, False), (b, False), (c, False)] False 
[(a, False), (b, False), (c, True)] False 
[(a, False), (b, True), (c, False)] False 
[(a, False), (b, True), (c, True)] False 
[(a, True), (b, False), (c, False)] False 
[(a, True), (b, False), (c, True)] True 
[(a, True), (b, True), (c, False)] True 
[(a, True), (b, True), (c, True)] True 

Questo è più breve della tua, ma utilizza esattamente il tuo approccio

+0

Sei fantastico. Grazie mille, ha funzionato perfettamente !!! – alvonellos