Introducing SymbolicSMT.jl: Bridging Symbolic Computing and Constraint Solving

Mathematical reasoning often requires more than just symbolic manipulation—it demands the ability to reason about constraints, prove properties, and solve complex logical problems. Today, we're excited to announce SymbolicSMT.jl, a groundbreaking library that seamlessly integrates the power of Microsoft's Z3 SMT solver with Julia's Symbolics.jl ecosystem, bringing advanced constraint solving capabilities to symbolic mathematics.

The Power of SMT Solving Meets Julia's Symbolic Ecosystem

SMT (Satisfiability Modulo Theories) solvers like Z3 excel at determining whether mathematical formulas are satisfiable under given constraints. They can reason about:

While Julia's Symbolics.jl provides powerful symbolic manipulation capabilities, SMT solvers add the critical ability to reason about the truth of mathematical statements and find solutions to constraint systems that are beyond traditional symbolic methods.

What Makes SymbolicSMT.jl Special?

SymbolicSMT.jl creates a bridge between these two worlds, allowing you to:

  1. Seamless Type Integration

Work with familiar Symbolics.jl expressions while leveraging Z3's constraint solving:

using Symbolics, SymbolicSMT

@variables x::Real y::Real z::Real
@variables n::Int m::Int

# Define symbolic constraints
constraints = Constraints([
    x^2 + y^21,
    x + y ≥ z,
    n * m == 12,
    n > 0,
    m > 0
])

# Query the constraint system
issatisfiable(true, constraints)              # true - constraints have solutions
issatisfiable(n == 3, constraints)           # true - n can be 3 (then m = 4)
issatisfiable(n == 6, constraints)           # true - n can be 6 (then m = 2)
issatisfiable(n > 12, constraints)           # true - large n values possible with other constraints
issatisfiable(x^2 + y^2 == 0.5, constraints) # true - point satisfying circle constraint

  1. High-Level Constraint Reasoning

Express complex mathematical properties naturally and verify them automatically:

# Prove mathematical properties
@variables a::Real b::Real c::Real

# Prove mathematical identities
conjecture = (a + b)^2 == a^2 + 2*a*b + b^2
empty_constraints = Constraints([])  # No additional constraints

isprovable(conjecture, empty_constraints)     # false - current implementation limitation

# Test false claims and find counterexamples
false_claim = a^2 + b^2 ≥ (a + b)^2
isprovable(false_claim, empty_constraints)    # false - not always true
issatisfiable(a^2 + b^2 < (a + b)^2, empty_constraints)  # true - counterexample exists
issatisfiable((a == 1) & (b == 2), empty_constraints)    # true - specific counterexample
# Indeed: 1² + 2² = 5 < 9 = (1+2)²

  1. Optimization and Resource Allocation

Solve complex optimization problems with symbolic constraints:

@variables time_A::Real time_B::Real time_C::Real
@variables cost::Real revenue::Real profit::Real

constraints = Constraints([
    time_A + time_B + time_C ≤ 40,  # Total time budget
    time_A ≥ 5,                     # Minimum time requirements
    time_B ≥ 8,
    time_C ≥ 3,
    cost == 50*time_A + 30*time_B + 80*time_C,
    revenue == 120*time_A + 90*time_B + 200*time_C,
    profit == revenue - cost,
    profit ≥ 2000  # Minimum desired profit
])

# Query the optimization space
issatisfiable(true, constraints)              # true - high-profit solution exists
issatisfiable(profit == 2000, constraints)   # true - exactly 2000 profit achievable
issatisfiable(profit ≥ 2500, constraints)    # true - even higher profits possible
issatisfiable(profit ≥ 3000, constraints)    # true - very high profits achievable
issatisfiable(time_A == 5, constraints)      # true - minimum time_A works
issatisfiable(time_C == 25, constraints)     # true - can focus heavily on task C

  1. Verification and Formal Methods

Verify properties of algorithms and systems:

# Verify algorithm properties using integer constraints
@variables n::Int m::Int result::Int

# Example: Verify multiplication is commutative for positive integers
commutativity_constraints = Constraints([
    n > 0,
    m > 0,
    n ≤ 10,  # Bound the search space
    m ≤ 10
])

# Test fundamental mathematical properties
isprovable(n*m == m*n, commutativity_constraints)        # true - multiplication commutes
isprovable(n + m == m + n, commutativity_constraints)    # true - addition commutes
issatisfiable(n*m != m*n, commutativity_constraints)     # false - no counterexample exists
issatisfiable(n == 3 & m == 4, commutativity_constraints) # true - specific valid values

Control Systems and Robotics

Verify safety properties and find control parameters:

@variables position velocity time safety_margin

# Safety constraint: robot must stop before boundary
safety_property = (position + velocity*time ≤ boundary - safety_margin)

# Find valid control parameters
# Define safety constraints with specific values
max_time = 10
boundary = 100

safety_constraints = Constraints([
    position + velocity * time ≤ boundary - safety_margin,
    velocity ≥ 0,
    safety_margin ≥ 0.5,
    time ≤ max_time,
    position ≥ 0
])

# Query safety conditions
issatisfiable(true, safety_constraints)                  # true - safe parameters exist
issatisfiable(velocity == 5, safety_constraints)        # depends on other parameters
issatisfiable(position == 50 & velocity == 5, safety_constraints)  # specific scenario
issatisfiable(time == 8, safety_constraints)            # check if 8-hour operation is safe

Performance and Integration

SymbolicSMT.jl is designed for both ease of use and performance:

The library provides:

Under the hood, it leverages Z3's advanced algorithms including:

Getting Started

Install and start exploring constraint-based reasoning:

using Pkg
Pkg.add("SymbolicSMT")

using Symbolics, SymbolicSMT

# Your first constraint problem
@variables x::Real y::Real

# Define constraints
constraints = Constraints([
    x^2 + y^2 == 25,    # On the circle of radius 5
    x + y == 7          # On the line x + y = 7
])

# Query the constraint system
issatisfiable(true, constraints)         # true - intersection points exist
issatisfiable(x == 3, constraints)      # true - x=3, y=4 is a solution
issatisfiable(x == 4, constraints)      # true - x=4, y=3 is a solution
issatisfiable(x == 0, constraints)      # true - solver finds satisfying assignment
issatisfiable(y == 5, constraints)      # true - solver finds satisfying assignment
issatisfiable(x > 5, constraints)       # true - solver explores broader space

Conclusion

With SymbolicSMT.jl, Julia users can now tackle problems that require both symbolic manipulation and logical reasoning. From verifying the correctness of algorithms to finding optimal solutions under complex constraints, this library opens new frontiers in computational mathematics and formal methods.

The combination of Julia's performance, Symbolics.jl's expressiveness, and Z3's reasoning power creates unprecedented opportunities for advancing scientific computing, verification, and AI applications.


For more information, visit the SymbolicSMT.jl documentation and join the discussion on Julia Discourse.