Skip to main content

What is SMT Solving?

SMT (Satisfiability Modulo Theories) solving is a technique for checking the satisfiability of logical formulas with respect to combinations of background theories. SMT solvers extend SAT (Boolean satisfiability) solvers by supporting reasoning about data types, arithmetic, arrays, and other structures.
The NL2FOL system uses SMT solvers to automatically verify whether a logical argument is valid or contains a fallacy.

Why Use SMT Solvers?

SMT solvers provide several advantages for logical verification:

Automation

Automatically check validity without manual proof construction

Efficiency

Modern solvers can handle complex formulas with many variables

Soundness

Guaranteed correct results based on formal logic

Completeness

Can determine SAT, UNSAT, or UNKNOWN for any formula

From FOL to SMT-LIB

The NL2FOL system converts first-order logic formulas to SMT-LIB format, a standardized input language for SMT solvers.

SMT-LIB Format

SMT-LIB uses S-expressions (similar to Lisp) to represent logical formulas:

The CVCGenerator Class

The CVCGenerator class (src/cvc.py) handles the conversion from FOL to SMT-LIB format.

Architecture

Key Components

The first step is to break down the formula into tokens:
This converts the formula string into a list of tokens, normalizing operators.
The system defines an Operator class to manage logical operators:
Operator Priorities:
  1. not (highest)
  2. exists, forall
  3. and
  4. or
  5. =>, = (lowest)
Predicates are parsed recursively to handle nested structures:
This handles predicates with multiple arguments, including nested predicates.

Sort System

The sort system ensures type consistency across predicates.

Sort Types

BoundSet

For variables bound by quantifiers (exists/forall)

UnboundSet

For free variables without quantifiers

Bool

For boolean expressions and compound formulas

Sort Inference

Sort Unification

The system ensures predicates are used consistently:
If a predicate is used with inconsistent sorts (e.g., IsTall(x) where x is BoundSet in one place and UnboundSet in another), the system raises an exception.

Prefix Form Conversion

SMT-LIB uses prefix notation (operator before operands). The system converts infix to prefix:

Algorithm

Parenthesization

The conversion works by:
  1. Reversing the infix formula
  2. Swapping parentheses
  3. Converting to postfix
  4. Building prefix expressions from the stack

Generating the SMT Script

The final step produces a complete SMT-LIB script:

Script Structure

Sets the logic to ALL (supports all theories) and enables model generation.
Declares custom sorts for bound and unbound variables.
Declares free variables with their sorts.
Declares predicates with their argument sorts and return type.
Asserts the negation of the formula. If this is satisfiable, the original formula is invalid.
Checks if the assertion is satisfiable and requests a model if so.

Interpreting Results

SMT solvers return one of three results:

SAT

SatisfiableA model exists that satisfies the formulaFor negated fallacies: FALLACY DETECTED

UNSAT

UnsatisfiableNo model can satisfy the formulaFor negated fallacies: VALID ARGUMENT

UNKNOWN

UnknownSolver couldn’t determine result (timeout, complexity)May need different solver or simplification

Example: Detecting a Fallacy

Let’s see how the solver detects a hasty generalization:
Formula: exists x (IsTall(x) and LovesCheese(x)) -> forall y (IsTall(y) -> LovesCheese(y)) Negated: NOT(exists x (IsTall(x) and LovesCheese(x)) -> forall y (IsTall(y) -> LovesCheese(y))) This is equivalent to:
Interpretation: There exists a tall person who loves cheese, AND there exists a tall person who doesn’t love cheese. Result: SAT - This is satisfiable! The model shows:
  • x is tall and loves cheese
  • y is tall and doesn’t love cheese
Since the negation is SAT, the original formula is invalidFALLACY DETECTED

Finite Model Finding

For some formulas, the system enables finite model finding:
Finite model finding restricts the solver to search only finite domains, which can improve performance for certain types of formulas.

Command-Line Usage

The CVC generator can be used directly from the command line:

Integration with SMT Solvers

The generated SMT-LIB scripts can be used with various solvers:

CVC5

Modern SMT solver with excellent performance

Z3

Microsoft’s powerful SMT solver
While the module is named cvc.py, the SMT-LIB format it generates is compatible with any SMT-LIB 2.0 compliant solver, including Z3, CVC4, CVC5, and others.

Performance Considerations

Complexity Factors

  1. Number of quantifiers: More quantifiers increase search space
  2. Nesting depth: Deeply nested formulas are harder to solve
  3. Number of predicates: More predicates means more possible interpretations
  4. Domain size: Larger domains (when specified) increase complexity

Optimization Strategies

Avoid alternating between exists and forall when possible, as this creates high complexity.
Enable finite model finding for formulas where infinite domains are unnecessary.
Apply logical simplifications (e.g., removing double negations) before passing to solver.

Next Steps

First-Order Logic

Review FOL fundamentals and notation

Translation Pipeline

See how natural language becomes FOL

API Reference

Use the CVCGenerator class

Quick Start

Try the complete system