ACAS Xu Collision Avoidance¶
Verify safety properties of the ACAS Xu airborne collision avoidance system – the canonical benchmark for neural network verification. This tutorial walks through loading ONNX models, parsing VNNLIB specifications, and verifying formal safety properties.
What You Will Learn¶
How to load an ONNX neural network and convert it to NNV format
How to parse VNNLIB specification files defining safety properties
How to verify formal safety properties using
verify_vnnlib()How to interpret verification results and extract output bounds
How to run batch verification across multiple networks
Background¶
The Airborne Collision Avoidance System (ACAS Xu) is a family of 45 neural networks designed to advise unmanned aircraft on collision avoidance maneuvers. Each network maps 5 sensor inputs to 5 advisory outputs:
Inputs:
Distance to intruder (ft)
Angle to intruder relative to ownship heading (rad)
Angle to ownship relative to intruder heading (rad)
Speed of ownship (ft/s)
Speed of intruder (ft/s)
Outputs (advisory with lowest score is selected):
Clear-of-Conflict (COC)
Weak Left
Weak Right
Strong Left
Strong Right
Safety properties define constraints like “if the intruder is directly ahead, the advisory should NOT be Clear-of-Conflict” – critical for avoiding mid-air collisions.
Prerequisites¶
NNV installed and on the MATLAB path
ACAS Xu ONNX networks in
data/ACASXu/onnx/VNNLIB property files in
data/ACASXu/vnnlib/
These files are included in the NNV repository.
Step 1: Load an ONNX Network¶
% Path to ACAS Xu networks
onnx_dir = fullfile(nnvroot(), 'data', 'ACASXu', 'onnx');
% Load one of the 45 networks (5x9 grid indexed by previous advisory and tau)
net_file = fullfile(onnx_dir, 'ACASXU_run2a_1_1_batch_2000.onnx');
% Import as MATLAB dlnetwork, then convert to NNV
dlnet = importNetworkFromONNX(net_file, InputDataFormats='BC');
net = matlab2nnv(dlnet);
fprintf('Network loaded: %d layers, input size %s, output size %s\n', ...
net.numLayers, mat2str(net.InputSize), mat2str(net.OutputSize));
Step 2: Load a VNNLIB Safety Property¶
VNNLIB is a standard format for specifying verification properties. Each file defines input bounds and output constraints:
% Path to property files
vnnlib_dir = fullfile(nnvroot(), 'data', 'ACASXu', 'vnnlib');
% Load Property 3
vnnlib_file = fullfile(vnnlib_dir, 'prop_3.vnnlib');
[lb, ub, prop] = load_vnnlib(vnnlib_file);
% lb, ub: input bounds (5x1 vectors)
% prop: output constraints (cell array of HalfSpace objects)
fprintf('Input bounds:\n');
for i = 1:length(lb)
fprintf(' x%d: [%.4f, %.4f]\n', i, lb(i), ub(i));
end
What’s in a VNNLIB File?
A VNNLIB file contains two parts:
Input constraints: Bounds on each input variable (e.g.,
x1 >= 0.3andx1 <= 0.5). These define the region of the input space to verify.Output constraints: Linear inequalities on the outputs (e.g.,
y1 <= y2meaning “the score for advisory 1 must not exceed advisory 2”). These define the safety property.
The load_vnnlib() function parses these into lower/upper bound vectors
and HalfSpace constraint objects.
Step 3: Verify the Property¶
% Create input set from the property bounds
input_set = Star(lb, ub);
% Configure verification
reachOptions = struct;
reachOptions.reachMethod = 'approx-star';
% Method 1: Direct VNNLIB verification (simplest)
result = net.verify_vnnlib(vnnlib_file, reachOptions);
% Method 2: Manual verification (more control)
output_sets = net.reach(input_set, reachOptions);
for i = 1:length(prop)
res = verify_specification(output_sets, prop{i});
fprintf('Property clause %d: %s\n', i, ...
{'UNSAFE (violated)', 'SAFE (holds)', 'UNKNOWN'}(res + 1));
end
Step 4: Examine the Output Bounds¶
% Get the output reachable set bounds
[out_lb, out_ub] = output_sets(1).getRanges();
fprintf('\nOutput bounds:\n');
advisories = {'COC', 'Weak Left', 'Weak Right', 'Strong Left', 'Strong Right'};
for i = 1:5
fprintf(' %12s: [%8.4f, %8.4f]\n', advisories{i}, out_lb(i), out_ub(i));
end
% The advisory with the LOWEST score is selected
% If the COC (index 1) lower bound exceeds all other upper bounds,
% then COC is never selected -- which is what Property 3 requires
Understanding Property 3¶
Property 3 states: “If the intruder is directly ahead and moving towards the ownship, the advisory should not be Clear-of-Conflict (COC).”
In VNNLIB terms:
Input region: Intruder ahead (specific angle/distance bounds)
Safety requirement: The COC output score should NOT be the minimum (i.e., COC should not be the selected advisory)
If verification returns SAFE, this means for ALL inputs within the specified region, the network will never advise Clear-of-Conflict – exactly what we need for collision avoidance safety.
Step 5: Batch Verification¶
Verify all 45 networks against a property:
results = zeros(5, 9); % 5x9 grid of ACAS Xu networks
times = zeros(5, 9);
for i = 1:5
for j = 1:9
% Load network
filename = sprintf('ACASXU_run2a_%d_%d_batch_2000.onnx', i, j);
filepath = fullfile(onnx_dir, filename);
dlnet = importNetworkFromONNX(filepath, InputDataFormats='BC');
net = matlab2nnv(dlnet);
% Verify
tic;
results(i,j) = net.verify_vnnlib(vnnlib_file, reachOptions);
times(i,j) = toc;
fprintf('Network (%d,%d): %s (%.2fs)\n', i, j, ...
{'UNSAFE','SAFE','UNKNOWN'}{results(i,j)+1}, times(i,j));
end
end
fprintf('\nSummary: %d SAFE, %d UNSAFE, %d UNKNOWN\n', ...
sum(results(:)==1), sum(results(:)==0), sum(results(:)==2));
fprintf('Total time: %.1f seconds\n', sum(times(:)));
Interpreting Results¶
Result |
Meaning |
|---|---|
1 (SAFE) |
The property holds for ALL inputs in the specified region. No input can produce an unsafe advisory. This is a formal guarantee. |
0 (UNSAFE) |
A violation was found. There exists an input in the specified region that produces an unsafe advisory. |
2 (UNKNOWN) |
The approximate method cannot determine the result. The
over-approximation overlaps with the unsafe region. Try |
Adapting to Your Own ONNX Model¶
The same ONNX + VNNLIB workflow works for any network:
Export your network to ONNX format
Write VNNLIB specifications for your safety properties
Load and verify:
dlnet = importNetworkFromONNX('your_model.onnx', InputDataFormats='BC');
net = matlab2nnv(dlnet);
result = net.verify_vnnlib('your_property.vnnlib', reachOptions);