Fuzzing and reducing failures#
Use the correctness guide to select the minimum gate. Generated tests and mutations of real inputs cover different failure modes; neither substitutes for the other. Every solver behavior change needs fresh evidence for its actual configuration.
Choose a generator and inspect coverage#
Input family |
Maintained entry points |
|---|---|
General QF_UF generation |
fuzz_external.py with FuzzSMT; explicit count/seed/reference/timeout |
Real and mixed arithmetic |
|
Integer and mixed integer |
|
Finite domains |
finite_domain_fuzz.py and its profile matrix |
Native sessions |
validate_incremental.py and scoped UF/LRA gates |
Real-seed mutation |
yinyang_fuzz.sh, with logic-specific configs |
The convenience make fuzzsmt target’s small default count is not a merge gate.
A skipped generator/dependency is not a pass. Install missing dependencies
where feasible; otherwise record the blocked gate and failed access/install
command. Counts must include valid inputs actually reaching the relevant solver
mechanism, not just files emitted by a generator.
Seed preparation and mutation limits#
Select a small corpus from an available division:
python3 scripts/build_fuzz_seed_corpus.py \
--root sandbox/non-incremental/QF_LIA \
--out benchmarks/seeds/qf_lia_division --per-family 2 --max-bytes 200000
The seed selector prefers
files below --max-bytes, but includes a family’s smallest file if none fit.
This is a soft size limit. Record actual sizes and family coverage, and set
the mutation tool’s own size limit consistently; otherwise selected seeds may
be skipped. Favoring small files also misses larger shapes. Keep important witnesses such as large
coefficients and proportional polynomial rows; the historical integer defects
show why small-coefficient generation alone is insufficient.
Prepare/sync the workspace first, then stage ignored seeds, and verify them again before submission. A subsequent tracked-file sync can remove the staged corpus. Mutation tasks may exhaust their wall budget before visiting all seeds: report visited seeds, mutations and completed solver calls, rather than claiming complete seed coverage.
Inspect operator config
and typefuzz config before describing
their coverage. The older LIA configs intentionally omit several operators;
this is a mutation-coverage restriction, not the current frontend’s capability
list. In particular, div, mod, and abs are now accepted extensions and
need dedicated coverage when changed. Malformed or out-of-fragment mutants
must be classified separately; valid input rejected by Primo is a failure.
Finite-domain activation#
The finite-domain generator allocates cases across logics, scenarios and known SAT/UNSAT outcomes, including nested/residual choices, observed equalities, definition aliases, shared domains, and transitive domain equalities.
python3 scripts/finite_domain_fuzz.py --solver ./build/primo \
--ref contrib/local/bin/z3 --ref contrib/local/bin/cvc5 \
--logic mixed --count 1000 --seed 4102 --timeout 5 \
--out fuzz-results/finite-domain-review
The amo activation profile requires raw and emitted AMO work. Structural
selection uses its own activation profile: selecting and recognizing structure
does not necessarily generate AMO clauses. Mixed Real cases must also reach
Real-equality transformation and mixed dispatch. Some activity requirements
apply per input, others to the whole corpus. Preserve that distinction and
check missing scenarios/rows as well as wrong answers. Validate successful SAT
models in a separate stage. The maintained full profile matrix is
slurm_finite_domain_fuzz_gate.sbatch.
Triage and reduction#
Retain original input, exact binary/options, reference outputs, exit statuses,
seed and limits. Reproduce the failure before reducing it. An old bugs/
directory is not current evidence: rerun and classify each retained case.
Write a predicate that preserves the specific defect, including valid input and the reference answer for a wrong-answer case. Then run:
python3 scripts/minimize_smt2.py --input failure.smt2 \
--predicate 'python3 path/to/reproducer.py' --output reduced.smt2 --timeout 5
The wrapper invokes ddSMT when installed. If missing, it copies the input and returns success; inspect its message and do not call that a successful reduction. Convert a confirmed minimal defect into an original regression test, then run the required fresh fuzz gate after the fix. A timeout-only case is a performance investigation; a reference disagreement remains unresolved until its cause is known.
Record pass, wrong answer, crash, invalid input, valid-input rejection, timeout, unknown/unsupported, reference disagreement and model outcomes separately. The experiment recording contract applies to every gate, including incomplete and rejected runs.