zonolayer 0.1.0__tar.gz

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Matthew
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.
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: zonolayer
3
+ Version: 0.1.0
4
+ Summary: Last-layer uncertainty modeling via zonotopic representations.
5
+ Author: Matthew McCann, Marco De Angelis
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/MattCodes03/zonolayer
8
+ Project-URL: Repository, https://github.com/MattCodes03/zonolayer
9
+ Project-URL: Bug Tracker, https://github.com/MattCodes03/zonolayer/issues
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: numpy
14
+ Requires-Dist: torch
15
+ Requires-Dist: matplotlib
16
+ Dynamic: license-file
17
+
18
+ # Zonolayer
19
+
20
+ [![Python Version](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/)
21
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
22
+ [![PyPI Version](https://img.shields.io/pypi/v/zonolayer)](https://pypi.org/project/zonolayer/)
23
+
24
+ **Zonolayer** is a Python package for **last-layer uncertainty modeling via zonotopic representations**.
25
+ It provides **zonotopic output bounds** and **statistical prediction intervals** for neural networks with interval-bounded outputs, enabling precise and interpretable uncertainty quantification in regression tasks.
26
+
27
+ ---
28
+
29
+ ## Features
30
+
31
+ - Compute **zonotopic bounds** for last-layer outputs.
32
+ - Combine **statistical prediction intervals** with interval uncertainty.
33
+ - Compatible with PyTorch networks exposing latent features.
34
+ - Modular, research-friendly, and easy to use.
35
+
36
+ By default, Zonolayer relies on **NumPy** for all numerical computations and interval handling.
37
+
38
+ If you require more advanced interval arithmetic (e.g., using [`pyinterval`](https://pypi.org/project/pyinterval/) or other specialized packages), you can install the optional dependencies and modify the code accordingly, or submit a request for support to be added. I appreciate any and all feedback.
39
+
40
+ ---
41
+
42
+ ## Installation
43
+
44
+ Ensure all requirements from `requirements.txt` are installed to reduce any potential issues.
45
+
46
+ ```bash
47
+ pip install zonolayer
48
+ ```
49
+
50
+ ---
51
+ ## Getting Started
52
+ See `basic_usage.py` in the examples directory for the quickest method to get up and running and start experimenting with the library.
53
+
@@ -0,0 +1,36 @@
1
+ # Zonolayer
2
+
3
+ [![Python Version](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
+ [![PyPI Version](https://img.shields.io/pypi/v/zonolayer)](https://pypi.org/project/zonolayer/)
6
+
7
+ **Zonolayer** is a Python package for **last-layer uncertainty modeling via zonotopic representations**.
8
+ It provides **zonotopic output bounds** and **statistical prediction intervals** for neural networks with interval-bounded outputs, enabling precise and interpretable uncertainty quantification in regression tasks.
9
+
10
+ ---
11
+
12
+ ## Features
13
+
14
+ - Compute **zonotopic bounds** for last-layer outputs.
15
+ - Combine **statistical prediction intervals** with interval uncertainty.
16
+ - Compatible with PyTorch networks exposing latent features.
17
+ - Modular, research-friendly, and easy to use.
18
+
19
+ By default, Zonolayer relies on **NumPy** for all numerical computations and interval handling.
20
+
21
+ If you require more advanced interval arithmetic (e.g., using [`pyinterval`](https://pypi.org/project/pyinterval/) or other specialized packages), you can install the optional dependencies and modify the code accordingly, or submit a request for support to be added. I appreciate any and all feedback.
22
+
23
+ ---
24
+
25
+ ## Installation
26
+
27
+ Ensure all requirements from `requirements.txt` are installed to reduce any potential issues.
28
+
29
+ ```bash
30
+ pip install zonolayer
31
+ ```
32
+
33
+ ---
34
+ ## Getting Started
35
+ See `basic_usage.py` in the examples directory for the quickest method to get up and running and start experimenting with the library.
36
+
@@ -0,0 +1,18 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "zonolayer"
7
+ version = "0.1.0"
8
+ description = "Last-layer uncertainty modeling via zonotopic representations."
9
+ authors = [{ name = "Matthew McCann" }, { name = "Marco De Angelis" }]
10
+ readme = "README.md"
11
+ license = "MIT"
12
+ requires-python = ">=3.9"
13
+ dependencies = ["numpy", "torch", "matplotlib"]
14
+
15
+ [project.urls]
16
+ "Homepage" = "https://github.com/MattCodes03/zonolayer"
17
+ "Repository" = "https://github.com/MattCodes03/zonolayer"
18
+ "Bug Tracker" = "https://github.com/MattCodes03/zonolayer/issues"
@@ -0,0 +1,13 @@
1
+ [metadata]
2
+ name = zonolayer
3
+ version = 0.1.0
4
+ license_files = LICENSE
5
+
6
+ [options]
7
+ packages = find:
8
+ python_requires = >=3.9
9
+
10
+ [egg_info]
11
+ tag_build =
12
+ tag_date = 0
13
+
@@ -0,0 +1,4 @@
1
+ from .core import Zonolayer
2
+ from .zonotope import Zonotope
3
+
4
+ __all__ = ["Zonolayer", "Zonotope"]
@@ -0,0 +1,151 @@
1
+ import numpy as np
2
+ import torch
3
+ from scipy.stats import t
4
+ from .zonotope import Zonotope
5
+
6
+
7
+ class Zonolayer:
8
+ """
9
+ Zonolayer: Last-layer uncertainty modeling via zonotopic representations.
10
+
11
+ This class fits a last-layer affine transformation to interval-bounded data,
12
+ producing zonotopic output bounds and statistical prediction intervals.
13
+
14
+ """
15
+
16
+ def __init__(self, centre_net, lambda_reg: float = 1e-6, alpha: float = 0.05):
17
+ """
18
+ Parameters
19
+ ----------
20
+ centre_net : torch.nn.Module
21
+ The trained neural network whose last-layer latent features are used.
22
+
23
+ lambda_reg : float, optional
24
+ Regularization strength for the pseudoinverse (default: 1e-6).
25
+
26
+ alpha : float, optional
27
+ Significance level for prediction intervals (default: 0.05 → 95% CI).
28
+ """
29
+ self.centre_net = centre_net
30
+ self.lambda_reg = lambda_reg
31
+ self.alpha = alpha
32
+
33
+ # Core methods
34
+ def _compute_zonotope_bounds(self, predicted_centre, latent_train, y_lower, y_upper, latent_test):
35
+ """Internal routine to compute zonotope-based bounds and statistical intervals."""
36
+
37
+ latent_train = np.asarray(latent_train)
38
+ y_lower = np.asarray(y_lower).flatten()
39
+ y_upper = np.asarray(y_upper).flatten()
40
+
41
+ # Center and radii of output intervals
42
+ centre_y = (y_lower + y_upper) / 2
43
+ radii_y = (y_upper - y_lower) / 2
44
+
45
+ # Create zonotope in output space
46
+ Y_zono = Zonotope(centre_y, np.diag(radii_y))
47
+ Phi = latent_train
48
+
49
+ # Regularized pseudoinverse
50
+ M = np.linalg.pinv(Phi.T @ Phi + self.lambda_reg *
51
+ np.eye(Phi.shape[1])) @ Phi.T
52
+
53
+ # Map zonotope into parameter space
54
+ Beta_zono = Y_zono.affine_map(M)
55
+
56
+ # Map into test feature space
57
+ Yhat_zono = Beta_zono.affine_map(latent_test)
58
+ y_lower_pred, y_upper_pred = Yhat_zono.output_interval()
59
+
60
+ # Statistical uncertainty
61
+ predicted_centre = np.asarray(predicted_centre).flatten()
62
+ y_mid = (y_upper + y_lower) / 2
63
+ beta_hat = np.linalg.lstsq(Phi, y_mid, rcond=None)[0]
64
+ residuals = y_mid - Phi @ beta_hat
65
+ sigma2 = np.mean(residuals**2)
66
+ sigma = np.sqrt(sigma2)
67
+
68
+ # t-value
69
+ n = len(latent_test)
70
+ t_val = t.ppf(1 - self.alpha / 2, df=n - 1)
71
+ r = 0.5 * (y_upper_pred - y_lower_pred)
72
+
73
+ # Prediction standard error
74
+ Phi_T_Phi_inv = np.linalg.inv(
75
+ Phi.T @ Phi + self.lambda_reg * np.eye(Phi.shape[1]))
76
+ SE_pred = sigma * \
77
+ np.sqrt(1 + np.sum((latent_test @ Phi_T_Phi_inv) * latent_test, axis=1))
78
+
79
+ # Combine statistical and zonotopic uncertainty
80
+ y_pred_min_stat = predicted_centre - r - t_val * SE_pred
81
+ y_pred_max_stat = predicted_centre + r + t_val * SE_pred
82
+
83
+ return {
84
+ "pred_centre": predicted_centre,
85
+ "Beta_zono": Beta_zono,
86
+ "Yhat_zono": Yhat_zono,
87
+ "y_lower_pred": y_lower_pred,
88
+ "y_upper_pred": y_upper_pred,
89
+ "pi_lower": y_pred_min_stat,
90
+ "pi_upper": y_pred_max_stat,
91
+ }
92
+
93
+ def predict(
94
+ self,
95
+ x_train: torch.Tensor,
96
+ y_lower: torch.Tensor,
97
+ y_upper: torch.Tensor,
98
+ n_points: int,
99
+ ):
100
+ """
101
+ Compute last-layer zonotope bounds and statistical prediction intervals.
102
+
103
+ Parameters
104
+ ----------
105
+ x_train : torch.Tensor
106
+ Training inputs.
107
+ y_lower, y_upper : numpy.ndarray
108
+ Lower and upper interval endpoints for training targets.
109
+ n_points : int, optional
110
+ Number of points to evaluate for visualization / interpolation.
111
+
112
+ Returns
113
+ -------
114
+ dict
115
+ Dictionary containing:
116
+ - y_lower_pred, y_upper_pred : zonotopic bounds
117
+ - pi_lower, pi_upper : statistical prediction intervals
118
+ - Beta_zono, Yhat_zono : zonotopic representations
119
+ """
120
+ self.centre_net.eval()
121
+
122
+ # Sort by input for clean visualization
123
+ x_sorted, idx = torch.sort(x_train, dim=0)
124
+ y_lb_sorted = y_lower[idx]
125
+ y_ub_sorted = y_upper[idx]
126
+
127
+ # Generate uniform test grid
128
+ x_plot = torch.linspace(
129
+ x_train.min(), x_train.max(), n_points).unsqueeze(1)
130
+
131
+ with torch.no_grad():
132
+ # Predictions and latents for test points
133
+ centre_pred, latent_test = self.centre_net(
134
+ x_plot, return_latent=True)
135
+
136
+ # Latents for training points
137
+ _, latent_train = self.centre_net(x_sorted, return_latent=True)
138
+
139
+ # Convert to numpy
140
+ latent_train_np = latent_train.numpy()
141
+ latent_test_np = latent_test.numpy()
142
+ y_lb_np = y_lb_sorted.flatten()
143
+ y_ub_np = y_ub_sorted.flatten()
144
+
145
+ return self._compute_zonotope_bounds(
146
+ predicted_centre=centre_pred.cpu().numpy(),
147
+ latent_train=latent_train_np,
148
+ y_lower=y_lb_np,
149
+ y_upper=y_ub_np,
150
+ latent_test=latent_test_np,
151
+ )
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,29 @@
1
+ import numpy as np
2
+
3
+
4
+ class Zonotope:
5
+ def __init__(self, centre, generators):
6
+ self.centre = np.array(centre).reshape(-1) # shape (n,)
7
+ self.generators = np.atleast_2d(generators) # shape (n, m)
8
+ if self.generators.shape[0] != self.centre.shape[0]:
9
+ raise ValueError("Generators must have same dimension as centre")
10
+ self.n = self.centre.shape[0] # dimension
11
+ self.m = self.generators.shape[1] # number of generators
12
+
13
+ def minkowski_sum(self, other):
14
+ new_centre = self.centre + other.centre
15
+ new_generators = np.hstack((self.generators, other.generators))
16
+ return Zonotope(new_centre, new_generators)
17
+
18
+ # Outer Approx. of the zonotope - Affine Arithmetic Paper
19
+ def output_interval(self):
20
+ # sum across generators
21
+ radius = np.sum(np.abs(self.generators), axis=1)
22
+ lower = self.centre - radius
23
+ upper = self.centre + radius
24
+ return lower, upper
25
+
26
+ def affine_map(self, A, b=None):
27
+ new_centre = A @ self.centre + (b if b is not None else 0)
28
+ new_generators = A @ self.generators
29
+ return Zonotope(new_centre, new_generators)
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: zonolayer
3
+ Version: 0.1.0
4
+ Summary: Last-layer uncertainty modeling via zonotopic representations.
5
+ Author: Matthew McCann, Marco De Angelis
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/MattCodes03/zonolayer
8
+ Project-URL: Repository, https://github.com/MattCodes03/zonolayer
9
+ Project-URL: Bug Tracker, https://github.com/MattCodes03/zonolayer/issues
10
+ Requires-Python: >=3.9
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: numpy
14
+ Requires-Dist: torch
15
+ Requires-Dist: matplotlib
16
+ Dynamic: license-file
17
+
18
+ # Zonolayer
19
+
20
+ [![Python Version](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/)
21
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
22
+ [![PyPI Version](https://img.shields.io/pypi/v/zonolayer)](https://pypi.org/project/zonolayer/)
23
+
24
+ **Zonolayer** is a Python package for **last-layer uncertainty modeling via zonotopic representations**.
25
+ It provides **zonotopic output bounds** and **statistical prediction intervals** for neural networks with interval-bounded outputs, enabling precise and interpretable uncertainty quantification in regression tasks.
26
+
27
+ ---
28
+
29
+ ## Features
30
+
31
+ - Compute **zonotopic bounds** for last-layer outputs.
32
+ - Combine **statistical prediction intervals** with interval uncertainty.
33
+ - Compatible with PyTorch networks exposing latent features.
34
+ - Modular, research-friendly, and easy to use.
35
+
36
+ By default, Zonolayer relies on **NumPy** for all numerical computations and interval handling.
37
+
38
+ If you require more advanced interval arithmetic (e.g., using [`pyinterval`](https://pypi.org/project/pyinterval/) or other specialized packages), you can install the optional dependencies and modify the code accordingly, or submit a request for support to be added. I appreciate any and all feedback.
39
+
40
+ ---
41
+
42
+ ## Installation
43
+
44
+ Ensure all requirements from `requirements.txt` are installed to reduce any potential issues.
45
+
46
+ ```bash
47
+ pip install zonolayer
48
+ ```
49
+
50
+ ---
51
+ ## Getting Started
52
+ See `basic_usage.py` in the examples directory for the quickest method to get up and running and start experimenting with the library.
53
+
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.cfg
5
+ zonolayer/__init__.py
6
+ zonolayer/core.py
7
+ zonolayer/version.py
8
+ zonolayer/zonotope.py
9
+ zonolayer.egg-info/PKG-INFO
10
+ zonolayer.egg-info/SOURCES.txt
11
+ zonolayer.egg-info/dependency_links.txt
12
+ zonolayer.egg-info/requires.txt
13
+ zonolayer.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ numpy
2
+ torch
3
+ matplotlib
@@ -0,0 +1 @@
1
+ zonolayer