sympy / sympy

A computer algebra system written in pure Python

Home Page:https://sympy.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature Request: Add Import/Export Functions for Boolean Expressions in Z3 and BDD Formats

YuriyTigiev opened this issue · comments

Hi SymPy Developers,

Could you please add functions for exporting and importing Boolean expressions in Z3 and BDD formats in the next release? This feature would be incredibly useful.

Thank you for your hard work!

Can you please share the usecase for the requirement ?

The feature request here is reasonable but it is not useful to have an issue open for it if there is no detail about what could be done.

There is no need to have an open issue for someone to work on this if they want. Someone can just open a PR.

I suggest closing this unless some useful information is added.

Can you take a look at https://github.com/sympy/sympy/blob/master/sympy/printing/smtlib.py first before that can be still usable for your application?

What are Z3 and BDD formats anyway? You have come up with ideas not easily searchable in google, but without any references.

The documentation of z3 says that input format is smtlib.
So I'm not sure why my suggestion was not even helpful.

https://github.com/Z3Prover/z3?tab=readme-ov-file#interfaces

Default input format is SMTLIB2

I'm not sure about bdd, however, I'm not even sure about it even can input from some text files
For example, are you suggesting to use their direct Python interface rather than specialized input-output text files?

I needed direct conversion from code without using text files.

Below is an example of the code generated by ChatGPT, but I couldn't use it.

I don't quite understand how I can use SMTLIB2.

Below is an example of one of the boolean expressions I am trying to simplify. This is a very small expression. In real tasks, the number of variables will be 100 times greater.


from sympy import symbols
from sympy.logic.boolalg import And, Or, Not, BooleanFunction
from z3 import And as Z3And, Or as Z3Or, Not as Z3Not, Bool, simplify, Solver

# Function to convert a SymPy expression to Z3
def sympy_to_z3(expr):
    if isinstance(expr, BooleanFunction):
        if isinstance(expr, And):
            return Z3And(*[sympy_to_z3(arg) for arg in expr.args])
        elif isinstance(expr, Or):
            return Z3Or(*[sympy_to_z3(arg) for arg in expr.args])
        elif isinstance(expr, Not):
            return Z3Not(sympy_to_z3(expr.args[0]))
    elif expr.is_Symbol:
        return Bool(str(expr))
    else:
        raise ValueError(f"Unsupported SymPy expression: {expr}")

# Function to convert a Z3 expression to SymPy
def z3_to_sympy(expr):
    if expr.decl().kind() == 263:  # Z3_OP_AND
        return And(*[z3_to_sympy(arg) for arg in expr.children()])
    elif expr.decl().kind() == 258:  # Z3_OP_OR
        return Or(*[z3_to_sympy(arg) for arg in expr.children()])
    elif expr.decl().kind() == 260:  # Z3_OP_NOT
        return Not(z3_to_sympy(expr.children()[0]))
    elif expr.decl().kind() == 235:  # Z3_OP_UNINTERPRETED
        return symbols(str(expr))
    else:
        raise ValueError(f"Unsupported Z3 expression: {expr}")

# Function to optimize a Z3 expression using Z3's solver
def optimize_z3_expr(z3_expr):
    s = Solver()
    s.add(z3_expr)
    if s.check() == z3.sat:
        model = s.model()
        return simplify(z3_expr)
    else:
        raise ValueError("The expression is unsatisfiable")

# Example usage
a, b, c = symbols('a b c')
sympy_expr = And(a, Or(b, Not(c)))

# Convert from SymPy to Z3
z3_expr = sympy_to_z3(sympy_expr)
print(f"Original Z3 Expression: {z3_expr}")

# Optimize the Z3 expression
optimized_z3_expr = optimize_z3_expr(z3_expr)
print(f"Optimized Z3 Expression: {optimized_z3_expr}")

# Convert back from Z3 to SymPy
sympy_converted = z3_to_sympy(optimized_z3_expr)
print(f"Optimized SymPy Expression: {sympy_converted}")

((x0 & ~x2) | (x1 & ~x2) | (x2 & ~x0 & ~x1)) & ((y2 & ~y4) | (y3 & ~y4) | (y4 & ~y2 & ~y3) | (y4 & ~y0 & ~y1 & ~y3)) & ((x0 & y4) ^ (x1 & y3) ^ (x2 & y2) ^ ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2)) ^ ((c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3))) & ~(((x0 & x1 & x2 & y2 & y3 & y4 & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x0 & x1 & x2 & y2 & y3 & y4 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3)) | (x0 & x1 & y3 & y4 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3) & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x0 & x2 & y2 & y4 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3) & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x1 & x2 & y2 & y3 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3) & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2)))) & ((x0 & x1 & y3 & y4) | (x0 & x2 & y2 & y4) | (x1 & x2 & y2 & y3) | (x0 & y4 & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x1 & y3 & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x2 & y2 & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x0 & y4 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3)) | (x1 & y3 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3)) | (x2 & y2 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3)) | ((c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3) & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))))) & ~(((x0 & x1 & x2 & y2 & y3 & y4 & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x0 & x1 & x2 & y2 & y3 & y4 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3)) | (x0 & x1 & y3 & y4 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3) & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x0 & x2 & y2 & y4 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3) & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x1 & x2 & y2 & y3 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3) & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2)))) ^ ((x0 & x1 & y3 & y4) | (x0 & x2 & y2 & y4) | (x1 & x2 & y2 & y3) | (x0 & y4 & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x1 & y3 & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x2 & y2 & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2))) | (x0 & y4 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3)) | (x1 & y3 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3)) | (x2 & y2 & (c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3)) | ((c2.0 | c2.1) & (c2.0 | x0) & (c2.0 | x1) & (c2.0 | x2) & (c2.0 | y1) & (c2.0 | y2) & (c2.0 | y3) & (c2.1 | x0) & (c2.1 | x1) & (c2.1 | x2) & (c2.1 | y1) & (c2.1 | y2) & (c2.1 | y3) & (x0 | x1) & (x0 | x2) & (x0 | y1) & (x0 | y2) & (x1 | x2) & (x1 | y1) & (x1 | y3) & (x2 | y2) & (x2 | y3) & (y1 | y2) & (y1 | y3) & (y2 | y3) & ((c2.0 & c2.1) | (c2.0 & x0 & y3) | (c2.0 & x1 & y2) | (c2.0 & x2 & y1) | (c2.1 & x0 & y3) | (c2.1 & x1 & y2) | (c2.1 & x2 & y1) | (x0 & x1 & y2 & y3) | (x0 & x2 & y1 & y3) | (x1 & x2 & y1 & y2)))))

It looks like your specification anyway needs extra dependency like z3 python interface.

I'm not even sure if that project have to be inside SymPy,
because it should anyway be dependent on both the versions of SymPy and Z3, for instance.

If you are having some expectation like, to ask us to do something in the next release

Could you please add functions for exporting and importing Boolean expressions in Z3 and BDD formats in the next release?

Unfortunately, the expectation may not be matched for you, sorry.
I don't think that it is high priority project.

And you may better spend time learning about SymPy, and try to fix your issue in your own project,
or try to employ someone else who can do the task.

I'm not even sure if that project have to be inside SymPy,

I think it makes sense to have this in SymPy. There already some things in sympy/logic/algorithms/z3_wrapper.py but just not quite a function for going directly from a SymPy expression.

The ChatGPT code is almost right. It just hallucinated the numbers for e.g. Z3_OP_AND:

In [24]: z3.Z3_OP_AND
Out[24]: 261

It would be better to use z3.Z3_OP_AND in the code rather than hardcoding the numbers.

Note to anyone looking to install z3 since this is the second time I have forgotten this: although the module is called z3 it is name is z3-solver on PyPI.