Symbolics.jl Interface
This page documents the Symbolics.jl frontend API for SymbolicSMT.jl, which provides a modern, user-friendly interface using @variables
and Num
types.
Overview
The Symbolics.jl interface wraps the core SymbolicUtils.jl backend with convenient dispatch methods that automatically handle conversion between Num
and SymbolicUtils.Symbolic
types.
Variable Creation
@variables
Macro
The @variables
macro is re-exported from Symbolics.jl for convenience. It creates symbolic variables with specified types:
using SymbolicSMT # @variables is available directly
@variables x::Real y::Real z::Integer p::Bool
Constraint Construction
SymbolicSMT.Constraints
— MethodConstraints(constraints::Vector{Num}, solvertype="QF_NRA")
Create constraints from Symbolics.jl Num
expressions.
This is a convenience constructor that accepts Num
types from Symbolics.jl, unwraps them to SymbolicUtils expressions, and creates the constraint set.
Arguments
constraints::Vector{Num}
: Vector of boolean Symbolics.jlNum
expressionssolvertype::String="QF_NRA"
: Z3 solver type to use
Examples
using Symbolics, SymbolicSMT
@variables x::Real y::Real
# Create constraints with Symbolics.jl syntax
constraints = Constraints([x > 0, y >= 0, x + y < 10])
# Use with standard SymbolicSMT functions
issatisfiable(x + y > 5, constraints)
Create constraints from Symbolics.jl Num
expressions:
@variables x::Real y::Real
# Create constraints with Symbolics.jl syntax
constraints = Constraints([x > 0, y >= 0, x + y < 10])
Satisfiability Checking
SymbolicSMT.issatisfiable
— Methodissatisfiable(expr::Num, constraints::Constraints)
Check satisfiability of a Symbolics.jl Num
expression.
This convenience method accepts Num
expressions from Symbolics.jl, unwraps them to SymbolicUtils, and delegates to the core implementation.
Arguments
expr::Num
: Boolean expression to check for satisfiabilityconstraints::Constraints
: Constraints that must be satisfied
Returns
true
: The expression can be satisfied given the constraintsfalse
: The expression cannot be satisfied given the constraintsnothing
: The solver cannot determine satisfiability (unknown)
Examples
using Symbolics, SymbolicSMT
@variables x::Real y::Real
constraints = Constraints([x > 0, y > 0])
# Check with Symbolics.jl Num expressions
issatisfiable(x < 0, constraints) # false
issatisfiable(x + y > 1, constraints) # true
Check if a Num
expression can be satisfied:
@variables x::Real y::Real
constraints = Constraints([x > 0, y > 0])
issatisfiable(x < 0, constraints) # false
issatisfiable(x + y > 1, constraints) # true
Provability Checking
SymbolicSMT.isprovable
— Methodisprovable(expr::Num, constraints::Constraints)
Check provability of a Symbolics.jl Num
expression.
This convenience method accepts Num
expressions from Symbolics.jl, unwraps them to SymbolicUtils, and delegates to the core implementation.
Arguments
expr::Num
: Expression to check for provabilityconstraints::Constraints
: Constraints under which to check provability
Returns
true
: The expression is provably true under the constraintsfalse
: The expression can be false under the constraints
Examples
using Symbolics, SymbolicSMT
@variables x::Real y::Real
constraints = Constraints([x >= 0, y >= 0])
# Check provability with Symbolics.jl
isprovable(x >= 0, constraints) # true
isprovable(x > y, constraints) # false
Check if a Num
expression is always true:
@variables x::Real y::Real
constraints = Constraints([x >= 0, y >= 0])
isprovable(x >= 0, constraints) # true
isprovable(x > y, constraints) # false
Expression Resolution
SymbolicSMT.resolve
— Methodresolve(expr::Num, constraints::Constraints)
Resolve a Symbolics.jl Num
expression to a boolean constant if possible.
This convenience method accepts Num
expressions from Symbolics.jl, unwraps them to SymbolicUtils, delegates to the core implementation, and wraps boolean results back to Num
if needed.
Arguments
expr::Num
: Expression to resolveconstraints::Constraints
: Constraints to use for resolution
Returns
true
: If the expression is provably truefalse
: If the expression is provably falseNum
: The wrapped original expression if it cannot be resolved
Examples
using Symbolics, SymbolicSMT
@variables x::Real
constraints = Constraints([x > 5])
resolve(x > 0, constraints) # true
resolve(x < 0, constraints) # false
resolve(x > 10, constraints) # x > 10 (as Num)
Resolve Num
expressions to constants when possible:
@variables x::Real
constraints = Constraints([x > 5])
resolve(x > 0, constraints) # true
resolve(x < 0, constraints) # false
resolve(x > 10, constraints) # x > 10 (as Num)
Type Handling
Variable Types
The Symbolics.jl interface supports all standard variable types:
# Real numbers (continuous)
@variables position::Real velocity::Real
# Integers (discrete)
@variables count::Integer index::Integer
# Booleans (logical)
@variables active::Bool valid::Bool
Expression Types
All expression types are automatically handled:
Arithmetic Expressions
@variables x::Real y::Real
expr1 = x + y
expr2 = 2*x - 3*y
expr3 = x^2 + y^2
expr4 = -x + 5
Comparison Expressions
comp1 = x > y
comp2 = x >= 0
comp3 = x == 5
comp4 = x <= 10
comp5 = x < y + 1
Boolean Expressions
@variables p::Bool q::Bool
bool1 = p & q
bool2 = p | q
bool3 = !p
bool4 = (p & q) | (!p & !q)
Mixed Expressions
@variables x::Real p::Bool
mixed1 = (x > 0) & p
mixed2 = p | (x < 5)
mixed3 = p => (x >= 0)
Conversion Details
Automatic Unwrapping
Num
expressions are automatically unwrapped to SymbolicUtils.Symbolic
:
@variables x::Real
num_expr = x > 0 # Symbolics.Num
symbolic_expr = unwrap(num_expr) # SymbolicUtils.BasicSymbolic{Bool}
Automatic Wrapping
Results are wrapped back to Num
when appropriate:
result = resolve(x > 10, constraints)
# If cannot resolve: returns Num
# If resolves to bool: returns Bool
Type Preservation
The interface preserves semantic meaning:
# Input: Num expression
# Processing: SymbolicUtils backend
# Output: Appropriate type (Bool for constants, Num for expressions)
Usage Patterns
Basic Workflow
using Symbolics, SymbolicSMT
# 1. Create variables
@variables x::Real y::Real
# 2. Define constraints
constraints = Constraints([x >= 0, y >= 0])
# 3. Query system
result1 = issatisfiable(x + y > 5, constraints)
result2 = isprovable(x >= 0, constraints)
result3 = resolve(x > 10, constraints)
Advanced Usage
# Mixed variable types
@variables pos::Real vel::Real gear::Integer active::Bool
# Complex constraint set
constraints = Constraints([
pos >= 0, # Real constraint
vel >= 0, vel <= 120, # Real bounds
gear >= 1, gear <= 5, # Integer constraint
active, # Boolean constraint
active => (vel > 0), # Conditional constraint
(gear > 3) => (vel > 50) # Gear-speed relationship
])
# Complex queries
can_be_stationary = issatisfiable(vel == 0, constraints)
always_moving = isprovable(vel > 0, constraints)
high_gear_fast = isprovable((gear > 3) => (vel > 50), constraints)
Comparison with SymbolicUtils Interface
Symbolics.jl Interface (Recommended)
using Symbolics, SymbolicSMT
@variables x::Real y::Real
constraints = Constraints([x > 0, y > 0])
result = issatisfiable(x + y > 1, constraints)
Benefits:
- Modern Julia ecosystem standard
- Clean
@variables
syntax - Automatic type handling
- Better integration with other packages
SymbolicUtils.jl Interface
using SymbolicUtils, SymbolicSMT
@syms x::Real y::Real
constraints = Constraints([x > 0, y > 0])
result = issatisfiable(x + y > 1, constraints)
When to use:
- Advanced symbolic manipulation
- Custom symbolic operations
- Lower-level control
- Existing SymbolicUtils.jl codebase
Mixed Usage
Both interfaces can be used together:
using Symbolics, SymbolicUtils, SymbolicSMT
# Mix Symbolics and SymbolicUtils variables
@variables x::Real # Symbolics.Num
@syms y::Real # SymbolicUtils.Symbolic
# Both work in the same constraint set
constraints = Constraints([x > 0, y > 0])
issatisfiable(x + y > 1, constraints) # Works seamlessly
Error Handling
The Symbolics.jl interface provides the same error handling as the SymbolicUtils backend:
Conversion Errors
# If expressions cannot be converted to Z3
try
constraints = Constraints([unsupported_expr])
catch e
# Detailed error message about conversion failure
println(e)
end
Type Mismatches
# Type mismatches are caught during unwrapping
@variables x::Real
# This would cause an error if x is used in boolean context incorrectly
# The error message will indicate the type mismatch
Performance Notes
Zero Overhead Design
The Symbolics.jl interface adds minimal overhead:
- Dispatch cost: Single method lookup
- Conversion cost: Simple unwrap/wrap operations
- Backend unchanged: Same optimized SymbolicUtils processing
Memory Usage
- Shared backend: No duplication of solver state
- Minimal wrappers:
Num
types are lightweight wrappers - Efficient conversion: Direct delegation without copying
Recommendations
For best performance:
- Batch constraint creation rather than creating many small sets
- Use appropriate variable types for your problem domain
- Prefer the Symbolics interface for new code (better ecosystem integration)
- Mix interfaces judiciously - conversion has minimal but non-zero cost