0

If I take a boolean expression and number of input variables from user, then how can I evaluate the expression (to create its truth table) by using dynamic nested loops instead of doing it like this:

expression= "a and (b or a)"
inputs=2
if inputs==2:
    
    for a in range(0,2):
      for b in range(0,2):
        x = eval(expression)
        print(a,b,x)

if inputs==3:
    
    for a in range(0,2):
      for b in range(0,2):
          for c in range(0,2):
              x = eval(expression)
              print(a,b,x)

It limits the number of variables user can evaluate expression on, as I can not write loops manually. I tried using itertools.product() for this, but I don't know how to give values to the iterating variables.

from itertools import product

variables=['a','b','c']             
for items in product(*variables):
     rows=(eval(expression))
     print(rows)

As you can see, it obviously gives error that a,b,c are undefined in eval(expression). How can I iterate each one of them over [0,1] ?

Junior
  • 1
  • 1

2 Answers2

0

I think you were on the right path here and itertools.product() is what you are looking for. The following is a one-liner, but you could expand it if you want. Note that I am not using eval, but rather a list comprehension paired with the already mentioned itertools.product(). Note also that you can use and, or and () in normal code.

import itertools

rows = [a and (b or c) for a, c, b in itertools.product([True, False], [True, False], [True, False])]
print(rows)

If you are using user input, it might make sense to define truthy values.

Also if you want the inputs for the truth-table, you can also do this first:

import itertools

inputs = [[a, b, c] for a, b, c in itertools.product([True, False], [True, False], [True, False])]
rows = [a and (b or c) for a, c, b in inputs]
print(rows)

Edit: If you have a lot of inputs, the logical expression would likely include any() and all().

Edit2: Now I understand what you mean. Here is a full version with a dynamic number of inputs using the above-mentioned any() and all(). In this example of a logical condition, the first half of the array (rounded down if it is an uneven length) needs to be true and at least one of the second half. Feel free to adapt the expression as you see fit. Note that your original expression does not make much sense. If the first part a is Truthy then the second part where you check for a or b is necessarily also Truthy because we already checked for a. That is why I picked a slightly modified version.

import itertools

input_num = int(input())

arrs = [[False, True]] * input_num
inputs = [x for x in itertools.product(*arrs)]
rows = [all(x[:int(len(x)/2)]) and any(x[int(len(x)/2):]) if len(x) > 1 else bool(x) for x in inputs ]
print(rows)
C Hecht
  • 932
  • 5
  • 14
  • Thank you ! But, you have explicitly mentioned three 'true false' lists for each variable which is exacty i want to be dynamic. But i did that from the answer of Karan by doing temp=[[0,1]]*inputs . But it no longer evaluates the function as desired, it give 1 on all rows with boolean operators and gives error if i write "d" as one of variable names. – Junior Aug 27 '21 at 17:56
  • I edited my answer to hopefully produce your expected result – C Hecht Aug 30 '21 at 07:39
  • The reason why all of your tests evaluated as True btw was that you likely did not unpack the list. This is what the little `*` does in the argument for the function product. – C Hecht Aug 30 '21 at 07:43
0

You could do it using itertools.product() simply

import itertools

inputs = int(input())

temp = [[0, 1]] * inputs

for combination in itertools.product(*temp):
    print(combination)
  • I tried this and it works perfect in iterating the loop over 0 and 1, but it does not evaluate the function correctly. And for some weird reason it always gives error on "d" variable. – Junior Aug 27 '21 at 17:50