Code and experiment launcher for the paper.
Title
SART: Sign-Absolute Reformulation Theory for Binary Variable Reduction in Neural Network Verification
Venue
Accepted at OOPSLA 2026
Authors
Jin Xu, Miaomiao Zhang, and Bowen Du
Affiliation
Tongji University, China
DOI
10.1145/3798237
Overview
SART is a binary-variable reduction theory for complete neural network verification. It breaks the standard one-unstable-ReLU-one-binary-variable encoding rule, and LayerABS builds on it as a progressive verifier that tightens bounds layer by layer to reduce complete solving cost. This repository contains the paper-aligned implementations of abstract_sart, abstract_milp, incomplete_layerabs, puresart, and standard_milp, together with benchmark assets, experiment presets, and exported paper-table summaries.
Supplementary Material
This repository has been cleaned into a single active maintenance path. The main LayerABS families, their paper-facing controllers, the benchmark/model variants, the paper presets, and the result summarization/export tools are all kept in-tree. Historical copies, one-off branches, and cached runtime artifacts were removed from the active layout.
- the refactored LayerABS family controllers and shared algorithm code under
sart/layerabs/ - baseline verifiers and related scripts under
sart/verify/ - benchmark models under
sart/models/ - benchmark property files under
sart/*_properties/andsart/mnist_vnnlib/ - conversion and preparation utilities under
sart/conversion_tools/ - a root launcher,
run_experiment.py, that can list scripts, run family controllers, run named paper presets, summarize completed runs, and export paper-table artifacts - tests under
tests/
External baseline frameworks such as PRIMA, Marabou, MIPVerify, and beta-CROWN are intentionally not integrated into the unified launcher. The in-tree paper presets focus on the repository's own LayerABS-family methods.
Recommended baseline:
- Python
3.9+ - dependencies from
requirements.txt - a working Gurobi installation and license for the MILP-based paths
Typical setup:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtIf you use Conda instead of venv, use your existing environment workflow and install the same requirements there.
Gurobi is required for:
LayerABS_abstract_milpLayerABS_standard_milpLayerABS_incomplete_layerabs- the complete/stats/time-limit family paths that invoke MILP refinement or complete solving
Some other verifier scripts under sart/verify/ also depend on Gurobi or other external packages.
.
├── README.md
├── run_experiment.py
├── paper_presets.py
├── paper_results.py
├── experiment_catalog.py
├── layerabs_naming.py
├── sart/
│ ├── models/
│ ├── mnist_properties/
│ ├── cifar_properties/
│ ├── acasxu_properties/
│ ├── vnncomp_eran_properties/
│ ├── mnist_vnnlib/
│ ├── conversion_tools/
│ ├── verify/
│ ├── result/
│ └── layerabs/
│ ├── LayerABS_*.py
│ ├── default_profiles/
│ ├── family_wrappers/
│ ├── layerabs_core/
│ ├── layerabs_variants/
│ └── support/
├── docs/
│ ├── code_classification.md
│ ├── layerabs_families.md
│ └── paper_tables/
└── tests/
Practical navigation rule:
- start from the root
LayerABS_*.pyfiles when you want the clean paper-facing entrypoint - use
default_profiles/when you want the repository's default benchmark/network wrapper for a family - use
family_wrappers/when you want another benchmark or network in an existing family - edit
layerabs_core/when you need shared algorithm logic - edit
layerabs_variants/when you only need to change family configuration, benchmark coverage, or default parameters
More detail for the layerabs/ subtree is in sart/layerabs/README.md.
The active LayerABS-side methods now follow the paper semantics directly.
LayerABS_abstract_sart.py: abstraction-enabled completeLayerABS(SART)LayerABS_abstract_milp.py: abstraction-enabled completeLayerABS(MILP)
These are the two complete methods in the paper where abstraction is present and the final complete stage uses either SART encoding or MILP encoding.
LayerABS_incomplete_layerabs.py:Incomplete-LayerABS
This controller follows the paper definition directly:
- Stage 1: abstract interpretation filter
- Stage 2: hybrid abstract SART encoding
- no Stage 3 complete fallback
The controller exposes the paper's Stage 2 depth parameter k through --k-layers. The current default is k=2.
LayerABS_puresart.py:PureSARTLayerABS_standard_milp.py:Standard MILP
These are the no-abstraction baseline families.
LayerABS_abstract_sart_stats.pyLayerABS_abstract_milp_stats.pyLayerABS_puresart_stats.pyLayerABS_standard_milp_stats.py
These families are used for runtime, unstable-neuron, and related statistics experiments.
LayerABS_abstract_sart_timelimit.py
This is the abstraction-enabled SART family for the time-limit experiments.
The repository now keeps only model-neutral controllers at the root of layerabs/.
| Script | Role |
|---|---|
LayerABS_abstract_sart.py |
paper-facing controller for abstraction-enabled complete LayerABS(SART) |
LayerABS_abstract_milp.py |
paper-facing controller for abstraction-enabled complete LayerABS(MILP) |
LayerABS_incomplete_layerabs.py |
paper-facing controller for Incomplete-LayerABS |
LayerABS_puresart.py |
paper-facing controller for PureSART |
LayerABS_standard_milp.py |
paper-facing controller for Standard MILP |
LayerABS_abstract_sart_stats.py |
stats controller for abstraction-enabled LayerABS(SART) |
LayerABS_abstract_milp_stats.py |
stats controller for abstraction-enabled LayerABS(MILP) |
LayerABS_puresart_stats.py |
stats controller for PureSART |
LayerABS_standard_milp_stats.py |
stats controller for Standard MILP |
LayerABS_abstract_sart_timelimit.py |
time-limit controller for abstraction-enabled LayerABS(SART) |
The benchmark/network-suffixed paper-default wrappers live under sart/layerabs/default_profiles/.
Current default profiles are:
LayerABS_abstract_sart_mnist_10x80.pyLayerABS_abstract_milp_mnist_5x50.pyLayerABS_incomplete_layerabs_mnist_10x80.pyLayerABS_puresart_mnist_10x80.pyLayerABS_standard_milp_mnist_10x80.pyLayerABS_abstract_sart_stats_mnist_6x100.pyLayerABS_abstract_milp_stats_mnist_6x100.pyLayerABS_puresart_stats_vnncomp_6x100.pyLayerABS_standard_milp_stats_vnncomp_6x100.pyLayerABS_abstract_sart_timelimit_mnist_10x80.py
Use the root controller when you want to select the variant explicitly. Use a default-profile script only when you want the repository's default benchmark/network wrapper or a stable paper-default path.
Variant names are now cleaner and paper-facing. Typical examples:
mnist_5x50mnist_5x80mnist_6x100mnist_9x100mnist_10x80mnist_9x200vnncomp_6x100vnncomp_9x100cifar10_5x50cifar10_6x80
VNN-COMP note:
- the paper's ERAN
5x100and8x100correspond to the code variantsvnncomp_6x100andvnncomp_9x100 - the code counts the output layer in the architecture label, while the paper names those models without counting the output layer
python run_experiment.py --list
python run_experiment.py --list --filter LayerABS_python run_experiment.py --list-layerabs
python run_experiment.py --list-layerabs-familiesUseful filters:
python run_experiment.py --list-layerabs --family abstract_sart
python run_experiment.py --list-layerabs --bucket family_wrappers/abstract_sart
python run_experiment.py --list-layerabs --content-group ablationpython run_experiment.py --script LayerABS_abstract_sart --script-arg=--variant --script-arg=mnist_5x50
python run_experiment.py --script LayerABS_abstract_milp --script-arg=--variant --script-arg=mnist_5x50
python run_experiment.py --script LayerABS_puresart --script-arg=--variant --script-arg=mnist_10x80
python run_experiment.py --script LayerABS_standard_milp --script-arg=--variant --script-arg=mnist_10x80python run_experiment.py --script LayerABS_incomplete_layerabs \
--script-arg=--variant --script-arg=mnist_5x50 \
--script-arg=--k-layers --script-arg=3python run_experiment.py --script LayerABS_abstract_sart --script-arg=--variant --script-arg=vnncomp_6x100 --dry-run
python run_experiment.py --paper-preset table8_vnncomp_complete --dry-runpython run_experiment.py --script sart/verify/mnist_new_5x50/deeppoly_mnist_new_5x50.pyThe root launcher, run_experiment.py, is the normal way to interact with the repository.
It supports:
- listing all runnable scripts
- listing LayerABS scripts and families
- filtering by family, benchmark, content group, or bucket
- running a script by path, normalized name, or experiment id
- running named paper presets
- summarizing completed paper presets
- exporting paper-table summaries in bulk
Common commands:
python run_experiment.py --help
python run_experiment.py --list-paper-presets
python run_experiment.py --paper-preset table4_layerabs_complete --dry-run
python run_experiment.py --summarize-paper-preset table4_layerabs_complete
python run_experiment.py --summarize-paper-preset table4_layerabs_complete --summary-format json
python run_experiment.py --export-paper-tablesThe plain --list output distinguishes:
layerabs_family_controllerlayerabs_default_profilethin_wrapperverify_script
The --list-layerabs output also includes the paper-facing paper_role.
The --list-layerabs-families output shows both:
path=for the canonical default profilecontroller=for the recommended root family controller
The repository includes named presets for the paper's internal LayerABS-family experiments.
table2_no_abstractiontable3_vnncomp_hard_casestable4_layerabs_completetable5_fallback_frequencytable6_incomplete_mnisttable7_sart_vs_milp_ablationtable8_vnncomp_completetable9_incomplete_vnncomp_k3table10_incomplete_vnncomp_k_sweeptable11_incomplete_vnncomp_ldsa_k3table12_incomplete_vnncomp_ldsa_k_sweep
supported: directly runnable from the current public controller pathpartial: the in-repo LayerABS side is runnable, but the full paper table depends on excluded external baselines or settingsunsupported: documented from the paper, but the required runtime mode is not exposed in the current public controller path
python run_experiment.py --list-paper-presets
python run_experiment.py --paper-preset table3 --dry-run
python run_experiment.py --paper-preset table6 --dry-run
python run_experiment.py --paper-preset table10 --dry-runImportant preset notes:
table3_vnncomp_hard_casesis supported and encodes the paper's seven hard VNN-COMP property IDs with the paper timeouttable6_incomplete_mnistandtable9_incomplete_vnncomp_k3apply the paper's30sper-solve Gurobi fairness limit through--mip-time-limit 30table11andtable12remain unsupported because the current public path does not expose the LDSA alternation mode used in those tables
The preset definitions live in paper_presets.py.
The repository can summarize completed preset runs and export them in machine-readable formats.
python run_experiment.py --summarize-paper-preset table4
python run_experiment.py --summarize-paper-preset table6 --summary-format json
python run_experiment.py --summarize-paper-preset table7 --summary-format tsvAvailable summary formats:
textjsontsv
You can also write the summary directly to a file:
python run_experiment.py --summarize-paper-preset table4 --summary-format tsv --summary-output table4.tsvpython run_experiment.py --export-paper-tables
python run_experiment.py --export-paper-tables docs/paper_tables
python run_experiment.py --export-paper-tables --filter table6This export produces:
- one
jsonfile per preset - one
tsvfile per preset index.jsonindex.tsv
The default export directory is docs/paper_tables/.
The result summarizer lives in paper_results.py.
table5_fallback_frequency now depends on StageOutcome: markers written by the verification runner. If the existing logs were generated before those markers were added, the summary will report stage_metrics=missing. In that case, rerun the preset before summarizing:
python run_experiment.py --paper-preset table5
python run_experiment.py --summarize-paper-preset table5Runtime outputs are written under sart/result/.
Typical locations:
sart/result/log/: per-run logssart/result/original_result/: textual result files written by the experiment scriptsdocs/paper_tables/: exported preset summaries injsonandtsv
The launcher's preset summary mode matches the newest compatible local artifacts for each preset run. For most families it prefers a matching result + log timestamp pair to avoid mixing results across methods.
This directory holds the shared implementation.
Important modules include:
layerabs_abstract_sart_family_propagation.pylayerabs_abstract_milp_family_propagation.pylayerabs_incomplete_family_propagation.pylayerabs_no_abstraction_propagation.pylayerabs_abstract_sart_stats_family_propagation.pylayerabs_abstract_milp_stats_family_propagation.pylayerabs_abstract_sart_timelimit_family_propagation.pylayerabs_verification_runners.pylayerabs_solver_helpers.pylayerabs_shared_helpers.pylayerabs_stage_helpers.pylayerabs_runtime_helpers.pylayerabs_stats_family_helpers.pylayerabs_logging_helpers.pylayerabs_process_helpers.pylayerabs_parallel_task_helpers.pylayerabs_parallel_args_helpers.py
This directory defines which benchmark/network variants each family supports. It is the normal place to edit:
- variant names
- default deltas
- model/property bindings
- special paper slices such as the Table 3 hard-case run
This directory holds thin wrappers for additional benchmark/network variants under each family. These files should remain small and should not carry duplicated algorithm logic.
This directory holds the other verifier entrypoints that are not part of the LayerABS family-controller layer.
- active methods are kept in the main tree
- historical copies, one-off branches, archived runtime dumps,
specialized/,legacy/, andnon_code_assets/were removed from the active repository structure __pycache__/and runtimefdl/snapshots are ignored and should not be committed- the active mainline now uses paper-facing method names consistently:
abstract_sart,abstract_milp,incomplete_layerabs,puresart,standard_milp
If PyCharm still shows red import underlines:
- make sure the project uses the same interpreter/environment that you use to run experiments
- mark the repository root as a source root if needed
- invalidate IDE caches if stale analysis remains
The active LayerABS code path was refactored to reduce import-time side effects, so remaining IDE red lines are now much more likely to be interpreter or cache issues rather than broken local structure.
- sart/layerabs/README.md: layout and entrypoint map for the LayerABS code tree
- docs/layerabs_families.md: family guide and refactor layout
- docs/code_classification.md: code classification and directory roles
- docs/paper_tables/README.md: exported paper-table artifacts
This repository is released under the MIT License.