aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorericmarin <maarin.eric@gmail.com>2026-03-23 17:53:21 +0100
committerericmarin <maarin.eric@gmail.com>2026-03-25 10:23:07 +0100
commit689c34076d08e59b1382864f9efcd983c8665ae5 (patch)
treeb76f3eb0ece697cb042d578a0a11800bd13a8dc8
parent4a9b66faae8bf362849b961ac2bf5dedc079c6ce (diff)
downloadvein-689c34076d08e59b1382864f9efcd983c8665ae5.tar.gz
vein-689c34076d08e59b1382864f9efcd983c8665ae5.zip
added FashionMNIST
xd
-rw-r--r--.gitignore17
-rw-r--r--README.md5
-rw-r--r--fashion_mnist/fashion_mnist.py53
-rw-r--r--fashion_mnist/fashion_mnist_argmax.vnnlib133
-rw-r--r--fashion_mnist/fashion_mnist_epsilon.vnnlib124
-rw-r--r--fashion_mnist/fashion_mnist_strict.vnnlib123
-rw-r--r--nneq.py6
-rw-r--r--notes.norg33
-rw-r--r--proof.norg23
-rw-r--r--verify_fashion_mnist.py32
-rw-r--r--verify_xor.py17
m---------vnncomp2025_benchmarks0
-rw-r--r--xor/xor_a.onnxbin4857 -> 0 bytes
-rw-r--r--xor/xor_a.onnx.data0
-rw-r--r--xor/xor_argmax.vnnlib7
-rw-r--r--xor/xor_b.onnxbin4987 -> 0 bytes
-rw-r--r--xor/xor_b.onnx.data0
-rw-r--r--xor/xor_epsilon.vnnlib5
-rw-r--r--xor/xor_strict.vnnlib5
19 files changed, 553 insertions, 30 deletions
diff --git a/.gitignore b/.gitignore
index 930f082..08dbf27 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,16 @@
-/nneq/__pycache__
+/inpla
+*/__pycache__
+/vnncomp2025_benchmarks/
+/fashion_mnist/FashionMNIST/raw
+/fashion_mnist/fashion_mnist_a.onnx
+/fashion_mnist/fashion_mnist_a.onnx.data
+/fashion_mnist/fashion_mnist_b.onnx
+/fashion_mnist/fashion_mnist_b.onnx.data
+/fashion_mnist/script_argmax.fish
+/fashion_mnist/script_epsilon.fish
+/fashion_mnist/script_strict.fish
+/xor/xor_a.onnx
+/xor/xor_a.onnx.data
+/xor/xor_b.onnx
+/xor/xor_b.onnx.data
+/fashion_mnist/FashionMNIST/raw
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ce759eb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+Requires my [fork of Inpla](https://github.com/eric-marin/inpla).
+
+- Clone the fork
+- **make** the executable
+- Copy the **inpla** executable in NNEQ/
diff --git a/fashion_mnist/fashion_mnist.py b/fashion_mnist/fashion_mnist.py
new file mode 100644
index 0000000..1c9dcf7
--- /dev/null
+++ b/fashion_mnist/fashion_mnist.py
@@ -0,0 +1,53 @@
+import torch, torch.nn as nn
+from torchvision.datasets import FashionMNIST
+from torch.utils.data import DataLoader
+from torchvision import transforms
+
+class FashionMNIST_MLP(nn.Module):
+ def __init__(self, hidden_dim):
+ super().__init__()
+ self.layers = nn.Sequential(
+ nn.Flatten(),
+ nn.Linear(6 * 6, hidden_dim),
+ nn.ReLU(),
+ nn.Linear(hidden_dim, 2)
+ )
+ def forward(self, x):
+ return self.layers(x)
+
+transform = transforms.Compose([
+ transforms.Resize((6, 6)),
+ transforms.ToTensor(),
+])
+
+train_dataset = FashionMNIST('./', download=True, transform=transform, train=True)
+tshirts_trousers = [id for id, data in enumerate(train_dataset.targets) if data.item() == 0 or data.item() == 1]
+train_dataset = torch.utils.data.Subset(train_dataset, tshirts_trousers)
+
+trainloader = DataLoader(train_dataset, batch_size=128, shuffle=True)
+
+def train_model(name: str, dim):
+ net = FashionMNIST_MLP(hidden_dim=dim)
+ loss_fn = nn.CrossEntropyLoss()
+ optimizer = torch.optim.Adam(net.parameters(), lr=1e-4)
+
+ print(f"Training {name}...")
+ for epoch in range(100):
+ global loss
+ for data in trainloader:
+ inputs, targets = data
+ optimizer.zero_grad()
+ outputs = net(inputs)
+ loss = loss_fn(outputs, targets)
+ loss.backward()
+ optimizer.step()
+ if (epoch + 1) % 10 == 0:
+ print(f" Epoch {epoch+1}, Loss: {loss.item():.4f}")
+ return net
+
+if __name__ == "__main__":
+ torch_net_a = train_model("Network A", 6).eval()
+ torch_net_b = train_model("Network B", 12).eval()
+
+ torch.onnx.export(torch_net_a, (torch.randn(1, 1, 6, 6),), "fashion_mnist_a.onnx")
+ torch.onnx.export(torch_net_b, (torch.randn(1, 1, 6, 6),), "fashion_mnist_b.onnx")
diff --git a/fashion_mnist/fashion_mnist_argmax.vnnlib b/fashion_mnist/fashion_mnist_argmax.vnnlib
new file mode 100644
index 0000000..0c4412b
--- /dev/null
+++ b/fashion_mnist/fashion_mnist_argmax.vnnlib
@@ -0,0 +1,133 @@
+; Argmax Equivalence for reduced FashionMNIST
+
+; Constant declaration
+(declare-const X_0 Real)
+(declare-const X_1 Real)
+(declare-const X_2 Real)
+(declare-const X_3 Real)
+(declare-const X_4 Real)
+(declare-const X_5 Real)
+(declare-const X_6 Real)
+(declare-const X_7 Real)
+(declare-const X_8 Real)
+(declare-const X_9 Real)
+(declare-const X_10 Real)
+(declare-const X_11 Real)
+(declare-const X_12 Real)
+(declare-const X_13 Real)
+(declare-const X_14 Real)
+(declare-const X_15 Real)
+(declare-const X_16 Real)
+(declare-const X_17 Real)
+(declare-const X_18 Real)
+(declare-const X_19 Real)
+(declare-const X_20 Real)
+(declare-const X_21 Real)
+(declare-const X_22 Real)
+(declare-const X_23 Real)
+(declare-const X_24 Real)
+(declare-const X_25 Real)
+(declare-const X_26 Real)
+(declare-const X_27 Real)
+(declare-const X_28 Real)
+(declare-const X_29 Real)
+(declare-const X_30 Real)
+(declare-const X_31 Real)
+(declare-const X_32 Real)
+(declare-const X_33 Real)
+(declare-const X_34 Real)
+(declare-const X_35 Real)
+(declare-const Y_0 Real)
+(declare-const Y_1 Real)
+(declare-const Y_2 Real)
+(declare-const Y_3 Real)
+
+; Bounded inputs: X must be within [0, 1]
+(assert (>= X_0 0.0))
+(assert (<= X_0 1.0))
+(assert (>= X_1 0.0))
+(assert (<= X_1 1.0))
+(assert (>= X_2 0.0))
+(assert (<= X_2 1.0))
+(assert (>= X_3 0.0))
+(assert (<= X_3 1.0))
+(assert (>= X_4 0.0))
+(assert (<= X_4 1.0))
+(assert (>= X_5 0.0))
+(assert (<= X_5 1.0))
+(assert (>= X_6 0.0))
+(assert (<= X_6 1.0))
+(assert (>= X_7 0.0))
+(assert (<= X_7 1.0))
+(assert (>= X_8 0.0))
+(assert (<= X_8 1.0))
+(assert (>= X_9 0.0))
+(assert (<= X_9 1.0))
+(assert (>= X_10 0.0))
+(assert (<= X_10 1.0))
+(assert (>= X_11 0.0))
+(assert (<= X_11 1.0))
+(assert (>= X_12 0.0))
+(assert (<= X_12 1.0))
+(assert (>= X_13 0.0))
+(assert (<= X_13 1.0))
+(assert (>= X_14 0.0))
+(assert (<= X_14 1.0))
+(assert (>= X_15 0.0))
+(assert (<= X_15 1.0))
+(assert (>= X_16 0.0))
+(assert (<= X_16 1.0))
+(assert (>= X_17 0.0))
+(assert (<= X_17 1.0))
+(assert (>= X_18 0.0))
+(assert (<= X_18 1.0))
+(assert (>= X_19 0.0))
+(assert (<= X_19 1.0))
+(assert (>= X_20 0.0))
+(assert (<= X_20 1.0))
+(assert (>= X_21 0.0))
+(assert (<= X_21 1.0))
+(assert (>= X_22 0.0))
+(assert (<= X_22 1.0))
+(assert (>= X_23 0.0))
+(assert (<= X_23 1.0))
+(assert (>= X_24 0.0))
+(assert (<= X_24 1.0))
+(assert (>= X_25 0.0))
+(assert (<= X_25 1.0))
+(assert (>= X_26 0.0))
+(assert (<= X_26 1.0))
+(assert (>= X_27 0.0))
+(assert (<= X_27 1.0))
+(assert (>= X_28 0.0))
+(assert (<= X_28 1.0))
+(assert (>= X_29 0.0))
+(assert (<= X_29 1.0))
+(assert (>= X_30 0.0))
+(assert (<= X_30 1.0))
+(assert (>= X_31 0.0))
+(assert (<= X_31 1.0))
+(assert (>= X_32 0.0))
+(assert (<= X_32 1.0))
+(assert (>= X_33 0.0))
+(assert (<= X_33 1.0))
+(assert (>= X_34 0.0))
+(assert (<= X_34 1.0))
+(assert (>= X_35 0.0))
+(assert (<= X_35 1.0))
+
+; Violation of argmax equivalence
+(assert (or
+ (and
+ (> Y_0 Y_1)
+ (or
+ (> Y_3 Y_2)
+ )
+ )
+ (and
+ (> Y_1 Y_0)
+ (or
+ (> Y_2 Y_3)
+ )
+ )
+))
diff --git a/fashion_mnist/fashion_mnist_epsilon.vnnlib b/fashion_mnist/fashion_mnist_epsilon.vnnlib
new file mode 100644
index 0000000..948e501
--- /dev/null
+++ b/fashion_mnist/fashion_mnist_epsilon.vnnlib
@@ -0,0 +1,124 @@
+; Strict Equivalence for reduced FashionMNIST
+
+; Constant declaration
+(declare-const X_0 Real)
+(declare-const X_1 Real)
+(declare-const X_2 Real)
+(declare-const X_3 Real)
+(declare-const X_4 Real)
+(declare-const X_5 Real)
+(declare-const X_6 Real)
+(declare-const X_7 Real)
+(declare-const X_8 Real)
+(declare-const X_9 Real)
+(declare-const X_10 Real)
+(declare-const X_11 Real)
+(declare-const X_12 Real)
+(declare-const X_13 Real)
+(declare-const X_14 Real)
+(declare-const X_15 Real)
+(declare-const X_16 Real)
+(declare-const X_17 Real)
+(declare-const X_18 Real)
+(declare-const X_19 Real)
+(declare-const X_20 Real)
+(declare-const X_21 Real)
+(declare-const X_22 Real)
+(declare-const X_23 Real)
+(declare-const X_24 Real)
+(declare-const X_25 Real)
+(declare-const X_26 Real)
+(declare-const X_27 Real)
+(declare-const X_28 Real)
+(declare-const X_29 Real)
+(declare-const X_30 Real)
+(declare-const X_31 Real)
+(declare-const X_32 Real)
+(declare-const X_33 Real)
+(declare-const X_34 Real)
+(declare-const X_35 Real)
+(declare-const Y_0 Real)
+(declare-const Y_1 Real)
+(declare-const Y_2 Real)
+(declare-const Y_3 Real)
+
+; Bounded inputs: X must be within [0, 1]
+(assert (>= X_0 0.0))
+(assert (<= X_0 1.0))
+(assert (>= X_1 0.0))
+(assert (<= X_1 1.0))
+(assert (>= X_2 0.0))
+(assert (<= X_2 1.0))
+(assert (>= X_3 0.0))
+(assert (<= X_3 1.0))
+(assert (>= X_4 0.0))
+(assert (<= X_4 1.0))
+(assert (>= X_5 0.0))
+(assert (<= X_5 1.0))
+(assert (>= X_6 0.0))
+(assert (<= X_6 1.0))
+(assert (>= X_7 0.0))
+(assert (<= X_7 1.0))
+(assert (>= X_8 0.0))
+(assert (<= X_8 1.0))
+(assert (>= X_9 0.0))
+(assert (<= X_9 1.0))
+(assert (>= X_10 0.0))
+(assert (<= X_10 1.0))
+(assert (>= X_11 0.0))
+(assert (<= X_11 1.0))
+(assert (>= X_12 0.0))
+(assert (<= X_12 1.0))
+(assert (>= X_13 0.0))
+(assert (<= X_13 1.0))
+(assert (>= X_14 0.0))
+(assert (<= X_14 1.0))
+(assert (>= X_15 0.0))
+(assert (<= X_15 1.0))
+(assert (>= X_16 0.0))
+(assert (<= X_16 1.0))
+(assert (>= X_17 0.0))
+(assert (<= X_17 1.0))
+(assert (>= X_18 0.0))
+(assert (<= X_18 1.0))
+(assert (>= X_19 0.0))
+(assert (<= X_19 1.0))
+(assert (>= X_20 0.0))
+(assert (<= X_20 1.0))
+(assert (>= X_21 0.0))
+(assert (<= X_21 1.0))
+(assert (>= X_22 0.0))
+(assert (<= X_22 1.0))
+(assert (>= X_23 0.0))
+(assert (<= X_23 1.0))
+(assert (>= X_24 0.0))
+(assert (<= X_24 1.0))
+(assert (>= X_25 0.0))
+(assert (<= X_25 1.0))
+(assert (>= X_26 0.0))
+(assert (<= X_26 1.0))
+(assert (>= X_27 0.0))
+(assert (<= X_27 1.0))
+(assert (>= X_28 0.0))
+(assert (<= X_28 1.0))
+(assert (>= X_29 0.0))
+(assert (<= X_29 1.0))
+(assert (>= X_30 0.0))
+(assert (<= X_30 1.0))
+(assert (>= X_31 0.0))
+(assert (<= X_31 1.0))
+(assert (>= X_32 0.0))
+(assert (<= X_32 1.0))
+(assert (>= X_33 0.0))
+(assert (<= X_33 1.0))
+(assert (>= X_34 0.0))
+(assert (<= X_34 1.0))
+(assert (>= X_35 0.0))
+(assert (<= X_35 1.0))
+
+; Violation of epsilon equivalence (epsilon = 0.1)
+(define-fun absolute ((x Real)) Real (if (>= x 0) x (- x)))
+(assert (or
+ (> (absolute (- Y_0 Y_2)) 0.1)
+ (> (absolute (- Y_1 Y_3)) 0.1)
+))
diff --git a/fashion_mnist/fashion_mnist_strict.vnnlib b/fashion_mnist/fashion_mnist_strict.vnnlib
new file mode 100644
index 0000000..8242c34
--- /dev/null
+++ b/fashion_mnist/fashion_mnist_strict.vnnlib
@@ -0,0 +1,123 @@
+; Strict Equivalence for reduced FashionMNIST
+
+; Constant declaration
+(declare-const X_0 Real)
+(declare-const X_1 Real)
+(declare-const X_2 Real)
+(declare-const X_3 Real)
+(declare-const X_4 Real)
+(declare-const X_5 Real)
+(declare-const X_6 Real)
+(declare-const X_7 Real)
+(declare-const X_8 Real)
+(declare-const X_9 Real)
+(declare-const X_10 Real)
+(declare-const X_11 Real)
+(declare-const X_12 Real)
+(declare-const X_13 Real)
+(declare-const X_14 Real)
+(declare-const X_15 Real)
+(declare-const X_16 Real)
+(declare-const X_17 Real)
+(declare-const X_18 Real)
+(declare-const X_19 Real)
+(declare-const X_20 Real)
+(declare-const X_21 Real)
+(declare-const X_22 Real)
+(declare-const X_23 Real)
+(declare-const X_24 Real)
+(declare-const X_25 Real)
+(declare-const X_26 Real)
+(declare-const X_27 Real)
+(declare-const X_28 Real)
+(declare-const X_29 Real)
+(declare-const X_30 Real)
+(declare-const X_31 Real)
+(declare-const X_32 Real)
+(declare-const X_33 Real)
+(declare-const X_34 Real)
+(declare-const X_35 Real)
+(declare-const Y_0 Real)
+(declare-const Y_1 Real)
+(declare-const Y_2 Real)
+(declare-const Y_3 Real)
+
+; Bounded inputs: X must be within [0, 1]
+(assert (>= X_0 0.0))
+(assert (<= X_0 1.0))
+(assert (>= X_1 0.0))
+(assert (<= X_1 1.0))
+(assert (>= X_2 0.0))
+(assert (<= X_2 1.0))
+(assert (>= X_3 0.0))
+(assert (<= X_3 1.0))
+(assert (>= X_4 0.0))
+(assert (<= X_4 1.0))
+(assert (>= X_5 0.0))
+(assert (<= X_5 1.0))
+(assert (>= X_6 0.0))
+(assert (<= X_6 1.0))
+(assert (>= X_7 0.0))
+(assert (<= X_7 1.0))
+(assert (>= X_8 0.0))
+(assert (<= X_8 1.0))
+(assert (>= X_9 0.0))
+(assert (<= X_9 1.0))
+(assert (>= X_10 0.0))
+(assert (<= X_10 1.0))
+(assert (>= X_11 0.0))
+(assert (<= X_11 1.0))
+(assert (>= X_12 0.0))
+(assert (<= X_12 1.0))
+(assert (>= X_13 0.0))
+(assert (<= X_13 1.0))
+(assert (>= X_14 0.0))
+(assert (<= X_14 1.0))
+(assert (>= X_15 0.0))
+(assert (<= X_15 1.0))
+(assert (>= X_16 0.0))
+(assert (<= X_16 1.0))
+(assert (>= X_17 0.0))
+(assert (<= X_17 1.0))
+(assert (>= X_18 0.0))
+(assert (<= X_18 1.0))
+(assert (>= X_19 0.0))
+(assert (<= X_19 1.0))
+(assert (>= X_20 0.0))
+(assert (<= X_20 1.0))
+(assert (>= X_21 0.0))
+(assert (<= X_21 1.0))
+(assert (>= X_22 0.0))
+(assert (<= X_22 1.0))
+(assert (>= X_23 0.0))
+(assert (<= X_23 1.0))
+(assert (>= X_24 0.0))
+(assert (<= X_24 1.0))
+(assert (>= X_25 0.0))
+(assert (<= X_25 1.0))
+(assert (>= X_26 0.0))
+(assert (<= X_26 1.0))
+(assert (>= X_27 0.0))
+(assert (<= X_27 1.0))
+(assert (>= X_28 0.0))
+(assert (<= X_28 1.0))
+(assert (>= X_29 0.0))
+(assert (<= X_29 1.0))
+(assert (>= X_30 0.0))
+(assert (<= X_30 1.0))
+(assert (>= X_31 0.0))
+(assert (<= X_31 1.0))
+(assert (>= X_32 0.0))
+(assert (<= X_32 1.0))
+(assert (>= X_33 0.0))
+(assert (<= X_33 1.0))
+(assert (>= X_34 0.0))
+(assert (<= X_34 1.0))
+(assert (>= X_35 0.0))
+(assert (<= X_35 1.0))
+
+; Violation of strict equivalence
+(assert (or
+ (not (= Y_0 Y_2))
+ (not (= Y_1 Y_3))
+))
diff --git a/nneq.py b/nneq.py
index 1549878..784002a 100644
--- a/nneq.py
+++ b/nneq.py
@@ -164,6 +164,9 @@ def inpla_export(model: onnx.ModelProto, bounds: Optional[Dict[str, List[float]]
interactions[in_name] = interactions[out_name]
yield from []
+ def op_reshape(node):
+ return op_flatten(node)
+
graph, initializers = model.graph, get_initializers(model.graph)
var_gen, wire_gen = NameGen("v"), NameGen("w")
interactions: Dict[str, List[List[str]]] = {}
@@ -172,6 +175,7 @@ def inpla_export(model: onnx.ModelProto, bounds: Optional[Dict[str, List[float]]
"Gemm": op_gemm,
"Relu": op_relu,
"Flatten": op_flatten,
+ "Reshape": op_reshape,
"MatMul": op_matmul
}
@@ -258,7 +262,7 @@ def z3_evaluate(model: str, X):
def net(model: onnx.ModelProto, X, bounds: Optional[Dict[str, List[float]]] = None):
model_hash = hashlib.sha256(model.SerializeToString()).hexdigest()
- bounds_key = tuple(sorted(bounds.items())) if bounds else None
+ bounds_key = tuple(sorted((k, tuple(v)) for k, v in bounds.items())) if bounds else None
cache_key = (model_hash, bounds_key)
if cache_key not in _INPLA_CACHE:
diff --git a/notes.norg b/notes.norg
index 9d05485..ed823b3 100644
--- a/notes.norg
+++ b/notes.norg
@@ -4,16 +4,37 @@ description: WIP tool to prove NNEQ using Interaction Nets as pre-processor fo m
authors: ericmarin
categories: research
created: 2026-03-14T09:21:24
-updated: 2026-03-21T11:53:27
+updated: 2026-03-25T09:32:43
version: 1.1.1
@end
* TODO
- - (?) Scalability: Added cache for already processed NN. Inpla is the bottleneck but now I removed most of the limits.
- - (x) Soundness of translated NN: {:proof.norg:}[PROOF]
- - (x) Compatibility with other types of NN: Added support for ONNX format. For now only GEMM and ReLU operations are implemented.
- - ( ) Comparison with other tool ({https://github.com/NeuralNetworkVerification/Marabou}[Marabou], {https://github.com/guykatzz/ReluplexCav2017}[Reluplex])
- - ( ) Add Range agent to enable ReLU optimization
+ - (!) Scalability:
+ Added cache for already processed NN.
+ Removed limits from Inpla, but it runs slow on big NN because of parsing overhead.
+ *I should write a Reduction Engine in Rust with a Work Stealing Queue to be more flexible.*
+
+ - (x) Soundness of translated NN:
+ Translation from NN to IN and the Interaction Rules are proved {:proof.norg:}[here].
+
+ - (x) Compatibility with other types of NN:
+ Added support for ONNX format.
+ Operations: Gemm, ReLU, Flatten, Reshape, Matmul.
+
+ - (+) Comparison with other tool ({https://github.com/NeuralNetworkVerification/Marabou}[Marabou], {https://github.com/guykatzz/ReluplexCav2017}[Reluplex]):
+ My tool is just a pre-processor that takes an NN, optimizes it using IN and converts in a format for SMT solvers.
+ Marabou and Reluplex are solvers and this tool could be used WITH them.
+ DeePoly/Marabou-Preprocessor: numeric bound tightening, lossy and heuristic.
+ ONNX-Simplifier: just folds constants.
+ Neurify: symbolic bound tightening (similar to the Range agent). Doesn't use a solver
+
+ - (!) Add Range agent to enable ReLU optimization:
+
+ - ( ) Merging Linear packets of the same variable when Adding:
+
+ ~ Completare passo induttivo dimostrazione
+ ~ 2 Reti uguali NOTE
+ ~ 1 Rete grande NOTE
* Agents
** Built-in
diff --git a/proof.norg b/proof.norg
index 7f35c1e..8ae8490 100644
--- a/proof.norg
+++ b/proof.norg
@@ -2,21 +2,21 @@
title: proof
description:
authors: ericmarin
-categories:
+categories: research
created: 2026-03-16T11:34:52
-updated: 2026-03-17T18:59:09
+updated: 2026-03-25T08:18:04
version: 1.1.1
@end
* Mathematical Definitions
- - Linear(x, q, r) ~ out => out = q*x + r %with q,r Real%
- - Concrete(k) ~ out => out = k %with k Real%
+ - Linear(x, q, r) ~ out => out = q*x + r
+ - Concrete(k) ~ out => out = k
- Add(out, b) ~ a => out = a + b
- - AddCheckLinear(out, x, q, r) ~ b => out = q*x + (r + b) %with q,r Real%
- - AddCheckConcrete(out, k) ~ b => out = k + b %with k Real%
+ - AddCheckLinear(out, x, q, r) ~ b => out = q*x + (r + b)
+ - AddCheckConcrete(out, k) ~ b => out = k + b
- Mul(out, b) ~ a => out = a * b
- - MulCheckLinear(out, x, q, r) ~ b => out = q*b*x + r*b %with q,r Real%
- - MulCheckConcrete(out, k) ~ b => out = k*b %with k Real%
+ - MulCheckLinear(out, x, q, r) ~ b => out = q*b*x + r*b
+ - MulCheckConcrete(out, k) ~ b => out = k*b
- ReLU(out) ~ x => out = IF (x > 0) THEN x ELSE 0
- Materialize(out) ~ x => out = x
@@ -47,10 +47,13 @@ version: 1.1.1
/Y = alpha * A * B + beta * C/
** Flatten
- Just identity mapping
+ Just identity mapping.
** MatMul
- Equal to Gemm with alpha=1 and beta=0
+ Equal to Gemm with alpha=1 and beta=0.
+
+** Reshape
+ Just identity mapping.
* Proof for the Interaction Rules
** Materialize
diff --git a/verify_fashion_mnist.py b/verify_fashion_mnist.py
new file mode 100644
index 0000000..48c8bc1
--- /dev/null
+++ b/verify_fashion_mnist.py
@@ -0,0 +1,32 @@
+import z3
+import nneq
+
+def check_property(onnx_a, onnx_b, vnnlib):
+ solver = nneq.Solver()
+
+ print(f"--- Checking {vnnlib} ---")
+
+ solver.load_onnx(onnx_a)
+ solver.load_onnx(onnx_b)
+ solver.load_vnnlib(vnnlib)
+
+ result = solver.check()
+
+ if result == z3.unsat:
+ print("VERIFIED (UNSAT): The networks are equivalent under this property.")
+ elif result == z3.sat:
+ print("FAILED (SAT): The networks are NOT equivalent.")
+ print("Counter-example input:")
+ print(solver.model())
+ # m = solver.model()
+ # sorted_symbols = sorted([s for s in m.decls() if s.name().startswith("X_")], key=lambda s: s.name())
+ # for s in sorted_symbols:
+ # print(f" {s.name()} = {m[s]}")
+ else:
+ print("UNKNOWN")
+ print("")
+
+if __name__ == "__main__":
+ check_property("./fashion_mnist/fashion_mnist_a.onnx", "./fashion_mnist/fashion_mnist_b.onnx", "./fashion_mnist/fashion_mnist_strict.vnnlib")
+ check_property("./fashion_mnist/fashion_mnist_a.onnx", "./fashion_mnist/fashion_mnist_b.onnx", "./fashion_mnist/fashion_mnist_epsilon.vnnlib")
+ check_property("./fashion_mnist/fashion_mnist_a.onnx", "./fashion_mnist/fashion_mnist_b.onnx", "./fashion_mnist/fashion_mnist_argmax.vnnlib")
diff --git a/verify_xor.py b/verify_xor.py
index 7328229..90623a0 100644
--- a/verify_xor.py
+++ b/verify_xor.py
@@ -1,7 +1,7 @@
import z3
import nneq
-def check_equivalence(onnx_a, onnx_b, vnnlib):
+def check_property(onnx_a, onnx_b, vnnlib):
solver = nneq.Solver()
print(f"--- Checking {vnnlib} ---")
@@ -17,15 +17,16 @@ def check_equivalence(onnx_a, onnx_b, vnnlib):
elif result == z3.sat:
print("FAILED (SAT): The networks are NOT equivalent.")
print("Counter-example input:")
- m = solver.model()
- sorted_symbols = sorted([s for s in m.decls() if s.name().startswith("X_")], key=lambda s: s.name())
- for s in sorted_symbols:
- print(f" {s.name()} = {m[s]}")
+ print(solver.model())
+ # m = solver.model()
+ # sorted_symbols = sorted([s for s in m.decls() if s.name().startswith("X_")], key=lambda s: s.name())
+ # for s in sorted_symbols:
+ # print(f" {s.name()} = {m[s]}")
else:
print("UNKNOWN")
print("")
if __name__ == "__main__":
- check_equivalence("./xor/xor_a.onnx", "./xor/xor_b.onnx", "./xor/xor_strict.vnnlib")
- check_equivalence("./xor/xor_a.onnx", "./xor/xor_b.onnx", "./xor/xor_epsilon.vnnlib")
- check_equivalence("./xor/xor_a.onnx", "./xor/xor_b.onnx", "./xor/xor_argmax.vnnlib")
+ check_property("./xor/xor_a.onnx", "./xor/xor_b.onnx", "./xor/xor_strict.vnnlib")
+ check_property("./xor/xor_a.onnx", "./xor/xor_b.onnx", "./xor/xor_epsilon.vnnlib")
+ check_property("./xor/xor_a.onnx", "./xor/xor_b.onnx", "./xor/xor_argmax.vnnlib")
diff --git a/vnncomp2025_benchmarks b/vnncomp2025_benchmarks
deleted file mode 160000
-Subproject 8b7b811b78ce6a329dc96f04ae6652da3c24594
diff --git a/xor/xor_a.onnx b/xor/xor_a.onnx
deleted file mode 100644
index 9c13609..0000000
--- a/xor/xor_a.onnx
+++ /dev/null
Binary files differ
diff --git a/xor/xor_a.onnx.data b/xor/xor_a.onnx.data
deleted file mode 100644
index e69de29..0000000
--- a/xor/xor_a.onnx.data
+++ /dev/null
diff --git a/xor/xor_argmax.vnnlib b/xor/xor_argmax.vnnlib
index 3043d70..d38bc31 100644
--- a/xor/xor_argmax.vnnlib
+++ b/xor/xor_argmax.vnnlib
@@ -1,11 +1,14 @@
+; Argmax Equivalence for XOR
+
+; Constant declaration
(declare-const X_0 Real)
(declare-const X_1 Real)
(declare-const Y_0 Real)
(declare-const Y_1 Real)
-; Discrete inputs: X must be 0 or 1
+; Bounded inputs: X must be 0 or 1
(assert (or (= X_0 0) (= X_0 1)))
(assert (or (= X_1 0) (= X_1 1)))
-; Violation of argmax equivalence (threshold 0.5)
+; Violation of argmax equivalence
(assert (not (= (> Y_0 0.5) (> Y_1 0.5))))
diff --git a/xor/xor_b.onnx b/xor/xor_b.onnx
deleted file mode 100644
index fb18840..0000000
--- a/xor/xor_b.onnx
+++ /dev/null
Binary files differ
diff --git a/xor/xor_b.onnx.data b/xor/xor_b.onnx.data
deleted file mode 100644
index e69de29..0000000
--- a/xor/xor_b.onnx.data
+++ /dev/null
diff --git a/xor/xor_epsilon.vnnlib b/xor/xor_epsilon.vnnlib
index d4e9bb7..427243e 100644
--- a/xor/xor_epsilon.vnnlib
+++ b/xor/xor_epsilon.vnnlib
@@ -1,9 +1,12 @@
+; Epsilon Equivalence for XOR
+
+; Constant declaration
(declare-const X_0 Real)
(declare-const X_1 Real)
(declare-const Y_0 Real)
(declare-const Y_1 Real)
-; Discrete inputs: X must be 0 or 1
+; Bounded inputs: X must be 0 or 1
(assert (or (= X_0 0) (= X_0 1)))
(assert (or (= X_1 0) (= X_1 1)))
diff --git a/xor/xor_strict.vnnlib b/xor/xor_strict.vnnlib
index fcf364e..bead476 100644
--- a/xor/xor_strict.vnnlib
+++ b/xor/xor_strict.vnnlib
@@ -1,9 +1,12 @@
+; Strict Equivalence for XOR
+
+; Constant declaration
(declare-const X_0 Real)
(declare-const X_1 Real)
(declare-const Y_0 Real)
(declare-const Y_1 Real)
-; Discrete inputs: X must be 0 or 1
+; Bounded inputs: X must be 0 or 1
(assert (or (= X_0 0) (= X_0 1)))
(assert (or (= X_1 0) (= X_1 1)))