Skip to content

Boolean expressions not simplified correctly #92

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kevin-cfs opened this issue Oct 23, 2019 · 4 comments
Open

Boolean expressions not simplified correctly #92

kevin-cfs opened this issue Oct 23, 2019 · 4 comments

Comments

@kevin-cfs
Copy link

kevin-cfs commented Oct 23, 2019

I am utilizing this code in a project of mine and am finding I have some really long boolean logic when I finish. I am relying heavily on the simplification component in order to make my whole project work but I realize that it doesn't seem to work as well as Wolfram Alpha. Here is a simple test.

logic = "( a & ~b & ~c )|( a & ( b | c ))"

According to Wolfram Alpha this evaluates to just 'a' but boolean.BooleanAlgebra(logic, simplify=True) doesn't change the results at all. This is a big issue for me. Has anyone else experienced the simplification not working effectively sometimes?

To further show this you can simplify this expression.
logic = "(~b & ~c) | (b | c)"
The result should be 1 or TRUE but the boolean parser gives a clearly wrong answer of "b|c|~c". But how can you ever have "c or not c"? That is clearly wrong.

b | c | (~b & ~c) | (b | c)
--|---|--------------------
T | T | T
T | F | T
F | T | T
F | F | T

@kevin-cfs kevin-cfs changed the title Boolean expressions not simplified Boolean expressions not simplified correctly Oct 23, 2019
@kevin-cfs
Copy link
Author

Update:

It seems that when you take an expression and run the simplify() function on it then it will sometimes give different results than parsing the string form of it will.

#######################################################################
import boolean

algebra = boolean.BooleanAlgebra()
a, b = algebra.symbols(*'ab')

logic = (a&b)|(~a|~b)
print(str(logic))
print(str(logic.simplify()))
print(str(algebra.parse(str(logic), simplify=True)))

logic = logic.simplify()
print(str(logic.simplify()))
print(str(algebra.parse(str(logic), simplify=True)))
#######################################################################

In this example we have a very simple case that tests out the difference between the simplify() function and the algebra.parse() function. And these are the results.

print 1 ==> (a&b)|(~a|~b)
print 2 ==> ~a|b|~b
print 3 ==> ~a|b|~b
print 4 ==> ~a|b|~b
print 5 ==> 1

As you can see. Both simlify() and algebra.parse() make an attempt to simplify the expression and it has technically made progress but clearly isn't finished. Both of them manage to do the same amount of work on the original input. Next you take the output an run it through this process again but this time when the shorter logic of '~a|b|~b' is parsed with the algebra object from a string it actually does get simplified further. This does not happen in every case but I have found it to be true here in this one.

I would love for this to work properly every time because I cannot even rely on running these statements multiple times in order to get these expressions worked down. I have to use this simplification process thousands of times with logic that contains tens of terms. If it fails to work on these small examples it will surely work on the much larger ones.

@pombredanne
Copy link
Collaborator

@kevin-cfs Thank you for the report!
The gist of the issue is that this implement a simplification algorithm, not a full boolean minimization (e.g. not Quine-McCluskey type algo as in https://en.wikipedia.org/wiki/Quine%E2%80%93McCluskey_algorithm ). This likely explains why "( a & ~b & ~c )|( a & ( b | c ))" may not be minimized.
That would be possible but a significant piece of work. Ideally integrating an existing library like @tpircher https://github.com/tpircher/quine-mccluskey would likely be the best option.

On a separate note, if the following happens:...

It seems that when you take an expression and run the simplify() function on it then it will sometimes give different results than parsing the string form of it will.

then that would likely be a bug. In general I always prefer to use expression strings or build them from nested AND/OR/NOT rather than build them from Python variables and operators.

In earnest, the support of Python-level operators such as in your a, b = algebra.symbols(*'ab');logic = (a&b)|(~a|~b) is likely a source of subtle issues. Parsing a string is always a better option IMHO.

@kevin-cfs
Copy link
Author

kevin-cfs commented Oct 25, 2019 via email

@pombredanne
Copy link
Collaborator

The ideal case would be to add full minimization here in boolean.py. If you care about it, you contribution would be much welcomed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants