NCET
NCET (Neural-network Constraint Embedding Toolkit) converts supported PyTorch neural networks into exact mixed-integer linear constraints. It preserves graph connectivity, including branches and residual/skip connections, rather than restricting models to sequential structures.
NCET is partly supported by Engineering and Physical Sciences Research Council grant number [EP/Y025946/1].
Documentation: https://xuwkk.github.io/ncet/
Installation
Install NCET from PyPI:
pip install ncet
For a local editable installation, run from the repository root:
pip install -e .
Quick start
This example exactly encodes a small residual network and maximizes its first output over a bounded input box:
import cvxpy as cp
import numpy as np
import torch
from torch import nn
from ncet import Bounds, form_milp
class ResidualMLP(nn.Module):
def __init__(self) -> None:
super().__init__()
self.linear = nn.Linear(2, 2)
with torch.no_grad():
self.linear.weight.copy_(
torch.tensor([[1.0, -1.0], [0.5, 1.0]])
)
self.linear.bias.copy_(torch.tensor([0.0, -0.25]))
def forward(self, x: torch.Tensor) -> torch.Tensor:
return torch.relu(self.linear(x)) + x
model = ResidualMLP().eval()
# Bounds describe one sample; do not include a batch dimension.
bounds = Bounds(
lower=np.array([-1.0, -1.0]),
upper=np.array([1.0, 1.0]),
)
encoding = form_milp(model, bounds, relu_binary_mode="reduced")
x = encoding.inputs["x"]
y = encoding.outputs[0]
problem = cp.Problem(cp.Maximize(y[0]), encoding.constraints)
problem.solve(solver=cp.SCIPY)
print(problem.status, problem.value) # optimal 3.0
print(x.value) # [ 1. -1.]
See the complete form_milp() user interface
for all arguments, accepted bound forms, return fields, and public exceptions.
Modeling scope
NCET captures static PyTorch FX graphs and normalizes the supported operations into a canonical graph intermediate representation (IR). The current operator set is Linear, Conv2d, AvgPool2d, MaxPool2d, ReLU, Add, Sub, Concat, Flatten, Reshape/View, Permute, Transpose, and static GetItem/Slice. Graph-based interval bound propagation and the CVXPY/MILP encoder support this operator set. See the current operator boundary for the accepted semantics and restrictions of each operator.
- Input bounds use
a single sample's shape, such as
(features,)or(channels, height, width), without a batch dimension. lowerandupperdefine elementwise box bounds $\mathrm{lower} \leq x \leq \mathrm{upper}$. The symmetric box $[x_0-\epsilon, x_0+\epsilon]$ is an $L_\infty$ ball. Coupled $L_1$, $L_2$, and other norm bounds are not currently accepted.relu_binary_mode="reduced"(the default) introduces binaries only for unstable ReLU elements."full"introduces one binary per ReLU element. Both modes are exact; see ReLU binary handling.- MaxPool2d uses the full exact formulation, with one binary selector for every valid candidate in each pooling window.
Requirements
NCET requires Python 3.10+, CVXPY 1.7.5+, NumPy 1.26+, SciPy 1.13+, and
PyTorch 2.2+. See pyproject.toml for the supported upper bounds.
Examples
| Notebook | Description |
|---|---|
| Representative operator test | Compares PyTorch and NCET outputs for a branched CNN using representative supported operators. |
| MNIST adversarial attack | Trains a small CNN and solves targeted and worst-case adversarial attacks with NCET. |
| Common failures and exceptions | Demonstrates common invalid inputs and models, their public exceptions, and supported fixes. |
License
NCET is licensed under the Apache License 2.0.
Citation
If you use NCET in your research, please cite:
@ARTICLE{xu2026learning,
author={Xu, Wangkun and Chu, Zhongda and Teng, Fei},
journal={IEEE Transactions on Power Systems},
title={Learning-Augmented Power System Operations: A Unified Optimization View},
year={2026},
volume={},
number={},
pages={1-21},
doi={10.1109/TPWRS.2026.3726363}}
Metadata
Release files for ncet 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ncet-0.1.0.tar.gz | 39.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ncet-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 74.4 kB
Release files / ncet-0.1.0.tar.gz
| Download URL | ncet-0.1.0.tar.gz |
|---|---|
| Size | 39.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f960e5d5f0ae4524709646e7bf5bee046cc4077d64ba80c372b8e9d1ab37a715
|
|
BLAKE2b-256 checksum How to use checksums |
19979e3daab72b59cd9727452da4181da6aa647c7a008cc9521f0c62d05f7279
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.11
|
Release files / ncet-0.1.0-py3-none-any.whl
| Download URL | ncet-0.1.0-py3-none-any.whl |
|---|---|
| Size | 34.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
77d6f7a8f2b61985c85a96679396c6edfb4d478bed5bb40228c8b8b7eb36f7e7
|
|
BLAKE2b-256 checksum How to use checksums |
7e4ed6556b5a97ea9b718d885f8f2b14c6777265dbd9c040a8d6e02a2a6b4041
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.11
|