Status: ✅ Production Ready
Solver: Z3 4.13.3
Test Coverage: 100% (12/12 tests passing)
z3 --version
# Z3 version 4.13.3 - 64 bit
make clean && make all
erl -pa _build/ebin -s smt_process_test run -s smt_parser_test run -s init stop
# All 12 tests should pass
cure_smt_solver.erl)cure_smt_solver:check_constraint(Constraint, Env).
% Returns: sat | unsat | unknown
cure_smt_solver:prove_constraint(Constraint, Env).
% Returns: true | false | unknown
cure_smt_solver:find_counterexample(Constraint, Env).
% Returns: {ok, Model} | none | unknown
{ok, Pid} = cure_smt_process:start_solver(z3, 5000).
% Solver: z3 | cvc5
% Timeout: milliseconds
Query = cure_smt_translator:generate_query(Constraint, Env),
Result = cure_smt_process:execute_query(Pid, Query).
% Returns: sat | unsat | {sat, Lines} | {error, Reason}
{ok, Model} = cure_smt_parser:parse_model(Lines).
% Returns: {ok, #{var => value}} | {error, Reason}
cure_smt_process:stop_solver(Pid).
% Constraint: x > 0
Constraint = #binary_op_expr{
op = '>',
left = #identifier_expr{name = x},
right = #literal_expr{value = 0}
},
Env = #{x => {type, int}},
% Check if satisfiable
cure_smt_solver:check_constraint(Constraint, Env).
% => sat (there exists x > 0)
% Find example
cure_smt_solver:find_counterexample(
#unary_op_expr{op = 'not', operand = Constraint},
Env
).
% => {ok, #{x => 0}} (x=0 is counterexample to x > 0)
% Constraint: y /= 0
Constraint = #binary_op_expr{
op = '/=',
left = #identifier_expr{name = y},
right = #literal_expr{value = 0}
},
Env = #{y => {type, int}},
% This is satisfiable (y can be non-zero)
cure_smt_solver:check_constraint(Constraint, Env).
% => sat
% But can we find y = 0? (violates constraint)
cure_smt_solver:find_counterexample(Constraint, Env).
% => {ok, #{y => 0}} (counterexample exists)
% Constraint: x + y == y + x (commutativity)
Constraint = #binary_op_expr{
op = '==',
left = #binary_op_expr{
op = '+',
left = #identifier_expr{name = x},
right = #identifier_expr{name = y}
},
right = #binary_op_expr{
op = '+',
left = #identifier_expr{name = y},
right = #identifier_expr{name = x}
}
},
Env = #{x => {type, int}, y => {type, int}},
% This should be proven true
cure_smt_solver:prove_constraint(Constraint, Env).
% => true (no counterexample exists)
% Constraint: (x > 0) and (y > 0) => (x + y > 0)
Constraint = #binary_op_expr{
op = '=>',
left = #binary_op_expr{
op = 'and',
left = #binary_op_expr{op = '>', left = var(x), right = lit(0)},
right = #binary_op_expr{op = '>', left = var(y), right = lit(0)}
},
right = #binary_op_expr{
op = '>',
left = #binary_op_expr{op = '+', left = var(x), right = var(y)},
right = lit(0)
}
},
Env = #{x => {type, int}, y => {type, int}},
cure_smt_solver:prove_constraint(Constraint, Env).
% => true (proven!)
% Verify that guards cover all possible integer values
% Guards: (x > 0) ∨ (x == 0) ∨ (x < 0)
% Build guard disjunction
GuardConjunction = #binary_op_expr{
op = 'or',
left = #binary_op_expr{
op = 'or',
left = #binary_op_expr{op = '>', left = var(x), right = lit(0)},
right = #binary_op_expr{op = '==', left = var(x), right = lit(0)}
},
right = #binary_op_expr{op = '<', left = var(x), right = lit(0)}
},
Env = #{x => {type, int}},
% Prove this is always true (tautology)
cure_smt_solver:prove_constraint(GuardConjunction, Env).
% => true (complete coverage!)
% Check for unreachable clause: (x > 10) when we already have (x >= 0)
Unreachable = #binary_op_expr{
op = 'and',
left = #binary_op_expr{op = '>=', left = var(x), right = lit(0)},
right = #binary_op_expr{op = '>', left = var(x), right = lit(10)}
},
% Check if (x > 10) is subsumed by (x >= 0)
cure_smt_solver:check_constraint(
#binary_op_expr{op = '=>',
left = #binary_op_expr{op = '>=', left = var(x), right = lit(0)},
right = #binary_op_expr{op = '>', left = var(x), right = lit(10)}
},
Env
).
% => unsat (not all x >= 0 satisfy x > 10, clause is reachable)
Guard Verification Use Cases:
- Completeness: Verify all possible values are covered
- Subsumption: Detect unreachable clauses
- Consistency: Check guards aren't contradictory
- Counterexamples: Find values that violate coverage
See cure_guard_smt.erl for implementation details.
+, -, * → (+ x y), (- x y), (* x y)/ → (/ x y) (real division)div → (div x y) (integer division)rem → (mod x y) (remainder)==, /= → (= x y), (not (= x y))<, > → (< x y), (> x y)=<, >= → (<= x y), (>= x y)and, or, not → (and x y), (or x y), (not x)andalso, orelse → same as and, or=> → (=> x y) (implication)- (negation) → (- x)not (boolean) → (not x)Int, Nat → Int (SMT integer)Bool → Bool (SMT boolean)Float, Real → Real (SMT real)The translator automatically infers the SMT logic:
- QF_LIA - Linear Integer Arithmetic (Int only)
- QF_LRA - Linear Real Arithmetic (Real only)
- QF_LIRA - Linear Mixed Integer/Real Arithmetic
- QF_NIA - Nonlinear Integer Arithmetic (with *, /)
Default timeout is 5000ms. Configure per-solver:
{ok, Pid} = cure_smt_process:start_solver(z3, 10000). % 10 seconds
Or use default:
{ok, Pid} = cure_smt_process:start_solver(z3, 5000).
All functions have graceful error handling:
case cure_smt_solver:check_constraint(Constraint, Env) of
sat -> io:format("Satisfiable~n");
unsat -> io:format("Unsatisfiable~n");
unknown -> io:format("Solver could not determine~n");
{error, Reason} -> io:format("Error: ~p~n", [Reason])
end.
If SMT solver fails, the system falls back to symbolic evaluation.
erl -pa _build/ebin -s smt_process_test run -s smt_parser_test run -s init stop
erl -pa _build/ebin -s smt_process_test run -s init stop
erl -pa _build/ebin -s smt_parser_test run -s init stop
Error: Z3 solver not found
Solution: Install Z3
sudo apt install z3 # Ubuntu/Debian
brew install z3 # macOS
{error, timeout}
Solution: Increase timeout
{ok, Pid} = cure_smt_process:start_solver(z3, 30000). % 30 seconds
{error, {parse_error, Reason}}
Solution: Check constraint syntax and types in environment.
User Code
↓
cure_smt_solver (High-level API)
↓
cure_smt_translator (AST → SMT-LIB)
↓
cure_smt_process (Solver management)
↓
Z3 Solver (via Erlang port)
↓
cure_smt_parser (Model extraction)
↓
Result
src/smt/cure_smt_solver.erl - High-level APIsrc/smt/cure_smt_translator.erl - Constraint translationsrc/smt/cure_smt_process.erl - Solver process managementsrc/smt/cure_smt_parser.erl - Model parsertest/smt_process_test.erl - Process management tests (7 tests)test/smt_parser_test.erl - Parser tests (5 tests)docs/SMT_INTEGRATION_COMPLETE.md - Complete overviewdocs/SMT_INTEGRATION_PLAN.md - Original plandocs/SMT_COMPLETION_PLAN.md - 4-step completion plandocs/SMT_SOLVER_INSTALLATION.md - Installation guide--smt-solver [z3|cvc5]--smt-timeout <ms>--no-smtVersion: 1.0
Last Updated: October 31, 2025
Status: Production Ready ✅
Note: SMT solver integration is available at the Erlang API level. CLI integration is not yet implemented.