vnnlib 1.0.0__cp311-cp311-macosx_10_15_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vnnlib/__init__.py +76 -0
- vnnlib/__init__.pyi +3 -0
- vnnlib/_core.cpp +287 -0
- vnnlib/_core.cpython-311-darwin.so +0 -0
- vnnlib/_core.pyi +270 -0
- vnnlib/compat/__init__.py +54 -0
- vnnlib/compat/py.typed +0 -0
- vnnlib/libVNNLib.dylib +0 -0
- vnnlib/py.typed +1 -0
- vnnlib-1.0.0.dist-info/METADATA +48 -0
- vnnlib-1.0.0.dist-info/RECORD +13 -0
- vnnlib-1.0.0.dist-info/WHEEL +6 -0
- vnnlib-1.0.0.dist-info/licenses/LICENSE +21 -0
vnnlib/__init__.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
VNNLib Python Bindings
|
|
3
|
+
|
|
4
|
+
Modern Python bindings for the VNNLib verification language parser.
|
|
5
|
+
Built with pybind11 for direct access to the BNFC-generated C++ AST.
|
|
6
|
+
|
|
7
|
+
Basic Usage:
|
|
8
|
+
import vnnlib
|
|
9
|
+
|
|
10
|
+
# Parse a VNNLIB file
|
|
11
|
+
query = vnnlib.parse_query_file("path/to/file.vnnlib")
|
|
12
|
+
|
|
13
|
+
# Access networks and constraints
|
|
14
|
+
for network in query.networks:
|
|
15
|
+
print(f"Network: {network.name}")
|
|
16
|
+
|
|
17
|
+
# Use compatibility module for reachability format
|
|
18
|
+
import vnnlib.compat
|
|
19
|
+
cases = vnnlib.compat.transform(query)
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from ._core import (
|
|
23
|
+
# Parsing functions
|
|
24
|
+
parse_query_file, parse_query_string,
|
|
25
|
+
|
|
26
|
+
# Core AST node types
|
|
27
|
+
Query, Network, Assertion,
|
|
28
|
+
InputDefinition, OutputDefinition, HiddenDefinition,
|
|
29
|
+
Version,
|
|
30
|
+
|
|
31
|
+
# Expression types
|
|
32
|
+
ArithExpr, BoolExpr,
|
|
33
|
+
Var, Literal, Float, Int, Negate, Plus, Minus, Multiply,
|
|
34
|
+
Comparison, GreaterThan, GreaterEqual, LessThan, LessEqual, Equal, NotEqual,
|
|
35
|
+
Connective, And, Or,
|
|
36
|
+
|
|
37
|
+
# Linear arithmetic
|
|
38
|
+
LinearArithExpr, Term,
|
|
39
|
+
|
|
40
|
+
# Enums and data types
|
|
41
|
+
DType, SymbolKind,
|
|
42
|
+
|
|
43
|
+
# Exceptions
|
|
44
|
+
VNNLibException,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Module metadata
|
|
48
|
+
__version__ = "1.0.0-dev"
|
|
49
|
+
__author__ = "Allen Antony"
|
|
50
|
+
__description__ = "Python bindings for VNNLib verification language"
|
|
51
|
+
__url__ = "https://github.com/VNNLIB/VNNLIB-Standard"
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
# Parsing functions
|
|
55
|
+
"parse_query_file", "parse_query_string",
|
|
56
|
+
|
|
57
|
+
# Core AST nodes
|
|
58
|
+
"Query", "Network", "Assertion",
|
|
59
|
+
"InputDefinition", "OutputDefinition", "HiddenDefinition",
|
|
60
|
+
"Version",
|
|
61
|
+
|
|
62
|
+
# Expression types
|
|
63
|
+
"ArithExpr", "BoolExpr",
|
|
64
|
+
"Var", "Literal", "Float", "Int", "Negate", "Plus", "Minus", "Multiply",
|
|
65
|
+
"Comparison", "GreaterThan", "GreaterEqual", "LessThan", "LessEqual", "Equal", "NotEqual",
|
|
66
|
+
"Connective", "And", "Or",
|
|
67
|
+
|
|
68
|
+
# Linear arithmetic
|
|
69
|
+
"LinearArithExpr", "Term",
|
|
70
|
+
|
|
71
|
+
# Enums and data types
|
|
72
|
+
"DType", "SymbolKind",
|
|
73
|
+
|
|
74
|
+
# Exceptions
|
|
75
|
+
"VNNLibException",
|
|
76
|
+
]
|
vnnlib/__init__.pyi
ADDED
vnnlib/_core.cpp
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
#include <pybind11/pybind11.h>
|
|
2
|
+
#include <pybind11/stl.h>
|
|
3
|
+
#include <memory>
|
|
4
|
+
#include <exception>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <vector>
|
|
7
|
+
|
|
8
|
+
#include "VNNLib.h"
|
|
9
|
+
#include "TypeChecker.h"
|
|
10
|
+
#include "TypedAST.h"
|
|
11
|
+
#include "TypedBuilder.h"
|
|
12
|
+
#include "LinearArithExpr.h"
|
|
13
|
+
#include "DNFConverter.h"
|
|
14
|
+
#include "CompatTransformer.h"
|
|
15
|
+
#include "Error.hpp"
|
|
16
|
+
|
|
17
|
+
namespace py = pybind11;
|
|
18
|
+
|
|
19
|
+
PYBIND11_MODULE(_core, m) {
|
|
20
|
+
m.doc() = "Python bindings for VNNLib parsing and AST traversal";
|
|
21
|
+
|
|
22
|
+
py::register_exception<VNNLibException>(m, "VNNLibException");
|
|
23
|
+
|
|
24
|
+
// Helper Types
|
|
25
|
+
py::enum_<TDataType>(m, "DType")
|
|
26
|
+
.value("Real", TDataType::Real)
|
|
27
|
+
.value("F16", TDataType::F16).value("F32", TDataType::F32).value("F64", TDataType::F64).value("BF16", TDataType::BF16)
|
|
28
|
+
.value("F8E4M3FN", TDataType::F8E4M3FN).value("F8E5M2", TDataType::F8E5M2)
|
|
29
|
+
.value("F8E4M3FNUZ", TDataType::F8E4M3FNUZ).value("F8E5M2FNUZ", TDataType::F8E5M2FNUZ)
|
|
30
|
+
.value("F4E2M1", TDataType::F4E2M1)
|
|
31
|
+
.value("I8", TDataType::I8).value("I16", TDataType::I16).value("I32", TDataType::I32).value("I64", TDataType::I64)
|
|
32
|
+
.value("U8", TDataType::U8).value("U16", TDataType::U16).value("U32", TDataType::U32).value("U64", TDataType::U64)
|
|
33
|
+
.value("C64", TDataType::C64).value("C128", TDataType::C128)
|
|
34
|
+
.value("Bool", TDataType::Bool).value("String", TDataType::String)
|
|
35
|
+
.value("Unknown", TDataType::Unknown)
|
|
36
|
+
.value("NegativeIntConstant", TDataType::NegativeIntConstant)
|
|
37
|
+
.value("PositiveIntConstant", TDataType::PositiveIntConstant)
|
|
38
|
+
.value("FloatConstant", TDataType::FloatConstant);
|
|
39
|
+
|
|
40
|
+
py::enum_<SymbolKind>(m, "SymbolKind")
|
|
41
|
+
.value("Input", SymbolKind::Input)
|
|
42
|
+
.value("Hidden", SymbolKind::Hidden)
|
|
43
|
+
.value("Output", SymbolKind::Output)
|
|
44
|
+
.value("Unknown", SymbolKind::Unknown);
|
|
45
|
+
|
|
46
|
+
py::class_<TNode>(m, "Node")
|
|
47
|
+
.def("__str__", [](const TNode& n){ return n.toString(); })
|
|
48
|
+
.def("children", [](py::object self){
|
|
49
|
+
const TNode& n = self.cast<const TNode&>();
|
|
50
|
+
std::vector<const TNode*> children;
|
|
51
|
+
n.children(children);
|
|
52
|
+
py::tuple out(children.size());
|
|
53
|
+
|
|
54
|
+
for (int i = 0; i < children.size(); ++i) {
|
|
55
|
+
out[i] = py::cast(children[i], py::return_value_policy::reference_internal, self);
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// --- LinearArithExpr ---
|
|
61
|
+
py::class_<LinearArithExpr::Term>(m, "Term")
|
|
62
|
+
.def_property_readonly("coeff", [](const LinearArithExpr::Term& t){ return t.coeff; })
|
|
63
|
+
.def_property_readonly("var", [](const LinearArithExpr::Term& t){ return t.var; }, py::return_value_policy::reference_internal)
|
|
64
|
+
.def_property_readonly("var_name", [](const LinearArithExpr::Term& t){ return t.varName; });
|
|
65
|
+
|
|
66
|
+
py::class_<LinearArithExpr>(m, "LinearArithExpr")
|
|
67
|
+
.def_property_readonly("terms", [](const LinearArithExpr& e){ return e.getTerms(); })
|
|
68
|
+
.def_property_readonly("constant", [](const LinearArithExpr& e){ return e.getConstant(); });
|
|
69
|
+
|
|
70
|
+
// --- Arithmetic Operations ---
|
|
71
|
+
py::class_<TArithExpr, TNode>(m, "ArithExpr")
|
|
72
|
+
.def_property_readonly("dtype", [](const TArithExpr& e){ return e.dtype; })
|
|
73
|
+
.def("to_linear_expr", [](const TArithExpr& e){
|
|
74
|
+
auto lin_expr = linearize(&e);
|
|
75
|
+
return py::cast(lin_expr.release(), py::return_value_policy::take_ownership);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
py::class_<TVarExpr, TArithExpr>(m, "Var")
|
|
79
|
+
.def_property_readonly("name", [](const TVarExpr& v){ return v.symbol ? v.symbol->name : std::string{}; })
|
|
80
|
+
.def_property_readonly("onnx_name", [](const TVarExpr& v)->py::object{
|
|
81
|
+
if (v.symbol->onnxName.empty()) return py::none();
|
|
82
|
+
return py::str(v.symbol->onnxName);
|
|
83
|
+
})
|
|
84
|
+
.def_property_readonly("dtype", [](const TVarExpr& v){ return v.symbol->dtype; })
|
|
85
|
+
.def_property_readonly("shape", [](const TVarExpr& v){ return v.symbol->shape; })
|
|
86
|
+
.def_property_readonly("kind", [](const TVarExpr& v){ return v.symbol->kind; })
|
|
87
|
+
.def_property_readonly("network_name",[](const TVarExpr& v){ return v.symbol->networkName; })
|
|
88
|
+
.def_property_readonly("indices", [](const TVarExpr& v){ return v.indices; })
|
|
89
|
+
.def_property_readonly("line", [](const TVarExpr& v){ return v.line; });
|
|
90
|
+
|
|
91
|
+
py::class_<TLiteral, TArithExpr>(m, "Literal")
|
|
92
|
+
.def_property_readonly("lexeme", [](const TLiteral& e){ return e.lexeme; })
|
|
93
|
+
.def_property_readonly("line", [](const TLiteral& e){ return e.line; });
|
|
94
|
+
|
|
95
|
+
py::class_<TFloat, TLiteral>(m, "Float")
|
|
96
|
+
.def_property_readonly("value", [](const TFloat& n){ return n.value; });
|
|
97
|
+
|
|
98
|
+
py::class_<TInt, TLiteral>(m, "Int")
|
|
99
|
+
.def_property_readonly("value", [](const TInt& n){ return n.value; });
|
|
100
|
+
|
|
101
|
+
py::class_<TNegate, TArithExpr>(m, "Negate")
|
|
102
|
+
.def_property_readonly("expr", [](const TNegate& n){ return n.expr.get(); }, py::return_value_policy::reference_internal);
|
|
103
|
+
|
|
104
|
+
py::class_<TPlus, TArithExpr>(m, "Plus")
|
|
105
|
+
.def_property_readonly("args", [](const TPlus& n){
|
|
106
|
+
py::tuple args_tuple(n.args.size());
|
|
107
|
+
for (size_t i = 0; i < n.args.size(); ++i)
|
|
108
|
+
args_tuple[i] = py::cast(n.args[i].get(), py::return_value_policy::reference_internal, py::cast(&n));
|
|
109
|
+
return args_tuple;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
py::class_<TMinus, TArithExpr>(m, "Minus")
|
|
113
|
+
.def_property_readonly("head", [](const TMinus& n){ return n.head.get(); }, py::return_value_policy::reference_internal)
|
|
114
|
+
.def_property_readonly("rest", [](const TMinus& n){
|
|
115
|
+
py::tuple rest_tuple(n.rest.size());
|
|
116
|
+
for (size_t i = 0; i < n.rest.size(); ++i)
|
|
117
|
+
rest_tuple[i] = py::cast(n.rest[i].get(), py::return_value_policy::reference_internal, py::cast(&n));
|
|
118
|
+
return rest_tuple;
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
py::class_<TMultiply, TArithExpr>(m, "Multiply")
|
|
122
|
+
.def_property_readonly("args", [](const TMultiply& n){
|
|
123
|
+
py::tuple args_tuple(n.args.size());
|
|
124
|
+
for (size_t i = 0; i < n.args.size(); ++i)
|
|
125
|
+
args_tuple[i] = py::cast(n.args[i].get(), py::return_value_policy::reference_internal, py::cast(&n));
|
|
126
|
+
return args_tuple;
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// ---------- Boolean Operations ----------
|
|
130
|
+
py::class_<TBoolExpr, TNode>(m, "BoolExpr")
|
|
131
|
+
.def("to_dnf", [](const TBoolExpr& e){
|
|
132
|
+
DNF dnf = toDNF(&e);
|
|
133
|
+
py::list py_dnf;
|
|
134
|
+
|
|
135
|
+
for (size_t i = 0; i < dnf.size(); ++i) {
|
|
136
|
+
auto& clause = dnf[i];
|
|
137
|
+
py::list py_clause;
|
|
138
|
+
for (auto* lit : clause) {
|
|
139
|
+
py_clause.append(py::cast(lit, py::return_value_policy::reference_internal, py::cast(&e)));
|
|
140
|
+
}
|
|
141
|
+
py_dnf.append(py_clause);
|
|
142
|
+
}
|
|
143
|
+
return py_dnf;
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
py::class_<TCompare, TBoolExpr>(m, "Comparison")
|
|
147
|
+
.def_property_readonly("lhs", [](const TCompare& n){ return n.lhs.get(); }, py::return_value_policy::reference_internal)
|
|
148
|
+
.def_property_readonly("rhs", [](const TCompare& n){ return n.rhs.get(); }, py::return_value_policy::reference_internal);
|
|
149
|
+
|
|
150
|
+
py::class_<TGreaterThan, TCompare>(m, "GreaterThan");
|
|
151
|
+
py::class_<TEqual, TCompare>(m, "Equal");
|
|
152
|
+
py::class_<TLessThan, TCompare>(m, "LessThan");
|
|
153
|
+
py::class_<TGreaterEqual, TCompare>(m, "GreaterEqual");
|
|
154
|
+
py::class_<TLessEqual, TCompare>(m, "LessEqual");
|
|
155
|
+
py::class_<TNotEqual, TCompare>(m, "NotEqual");
|
|
156
|
+
|
|
157
|
+
py::class_<TConnective, TBoolExpr>(m, "Connective")
|
|
158
|
+
.def_property_readonly("args", [](const TConnective& n){
|
|
159
|
+
py::tuple args_tuple(n.args.size());
|
|
160
|
+
for (size_t i = 0; i < n.args.size(); ++i)
|
|
161
|
+
args_tuple[i] = py::cast(n.args[i].get(), py::return_value_policy::reference_internal, py::cast(&n));
|
|
162
|
+
return args_tuple;
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
py::class_<TAnd, TConnective>(m, "And");
|
|
166
|
+
py::class_<TOr, TConnective>(m, "Or");
|
|
167
|
+
|
|
168
|
+
// --- Assertion ---
|
|
169
|
+
py::class_<TAssertion, TNode>(m, "Assertion")
|
|
170
|
+
.def_property_readonly("expr", [](const TAssertion& a){ return a.cond.get(); }, py::return_value_policy::reference_internal);
|
|
171
|
+
|
|
172
|
+
// --- Definitions ---
|
|
173
|
+
py::class_<TInputDefinition, TNode>(m, "InputDefinition")
|
|
174
|
+
.def_property_readonly("name", [](const TInputDefinition& d){ return d.symbol ? d.symbol->name : std::string{}; })
|
|
175
|
+
.def_property_readonly("onnx_name", [](const TInputDefinition& d)->py::object{
|
|
176
|
+
if (d.symbol->onnxName.empty()) return py::none();
|
|
177
|
+
return py::str(d.symbol->onnxName);
|
|
178
|
+
})
|
|
179
|
+
.def_property_readonly("dtype", [](const TInputDefinition& d){ return d.symbol ? d.symbol->dtype : TDataType::Unknown; })
|
|
180
|
+
.def_property_readonly("shape", [](const TInputDefinition& d){ return d.symbol ? d.symbol->shape : Shape{}; })
|
|
181
|
+
.def_property_readonly("kind", [](const TInputDefinition& d){ return d.symbol ? d.symbol->kind : SymbolKind::Unknown; })
|
|
182
|
+
.def_property_readonly("network_name", [](const TInputDefinition& d){ return d.symbol ? d.symbol->networkName : std::string{}; });
|
|
183
|
+
|
|
184
|
+
py::class_<THiddenDefinition, TNode>(m, "HiddenDefinition")
|
|
185
|
+
.def_property_readonly("name", [](const THiddenDefinition& d){ return d.symbol ? d.symbol->name : std::string{}; })
|
|
186
|
+
.def_property_readonly("onnx_name", [](const THiddenDefinition& d)->py::object{
|
|
187
|
+
if (d.symbol->onnxName.empty()) return py::none();
|
|
188
|
+
return py::str(d.symbol->onnxName);
|
|
189
|
+
})
|
|
190
|
+
.def_property_readonly("dtype", [](const THiddenDefinition& d){ return d.symbol ? d.symbol->dtype : TDataType::Unknown; })
|
|
191
|
+
.def_property_readonly("shape", [](const THiddenDefinition& d){ return d.symbol ? d.symbol->shape : Shape{}; })
|
|
192
|
+
.def_property_readonly("kind", [](const THiddenDefinition& d){ return d.symbol ? d.symbol->kind : SymbolKind::Unknown; })
|
|
193
|
+
.def_property_readonly("network_name", [](const THiddenDefinition& d){ return d.symbol ? d.symbol->networkName : std::string{}; });
|
|
194
|
+
|
|
195
|
+
py::class_<TOutputDefinition, TNode>(m, "OutputDefinition")
|
|
196
|
+
.def_property_readonly("name", [](const TOutputDefinition& d){ return d.symbol ? d.symbol->name : std::string{}; })
|
|
197
|
+
.def_property_readonly("onnx_name", [](const TOutputDefinition& d)->py::object{
|
|
198
|
+
if (d.symbol->onnxName.empty()) return py::none();
|
|
199
|
+
return py::str(d.symbol->onnxName);
|
|
200
|
+
})
|
|
201
|
+
.def_property_readonly("dtype", [](const TOutputDefinition& d){ return d.symbol ? d.symbol->dtype : TDataType::Unknown; })
|
|
202
|
+
.def_property_readonly("shape", [](const TOutputDefinition& d){ return d.symbol ? d.symbol->shape : Shape{}; })
|
|
203
|
+
.def_property_readonly("kind", [](const TOutputDefinition& d){ return d.symbol ? d.symbol->kind : SymbolKind::Unknown; })
|
|
204
|
+
.def_property_readonly("network_name", [](const TOutputDefinition& d){ return d.symbol ? d.symbol->networkName : std::string{}; });
|
|
205
|
+
|
|
206
|
+
// --- Network ---
|
|
207
|
+
py::class_<TNetworkDefinition, TNode>(m, "Network")
|
|
208
|
+
.def_property_readonly("name", [](const TNetworkDefinition& n){ return n.networkName; })
|
|
209
|
+
.def_property_readonly("isometric_to", [](const TNetworkDefinition& n){ return n.isometricTo; })
|
|
210
|
+
.def_property_readonly("equal_to", [](const TNetworkDefinition& n){ return n.equalTo; })
|
|
211
|
+
.def_property_readonly("inputs", [](const TNetworkDefinition& n){
|
|
212
|
+
py::tuple input_tuple(n.inputs.size());
|
|
213
|
+
for (size_t i = 0; i < n.inputs.size(); ++i)
|
|
214
|
+
input_tuple[i] = py::cast(n.inputs[i].get(), py::return_value_policy::reference_internal, py::cast(&n));
|
|
215
|
+
return input_tuple;
|
|
216
|
+
})
|
|
217
|
+
.def_property_readonly("hidden", [](const TNetworkDefinition& n){
|
|
218
|
+
py::tuple hidden_tuple(n.hidden.size());
|
|
219
|
+
for (size_t i = 0; i < n.hidden.size(); ++i)
|
|
220
|
+
hidden_tuple[i] = py::cast(n.hidden[i].get(), py::return_value_policy::reference_internal, py::cast(&n));
|
|
221
|
+
return hidden_tuple;
|
|
222
|
+
})
|
|
223
|
+
.def_property_readonly("outputs", [](const TNetworkDefinition& n){
|
|
224
|
+
py::tuple output_tuple(n.outputs.size());
|
|
225
|
+
for (size_t i = 0; i < n.outputs.size(); ++i)
|
|
226
|
+
output_tuple[i] = py::cast(n.outputs[i].get(), py::return_value_policy::reference_internal, py::cast(&n));
|
|
227
|
+
return output_tuple;
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// --- Version ---
|
|
231
|
+
py::class_<TVersion, TNode>(m, "Version")
|
|
232
|
+
.def_property_readonly("major", [](const TVersion& v){ return v.major; })
|
|
233
|
+
.def_property_readonly("minor", [](const TVersion& v){ return v.minor; });
|
|
234
|
+
|
|
235
|
+
// --- Query ---
|
|
236
|
+
py::class_<TQuery, TNode>(m, "Query")
|
|
237
|
+
.def_property_readonly("networks", [](const TQuery& q){
|
|
238
|
+
py::tuple network_tuple(q.networks.size());
|
|
239
|
+
for (size_t i = 0; i < q.networks.size(); ++i)
|
|
240
|
+
network_tuple[i] = py::cast(q.networks[i].get(), py::return_value_policy::reference_internal, py::cast(&q));
|
|
241
|
+
return network_tuple;
|
|
242
|
+
})
|
|
243
|
+
.def_property_readonly("assertions", [](const TQuery& q){
|
|
244
|
+
py::tuple assertion_tuple(q.assertions.size());
|
|
245
|
+
for (size_t i = 0; i < q.assertions.size(); ++i)
|
|
246
|
+
assertion_tuple[i] = py::cast(q.assertions[i].get(), py::return_value_policy::reference_internal, py::cast(&q));
|
|
247
|
+
return assertion_tuple;
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// --- CompatTransformer ---
|
|
251
|
+
py::class_<Polytope>(m, "Polytope")
|
|
252
|
+
.def_property_readonly("coeff_matrix", [](const Polytope& p){ return p.coeffMatrix; })
|
|
253
|
+
.def_property_readonly("rhs", [](const Polytope& p){ return p.rhs; });
|
|
254
|
+
|
|
255
|
+
py::class_<SpecCase>(m, "SpecCase")
|
|
256
|
+
.def_property_readonly("input_box", [](const SpecCase& c){ return c.inputBox; })
|
|
257
|
+
.def_property_readonly("output_constraints", [](const SpecCase& c){ return c.outputConstraints; },
|
|
258
|
+
py::return_value_policy::reference_internal);
|
|
259
|
+
|
|
260
|
+
// --- API ---
|
|
261
|
+
m.def("parse_query_file", [](const std::string& path) {
|
|
262
|
+
return parseQueryFile(path);
|
|
263
|
+
},
|
|
264
|
+
py::return_value_policy::move,
|
|
265
|
+
py::arg("path"));
|
|
266
|
+
|
|
267
|
+
m.def("parse_query_string", [](const std::string& content) {
|
|
268
|
+
return parseQueryString(content);
|
|
269
|
+
},
|
|
270
|
+
py::return_value_policy::move,
|
|
271
|
+
py::arg("content"));
|
|
272
|
+
|
|
273
|
+
m.def("transform_to_compat", [](const TQuery& query) {
|
|
274
|
+
CompatTransformer transformer(&query);
|
|
275
|
+
const auto& cases = transformer.transform();
|
|
276
|
+
|
|
277
|
+
py::list py_cases;
|
|
278
|
+
for (const auto& c : cases) {
|
|
279
|
+
py_cases.append(py::cast(c, py::return_value_policy::move));
|
|
280
|
+
}
|
|
281
|
+
return py_cases;
|
|
282
|
+
},
|
|
283
|
+
py::arg("query"));
|
|
284
|
+
|
|
285
|
+
m.attr("__version__") = "0.2.0";
|
|
286
|
+
}
|
|
287
|
+
|
|
Binary file
|
vnnlib/_core.pyi
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""Type stubs for VNNLib (typed AST)"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import List, Tuple, Optional, Any
|
|
5
|
+
from enum import Enum
|
|
6
|
+
|
|
7
|
+
# --- Exceptions --------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
class VNNLibException(Exception): ...
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# --- Enums / Aliases --------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
class DType(Enum):
|
|
15
|
+
F16: DType
|
|
16
|
+
F32: DType
|
|
17
|
+
F64: DType
|
|
18
|
+
BF16: DType
|
|
19
|
+
F8E4M3FN: DType
|
|
20
|
+
F8E5M2: DType
|
|
21
|
+
F8E4M3FNUZ: DType
|
|
22
|
+
F8E5M2FNUZ: DType
|
|
23
|
+
F4E2M1: DType
|
|
24
|
+
I8: DType
|
|
25
|
+
I16: DType
|
|
26
|
+
I32: DType
|
|
27
|
+
I64: DType
|
|
28
|
+
U8: DType
|
|
29
|
+
U16: DType
|
|
30
|
+
U32: DType
|
|
31
|
+
U64: DType
|
|
32
|
+
C64: DType
|
|
33
|
+
C128: DType
|
|
34
|
+
Bool: DType
|
|
35
|
+
String: DType
|
|
36
|
+
Unknown: DType
|
|
37
|
+
NegativeIntConstant: DType
|
|
38
|
+
PositiveIntConstant: DType
|
|
39
|
+
FloatConstant: DType
|
|
40
|
+
|
|
41
|
+
class SymbolKind(Enum):
|
|
42
|
+
Input: SymbolKind
|
|
43
|
+
Hidden: SymbolKind
|
|
44
|
+
Output: SymbolKind
|
|
45
|
+
Unknown: SymbolKind
|
|
46
|
+
|
|
47
|
+
Shape = List[int]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# --- Base node ---------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
class Node:
|
|
53
|
+
def __str__(self) -> str: ...
|
|
54
|
+
def children(self) -> Tuple[Node, ...]: ...
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# --- Arithmetic --------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
class ArithExpr(Node):
|
|
60
|
+
@property
|
|
61
|
+
def dtype(self) -> DType: ...
|
|
62
|
+
def to_linear_expr(self) -> LinearArithExpr: ...
|
|
63
|
+
|
|
64
|
+
class Var(ArithExpr):
|
|
65
|
+
@property
|
|
66
|
+
def name(self) -> str: ...
|
|
67
|
+
@property
|
|
68
|
+
def indices(self) -> List[int]: ...
|
|
69
|
+
@property
|
|
70
|
+
def dtype(self) -> DType: ...
|
|
71
|
+
@property
|
|
72
|
+
def shape(self) -> Shape: ...
|
|
73
|
+
@property
|
|
74
|
+
def kind(self) -> SymbolKind: ...
|
|
75
|
+
@property
|
|
76
|
+
def onnx_name(self) -> Optional[str]: ...
|
|
77
|
+
@property
|
|
78
|
+
def network_name(self) -> str: ...
|
|
79
|
+
@property
|
|
80
|
+
def line(self) -> int: ...
|
|
81
|
+
|
|
82
|
+
class Literal(ArithExpr):
|
|
83
|
+
@property
|
|
84
|
+
def lexeme(self) -> str: ...
|
|
85
|
+
@property
|
|
86
|
+
def line(self) -> int: ...
|
|
87
|
+
|
|
88
|
+
class Float(ArithExpr):
|
|
89
|
+
@property
|
|
90
|
+
def value(self) -> float: ...
|
|
91
|
+
|
|
92
|
+
class Int(ArithExpr):
|
|
93
|
+
@property
|
|
94
|
+
def value(self) -> int: ...
|
|
95
|
+
|
|
96
|
+
class IntExpr(ArithExpr):
|
|
97
|
+
@property
|
|
98
|
+
def value(self) -> int: ...
|
|
99
|
+
@property
|
|
100
|
+
def lexeme(self) -> str: ...
|
|
101
|
+
|
|
102
|
+
class Negate(ArithExpr):
|
|
103
|
+
@property
|
|
104
|
+
def expr(self) -> ArithExpr: ...
|
|
105
|
+
|
|
106
|
+
class Plus(ArithExpr):
|
|
107
|
+
@property
|
|
108
|
+
def args(self) -> Tuple[ArithExpr, ...]: ...
|
|
109
|
+
|
|
110
|
+
class Minus(ArithExpr):
|
|
111
|
+
@property
|
|
112
|
+
def head(self) -> ArithExpr: ...
|
|
113
|
+
@property
|
|
114
|
+
def rest(self) -> Tuple[ArithExpr, ...]: ...
|
|
115
|
+
|
|
116
|
+
class Multiply(ArithExpr):
|
|
117
|
+
@property
|
|
118
|
+
def args(self) -> Tuple[ArithExpr, ...]: ...
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# --- Linear Arithmetic -------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
class Term:
|
|
124
|
+
@property
|
|
125
|
+
def coeff(self) -> float: ...
|
|
126
|
+
@property
|
|
127
|
+
def var_name(self) -> str: ...
|
|
128
|
+
@property
|
|
129
|
+
def var(self) -> Var: ...
|
|
130
|
+
|
|
131
|
+
class LinearArithExpr:
|
|
132
|
+
@property
|
|
133
|
+
def terms(self) -> List[Term]: ...
|
|
134
|
+
@property
|
|
135
|
+
def constant(self) -> float: ...
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# --- Boolean -----------------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
class BoolExpr(Node):
|
|
141
|
+
def to_dnf(self) -> List[List[Comparison]]: ...
|
|
142
|
+
|
|
143
|
+
class Comparison(BoolExpr):
|
|
144
|
+
@property
|
|
145
|
+
def lhs(self) -> ArithExpr: ...
|
|
146
|
+
@property
|
|
147
|
+
def rhs(self) -> ArithExpr: ...
|
|
148
|
+
|
|
149
|
+
class GreaterThan(Comparison): ...
|
|
150
|
+
class LessThan(Comparison): ...
|
|
151
|
+
class GreaterEqual(Comparison): ...
|
|
152
|
+
class LessEqual(Comparison): ...
|
|
153
|
+
class Equal(Comparison): ...
|
|
154
|
+
class NotEqual(Comparison): ...
|
|
155
|
+
|
|
156
|
+
class Connective(BoolExpr):
|
|
157
|
+
@property
|
|
158
|
+
def args(self) -> Tuple[BoolExpr, ...]: ...
|
|
159
|
+
|
|
160
|
+
class And(Connective): ...
|
|
161
|
+
class Or(Connective): ...
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# --- Assertions --------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
class Assertion(Node):
|
|
167
|
+
@property
|
|
168
|
+
def expr(self) -> BoolExpr: ...
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# --- Declarations ------------------------------------------------------------
|
|
172
|
+
|
|
173
|
+
class InputDefinition(Node):
|
|
174
|
+
@property
|
|
175
|
+
def name(self) -> str: ...
|
|
176
|
+
@property
|
|
177
|
+
def dtype(self) -> DType: ...
|
|
178
|
+
@property
|
|
179
|
+
def shape(self) -> Shape: ...
|
|
180
|
+
@property
|
|
181
|
+
def kind(self) -> SymbolKind: ...
|
|
182
|
+
@property
|
|
183
|
+
def onnx_name(self) -> Optional[str]: ...
|
|
184
|
+
@property
|
|
185
|
+
def network_name(self) -> str: ...
|
|
186
|
+
|
|
187
|
+
class HiddenDefinition(Node):
|
|
188
|
+
@property
|
|
189
|
+
def name(self) -> str: ...
|
|
190
|
+
@property
|
|
191
|
+
def dtype(self) -> DType: ...
|
|
192
|
+
@property
|
|
193
|
+
def shape(self) -> Shape: ...
|
|
194
|
+
@property
|
|
195
|
+
def kind(self) -> SymbolKind: ...
|
|
196
|
+
@property
|
|
197
|
+
def onnx_name(self) -> Optional[str]: ...
|
|
198
|
+
@property
|
|
199
|
+
def network_name(self) -> str: ...
|
|
200
|
+
|
|
201
|
+
class OutputDefinition(Node):
|
|
202
|
+
@property
|
|
203
|
+
def name(self) -> str: ...
|
|
204
|
+
@property
|
|
205
|
+
def dtype(self) -> DType: ...
|
|
206
|
+
@property
|
|
207
|
+
def shape(self) -> Shape: ...
|
|
208
|
+
@property
|
|
209
|
+
def kind(self) -> SymbolKind: ...
|
|
210
|
+
@property
|
|
211
|
+
def onnx_name(self) -> Optional[str]: ...
|
|
212
|
+
@property
|
|
213
|
+
def network_name(self) -> str: ...
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# --- Network ---------------------------------------------------------
|
|
217
|
+
|
|
218
|
+
class Network(Node):
|
|
219
|
+
@property
|
|
220
|
+
def name(self) -> str: ...
|
|
221
|
+
@property
|
|
222
|
+
def equal_to(self) -> str: ...
|
|
223
|
+
@property
|
|
224
|
+
def isometric_to(self) -> str: ...
|
|
225
|
+
@property
|
|
226
|
+
def inputs(self) -> Tuple[InputDefinition, ...]: ...
|
|
227
|
+
@property
|
|
228
|
+
def hidden(self) -> Tuple[HiddenDefinition, ...]: ...
|
|
229
|
+
@property
|
|
230
|
+
def outputs(self) -> Tuple[OutputDefinition, ...]: ...
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
# --- Version -----------------------------------------------------------
|
|
234
|
+
|
|
235
|
+
class Version(Node):
|
|
236
|
+
@property
|
|
237
|
+
def major(self) -> int: ...
|
|
238
|
+
@property
|
|
239
|
+
def minor(self) -> int: ...
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class Query(Node):
|
|
243
|
+
@property
|
|
244
|
+
def networks(self) -> Tuple[Network, ...]: ...
|
|
245
|
+
@property
|
|
246
|
+
def assertions(self) -> Tuple[Assertion, ...]: ...
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# --- Compatibility (Reachability Format) ------------------------------------
|
|
250
|
+
|
|
251
|
+
class Polytope:
|
|
252
|
+
@property
|
|
253
|
+
def coeff_matrix(self) -> List[List[float]]: ...
|
|
254
|
+
@property
|
|
255
|
+
def rhs(self) -> List[float]: ...
|
|
256
|
+
|
|
257
|
+
class SpecCase:
|
|
258
|
+
@property
|
|
259
|
+
def input_box(self) -> List[Tuple[float, float]]: ...
|
|
260
|
+
@property
|
|
261
|
+
def output_constraints(self) -> List[Polytope]: ...
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
# --- Parse API (typed) -------------------------------------------------------
|
|
265
|
+
|
|
266
|
+
def parse_query_file(path: str) -> Query: ...
|
|
267
|
+
def parse_query_string(content: str) -> Query: ...
|
|
268
|
+
def transform_to_compat(query: Query) -> List[SpecCase]: ...
|
|
269
|
+
|
|
270
|
+
__version__: str
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
VNNLib Compatibility Module
|
|
3
|
+
|
|
4
|
+
This module provides classes and functions for converting VNNLib specifications
|
|
5
|
+
to reachability format compatible with reachability analysis tools.
|
|
6
|
+
|
|
7
|
+
The reachability format represents verification problems as:
|
|
8
|
+
1. Input constraints as box bounds (lower/upper bounds per input dimension)
|
|
9
|
+
2. Output constraints as polytopes in the form Ay ≤ b
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from .._core import Polytope, SpecCase, transform_to_compat
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"Polytope",
|
|
16
|
+
"SpecCase",
|
|
17
|
+
"transform",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
def transform(query):
|
|
21
|
+
"""
|
|
22
|
+
Transform a VNNLib Query to reachability format.
|
|
23
|
+
|
|
24
|
+
This function converts VNNLib specifications into a list of reachability cases.
|
|
25
|
+
Each case consists of:
|
|
26
|
+
1. Input box bounds: lower and upper bounds for each input dimension
|
|
27
|
+
2. Output polytopes: constraints in the form Ay ≤ b representing disjunctions
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
query : vnnlib.Query
|
|
32
|
+
The parsed VNNLib Query object to transform
|
|
33
|
+
|
|
34
|
+
Returns
|
|
35
|
+
-------
|
|
36
|
+
List[SpecCase]
|
|
37
|
+
A list of reachability cases with input bounds and output constraints
|
|
38
|
+
|
|
39
|
+
Raises
|
|
40
|
+
------
|
|
41
|
+
VNNLibException
|
|
42
|
+
If the specification cannot be converted to reachability format.
|
|
43
|
+
|
|
44
|
+
Example
|
|
45
|
+
-------
|
|
46
|
+
>>> import vnnlib
|
|
47
|
+
>>> import vnnlib.compat
|
|
48
|
+
>>> query = vnnlib.parse_query_string(content)
|
|
49
|
+
>>> cases = vnnlib.compat.transform(query)
|
|
50
|
+
>>> case = cases[0]
|
|
51
|
+
>>> print(f"Input bounds: {case.input_box}")
|
|
52
|
+
>>> print(f"Output polytopes: {len(case.output_constraints)}")
|
|
53
|
+
"""
|
|
54
|
+
return transform_to_compat(query)
|
vnnlib/compat/py.typed
ADDED
|
File without changes
|
vnnlib/libVNNLib.dylib
ADDED
|
Binary file
|
vnnlib/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Stub-only package"""
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: vnnlib
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python bindings for VNNLib parsing and AST manipulation
|
|
5
|
+
Author-Email: Allen Antony <allenantony2001@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.7
|
|
8
|
+
Requires-Dist: pybind11>=2.6.0
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# VNN-LIB Python
|
|
12
|
+
|
|
13
|
+
A Python package for parsing and manipulating neural network properties in the updated [VNN-LIB format](https://www.vnnlib.org/).
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
Features include:
|
|
18
|
+
- Parsing: Convert VNN-LIB file or string into a type-checked AST
|
|
19
|
+
- AST traversal: Access, traverse, and convert the AST back to a string.
|
|
20
|
+
- Transformers:
|
|
21
|
+
- Linearise arithmetic expressions
|
|
22
|
+
- Convert boolean expressions to Disjunctive Normal Form (DNF)
|
|
23
|
+
- Transform spec to reachability format used in prior VNN-COMPs.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
Install the latest stable version via PyPi:
|
|
28
|
+
```bash
|
|
29
|
+
pip install vnnlib
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Basic Usage
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
import vnnlib
|
|
36
|
+
|
|
37
|
+
# Parse a VNN-LIB specification
|
|
38
|
+
query = vnnlib.parse_query_file("path/to/spec.vnnlib")
|
|
39
|
+
|
|
40
|
+
for assertion in query.assertions:
|
|
41
|
+
print(assertion)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Version compatibility
|
|
45
|
+
|
|
46
|
+
| VNNLIB-Python version | VNNLIB version |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| v1.0 | v2.0 |
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
vnnlib-1.0.0.dist-info/RECORD,,
|
|
2
|
+
vnnlib-1.0.0.dist-info/WHEEL,sha256=_zINgRxDmPoJWl94R6FZTGt8Bzncj3Uu9X9upp27784,143
|
|
3
|
+
vnnlib-1.0.0.dist-info/METADATA,sha256=wnjLAqg4wr6n4vhRvMk3n7JSaorccIUrswfn5L16WMI,1171
|
|
4
|
+
vnnlib-1.0.0.dist-info/licenses/LICENSE,sha256=aRYsrTcINTRh5FTXvbHARWhog18NPO_tjECDhbAOzR0,1086
|
|
5
|
+
vnnlib/libVNNLib.dylib,sha256=iFgVLr4nzrOE2Sg8kfzx3UTXZH_iJYF8WLv_9YIge3g,367264
|
|
6
|
+
vnnlib/__init__.pyi,sha256=YChDCtUFDV14VsSrt5Bz8stAebymJI0wZDULC-qUopU,66
|
|
7
|
+
vnnlib/_core.pyi,sha256=3FZcIOvRfm9LN7VwttvNUrRH5wky1Ug0oeAX-8KUGRg,6219
|
|
8
|
+
vnnlib/_core.cpp,sha256=ILh96cmpasRhqMZFkz60Z9w7lOMAekoFGUv0WR-QOvk,13238
|
|
9
|
+
vnnlib/__init__.py,sha256=-TtOOw7D9hk8tXZyyMStBJwnkdxN0eulf3OVPHlk1PI,1990
|
|
10
|
+
vnnlib/py.typed,sha256=wedgqpT4WwmZzs6C28NAC9NiqQc0Yvpd-7QizLn4QFo,24
|
|
11
|
+
vnnlib/_core.cpython-311-darwin.so,sha256=KtEF15dsvbQ1J45HFZAO2zKQHg086h3DcnqxH48kNX0,346448
|
|
12
|
+
vnnlib/compat/__init__.py,sha256=FY8SajqtUAVDliUfrFV19QEd5IOomeSjE3T3DLd_qL8,1597
|
|
13
|
+
vnnlib/compat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Allen Anthony, Matthew Daggitt
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|