├── .gitignore ├── .readthedocs.yaml ├── LICENSE ├── README.md ├── __pycache__ ├── demo_mdiPLS.cpython-313.pyc ├── dipals.cpython-39.pyc └── functions.cpython-39.pyc ├── build └── lib │ └── diPLSlib │ ├── __init__.py │ ├── dipals.py │ └── functions.py ├── changelog.md ├── data └── corn.mat ├── demo.png ├── diPLSlib.egg-info ├── PKG-INFO ├── SOURCES.txt ├── dependency_links.txt ├── requires.txt └── top_level.txt ├── diPLSlib ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-313.pyc │ ├── dipals.cpython-313.pyc │ └── functions.cpython-313.pyc ├── functions.py ├── models.py └── utils │ ├── __init__.py │ └── misc.py ├── doc ├── Makefile ├── _build │ ├── doctrees │ │ ├── diPLSlib.doctree │ │ ├── diPLSlib.utils.doctree │ │ ├── environment.pickle │ │ ├── index.doctree │ │ └── modules.doctree │ └── html │ │ ├── .buildinfo │ │ ├── .buildinfo.bak │ │ ├── _modules │ │ ├── diPLSlib │ │ │ ├── functions.html │ │ │ ├── models.html │ │ │ └── utils │ │ │ │ └── misc.html │ │ ├── index.html │ │ └── sklearn │ │ │ └── utils │ │ │ └── _metadata_requests.html │ │ ├── _sources │ │ ├── diPLSlib.rst.txt │ │ ├── diPLSlib.utils.rst.txt │ │ ├── index.rst.txt │ │ └── modules.rst.txt │ │ ├── _static │ │ ├── _sphinx_javascript_frameworks_compat.js │ │ ├── basic.css │ │ ├── css │ │ │ ├── badge_only.css │ │ │ ├── fonts │ │ │ │ ├── Roboto-Slab-Bold.woff │ │ │ │ ├── Roboto-Slab-Bold.woff2 │ │ │ │ ├── Roboto-Slab-Regular.woff │ │ │ │ ├── Roboto-Slab-Regular.woff2 │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ ├── fontawesome-webfont.woff2 │ │ │ │ ├── lato-bold-italic.woff │ │ │ │ ├── lato-bold-italic.woff2 │ │ │ │ ├── lato-bold.woff │ │ │ │ ├── lato-bold.woff2 │ │ │ │ ├── lato-normal-italic.woff │ │ │ │ ├── lato-normal-italic.woff2 │ │ │ │ ├── lato-normal.woff │ │ │ │ └── lato-normal.woff2 │ │ │ └── theme.css │ │ ├── doctools.js │ │ ├── documentation_options.js │ │ ├── file.png │ │ ├── fonts │ │ │ ├── Lato │ │ │ │ ├── lato-bold.eot │ │ │ │ ├── lato-bold.ttf │ │ │ │ ├── lato-bold.woff │ │ │ │ ├── lato-bold.woff2 │ │ │ │ ├── lato-bolditalic.eot │ │ │ │ ├── lato-bolditalic.ttf │ │ │ │ ├── lato-bolditalic.woff │ │ │ │ ├── lato-bolditalic.woff2 │ │ │ │ ├── lato-italic.eot │ │ │ │ ├── lato-italic.ttf │ │ │ │ ├── lato-italic.woff │ │ │ │ ├── lato-italic.woff2 │ │ │ │ ├── lato-regular.eot │ │ │ │ ├── lato-regular.ttf │ │ │ │ ├── lato-regular.woff │ │ │ │ └── lato-regular.woff2 │ │ │ └── RobotoSlab │ │ │ │ ├── roboto-slab-v7-bold.eot │ │ │ │ ├── roboto-slab-v7-bold.ttf │ │ │ │ ├── roboto-slab-v7-bold.woff │ │ │ │ ├── roboto-slab-v7-bold.woff2 │ │ │ │ ├── roboto-slab-v7-regular.eot │ │ │ │ ├── roboto-slab-v7-regular.ttf │ │ │ │ ├── roboto-slab-v7-regular.woff │ │ │ │ └── roboto-slab-v7-regular.woff2 │ │ ├── jquery.js │ │ ├── js │ │ │ ├── badge_only.js │ │ │ ├── theme.js │ │ │ └── versions.js │ │ ├── language_data.js │ │ ├── minus.png │ │ ├── plus.png │ │ ├── pygments.css │ │ ├── searchtools.js │ │ └── sphinx_highlight.js │ │ ├── diPLSlib.html │ │ ├── diPLSlib.utils.html │ │ ├── genindex.html │ │ ├── index.html │ │ ├── modules.html │ │ ├── objects.inv │ │ ├── py-modindex.html │ │ ├── search.html │ │ └── searchindex.js ├── conf.py ├── diPLSlib.rst ├── diPLSlib.utils.rst ├── index.rst ├── make.bat └── modules.rst ├── notebooks ├── demo_ModelSelection.ipynb ├── demo_daPLS.ipynb ├── demo_diPLS.ipynb ├── demo_edPLS.ipynb ├── demo_gctPLS.ipynb └── demo_mdiPLS.ipynb ├── requirements.txt ├── setup.py └── tests └── test_doctests.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Python bytecode files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # Ignore virtual environment directories 6 | venv/ 7 | env/ 8 | 9 | # Ignore distribution files 10 | dist/ 11 | build/ 12 | *.egg-info/ 13 | 14 | # Ignore the .env file 15 | .env 16 | 17 | # ignore the release notes file 18 | .release_notes.md 19 | 20 | # Ignore the contributing file 21 | .contributing.md 22 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.12" 12 | # You can also specify other tool versions: 13 | # nodejs: "20" 14 | # rust: "1.70" 15 | # golang: "1.20" 16 | 17 | # Build documentation in the "docs/" directory with Sphinx 18 | sphinx: 19 | configuration: doc/conf.py 20 | # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs 21 | # builder: "dirhtml" 22 | # Fail on all warnings to avoid broken references 23 | # fail_on_warning: true 24 | # Optionally build your docs in additional formats such as PDF and ePub 25 | # formats: 26 | # - pdf 27 | # - epub 28 | 29 | # Optional but recommended, declare the Python requirements required 30 | # to build your documentation 31 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 32 | python: 33 | install: 34 | - requirements: requirements.txt 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # diPLSlib: A Python library for domain adaptation in multivariate calibration 2 | 3 | ![](https://img.shields.io/badge/python-3.13-blue.svg) 4 | ![](https://static.pepy.tech/badge/diplslib) 5 | 6 | ![](https://user-images.githubusercontent.com/77445667/104728864-d5fede80-5737-11eb-8aad-59f9901a0cf4.png) 7 | 8 | diPLSlib has been created to build privacy-preserving regression models and to perform calibration model maintenance by domain adaptation. It has a scikit-learn compatible API and features following methods: 9 | 10 | - (Multiple) Domain-invariant partial least squares regression (di-PLS/mdi-PLS) 11 | - Graph-based calibration transfer (GCT-PLS) 12 | - $(\epsilon, \delta)$-differentially private partial least squares regression (edPLS) 13 | 14 | **Citation**: If you use this library in your research, please cite the following reference: 15 | 16 | ``` 17 | Nikzad-Langerodi R.(2024). diPLSlib : A Python library for domain adaptation in multivariate calibration (version 2.4.1). URL: https://di-pls.readthedocs.io/ 18 | ``` 19 | or in Bibtex format : 20 | ```bibtex 21 | @misc{nikzad2024diPLSlib, 22 | author = {Nikzad-Langerodi, Ramin}, 23 | month = {12}, 24 | title = {diPLSlib: A Python library for domain adaptation in multivariate calibration}, 25 | url = {https://di-pls.readthedocs.io/}, 26 | year = {2024} 27 | } 28 | ``` 29 | 30 | # Installation 31 | ```bash 32 | pip install diPLSlib 33 | ``` 34 | 35 | # Quick Start 36 | ## How to apply di-PLS 37 | Train regression model 38 | ```python 39 | from diPLSlib.models import DIPLS 40 | from diPLSlib.utils import misc 41 | 42 | l = 100000 # or l = (10000, 100) Regularization 43 | m = DIPLS(A=2, l=l) 44 | m.fit(X, y, X_source, X_target) 45 | 46 | # Typically X=X_source and y are the corresponding response values 47 | ``` 48 | Apply the model 49 | ```python 50 | yhat_dipls = m.predict(X_test) 51 | err = misc.rmse(y_test, yhat_dipls) 52 | ``` 53 | 54 | ## How to apply mdi-PLS 55 | ```python 56 | from diPLSlib.models import DIPLS 57 | 58 | l = 100000 # or l = (5, 100, 1000) Regularization 59 | m = DIPLS(A=3, l=l, target_domain=2) 60 | m.fit(X, y, X_source, X_target) 61 | 62 | # X_target = [X1, X2, ... , Xk] is a list of target domain data 63 | # The parameter target_domain specifies for which domain the model should be trained (here X2). 64 | ``` 65 | 66 | ## How to apply GCT-PLS 67 | ```python 68 | from diPLSlib.models import GCTPLS 69 | 70 | # Training 71 | l = 10 # or l = (10, 10) Regularization 72 | m = GCTPLS(A=2, l=l) 73 | m.fit(X, y, X_source, X_target) 74 | 75 | # X_source and X_target hold the same samples measured in the source and target domain, respectively. 76 | ``` 77 | 78 | ## How to apply EDPLS 79 | ```python 80 | from diPLSlib.models import EDPLS 81 | 82 | # Training 83 | epsilon = 1 # Privacy loss 84 | delta = 0.05 # Failure probability of the privacy guarantee 85 | m = EDPLS(A=2, epsilon=epsilon, delta=delta) 86 | m.fit(X, y) 87 | ``` 88 | 89 | ## How to apply KDAPLS 90 | ```python 91 | from diPLSlib.models import KDAPLS 92 | 93 | # Training 94 | model = KDAPLS(A=2, l=0.5, kernel_params={"type": "rbf", "gamma": 0.001}) 95 | model.fit(x, y, xs, xt) 96 | ``` 97 | 98 | ## Examples 99 | For more examples, please refer to the [Notebooks](notebooks): 100 | 101 | - [Domain adaptation with di-PLS](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_diPLS.ipynb) 102 | - [Including multiple domains (mdi-PLS)](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_mdiPLS.ipynb) 103 | - [Implicit calibration transfer with GCT-PLS](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_gctPLS.ipynb) 104 | - [Model selection (with `scikit-learn`)](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_ModelSelection.ipynb) 105 | - [Privacy-preserving regression with EDPLS](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_edPLS.ipynb) 106 | - [Non-parametric domain adaptation with KDAPLS](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_daPLS.ipynb) 107 | 108 | # Documentation 109 | The documentation can be found [here](https://di-pls.readthedocs.io/en/latest/diPLSlib.html). 110 | 111 | # Acknowledgements 112 | The first version of di-PLS was developed by Ramin Nikzad-Langerodi, Werner Zellinger, Edwin Lughofer, Bernhard Moser and Susanne Saminger-Platz 113 | and published in: 114 | 115 | - *Ramin Nikzad-Langerodi, Werner Zellinger, Edwin Lughofer, and Susanne Saminger-Platz 116 | Analytical Chemistry 2018 90 (11), 6693-6701 https://doi.org/10.1021/acs.analchem.8b00498* 117 | 118 | Further refinements to the initial algorithm were published in: 119 | 120 | - *R. Nikzad-Langerodi, W. Zellinger, S. Saminger-Platz and B. Moser, "Domain-Invariant Regression Under Beer-Lambert's Law," 2019 18th IEEE International Conference On Machine Learning And Applications (ICMLA), Boca Raton, FL, USA, 2019, pp. 581-586, https://doi.org/10.1109/ICMLA.2019.00108.* 121 | 122 | - *Ramin Nikzad-Langerodi, Werner Zellinger, Susanne Saminger-Platz, Bernhard A. Moser, 123 | Domain adaptation for regression under Beer–Lambert’s law, 124 | Knowledge-Based Systems, Volume 210, 2020, https://doi.org/10.1016/j.knosys.2020.106447.* 125 | 126 | - *Bianca Mikulasek, Valeria Fonseca Diaz, David Gabauer, Christoph Herwig, Ramin Nikzad-Langerodi, 127 | "Partial least squares regression with multiple domains" Journal of Chemometrics 2023 37 (5), e3477, https://doi.org/10.13140/RG.2.2.23750.75845* 128 | 129 | - *Ramin Nikzad-Langerodi & Florian Sobieczky (2021). Graph‐based calibration transfer. Journal of Chemometrics, 35(4), e3319. https://doi.org/10.1002/cem.3319* 130 | 131 | - *Ramin Nikzad-Langerodi, Mohit Kumar, Du Nguyen Duy, and Mahtab Alghasi (2024), "(epsilon, delta)-Differentially Private Partial Least Squares Regression", unpublished.* 132 | 133 | # Contact us 134 | Bottleneck Analytics GmbH 135 | info@bottleneck-analytics.com 136 | 137 | -------------------------------------------------------------------------------- /__pycache__/demo_mdiPLS.cpython-313.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/__pycache__/demo_mdiPLS.cpython-313.pyc -------------------------------------------------------------------------------- /__pycache__/dipals.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/__pycache__/dipals.cpython-39.pyc -------------------------------------------------------------------------------- /__pycache__/functions.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/__pycache__/functions.cpython-39.pyc -------------------------------------------------------------------------------- /build/lib/diPLSlib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/build/lib/diPLSlib/__init__.py -------------------------------------------------------------------------------- /build/lib/diPLSlib/dipals.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Bottleneck Analytics GmbH 4 | info@bottleneck-analytics.com 5 | 6 | @author: Dr. Ramin Nikzad-Langerodi 7 | """ 8 | 9 | # Modules 10 | import numpy as np 11 | import matplotlib.pyplot as plt 12 | from diPLSlib import functions as algo 13 | import scipy.stats 14 | 15 | 16 | class model: 17 | def __init__(self, x, y, xs, xt, A): 18 | self.x = x # Labeled X-Data (usually x = xs) 19 | self.n = np.shape(x)[0] # Number of X samples 20 | self.ns = np.shape(xs)[0] # Number of Xs samples 21 | self.nt = np.shape(xt)[0] # Number of Xs samples 22 | self.k = np.shape(x)[1] # Number of X variables 23 | self.y = y # Response variable corresponding to X data 24 | self.xs = xs # Source domain X data 25 | self.xt = xt # Target domain X data 26 | self.mu = np.mean(x, 0) # Column means of x 27 | self.mu_s = np.mean(xs, 0) # Column means of xs 28 | if(type(self.xt) is list): # Column Means of xt 29 | self.ndomains = len(self.xt) # Multiple Target Domains 30 | mu_t = np.zeros([self.ndomains, self.k]) 31 | 32 | for i in range(self.ndomains): 33 | mu_t[i, :] = np.mean(self.xt[i], 0) 34 | self.mu_t = mu_t 35 | else: 36 | self.mu_t = np.mean(xt, 0) # Single Target Domain 37 | self.T = [] # Projections (scores) 38 | self.Ts = [] # Source domain scores 39 | self.Tt = [] # Target domain scores 40 | self.P = [] # Loadings 41 | self.Ps = [] # Source domain loadings 42 | self.Pt = [] # Target domain loadings 43 | self.W = [] # Weights 44 | self.A = A # Number of LVs in the model 45 | self.opt_l = [] # Optimal set of regularization parameters 46 | self.b0 = np.mean(y,0) # Offset 47 | self.b = [] # Regression coefficients 48 | self.yhat= [] # Predicted response values 49 | self.rmsec = [] # Root Mean Squared Error of Calibration 50 | self.C = [] # Inner relationship coefficients such that y = c*T 51 | 52 | 53 | def fit(self, l=0, centering=True, heuristic=False, target_domain=0): 54 | """ 55 | Fit di-PLS model. 56 | 57 | 58 | Parameters 59 | ---------- 60 | l: list 61 | Regularization parameter. Either a single or different l's for each LV 62 | can be passed 63 | 64 | centering: bool 65 | If set to True, Source and Target Domain Data are Mean Centered (default) 66 | 67 | heuristic: bool 68 | If True the regularization parameter is set to a heuristic value 69 | 70 | target_domain: int 71 | If multiple target domains are passed, target_domain specifies for which of the target domains 72 | the model should apply. If target_domain=0, the model applies to the source domain, 73 | if target_domain=1, the model applies to the first target domain etc. 74 | 75 | """ 76 | 77 | # Mean Centering 78 | b0 = np.mean(self.y) 79 | y = self.y - b0 80 | 81 | 82 | if centering is True: 83 | 84 | x = self.x[..., :] - self.mu 85 | xs = self.xs[..., :] - self.mu_s 86 | 87 | 88 | # Mutliple target domains 89 | if(type(self.xt) is list): 90 | 91 | xt = [self.xt[i][..., :] - self.mu_t[i, :] for i in range(self.ndomains)] 92 | 93 | else: 94 | 95 | xt = self.xt[..., :] - self.mu_t 96 | 97 | 98 | else: 99 | 100 | x = self.x 101 | xs = self.xs 102 | xt = self.xt 103 | 104 | 105 | # Fit model and store matrices 106 | A = self.A 107 | (b, T, Ts, Tt, W, P, Ps, Pt, E, Es, Et, Ey, C, opt_l, discrepancy) = algo.dipals(x, y, xs, xt, A, l, heuristic=heuristic, target_domain=target_domain) 108 | 109 | self.b = b 110 | self.b0 = b0 111 | self.T = T 112 | self.Ts = Ts 113 | self.Tt = Tt 114 | self.W = W 115 | self.P = P 116 | self.Ps = Ps 117 | self.Pt = Pt 118 | self.E = E 119 | self.Es = Es 120 | self.Et = Et 121 | self.Ey = Ey 122 | self.C = C 123 | self.discrepancy = discrepancy 124 | self.target_domain = target_domain 125 | 126 | 127 | if heuristic is True: 128 | 129 | self.opt_l = opt_l 130 | 131 | 132 | def predict(self, x_test, y_test=[], rescale='Target'): 133 | """ 134 | Predict function for di-PLS models 135 | 136 | Parameters 137 | ---------- 138 | 139 | x_test: numpy array (N x K) 140 | X data 141 | 142 | y_test: numpy array (N x 1) 143 | Y data (optional) 144 | 145 | rescale: str or numpy.ndarray 146 | Determines Rescaling of the Test Data (Default is Rescaling to Target Domain Training Set) 147 | If Array is passed, than Test Data will be Rescaled to mean of the provided Array 148 | 149 | 150 | Returns 151 | ------- 152 | 153 | yhat: numpy array (N x 1) 154 | Predicted Y 155 | 156 | 157 | RMSE: int 158 | Root mean squared error 159 | """ 160 | 161 | # Rescale Test data 162 | if(type(rescale) is str): 163 | 164 | if(rescale == 'Target'): 165 | 166 | if(type(self.xt) is list): 167 | 168 | if(self.target_domain==0): 169 | 170 | Xtest = x_test[...,:] - self.mu_s 171 | 172 | else: 173 | 174 | Xtest = x_test[...,:] - self.mu_t[self.target_domain-1, :] 175 | 176 | else: 177 | 178 | Xtest = x_test[...,:] - self.mu_t 179 | 180 | elif(rescale == 'Source'): 181 | 182 | Xtest = x_test[...,:] - self.mu_s 183 | 184 | elif(rescale == 'none'): 185 | 186 | Xtest = x_test 187 | 188 | elif(type(rescale) is np.ndarray): 189 | 190 | Xtest = x_test[...,:] - np.mean(rescale,0) 191 | 192 | else: 193 | 194 | raise Exception('rescale must either be Source, Target or a Dataset') 195 | 196 | 197 | yhat = Xtest@self.b + self.b0 198 | 199 | error = algo.rmse(yhat,y_test) 200 | 201 | 202 | return yhat,error 203 | 204 | 205 | 206 | # Create a separate class for GCT-PLS model inheriting from class model 207 | class GCTPLS(model): 208 | def __init__(self, x:np.ndarray, y:np.ndarray, xs:np.ndarray, xt:np.ndarray, A:int=2): 209 | 210 | model.__init__(self, x, y, xs, xt, A) 211 | 212 | 213 | def fit(self, l=0, centering=True, heuristic=False): 214 | """ 215 | Fit GCT-PLS model. 216 | 217 | Parameters 218 | ---------- 219 | l: list 220 | Regularization parameter. Either a single or different l's for each LV 221 | can be passed 222 | 223 | centering: bool 224 | If set to True, Source and Target Domain Data are Mean Centered (default) 225 | 226 | heuristic: bool 227 | If True the regularization parameter is set to a heuristic value 228 | 229 | 230 | """ 231 | 232 | # Mean Centering 233 | if centering is True: 234 | 235 | x = self.x[...,:] - self.mu 236 | y = self.y - self.b0 237 | 238 | else: 239 | 240 | x = self.x 241 | y = self.y 242 | 243 | 244 | xs = self.xs 245 | xt = self.xt 246 | 247 | # Fit model and store matrices 248 | A = self.A 249 | (b, T, Ts, Tt, W, P, Ps, Pt, E, Es, Et, Ey, C, opt_l, discrepancy) = algo.gctpls(x, y, xs, xt, A, l, heuristic=heuristic, laplacian=True) 250 | 251 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | 6 | ## [2.5.0] - 2024-02-14 7 | Domain adaptive partial least squares regression 8 | 9 | ### Added 10 | - New model class `DAPLS` for (kernel) domain adaptive partial least squares regression. 11 | - `demo_daPLS.ipynb` notebook for demonstration of the new model class. 12 | - Documentation for the new model class included. 13 | - Usage pattern for the new model class added to the README. 14 | - Demo of the heuristic regularization parameter selection for the `DIPLS` class. 15 | 16 | ### Changed 17 | - Changed the `demo_ModelSelection.ipynb` notebook to include a demonstration of the heuristic regularization parameter selection for the `DIPLS` class. 18 | 19 | ### Fixed 20 | - Fixed failure of `check_estimator()` in the `EDPLS` class. 21 | 22 | ### Removed 23 | N/A 24 | 25 | ### Breaking Changes 26 | N/A 27 | 28 | ## [2.4.2] - 2024-12-13 29 | 30 | ### Added 31 | - **kwargs for `fit` functions 32 | 33 | ### Changed 34 | - Changed the signature of the `fit` method in the `DIPLS` and `GCTPLS` classes to accept **kwargs. 35 | 36 | ### Fixed 37 | - N/A 38 | 39 | ### Removed 40 | - N/A 41 | 42 | ### Breaking Changes 43 | - N/A 44 | 45 | ## [unreleased] - 2024-11-05 46 | 47 | ### Added 48 | - 'check_estimator()' added to the doctests to validate model classes. 49 | 50 | ### Changed 51 | - Input/Output validation added to diPLSlib.models and diPLSlib.functions. 52 | - Changed public to private attributes added in the 'fit()' method. 53 | - Notebooks adapted. 54 | - 'demo_ModelSelection_SciKitLearn.ipynb' added. 55 | - Tests excecuted properly. 56 | 57 | ### Fixed 58 | N/A 59 | 60 | ### Removed 61 | N/A 62 | 63 | ### Breaking Changes 64 | - Changed type of parameter 'l' from Union[int, List[int]] to Union[float, tuple] in 'DIPLS' and 'GCTPLS' classes. 65 | 66 | ## [2.3.0] - 2024-11-06 67 | 68 | ### Added 69 | - New feature for model selection using cross-validation. 70 | - Additional unit tests for new features. 71 | - Documentation for the new model selection feature. 72 | 73 | ### Changed 74 | - Refactored code for better readability and maintainability. 75 | - Updated dependencies to the latest versions. 76 | 77 | ### Fixed 78 | - Fixed a bug in the `predict()` method of the `DIPLS` class. 79 | 80 | ### Removed 81 | - Deprecated methods removed from `diPLSlib.utils`. 82 | 83 | ### Breaking Changes 84 | - Refactored `fit()` method signature in `DIPLS` and `GCTPLS` classes. 85 | 86 | [2.3.0]: https://github.com/B-Analytics/di-PLS/releases/tag/v2.3.0 87 | [2.2.1]: https://github.com/B-Analytics/di-PLS/releases/tag/v2.2.1 88 | 89 | ## [2.2.1] - 2024-11-04 90 | 91 | ### Added 92 | N/A 93 | 94 | ### Changed 95 | N/A 96 | 97 | ### Fixed 98 | - Bug in the extraction of the number of samples nt in the fit method corrected. 99 | - Tested correct behavior in the notebooks. 100 | 101 | ### Removed 102 | N/A 103 | 104 | [2.2.1]: https://github.com/B-Analytics/di-PLS/releases/tag/v2.2.1 105 | 106 | ## [2.2.0] - 2024-11-02 107 | 108 | ### Added 109 | - Unittests for models, functions and utils 110 | 111 | ### Changed 112 | - DIPLS and GCTPLS classes now compatible with sklearn. 113 | - Documentation updated. 114 | 115 | ### Fixed 116 | - N/A 117 | 118 | ### Removed 119 | - N/A 120 | 121 | [2.2.0]: https://github.com/B-Analytics/di-PLS/releases/tag/v2.2.0 122 | 123 | ## [2.1.0] - 2024-11-02 124 | ### Added 125 | - utils submodule added to outsource utility functions. 126 | - Documentation added 127 | 128 | ### Changed 129 | - N/A 130 | 131 | ### Fixed 132 | - N/A 133 | 134 | ### Removed 135 | - N/A 136 | 137 | [2.1.0]: https://github.com/B-Analytics/di-PLS/releases/tag/v2.1.0 138 | 139 | ## [2.0.0] - 2024-10-30 140 | ### Added 141 | - Major overhaul of the project architecture. 142 | - New 'GCTPLS' class for Calibration Transfer. 143 | - Demo notebook for GCT-PLS. 144 | - Data Repository for the demo notebook. 145 | - Changelog added. 146 | 147 | ### Changed 148 | - Changed class names from 'model' to 'DIPLS' and 'GCTPLS'. 149 | 150 | ### Fixed 151 | - Minor bug fixes related to predict function. 152 | 153 | ### Removed 154 | - N/A 155 | 156 | [2.0.0]: https://github.com/B-Analytics/di-PLS/releases/tag/v2.0.0 157 | 158 | ## [1.0.2] - 2024-10-30 159 | ### Added 160 | - N/A 161 | 162 | ### Changed 163 | - N/A 164 | 165 | ### Fixed 166 | - Installation and Usage sections in documentation. 167 | 168 | ### Removed 169 | - N/A 170 | 171 | [1.0.2]: https://github.com/B-Analytics/di-PLS/releases/tag/v1.0.2 172 | 173 | ## [1.0.0] - 2024-10-30 174 | ### Added 175 | - Initial release of the project. 176 | - 'Model' class with 'fit' and 'predict' methods. 177 | - Support for domain adaptation scenarios with multiple domains. 178 | 179 | ### Changed 180 | - N/A 181 | 182 | ### Fixed 183 | - N/A 184 | 185 | ### Removed 186 | - N/A 187 | 188 | [1.0.0]: https://github.com/B-Analytics/di-PLS/releases/tag/v1.0.0 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | -------------------------------------------------------------------------------- /data/corn.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/data/corn.mat -------------------------------------------------------------------------------- /demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/demo.png -------------------------------------------------------------------------------- /diPLSlib.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 2.1 2 | Name: diPLSlib 3 | Version: 2.5.0 4 | Summary: Python package for domain adaptation in multivariate regression 5 | Home-page: https://github.com/B-Analytics/di-PLS 6 | Author: Ramin Nikzad-Langerodi 7 | Author-email: ramin.nikzad-langerodi@scch.at 8 | Classifier: Programming Language :: Python :: 3 9 | Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3) 10 | Classifier: Operating System :: OS Independent 11 | Requires-Python: >=3.6 12 | Description-Content-Type: text/markdown 13 | License-File: LICENSE 14 | Requires-Dist: numpy 15 | Requires-Dist: matplotlib 16 | Requires-Dist: scipy 17 | Requires-Dist: scikit-learn 18 | 19 | # diPLSlib: A Python library for domain adaptation in multivariate calibration 20 | 21 | ![](https://img.shields.io/badge/python-3.13-blue.svg) 22 | ![](https://static.pepy.tech/badge/diplslib) 23 | 24 | ![](https://user-images.githubusercontent.com/77445667/104728864-d5fede80-5737-11eb-8aad-59f9901a0cf4.png) 25 | 26 | diPLSlib has been created to build privacy-preserving regression models and to perform calibration model maintenance by domain adaptation. It has a scikit-learn compatible API and features following methods: 27 | 28 | - (Multiple) Domain-invariant partial least squares regression (di-PLS/mdi-PLS) 29 | - Graph-based calibration transfer (GCT-PLS) 30 | - $(\epsilon, \delta)$-differentially private partial least squares regression (edPLS) 31 | 32 | **Citation**: If you use this library in your research, please cite the following reference: 33 | 34 | ``` 35 | Nikzad-Langerodi R.(2024). diPLSlib : A Python library for domain adaptation in multivariate calibration (version 2.4.1). URL: https://di-pls.readthedocs.io/ 36 | ``` 37 | or in Bibtex format : 38 | ```bibtex 39 | @misc{nikzad2024diPLSlib, 40 | author = {Nikzad-Langerodi, Ramin}, 41 | month = {12}, 42 | title = {diPLSlib: A Python library for domain adaptation in multivariate calibration}, 43 | url = {https://di-pls.readthedocs.io/}, 44 | year = {2024} 45 | } 46 | ``` 47 | 48 | # Installation 49 | ```bash 50 | pip install diPLSlib 51 | ``` 52 | 53 | # Quick Start 54 | ## How to apply di-PLS 55 | Train regression model 56 | ```python 57 | from diPLSlib.models import DIPLS 58 | from diPLSlib.utils import misc 59 | 60 | l = 100000 # or l = (10000, 100) Regularization 61 | m = DIPLS(A=2, l=l) 62 | m.fit(X, y, X_source, X_target) 63 | 64 | # Typically X=X_source and y are the corresponding response values 65 | ``` 66 | Apply the model 67 | ```python 68 | yhat_dipls = m.predict(X_test) 69 | err = misc.rmse(y_test, yhat_dipls) 70 | ``` 71 | 72 | ## How to apply mdi-PLS 73 | ```python 74 | from diPLSlib.models import DIPLS 75 | 76 | l = 100000 # or l = (5, 100, 1000) Regularization 77 | m = DIPLS(A=3, l=l, target_domain=2) 78 | m.fit(X, y, X_source, X_target) 79 | 80 | # X_target = [X1, X2, ... , Xk] is a list of target domain data 81 | # The parameter target_domain specifies for which domain the model should be trained (here X2). 82 | ``` 83 | 84 | ## How to apply GCT-PLS 85 | ```python 86 | from diPLSlib.models import GCTPLS 87 | 88 | # Training 89 | l = 10 # or l = (10, 10) Regularization 90 | m = GCTPLS(A=2, l=l) 91 | m.fit(X, y, X_source, X_target) 92 | 93 | # X_source and X_target hold the same samples measured in the source and target domain, respectively. 94 | ``` 95 | 96 | ## How to apply EDPLS 97 | ```python 98 | from diPLSlib.models import EDPLS 99 | 100 | # Training 101 | epsilon = 1 # Privacy loss 102 | delta = 0.05 # Failure probability of the privacy guarantee 103 | m = EDPLS(A=2, epsilon=epsilon, delta=delta) 104 | m.fit(X, y) 105 | ``` 106 | 107 | ## How to apply KDAPLS 108 | ```python 109 | from diPLSlib.models import KDAPLS 110 | 111 | # Training 112 | model = KDAPLS(A=2, l=0.5, kernel_params={"type": "rbf", "gamma": 0.001}) 113 | model.fit(x, y, xs, xt) 114 | ``` 115 | 116 | ## Examples 117 | For more examples, please refer to the [Notebooks](notebooks): 118 | 119 | - [Domain adaptation with di-PLS](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_diPLS.ipynb) 120 | - [Including multiple domains (mdi-PLS)](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_mdiPLS.ipynb) 121 | - [Implicit calibration transfer with GCT-PLS](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_gctPLS.ipynb) 122 | - [Model selection (with `scikit-learn`)](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_ModelSelection.ipynb) 123 | - [Privacy-preserving regression with EDPLS](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_edPLS.ipynb) 124 | - [Non-parametric domain adaptation with KDAPLS](https://github.com/B-Analytics/diPLSlib/blob/main/notebooks/demo_daPLS.ipynb) 125 | 126 | # Documentation 127 | The documentation can be found [here](https://di-pls.readthedocs.io/en/latest/diPLSlib.html). 128 | 129 | # Acknowledgements 130 | The first version of di-PLS was developed by Ramin Nikzad-Langerodi, Werner Zellinger, Edwin Lughofer, Bernhard Moser and Susanne Saminger-Platz 131 | and published in: 132 | 133 | - *Ramin Nikzad-Langerodi, Werner Zellinger, Edwin Lughofer, and Susanne Saminger-Platz 134 | Analytical Chemistry 2018 90 (11), 6693-6701 https://doi.org/10.1021/acs.analchem.8b00498* 135 | 136 | Further refinements to the initial algorithm were published in: 137 | 138 | - *R. Nikzad-Langerodi, W. Zellinger, S. Saminger-Platz and B. Moser, "Domain-Invariant Regression Under Beer-Lambert's Law," 2019 18th IEEE International Conference On Machine Learning And Applications (ICMLA), Boca Raton, FL, USA, 2019, pp. 581-586, https://doi.org/10.1109/ICMLA.2019.00108.* 139 | 140 | - *Ramin Nikzad-Langerodi, Werner Zellinger, Susanne Saminger-Platz, Bernhard A. Moser, 141 | Domain adaptation for regression under Beer–Lambert’s law, 142 | Knowledge-Based Systems, Volume 210, 2020, https://doi.org/10.1016/j.knosys.2020.106447.* 143 | 144 | - *Bianca Mikulasek, Valeria Fonseca Diaz, David Gabauer, Christoph Herwig, Ramin Nikzad-Langerodi, 145 | "Partial least squares regression with multiple domains" Journal of Chemometrics 2023 37 (5), e3477, https://doi.org/10.13140/RG.2.2.23750.75845* 146 | 147 | - *Ramin Nikzad-Langerodi & Florian Sobieczky (2021). Graph‐based calibration transfer. Journal of Chemometrics, 35(4), e3319. https://doi.org/10.1002/cem.3319* 148 | 149 | - *Ramin Nikzad-Langerodi, Mohit Kumar, Du Nguyen Duy, and Mahtab Alghasi (2024), "(epsilon, delta)-Differentially Private Partial Least Squares Regression", unpublished.* 150 | 151 | # Contact us 152 | Bottleneck Analytics GmbH 153 | info@bottleneck-analytics.com 154 | 155 | -------------------------------------------------------------------------------- /diPLSlib.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | LICENSE 2 | README.md 3 | setup.py 4 | diPLSlib/__init__.py 5 | diPLSlib/functions.py 6 | diPLSlib/models.py 7 | diPLSlib.egg-info/PKG-INFO 8 | diPLSlib.egg-info/SOURCES.txt 9 | diPLSlib.egg-info/dependency_links.txt 10 | diPLSlib.egg-info/requires.txt 11 | diPLSlib.egg-info/top_level.txt 12 | diPLSlib/utils/__init__.py 13 | diPLSlib/utils/misc.py 14 | tests/test_doctests.py -------------------------------------------------------------------------------- /diPLSlib.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /diPLSlib.egg-info/requires.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | matplotlib 3 | scipy 4 | scikit-learn 5 | -------------------------------------------------------------------------------- /diPLSlib.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | diPLSlib 2 | -------------------------------------------------------------------------------- /diPLSlib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/diPLSlib/__init__.py -------------------------------------------------------------------------------- /diPLSlib/__pycache__/__init__.cpython-313.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/diPLSlib/__pycache__/__init__.cpython-313.pyc -------------------------------------------------------------------------------- /diPLSlib/__pycache__/dipals.cpython-313.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/diPLSlib/__pycache__/dipals.cpython-313.pyc -------------------------------------------------------------------------------- /diPLSlib/__pycache__/functions.cpython-313.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/diPLSlib/__pycache__/functions.cpython-313.pyc -------------------------------------------------------------------------------- /diPLSlib/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/diPLSlib/utils/__init__.py -------------------------------------------------------------------------------- /diPLSlib/utils/misc.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Some helper functions for diPLSlib 3 | ''' 4 | 5 | import numpy as np 6 | from scipy.stats import norm 7 | from scipy.stats import f 8 | from math import exp, sqrt 9 | from scipy.special import erf 10 | 11 | def gengaus(length, mu, sigma, mag, noise=0): 12 | """ 13 | Generate a Gaussian spectrum-like signal with optional random noise. 14 | 15 | Parameters 16 | ---------- 17 | 18 | length : int 19 | Length of the generated signal. 20 | 21 | mu : float 22 | Mean of the Gaussian function. 23 | 24 | sigma : float 25 | Standard deviation of the Gaussian function. 26 | 27 | mag : float 28 | Magnitude of the Gaussian signal. 29 | 30 | noise : float, optional (default=0) 31 | Standard deviation of the Gaussian noise to be added to the signal. 32 | 33 | Returns 34 | ------- 35 | 36 | signal : ndarray of shape (length,) 37 | The generated Gaussian signal with noise. 38 | 39 | Examples 40 | -------- 41 | 42 | >>> from diPLSlib.utils.misc import gengaus 43 | >>> import numpy as np 44 | >>> import scipy.stats 45 | >>> signal = gengaus(100, 50, 10, 5, noise=0.1) 46 | """ 47 | 48 | s = mag*norm.pdf(np.arange(length),mu,sigma) 49 | n = noise*np.random.rand(length) 50 | signal = s + n 51 | 52 | return signal 53 | 54 | 55 | def hellipse(X, alpha=0.05): 56 | """ 57 | Compute the 95% confidence interval ellipse for a 2D scatter plot. 58 | 59 | Parameters 60 | ---------- 61 | 62 | X : ndarray of shape (n_samples, 2) 63 | Matrix of data points. 64 | 65 | alpha : float, optional (default=0.05) 66 | Significance level for the confidence interval. 67 | 68 | Returns 69 | ------- 70 | 71 | el : ndarray of shape (2, 100) 72 | Coordinates of the ellipse's points. To plot, use `plt.plot(el[0, :], el[1, :])`. 73 | 74 | Examples 75 | -------- 76 | 77 | >>> import matplotlib.pyplot as plt 78 | >>> import numpy as np 79 | >>> from diPLSlib.utils.misc import hellipse 80 | >>> X = np.random.random((100, 2)) 81 | >>> el = hellipse(X) 82 | >>> plt.scatter(X[:,0], X[:,1], label='Data points') # doctest: +ELLIPSIS 83 | 84 | >>> plt.plot(el[0,:], el[1,:], label='95% Confidence Ellipse') # doctest: +ELLIPSIS 85 | [] 86 | >>> plt.legend() # doctest: +ELLIPSIS 87 | 88 | """ 89 | 90 | # Means 91 | mean_all = np.zeros((2,1)) 92 | mean_all[0] = np.mean(X[:,0]) 93 | mean_all[1] = np.mean(X[:,1]) 94 | 95 | # Covariance matrix 96 | X = X[:,:2] 97 | comat_all = np.cov(np.transpose(X)) 98 | 99 | # SVD 100 | U,S,V = np.linalg.svd(comat_all) 101 | 102 | # Confidence limit computed as the 95% quantile of the F-Distribution 103 | N = np.shape(X)[0] 104 | quant = 1 - alpha 105 | Conf = (2*(N-2))/(N-2)*f.ppf(quant,2,(N-2)) 106 | 107 | # Evalute CI on (0,2pi) 108 | el = np.zeros((2,100)) 109 | t = np.linspace(0,2*np.pi,100) 110 | for j in np.arange(100): 111 | sT = np.matmul(U,np.diag(np.sqrt(S*Conf))) 112 | el[:,j] = np.transpose(mean_all)+np.matmul(sT,np.array([np.cos(t[j]),np.sin(t[j])])) 113 | 114 | return el 115 | 116 | 117 | def rmse(y, yhat): 118 | """ 119 | Compute the Root Mean Squared Error (RMSE) between two arrays. 120 | 121 | Parameters 122 | ---------- 123 | 124 | y : ndarray of shape (n_samples,) 125 | True values. 126 | 127 | yhat : ndarray of shape (n_samples,) 128 | Predicted values. 129 | 130 | Returns 131 | ------- 132 | 133 | error : ndarray of shape (n_samples,) 134 | The RMSE between `y` and `yhat`. 135 | 136 | Examples 137 | -------- 138 | 139 | >>> import numpy as np 140 | >>> from diPLSlib.utils.misc import rmse 141 | >>> x = np.array([1, 2, 3]) 142 | >>> y = np.array([2, 3, 4]) 143 | >>> error = rmse(x, y) 144 | >>> print(error) 145 | 1.0 146 | """ 147 | 148 | return np.sqrt(((y.ravel()-yhat.ravel())**2).mean()) 149 | 150 | 151 | def calibrateAnalyticGaussianMechanism(epsilon, delta, GS, tol = 1.e-12): 152 | """ 153 | Calibrate a Gaussian perturbation for differential privacy using the analytic Gaussian mechanism of [Balle and Wang, ICML'18] 154 | 155 | Parameters 156 | ---------- 157 | epsilon : float 158 | Privacy parameter epsilon 159 | 160 | delta : float 161 | Desired privacy failure probability 162 | 163 | GS : float 164 | Upper bound on the L2-sensitivity of the function to which the mechanism is applied 165 | 166 | tol : float 167 | Error tolerance for binary search 168 | 169 | 170 | Returns 171 | ------- 172 | sigma : float 173 | Standard deviation of Gaussian noise needed to achieve (epsilon,delta)-DP under global sensitivity GS 174 | 175 | References 176 | ---------- 177 | - Balle, B., & Wang, Y. X. (2018, July). Improving the gaussian mechanism for differential privacy: Analytical calibration and optimal denoising. In International Conference on Machine Learning (pp. 394-403). PMLR. 178 | 179 | Examples 180 | -------- 181 | >>> from diPLSlib.utils.misc import calibrateAnalyticGaussianMechanism 182 | >>> calibrateAnalyticGaussianMechanism(1.0, 1e-5, 1.0) 183 | 3.730631634944469 184 | """ 185 | 186 | def Phi(t): 187 | return 0.5*(1.0 + erf(float(t)/sqrt(2.0))) 188 | 189 | def caseA(epsilon,s): 190 | return Phi(sqrt(epsilon*s)) - exp(epsilon)*Phi(-sqrt(epsilon*(s+2.0))) 191 | 192 | def caseB(epsilon,s): 193 | return Phi(-sqrt(epsilon*s)) - exp(epsilon)*Phi(-sqrt(epsilon*(s+2.0))) 194 | 195 | def doubling_trick(predicate_stop, s_inf, s_sup): 196 | while(not predicate_stop(s_sup)): 197 | s_inf = s_sup 198 | s_sup = 2.0*s_inf 199 | return s_inf, s_sup 200 | 201 | def binary_search(predicate_stop, predicate_left, s_inf, s_sup): 202 | s_mid = s_inf + (s_sup-s_inf)/2.0 203 | while(not predicate_stop(s_mid)): 204 | if (predicate_left(s_mid)): 205 | s_sup = s_mid 206 | else: 207 | s_inf = s_mid 208 | s_mid = s_inf + (s_sup-s_inf)/2.0 209 | return s_mid 210 | 211 | delta_thr = caseA(epsilon, 0.0) 212 | 213 | if (delta == delta_thr): 214 | alpha = 1.0 215 | 216 | else: 217 | if (delta > delta_thr): 218 | predicate_stop_DT = lambda s : caseA(epsilon, s) >= delta 219 | function_s_to_delta = lambda s : caseA(epsilon, s) 220 | predicate_left_BS = lambda s : function_s_to_delta(s) > delta 221 | function_s_to_alpha = lambda s : sqrt(1.0 + s/2.0) - sqrt(s/2.0) 222 | 223 | else: 224 | predicate_stop_DT = lambda s : caseB(epsilon, s) <= delta 225 | function_s_to_delta = lambda s : caseB(epsilon, s) 226 | predicate_left_BS = lambda s : function_s_to_delta(s) < delta 227 | function_s_to_alpha = lambda s : sqrt(1.0 + s/2.0) + sqrt(s/2.0) 228 | 229 | predicate_stop_BS = lambda s : abs(function_s_to_delta(s) - delta) <= tol 230 | 231 | s_inf, s_sup = doubling_trick(predicate_stop_DT, 0.0, 1.0) 232 | s_final = binary_search(predicate_stop_BS, predicate_left_BS, s_inf, s_sup) 233 | alpha = function_s_to_alpha(s_final) 234 | 235 | sigma = alpha*GS/sqrt(2.0*epsilon) 236 | 237 | return sigma -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /doc/_build/doctrees/diPLSlib.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/doctrees/diPLSlib.doctree -------------------------------------------------------------------------------- /doc/_build/doctrees/diPLSlib.utils.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/doctrees/diPLSlib.utils.doctree -------------------------------------------------------------------------------- /doc/_build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/doctrees/environment.pickle -------------------------------------------------------------------------------- /doc/_build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/doctrees/index.doctree -------------------------------------------------------------------------------- /doc/_build/doctrees/modules.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/doctrees/modules.doctree -------------------------------------------------------------------------------- /doc/_build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file records the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: c06bbb0eaad82c518ef5e37c9765238d 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /doc/_build/html/.buildinfo.bak: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file records the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: a9ab0143384d0957b09b608e96947e9c 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /doc/_build/html/_modules/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Overview: module code — diPLSlib 2.5.0 documentation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 50 | 51 |
55 | 56 |
57 |
58 |
59 |
    60 |
  • 61 | 62 |
  • 63 |
  • 64 |
65 |
66 |
67 |
68 |
69 | 70 |

All modules for which code is available

71 | 75 | 76 |
77 |
78 |
79 | 80 |
81 | 82 |
83 |

© Copyright 2025, Ramin Nikzad-Langerodi.

84 |
85 | 86 | Built with Sphinx using a 87 | theme 88 | provided by Read the Docs. 89 | 90 | 91 |
92 |
93 |
94 |
95 |
96 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /doc/_build/html/_sources/diPLSlib.rst.txt: -------------------------------------------------------------------------------- 1 | diPLSlib package 2 | ================ 3 | 4 | 5 | diPLSlib.functions module 6 | ------------------------- 7 | 8 | .. automodule:: diPLSlib.functions 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | diPLSlib.models module 14 | ---------------------- 15 | 16 | .. automodule:: diPLSlib.models 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | 21 | diPLSlib.utils subpackage 22 | ------------------------- 23 | 24 | .. toctree:: 25 | :maxdepth: 4 26 | 27 | diPLSlib.utils 28 | 29 | Module contents 30 | --------------- 31 | 32 | .. automodule:: diPLSlib 33 | :members: 34 | :undoc-members: 35 | :show-inheritance: 36 | -------------------------------------------------------------------------------- /doc/_build/html/_sources/diPLSlib.utils.rst.txt: -------------------------------------------------------------------------------- 1 | diPLSlib.utils subpackage 2 | ========================= 3 | 4 | 5 | diPLSlib.utils.misc module 6 | -------------------------- 7 | 8 | .. automodule:: diPLSlib.utils.misc 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | Module contents 14 | --------------- 15 | 16 | .. automodule:: diPLSlib.utils 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | -------------------------------------------------------------------------------- /doc/_build/html/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. diPLSlib documentation master file, created by 2 | sphinx-quickstart on Sun Nov 3 00:13:47 2024. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | diPLSlib documentation 7 | ====================== 8 | 9 | Introduction 10 | ------------ 11 | 12 | **diPLSlib** is a Python library designed for domain adaptation in multivariate calibration, with a focus on privacy-preserving regression and calibration model maintenance. It provides a scikit-learn compatible API and implements advanced methods for aligning data distributions across different domains, enabling robust and transferable regression models. 13 | 14 | The library features several state-of-the-art algorithms, including: 15 | 16 | - **Domain-Invariant Partial Least Squares (di-PLS/mdi-PLS):** Aligns feature distributions between source and target domains to improve model generalization. 17 | - **Graph-based Calibration Transfer (GCT-PLS):** Minimizes discrepancies between paired samples from different domains in the latent variable space. 18 | - **Kernel Domain Adaptive PLS (KDAPLS):** Projects data into a reproducing kernel Hilbert space for non-parametric domain adaptation. 19 | - **Differentially Private PLS (EDPLS):** Ensures privacy guarantees for sensitive data using the :math:`(\epsilon, \delta)`-differential privacy framework. 20 | 21 | diPLSlib is suitable for chemometrics, analytical chemistry, and other fields where robust calibration transfer and privacy-preserving modeling are required. For more details, usage examples, and API documentation, please refer to the sections below. 22 | 23 | .. toctree:: 24 | :maxdepth: 2 25 | :caption: Contents: 26 | 27 | diPLSlib 28 | -------------------------------------------------------------------------------- /doc/_build/html/_sources/modules.rst.txt: -------------------------------------------------------------------------------- 1 | diPLSlib 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | diPLSlib 8 | -------------------------------------------------------------------------------- /doc/_build/html/_static/_sphinx_javascript_frameworks_compat.js: -------------------------------------------------------------------------------- 1 | /* Compatability shim for jQuery and underscores.js. 2 | * 3 | * Copyright Sphinx contributors 4 | * Released under the two clause BSD licence 5 | */ 6 | 7 | /** 8 | * small helper function to urldecode strings 9 | * 10 | * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL 11 | */ 12 | jQuery.urldecode = function(x) { 13 | if (!x) { 14 | return x 15 | } 16 | return decodeURIComponent(x.replace(/\+/g, ' ')); 17 | }; 18 | 19 | /** 20 | * small helper function to urlencode strings 21 | */ 22 | jQuery.urlencode = encodeURIComponent; 23 | 24 | /** 25 | * This function returns the parsed url parameters of the 26 | * current request. Multiple values per key are supported, 27 | * it will always return arrays of strings for the value parts. 28 | */ 29 | jQuery.getQueryParameters = function(s) { 30 | if (typeof s === 'undefined') 31 | s = document.location.search; 32 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 33 | var result = {}; 34 | for (var i = 0; i < parts.length; i++) { 35 | var tmp = parts[i].split('=', 2); 36 | var key = jQuery.urldecode(tmp[0]); 37 | var value = jQuery.urldecode(tmp[1]); 38 | if (key in result) 39 | result[key].push(value); 40 | else 41 | result[key] = [value]; 42 | } 43 | return result; 44 | }; 45 | 46 | /** 47 | * highlight a given string on a jquery object by wrapping it in 48 | * span elements with the given class name. 49 | */ 50 | jQuery.fn.highlightText = function(text, className) { 51 | function highlight(node, addItems) { 52 | if (node.nodeType === 3) { 53 | var val = node.nodeValue; 54 | var pos = val.toLowerCase().indexOf(text); 55 | if (pos >= 0 && 56 | !jQuery(node.parentNode).hasClass(className) && 57 | !jQuery(node.parentNode).hasClass("nohighlight")) { 58 | var span; 59 | var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); 60 | if (isInSVG) { 61 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); 62 | } else { 63 | span = document.createElement("span"); 64 | span.className = className; 65 | } 66 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 67 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 68 | document.createTextNode(val.substr(pos + text.length)), 69 | node.nextSibling)); 70 | node.nodeValue = val.substr(0, pos); 71 | if (isInSVG) { 72 | var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); 73 | var bbox = node.parentElement.getBBox(); 74 | rect.x.baseVal.value = bbox.x; 75 | rect.y.baseVal.value = bbox.y; 76 | rect.width.baseVal.value = bbox.width; 77 | rect.height.baseVal.value = bbox.height; 78 | rect.setAttribute('class', className); 79 | addItems.push({ 80 | "parent": node.parentNode, 81 | "target": rect}); 82 | } 83 | } 84 | } 85 | else if (!jQuery(node).is("button, select, textarea")) { 86 | jQuery.each(node.childNodes, function() { 87 | highlight(this, addItems); 88 | }); 89 | } 90 | } 91 | var addItems = []; 92 | var result = this.each(function() { 93 | highlight(this, addItems); 94 | }); 95 | for (var i = 0; i < addItems.length; ++i) { 96 | jQuery(addItems[i].parent).before(addItems[i].target); 97 | } 98 | return result; 99 | }; 100 | 101 | /* 102 | * backward compatibility for jQuery.browser 103 | * This will be supported until firefox bug is fixed. 104 | */ 105 | if (!jQuery.browser) { 106 | jQuery.uaMatch = function(ua) { 107 | ua = ua.toLowerCase(); 108 | 109 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 110 | /(webkit)[ \/]([\w.]+)/.exec(ua) || 111 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 112 | /(msie) ([\w.]+)/.exec(ua) || 113 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || 114 | []; 115 | 116 | return { 117 | browser: match[ 1 ] || "", 118 | version: match[ 2 ] || "0" 119 | }; 120 | }; 121 | jQuery.browser = {}; 122 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; 123 | } 124 | -------------------------------------------------------------------------------- /doc/_build/html/_static/basic.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Sphinx stylesheet -- basic theme. 3 | */ 4 | 5 | /* -- main layout ----------------------------------------------------------- */ 6 | 7 | div.clearer { 8 | clear: both; 9 | } 10 | 11 | div.section::after { 12 | display: block; 13 | content: ''; 14 | clear: left; 15 | } 16 | 17 | /* -- relbar ---------------------------------------------------------------- */ 18 | 19 | div.related { 20 | width: 100%; 21 | font-size: 90%; 22 | } 23 | 24 | div.related h3 { 25 | display: none; 26 | } 27 | 28 | div.related ul { 29 | margin: 0; 30 | padding: 0 0 0 10px; 31 | list-style: none; 32 | } 33 | 34 | div.related li { 35 | display: inline; 36 | } 37 | 38 | div.related li.right { 39 | float: right; 40 | margin-right: 5px; 41 | } 42 | 43 | /* -- sidebar --------------------------------------------------------------- */ 44 | 45 | div.sphinxsidebarwrapper { 46 | padding: 10px 5px 0 10px; 47 | } 48 | 49 | div.sphinxsidebar { 50 | float: left; 51 | width: 230px; 52 | margin-left: -100%; 53 | font-size: 90%; 54 | word-wrap: break-word; 55 | overflow-wrap : break-word; 56 | } 57 | 58 | div.sphinxsidebar ul { 59 | list-style: none; 60 | } 61 | 62 | div.sphinxsidebar ul ul, 63 | div.sphinxsidebar ul.want-points { 64 | margin-left: 20px; 65 | list-style: square; 66 | } 67 | 68 | div.sphinxsidebar ul ul { 69 | margin-top: 0; 70 | margin-bottom: 0; 71 | } 72 | 73 | div.sphinxsidebar form { 74 | margin-top: 10px; 75 | } 76 | 77 | div.sphinxsidebar input { 78 | border: 1px solid #98dbcc; 79 | font-family: sans-serif; 80 | font-size: 1em; 81 | } 82 | 83 | div.sphinxsidebar #searchbox form.search { 84 | overflow: hidden; 85 | } 86 | 87 | div.sphinxsidebar #searchbox input[type="text"] { 88 | float: left; 89 | width: 80%; 90 | padding: 0.25em; 91 | box-sizing: border-box; 92 | } 93 | 94 | div.sphinxsidebar #searchbox input[type="submit"] { 95 | float: left; 96 | width: 20%; 97 | border-left: none; 98 | padding: 0.25em; 99 | box-sizing: border-box; 100 | } 101 | 102 | 103 | img { 104 | border: 0; 105 | max-width: 100%; 106 | } 107 | 108 | /* -- search page ----------------------------------------------------------- */ 109 | 110 | ul.search { 111 | margin-top: 10px; 112 | } 113 | 114 | ul.search li { 115 | padding: 5px 0; 116 | } 117 | 118 | ul.search li a { 119 | font-weight: bold; 120 | } 121 | 122 | ul.search li p.context { 123 | color: #888; 124 | margin: 2px 0 0 30px; 125 | text-align: left; 126 | } 127 | 128 | ul.keywordmatches li.goodmatch a { 129 | font-weight: bold; 130 | } 131 | 132 | /* -- index page ------------------------------------------------------------ */ 133 | 134 | table.contentstable { 135 | width: 90%; 136 | margin-left: auto; 137 | margin-right: auto; 138 | } 139 | 140 | table.contentstable p.biglink { 141 | line-height: 150%; 142 | } 143 | 144 | a.biglink { 145 | font-size: 1.3em; 146 | } 147 | 148 | span.linkdescr { 149 | font-style: italic; 150 | padding-top: 5px; 151 | font-size: 90%; 152 | } 153 | 154 | /* -- general index --------------------------------------------------------- */ 155 | 156 | table.indextable { 157 | width: 100%; 158 | } 159 | 160 | table.indextable td { 161 | text-align: left; 162 | vertical-align: top; 163 | } 164 | 165 | table.indextable ul { 166 | margin-top: 0; 167 | margin-bottom: 0; 168 | list-style-type: none; 169 | } 170 | 171 | table.indextable > tbody > tr > td > ul { 172 | padding-left: 0em; 173 | } 174 | 175 | table.indextable tr.pcap { 176 | height: 10px; 177 | } 178 | 179 | table.indextable tr.cap { 180 | margin-top: 10px; 181 | background-color: #f2f2f2; 182 | } 183 | 184 | img.toggler { 185 | margin-right: 3px; 186 | margin-top: 3px; 187 | cursor: pointer; 188 | } 189 | 190 | div.modindex-jumpbox { 191 | border-top: 1px solid #ddd; 192 | border-bottom: 1px solid #ddd; 193 | margin: 1em 0 1em 0; 194 | padding: 0.4em; 195 | } 196 | 197 | div.genindex-jumpbox { 198 | border-top: 1px solid #ddd; 199 | border-bottom: 1px solid #ddd; 200 | margin: 1em 0 1em 0; 201 | padding: 0.4em; 202 | } 203 | 204 | /* -- domain module index --------------------------------------------------- */ 205 | 206 | table.modindextable td { 207 | padding: 2px; 208 | border-collapse: collapse; 209 | } 210 | 211 | /* -- general body styles --------------------------------------------------- */ 212 | 213 | div.body { 214 | min-width: 360px; 215 | max-width: 800px; 216 | } 217 | 218 | div.body p, div.body dd, div.body li, div.body blockquote { 219 | -moz-hyphens: auto; 220 | -ms-hyphens: auto; 221 | -webkit-hyphens: auto; 222 | hyphens: auto; 223 | } 224 | 225 | a.headerlink { 226 | visibility: hidden; 227 | } 228 | 229 | a:visited { 230 | color: #551A8B; 231 | } 232 | 233 | h1:hover > a.headerlink, 234 | h2:hover > a.headerlink, 235 | h3:hover > a.headerlink, 236 | h4:hover > a.headerlink, 237 | h5:hover > a.headerlink, 238 | h6:hover > a.headerlink, 239 | dt:hover > a.headerlink, 240 | caption:hover > a.headerlink, 241 | p.caption:hover > a.headerlink, 242 | div.code-block-caption:hover > a.headerlink { 243 | visibility: visible; 244 | } 245 | 246 | div.body p.caption { 247 | text-align: inherit; 248 | } 249 | 250 | div.body td { 251 | text-align: left; 252 | } 253 | 254 | .first { 255 | margin-top: 0 !important; 256 | } 257 | 258 | p.rubric { 259 | margin-top: 30px; 260 | font-weight: bold; 261 | } 262 | 263 | img.align-left, figure.align-left, .figure.align-left, object.align-left { 264 | clear: left; 265 | float: left; 266 | margin-right: 1em; 267 | } 268 | 269 | img.align-right, figure.align-right, .figure.align-right, object.align-right { 270 | clear: right; 271 | float: right; 272 | margin-left: 1em; 273 | } 274 | 275 | img.align-center, figure.align-center, .figure.align-center, object.align-center { 276 | display: block; 277 | margin-left: auto; 278 | margin-right: auto; 279 | } 280 | 281 | img.align-default, figure.align-default, .figure.align-default { 282 | display: block; 283 | margin-left: auto; 284 | margin-right: auto; 285 | } 286 | 287 | .align-left { 288 | text-align: left; 289 | } 290 | 291 | .align-center { 292 | text-align: center; 293 | } 294 | 295 | .align-default { 296 | text-align: center; 297 | } 298 | 299 | .align-right { 300 | text-align: right; 301 | } 302 | 303 | /* -- sidebars -------------------------------------------------------------- */ 304 | 305 | div.sidebar, 306 | aside.sidebar { 307 | margin: 0 0 0.5em 1em; 308 | border: 1px solid #ddb; 309 | padding: 7px; 310 | background-color: #ffe; 311 | width: 40%; 312 | float: right; 313 | clear: right; 314 | overflow-x: auto; 315 | } 316 | 317 | p.sidebar-title { 318 | font-weight: bold; 319 | } 320 | 321 | nav.contents, 322 | aside.topic, 323 | div.admonition, div.topic, blockquote { 324 | clear: left; 325 | } 326 | 327 | /* -- topics ---------------------------------------------------------------- */ 328 | 329 | nav.contents, 330 | aside.topic, 331 | div.topic { 332 | border: 1px solid #ccc; 333 | padding: 7px; 334 | margin: 10px 0 10px 0; 335 | } 336 | 337 | p.topic-title { 338 | font-size: 1.1em; 339 | font-weight: bold; 340 | margin-top: 10px; 341 | } 342 | 343 | /* -- admonitions ----------------------------------------------------------- */ 344 | 345 | div.admonition { 346 | margin-top: 10px; 347 | margin-bottom: 10px; 348 | padding: 7px; 349 | } 350 | 351 | div.admonition dt { 352 | font-weight: bold; 353 | } 354 | 355 | p.admonition-title { 356 | margin: 0px 10px 5px 0px; 357 | font-weight: bold; 358 | } 359 | 360 | div.body p.centered { 361 | text-align: center; 362 | margin-top: 25px; 363 | } 364 | 365 | /* -- content of sidebars/topics/admonitions -------------------------------- */ 366 | 367 | div.sidebar > :last-child, 368 | aside.sidebar > :last-child, 369 | nav.contents > :last-child, 370 | aside.topic > :last-child, 371 | div.topic > :last-child, 372 | div.admonition > :last-child { 373 | margin-bottom: 0; 374 | } 375 | 376 | div.sidebar::after, 377 | aside.sidebar::after, 378 | nav.contents::after, 379 | aside.topic::after, 380 | div.topic::after, 381 | div.admonition::after, 382 | blockquote::after { 383 | display: block; 384 | content: ''; 385 | clear: both; 386 | } 387 | 388 | /* -- tables ---------------------------------------------------------------- */ 389 | 390 | table.docutils { 391 | margin-top: 10px; 392 | margin-bottom: 10px; 393 | border: 0; 394 | border-collapse: collapse; 395 | } 396 | 397 | table.align-center { 398 | margin-left: auto; 399 | margin-right: auto; 400 | } 401 | 402 | table.align-default { 403 | margin-left: auto; 404 | margin-right: auto; 405 | } 406 | 407 | table caption span.caption-number { 408 | font-style: italic; 409 | } 410 | 411 | table caption span.caption-text { 412 | } 413 | 414 | table.docutils td, table.docutils th { 415 | padding: 1px 8px 1px 5px; 416 | border-top: 0; 417 | border-left: 0; 418 | border-right: 0; 419 | border-bottom: 1px solid #aaa; 420 | } 421 | 422 | th { 423 | text-align: left; 424 | padding-right: 5px; 425 | } 426 | 427 | table.citation { 428 | border-left: solid 1px gray; 429 | margin-left: 1px; 430 | } 431 | 432 | table.citation td { 433 | border-bottom: none; 434 | } 435 | 436 | th > :first-child, 437 | td > :first-child { 438 | margin-top: 0px; 439 | } 440 | 441 | th > :last-child, 442 | td > :last-child { 443 | margin-bottom: 0px; 444 | } 445 | 446 | /* -- figures --------------------------------------------------------------- */ 447 | 448 | div.figure, figure { 449 | margin: 0.5em; 450 | padding: 0.5em; 451 | } 452 | 453 | div.figure p.caption, figcaption { 454 | padding: 0.3em; 455 | } 456 | 457 | div.figure p.caption span.caption-number, 458 | figcaption span.caption-number { 459 | font-style: italic; 460 | } 461 | 462 | div.figure p.caption span.caption-text, 463 | figcaption span.caption-text { 464 | } 465 | 466 | /* -- field list styles ----------------------------------------------------- */ 467 | 468 | table.field-list td, table.field-list th { 469 | border: 0 !important; 470 | } 471 | 472 | .field-list ul { 473 | margin: 0; 474 | padding-left: 1em; 475 | } 476 | 477 | .field-list p { 478 | margin: 0; 479 | } 480 | 481 | .field-name { 482 | -moz-hyphens: manual; 483 | -ms-hyphens: manual; 484 | -webkit-hyphens: manual; 485 | hyphens: manual; 486 | } 487 | 488 | /* -- hlist styles ---------------------------------------------------------- */ 489 | 490 | table.hlist { 491 | margin: 1em 0; 492 | } 493 | 494 | table.hlist td { 495 | vertical-align: top; 496 | } 497 | 498 | /* -- object description styles --------------------------------------------- */ 499 | 500 | .sig { 501 | font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; 502 | } 503 | 504 | .sig-name, code.descname { 505 | background-color: transparent; 506 | font-weight: bold; 507 | } 508 | 509 | .sig-name { 510 | font-size: 1.1em; 511 | } 512 | 513 | code.descname { 514 | font-size: 1.2em; 515 | } 516 | 517 | .sig-prename, code.descclassname { 518 | background-color: transparent; 519 | } 520 | 521 | .optional { 522 | font-size: 1.3em; 523 | } 524 | 525 | .sig-paren { 526 | font-size: larger; 527 | } 528 | 529 | .sig-param.n { 530 | font-style: italic; 531 | } 532 | 533 | /* C++ specific styling */ 534 | 535 | .sig-inline.c-texpr, 536 | .sig-inline.cpp-texpr { 537 | font-family: unset; 538 | } 539 | 540 | .sig.c .k, .sig.c .kt, 541 | .sig.cpp .k, .sig.cpp .kt { 542 | color: #0033B3; 543 | } 544 | 545 | .sig.c .m, 546 | .sig.cpp .m { 547 | color: #1750EB; 548 | } 549 | 550 | .sig.c .s, .sig.c .sc, 551 | .sig.cpp .s, .sig.cpp .sc { 552 | color: #067D17; 553 | } 554 | 555 | 556 | /* -- other body styles ----------------------------------------------------- */ 557 | 558 | ol.arabic { 559 | list-style: decimal; 560 | } 561 | 562 | ol.loweralpha { 563 | list-style: lower-alpha; 564 | } 565 | 566 | ol.upperalpha { 567 | list-style: upper-alpha; 568 | } 569 | 570 | ol.lowerroman { 571 | list-style: lower-roman; 572 | } 573 | 574 | ol.upperroman { 575 | list-style: upper-roman; 576 | } 577 | 578 | :not(li) > ol > li:first-child > :first-child, 579 | :not(li) > ul > li:first-child > :first-child { 580 | margin-top: 0px; 581 | } 582 | 583 | :not(li) > ol > li:last-child > :last-child, 584 | :not(li) > ul > li:last-child > :last-child { 585 | margin-bottom: 0px; 586 | } 587 | 588 | ol.simple ol p, 589 | ol.simple ul p, 590 | ul.simple ol p, 591 | ul.simple ul p { 592 | margin-top: 0; 593 | } 594 | 595 | ol.simple > li:not(:first-child) > p, 596 | ul.simple > li:not(:first-child) > p { 597 | margin-top: 0; 598 | } 599 | 600 | ol.simple p, 601 | ul.simple p { 602 | margin-bottom: 0; 603 | } 604 | 605 | aside.footnote > span, 606 | div.citation > span { 607 | float: left; 608 | } 609 | aside.footnote > span:last-of-type, 610 | div.citation > span:last-of-type { 611 | padding-right: 0.5em; 612 | } 613 | aside.footnote > p { 614 | margin-left: 2em; 615 | } 616 | div.citation > p { 617 | margin-left: 4em; 618 | } 619 | aside.footnote > p:last-of-type, 620 | div.citation > p:last-of-type { 621 | margin-bottom: 0em; 622 | } 623 | aside.footnote > p:last-of-type:after, 624 | div.citation > p:last-of-type:after { 625 | content: ""; 626 | clear: both; 627 | } 628 | 629 | dl.field-list { 630 | display: grid; 631 | grid-template-columns: fit-content(30%) auto; 632 | } 633 | 634 | dl.field-list > dt { 635 | font-weight: bold; 636 | word-break: break-word; 637 | padding-left: 0.5em; 638 | padding-right: 5px; 639 | } 640 | 641 | dl.field-list > dd { 642 | padding-left: 0.5em; 643 | margin-top: 0em; 644 | margin-left: 0em; 645 | margin-bottom: 0em; 646 | } 647 | 648 | dl { 649 | margin-bottom: 15px; 650 | } 651 | 652 | dd > :first-child { 653 | margin-top: 0px; 654 | } 655 | 656 | dd ul, dd table { 657 | margin-bottom: 10px; 658 | } 659 | 660 | dd { 661 | margin-top: 3px; 662 | margin-bottom: 10px; 663 | margin-left: 30px; 664 | } 665 | 666 | .sig dd { 667 | margin-top: 0px; 668 | margin-bottom: 0px; 669 | } 670 | 671 | .sig dl { 672 | margin-top: 0px; 673 | margin-bottom: 0px; 674 | } 675 | 676 | dl > dd:last-child, 677 | dl > dd:last-child > :last-child { 678 | margin-bottom: 0; 679 | } 680 | 681 | dt:target, span.highlighted { 682 | background-color: #fbe54e; 683 | } 684 | 685 | rect.highlighted { 686 | fill: #fbe54e; 687 | } 688 | 689 | dl.glossary dt { 690 | font-weight: bold; 691 | font-size: 1.1em; 692 | } 693 | 694 | .versionmodified { 695 | font-style: italic; 696 | } 697 | 698 | .system-message { 699 | background-color: #fda; 700 | padding: 5px; 701 | border: 3px solid red; 702 | } 703 | 704 | .footnote:target { 705 | background-color: #ffa; 706 | } 707 | 708 | .line-block { 709 | display: block; 710 | margin-top: 1em; 711 | margin-bottom: 1em; 712 | } 713 | 714 | .line-block .line-block { 715 | margin-top: 0; 716 | margin-bottom: 0; 717 | margin-left: 1.5em; 718 | } 719 | 720 | .guilabel, .menuselection { 721 | font-family: sans-serif; 722 | } 723 | 724 | .accelerator { 725 | text-decoration: underline; 726 | } 727 | 728 | .classifier { 729 | font-style: oblique; 730 | } 731 | 732 | .classifier:before { 733 | font-style: normal; 734 | margin: 0 0.5em; 735 | content: ":"; 736 | display: inline-block; 737 | } 738 | 739 | abbr, acronym { 740 | border-bottom: dotted 1px; 741 | cursor: help; 742 | } 743 | 744 | .translated { 745 | background-color: rgba(207, 255, 207, 0.2) 746 | } 747 | 748 | .untranslated { 749 | background-color: rgba(255, 207, 207, 0.2) 750 | } 751 | 752 | /* -- code displays --------------------------------------------------------- */ 753 | 754 | pre { 755 | overflow: auto; 756 | overflow-y: hidden; /* fixes display issues on Chrome browsers */ 757 | } 758 | 759 | pre, div[class*="highlight-"] { 760 | clear: both; 761 | } 762 | 763 | span.pre { 764 | -moz-hyphens: none; 765 | -ms-hyphens: none; 766 | -webkit-hyphens: none; 767 | hyphens: none; 768 | white-space: nowrap; 769 | } 770 | 771 | div[class*="highlight-"] { 772 | margin: 1em 0; 773 | } 774 | 775 | td.linenos pre { 776 | border: 0; 777 | background-color: transparent; 778 | color: #aaa; 779 | } 780 | 781 | table.highlighttable { 782 | display: block; 783 | } 784 | 785 | table.highlighttable tbody { 786 | display: block; 787 | } 788 | 789 | table.highlighttable tr { 790 | display: flex; 791 | } 792 | 793 | table.highlighttable td { 794 | margin: 0; 795 | padding: 0; 796 | } 797 | 798 | table.highlighttable td.linenos { 799 | padding-right: 0.5em; 800 | } 801 | 802 | table.highlighttable td.code { 803 | flex: 1; 804 | overflow: hidden; 805 | } 806 | 807 | .highlight .hll { 808 | display: block; 809 | } 810 | 811 | div.highlight pre, 812 | table.highlighttable pre { 813 | margin: 0; 814 | } 815 | 816 | div.code-block-caption + div { 817 | margin-top: 0; 818 | } 819 | 820 | div.code-block-caption { 821 | margin-top: 1em; 822 | padding: 2px 5px; 823 | font-size: small; 824 | } 825 | 826 | div.code-block-caption code { 827 | background-color: transparent; 828 | } 829 | 830 | table.highlighttable td.linenos, 831 | span.linenos, 832 | div.highlight span.gp { /* gp: Generic.Prompt */ 833 | user-select: none; 834 | -webkit-user-select: text; /* Safari fallback only */ 835 | -webkit-user-select: none; /* Chrome/Safari */ 836 | -moz-user-select: none; /* Firefox */ 837 | -ms-user-select: none; /* IE10+ */ 838 | } 839 | 840 | div.code-block-caption span.caption-number { 841 | padding: 0.1em 0.3em; 842 | font-style: italic; 843 | } 844 | 845 | div.code-block-caption span.caption-text { 846 | } 847 | 848 | div.literal-block-wrapper { 849 | margin: 1em 0; 850 | } 851 | 852 | code.xref, a code { 853 | background-color: transparent; 854 | font-weight: bold; 855 | } 856 | 857 | h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { 858 | background-color: transparent; 859 | } 860 | 861 | .viewcode-link { 862 | float: right; 863 | } 864 | 865 | .viewcode-back { 866 | float: right; 867 | font-family: sans-serif; 868 | } 869 | 870 | div.viewcode-block:target { 871 | margin: -1px -10px; 872 | padding: 0 10px; 873 | } 874 | 875 | /* -- math display ---------------------------------------------------------- */ 876 | 877 | img.math { 878 | vertical-align: middle; 879 | } 880 | 881 | div.body div.math p { 882 | text-align: center; 883 | } 884 | 885 | span.eqno { 886 | float: right; 887 | } 888 | 889 | span.eqno a.headerlink { 890 | position: absolute; 891 | z-index: 1; 892 | } 893 | 894 | div.math:hover a.headerlink { 895 | visibility: visible; 896 | } 897 | 898 | /* -- printout stylesheet --------------------------------------------------- */ 899 | 900 | @media print { 901 | div.document, 902 | div.documentwrapper, 903 | div.bodywrapper { 904 | margin: 0 !important; 905 | width: 100%; 906 | } 907 | 908 | div.sphinxsidebar, 909 | div.related, 910 | div.footer, 911 | #top-link { 912 | display: none; 913 | } 914 | } -------------------------------------------------------------------------------- /doc/_build/html/_static/css/badge_only.css: -------------------------------------------------------------------------------- 1 | .clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions .rst-other-versions .rtd-current-item{font-weight:700}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}#flyout-search-form{padding:6px} -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/lato-bold-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/lato-bold-italic.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/lato-bold-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/lato-bold-italic.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/lato-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/lato-bold.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/lato-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/lato-bold.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/lato-normal-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/lato-normal-italic.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/lato-normal-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/lato-normal-italic.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/lato-normal.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/lato-normal.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/css/fonts/lato-normal.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/css/fonts/lato-normal.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Base JavaScript utilities for all Sphinx HTML documentation. 3 | */ 4 | "use strict"; 5 | 6 | const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ 7 | "TEXTAREA", 8 | "INPUT", 9 | "SELECT", 10 | "BUTTON", 11 | ]); 12 | 13 | const _ready = (callback) => { 14 | if (document.readyState !== "loading") { 15 | callback(); 16 | } else { 17 | document.addEventListener("DOMContentLoaded", callback); 18 | } 19 | }; 20 | 21 | /** 22 | * Small JavaScript module for the documentation. 23 | */ 24 | const Documentation = { 25 | init: () => { 26 | Documentation.initDomainIndexTable(); 27 | Documentation.initOnKeyListeners(); 28 | }, 29 | 30 | /** 31 | * i18n support 32 | */ 33 | TRANSLATIONS: {}, 34 | PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), 35 | LOCALE: "unknown", 36 | 37 | // gettext and ngettext don't access this so that the functions 38 | // can safely bound to a different name (_ = Documentation.gettext) 39 | gettext: (string) => { 40 | const translated = Documentation.TRANSLATIONS[string]; 41 | switch (typeof translated) { 42 | case "undefined": 43 | return string; // no translation 44 | case "string": 45 | return translated; // translation exists 46 | default: 47 | return translated[0]; // (singular, plural) translation tuple exists 48 | } 49 | }, 50 | 51 | ngettext: (singular, plural, n) => { 52 | const translated = Documentation.TRANSLATIONS[singular]; 53 | if (typeof translated !== "undefined") 54 | return translated[Documentation.PLURAL_EXPR(n)]; 55 | return n === 1 ? singular : plural; 56 | }, 57 | 58 | addTranslations: (catalog) => { 59 | Object.assign(Documentation.TRANSLATIONS, catalog.messages); 60 | Documentation.PLURAL_EXPR = new Function( 61 | "n", 62 | `return (${catalog.plural_expr})` 63 | ); 64 | Documentation.LOCALE = catalog.locale; 65 | }, 66 | 67 | /** 68 | * helper function to focus on search bar 69 | */ 70 | focusSearchBar: () => { 71 | document.querySelectorAll("input[name=q]")[0]?.focus(); 72 | }, 73 | 74 | /** 75 | * Initialise the domain index toggle buttons 76 | */ 77 | initDomainIndexTable: () => { 78 | const toggler = (el) => { 79 | const idNumber = el.id.substr(7); 80 | const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); 81 | if (el.src.substr(-9) === "minus.png") { 82 | el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; 83 | toggledRows.forEach((el) => (el.style.display = "none")); 84 | } else { 85 | el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; 86 | toggledRows.forEach((el) => (el.style.display = "")); 87 | } 88 | }; 89 | 90 | const togglerElements = document.querySelectorAll("img.toggler"); 91 | togglerElements.forEach((el) => 92 | el.addEventListener("click", (event) => toggler(event.currentTarget)) 93 | ); 94 | togglerElements.forEach((el) => (el.style.display = "")); 95 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); 96 | }, 97 | 98 | initOnKeyListeners: () => { 99 | // only install a listener if it is really needed 100 | if ( 101 | !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && 102 | !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS 103 | ) 104 | return; 105 | 106 | document.addEventListener("keydown", (event) => { 107 | // bail for input elements 108 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 109 | // bail with special keys 110 | if (event.altKey || event.ctrlKey || event.metaKey) return; 111 | 112 | if (!event.shiftKey) { 113 | switch (event.key) { 114 | case "ArrowLeft": 115 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 116 | 117 | const prevLink = document.querySelector('link[rel="prev"]'); 118 | if (prevLink && prevLink.href) { 119 | window.location.href = prevLink.href; 120 | event.preventDefault(); 121 | } 122 | break; 123 | case "ArrowRight": 124 | if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; 125 | 126 | const nextLink = document.querySelector('link[rel="next"]'); 127 | if (nextLink && nextLink.href) { 128 | window.location.href = nextLink.href; 129 | event.preventDefault(); 130 | } 131 | break; 132 | } 133 | } 134 | 135 | // some keyboard layouts may need Shift to get / 136 | switch (event.key) { 137 | case "/": 138 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; 139 | Documentation.focusSearchBar(); 140 | event.preventDefault(); 141 | } 142 | }); 143 | }, 144 | }; 145 | 146 | // quick alias for translations 147 | const _ = Documentation.gettext; 148 | 149 | _ready(Documentation.init); 150 | -------------------------------------------------------------------------------- /doc/_build/html/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | const DOCUMENTATION_OPTIONS = { 2 | VERSION: '2.5.0', 3 | LANGUAGE: 'en', 4 | COLLAPSE_INDEX: false, 5 | BUILDER: 'html', 6 | FILE_SUFFIX: '.html', 7 | LINK_SUFFIX: '.html', 8 | HAS_SOURCE: true, 9 | SOURCELINK_SUFFIX: '.txt', 10 | NAVIGATION_WITH_KEYS: false, 11 | SHOW_SEARCH_SUMMARY: true, 12 | ENABLE_SEARCH_SHORTCUTS: true, 13 | }; -------------------------------------------------------------------------------- /doc/_build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/file.png -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-bold.eot -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-bold.ttf -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-bold.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-bold.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-bolditalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-bolditalic.eot -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-bolditalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-bolditalic.ttf -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-italic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-italic.eot -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-italic.ttf -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-italic.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-italic.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-regular.eot -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-regular.ttf -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-regular.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/Lato/lato-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/Lato/lato-regular.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff -------------------------------------------------------------------------------- /doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 -------------------------------------------------------------------------------- /doc/_build/html/_static/js/badge_only.js: -------------------------------------------------------------------------------- 1 | !function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}}); -------------------------------------------------------------------------------- /doc/_build/html/_static/js/theme.js: -------------------------------------------------------------------------------- 1 | !function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t a.language.name.localeCompare(b.language.name)); 14 | 15 | const languagesHTML = ` 16 |
17 |
Languages
18 | ${languages 19 | .map( 20 | (translation) => ` 21 |
22 | ${translation.language.code} 23 |
24 | `, 25 | ) 26 | .join("\n")} 27 |
28 | `; 29 | return languagesHTML; 30 | } 31 | 32 | function renderVersions(config) { 33 | if (!config.versions.active.length) { 34 | return ""; 35 | } 36 | const versionsHTML = ` 37 |
38 |
Versions
39 | ${config.versions.active 40 | .map( 41 | (version) => ` 42 |
43 | ${version.slug} 44 |
45 | `, 46 | ) 47 | .join("\n")} 48 |
49 | `; 50 | return versionsHTML; 51 | } 52 | 53 | function renderDownloads(config) { 54 | if (!Object.keys(config.versions.current.downloads).length) { 55 | return ""; 56 | } 57 | const downloadsNameDisplay = { 58 | pdf: "PDF", 59 | epub: "Epub", 60 | htmlzip: "HTML", 61 | }; 62 | 63 | const downloadsHTML = ` 64 |
65 |
Downloads
66 | ${Object.entries(config.versions.current.downloads) 67 | .map( 68 | ([name, url]) => ` 69 |
70 | ${downloadsNameDisplay[name]} 71 |
72 | `, 73 | ) 74 | .join("\n")} 75 |
76 | `; 77 | return downloadsHTML; 78 | } 79 | 80 | document.addEventListener("readthedocs-addons-data-ready", function (event) { 81 | const config = event.detail.data(); 82 | 83 | const flyout = ` 84 |
85 | 86 | Read the Docs 87 | v: ${config.versions.current.slug} 88 | 89 | 90 |
91 |
92 | ${renderLanguages(config)} 93 | ${renderVersions(config)} 94 | ${renderDownloads(config)} 95 |
96 |
On Read the Docs
97 |
98 | Project Home 99 |
100 |
101 | Builds 102 |
103 |
104 | Downloads 105 |
106 |
107 |
108 |
Search
109 |
110 |
111 | 118 |
119 |
120 |
121 |
122 | 123 | Hosted by Read the Docs 124 | 125 |
126 |
127 | `; 128 | 129 | // Inject the generated flyout into the body HTML element. 130 | document.body.insertAdjacentHTML("beforeend", flyout); 131 | 132 | // Trigger the Read the Docs Addons Search modal when clicking on the "Search docs" input from inside the flyout. 133 | document 134 | .querySelector("#flyout-search-form") 135 | .addEventListener("focusin", () => { 136 | const event = new CustomEvent("readthedocs-search-show"); 137 | document.dispatchEvent(event); 138 | }); 139 | }) 140 | } 141 | 142 | if (themeLanguageSelector || themeVersionSelector) { 143 | function onSelectorSwitch(event) { 144 | const option = event.target.selectedIndex; 145 | const item = event.target.options[option]; 146 | window.location.href = item.dataset.url; 147 | } 148 | 149 | document.addEventListener("readthedocs-addons-data-ready", function (event) { 150 | const config = event.detail.data(); 151 | 152 | const versionSwitch = document.querySelector( 153 | "div.switch-menus > div.version-switch", 154 | ); 155 | if (themeVersionSelector) { 156 | let versions = config.versions.active; 157 | if (config.versions.current.hidden || config.versions.current.type === "external") { 158 | versions.unshift(config.versions.current); 159 | } 160 | const versionSelect = ` 161 | 174 | `; 175 | 176 | versionSwitch.innerHTML = versionSelect; 177 | versionSwitch.firstElementChild.addEventListener("change", onSelectorSwitch); 178 | } 179 | 180 | const languageSwitch = document.querySelector( 181 | "div.switch-menus > div.language-switch", 182 | ); 183 | 184 | if (themeLanguageSelector) { 185 | if (config.projects.translations.length) { 186 | // Add the current language to the options on the selector 187 | let languages = config.projects.translations.concat( 188 | config.projects.current, 189 | ); 190 | languages = languages.sort((a, b) => 191 | a.language.name.localeCompare(b.language.name), 192 | ); 193 | 194 | const languageSelect = ` 195 | 208 | `; 209 | 210 | languageSwitch.innerHTML = languageSelect; 211 | languageSwitch.firstElementChild.addEventListener("change", onSelectorSwitch); 212 | } 213 | else { 214 | languageSwitch.remove(); 215 | } 216 | } 217 | }); 218 | } 219 | 220 | document.addEventListener("readthedocs-addons-data-ready", function (event) { 221 | // Trigger the Read the Docs Addons Search modal when clicking on "Search docs" input from the topnav. 222 | document 223 | .querySelector("[role='search'] input") 224 | .addEventListener("focusin", () => { 225 | const event = new CustomEvent("readthedocs-search-show"); 226 | document.dispatchEvent(event); 227 | }); 228 | }); -------------------------------------------------------------------------------- /doc/_build/html/_static/language_data.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This script contains the language-specific data used by searchtools.js, 3 | * namely the list of stopwords, stemmer, scorer and splitter. 4 | */ 5 | 6 | var stopwords = ["a", "and", "are", "as", "at", "be", "but", "by", "for", "if", "in", "into", "is", "it", "near", "no", "not", "of", "on", "or", "such", "that", "the", "their", "then", "there", "these", "they", "this", "to", "was", "will", "with"]; 7 | 8 | 9 | /* Non-minified version is copied as a separate JS file, if available */ 10 | 11 | /** 12 | * Porter Stemmer 13 | */ 14 | var Stemmer = function() { 15 | 16 | var step2list = { 17 | ational: 'ate', 18 | tional: 'tion', 19 | enci: 'ence', 20 | anci: 'ance', 21 | izer: 'ize', 22 | bli: 'ble', 23 | alli: 'al', 24 | entli: 'ent', 25 | eli: 'e', 26 | ousli: 'ous', 27 | ization: 'ize', 28 | ation: 'ate', 29 | ator: 'ate', 30 | alism: 'al', 31 | iveness: 'ive', 32 | fulness: 'ful', 33 | ousness: 'ous', 34 | aliti: 'al', 35 | iviti: 'ive', 36 | biliti: 'ble', 37 | logi: 'log' 38 | }; 39 | 40 | var step3list = { 41 | icate: 'ic', 42 | ative: '', 43 | alize: 'al', 44 | iciti: 'ic', 45 | ical: 'ic', 46 | ful: '', 47 | ness: '' 48 | }; 49 | 50 | var c = "[^aeiou]"; // consonant 51 | var v = "[aeiouy]"; // vowel 52 | var C = c + "[^aeiouy]*"; // consonant sequence 53 | var V = v + "[aeiou]*"; // vowel sequence 54 | 55 | var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0 56 | var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 57 | var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 58 | var s_v = "^(" + C + ")?" + v; // vowel in stem 59 | 60 | this.stemWord = function (w) { 61 | var stem; 62 | var suffix; 63 | var firstch; 64 | var origword = w; 65 | 66 | if (w.length < 3) 67 | return w; 68 | 69 | var re; 70 | var re2; 71 | var re3; 72 | var re4; 73 | 74 | firstch = w.substr(0,1); 75 | if (firstch == "y") 76 | w = firstch.toUpperCase() + w.substr(1); 77 | 78 | // Step 1a 79 | re = /^(.+?)(ss|i)es$/; 80 | re2 = /^(.+?)([^s])s$/; 81 | 82 | if (re.test(w)) 83 | w = w.replace(re,"$1$2"); 84 | else if (re2.test(w)) 85 | w = w.replace(re2,"$1$2"); 86 | 87 | // Step 1b 88 | re = /^(.+?)eed$/; 89 | re2 = /^(.+?)(ed|ing)$/; 90 | if (re.test(w)) { 91 | var fp = re.exec(w); 92 | re = new RegExp(mgr0); 93 | if (re.test(fp[1])) { 94 | re = /.$/; 95 | w = w.replace(re,""); 96 | } 97 | } 98 | else if (re2.test(w)) { 99 | var fp = re2.exec(w); 100 | stem = fp[1]; 101 | re2 = new RegExp(s_v); 102 | if (re2.test(stem)) { 103 | w = stem; 104 | re2 = /(at|bl|iz)$/; 105 | re3 = new RegExp("([^aeiouylsz])\\1$"); 106 | re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 107 | if (re2.test(w)) 108 | w = w + "e"; 109 | else if (re3.test(w)) { 110 | re = /.$/; 111 | w = w.replace(re,""); 112 | } 113 | else if (re4.test(w)) 114 | w = w + "e"; 115 | } 116 | } 117 | 118 | // Step 1c 119 | re = /^(.+?)y$/; 120 | if (re.test(w)) { 121 | var fp = re.exec(w); 122 | stem = fp[1]; 123 | re = new RegExp(s_v); 124 | if (re.test(stem)) 125 | w = stem + "i"; 126 | } 127 | 128 | // Step 2 129 | re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; 130 | if (re.test(w)) { 131 | var fp = re.exec(w); 132 | stem = fp[1]; 133 | suffix = fp[2]; 134 | re = new RegExp(mgr0); 135 | if (re.test(stem)) 136 | w = stem + step2list[suffix]; 137 | } 138 | 139 | // Step 3 140 | re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; 141 | if (re.test(w)) { 142 | var fp = re.exec(w); 143 | stem = fp[1]; 144 | suffix = fp[2]; 145 | re = new RegExp(mgr0); 146 | if (re.test(stem)) 147 | w = stem + step3list[suffix]; 148 | } 149 | 150 | // Step 4 151 | re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; 152 | re2 = /^(.+?)(s|t)(ion)$/; 153 | if (re.test(w)) { 154 | var fp = re.exec(w); 155 | stem = fp[1]; 156 | re = new RegExp(mgr1); 157 | if (re.test(stem)) 158 | w = stem; 159 | } 160 | else if (re2.test(w)) { 161 | var fp = re2.exec(w); 162 | stem = fp[1] + fp[2]; 163 | re2 = new RegExp(mgr1); 164 | if (re2.test(stem)) 165 | w = stem; 166 | } 167 | 168 | // Step 5 169 | re = /^(.+?)e$/; 170 | if (re.test(w)) { 171 | var fp = re.exec(w); 172 | stem = fp[1]; 173 | re = new RegExp(mgr1); 174 | re2 = new RegExp(meq1); 175 | re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); 176 | if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) 177 | w = stem; 178 | } 179 | re = /ll$/; 180 | re2 = new RegExp(mgr1); 181 | if (re.test(w) && re2.test(w)) { 182 | re = /.$/; 183 | w = w.replace(re,""); 184 | } 185 | 186 | // and turn initial Y back to y 187 | if (firstch == "y") 188 | w = firstch.toLowerCase() + w.substr(1); 189 | return w; 190 | } 191 | } 192 | 193 | -------------------------------------------------------------------------------- /doc/_build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/minus.png -------------------------------------------------------------------------------- /doc/_build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/_static/plus.png -------------------------------------------------------------------------------- /doc/_build/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | pre { line-height: 125%; } 2 | td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 3 | span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } 4 | td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 5 | span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } 6 | .highlight .hll { background-color: #ffffcc } 7 | .highlight { background: #f8f8f8; } 8 | .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ 9 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 10 | .highlight .k { color: #008000; font-weight: bold } /* Keyword */ 11 | .highlight .o { color: #666666 } /* Operator */ 12 | .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ 13 | .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ 14 | .highlight .cp { color: #9C6500 } /* Comment.Preproc */ 15 | .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ 16 | .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ 17 | .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ 18 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 19 | .highlight .ge { font-style: italic } /* Generic.Emph */ 20 | .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ 21 | .highlight .gr { color: #E40000 } /* Generic.Error */ 22 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 23 | .highlight .gi { color: #008400 } /* Generic.Inserted */ 24 | .highlight .go { color: #717171 } /* Generic.Output */ 25 | .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 26 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 27 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 28 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 29 | .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 30 | .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 31 | .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 32 | .highlight .kp { color: #008000 } /* Keyword.Pseudo */ 33 | .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 34 | .highlight .kt { color: #B00040 } /* Keyword.Type */ 35 | .highlight .m { color: #666666 } /* Literal.Number */ 36 | .highlight .s { color: #BA2121 } /* Literal.String */ 37 | .highlight .na { color: #687822 } /* Name.Attribute */ 38 | .highlight .nb { color: #008000 } /* Name.Builtin */ 39 | .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 40 | .highlight .no { color: #880000 } /* Name.Constant */ 41 | .highlight .nd { color: #AA22FF } /* Name.Decorator */ 42 | .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ 43 | .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ 44 | .highlight .nf { color: #0000FF } /* Name.Function */ 45 | .highlight .nl { color: #767600 } /* Name.Label */ 46 | .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 47 | .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ 48 | .highlight .nv { color: #19177C } /* Name.Variable */ 49 | .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 50 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 51 | .highlight .mb { color: #666666 } /* Literal.Number.Bin */ 52 | .highlight .mf { color: #666666 } /* Literal.Number.Float */ 53 | .highlight .mh { color: #666666 } /* Literal.Number.Hex */ 54 | .highlight .mi { color: #666666 } /* Literal.Number.Integer */ 55 | .highlight .mo { color: #666666 } /* Literal.Number.Oct */ 56 | .highlight .sa { color: #BA2121 } /* Literal.String.Affix */ 57 | .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ 58 | .highlight .sc { color: #BA2121 } /* Literal.String.Char */ 59 | .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ 60 | .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 61 | .highlight .s2 { color: #BA2121 } /* Literal.String.Double */ 62 | .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ 63 | .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ 64 | .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ 65 | .highlight .sx { color: #008000 } /* Literal.String.Other */ 66 | .highlight .sr { color: #A45A77 } /* Literal.String.Regex */ 67 | .highlight .s1 { color: #BA2121 } /* Literal.String.Single */ 68 | .highlight .ss { color: #19177C } /* Literal.String.Symbol */ 69 | .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ 70 | .highlight .fm { color: #0000FF } /* Name.Function.Magic */ 71 | .highlight .vc { color: #19177C } /* Name.Variable.Class */ 72 | .highlight .vg { color: #19177C } /* Name.Variable.Global */ 73 | .highlight .vi { color: #19177C } /* Name.Variable.Instance */ 74 | .highlight .vm { color: #19177C } /* Name.Variable.Magic */ 75 | .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /doc/_build/html/_static/searchtools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Sphinx JavaScript utilities for the full-text search. 3 | */ 4 | "use strict"; 5 | 6 | /** 7 | * Simple result scoring code. 8 | */ 9 | if (typeof Scorer === "undefined") { 10 | var Scorer = { 11 | // Implement the following function to further tweak the score for each result 12 | // The function takes a result array [docname, title, anchor, descr, score, filename] 13 | // and returns the new score. 14 | /* 15 | score: result => { 16 | const [docname, title, anchor, descr, score, filename, kind] = result 17 | return score 18 | }, 19 | */ 20 | 21 | // query matches the full name of an object 22 | objNameMatch: 11, 23 | // or matches in the last dotted part of the object name 24 | objPartialMatch: 6, 25 | // Additive scores depending on the priority of the object 26 | objPrio: { 27 | 0: 15, // used to be importantResults 28 | 1: 5, // used to be objectResults 29 | 2: -5, // used to be unimportantResults 30 | }, 31 | // Used when the priority is not in the mapping. 32 | objPrioDefault: 0, 33 | 34 | // query found in title 35 | title: 15, 36 | partialTitle: 7, 37 | // query found in terms 38 | term: 5, 39 | partialTerm: 2, 40 | }; 41 | } 42 | 43 | // Global search result kind enum, used by themes to style search results. 44 | class SearchResultKind { 45 | static get index() { return "index"; } 46 | static get object() { return "object"; } 47 | static get text() { return "text"; } 48 | static get title() { return "title"; } 49 | } 50 | 51 | const _removeChildren = (element) => { 52 | while (element && element.lastChild) element.removeChild(element.lastChild); 53 | }; 54 | 55 | /** 56 | * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping 57 | */ 58 | const _escapeRegExp = (string) => 59 | string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string 60 | 61 | const _displayItem = (item, searchTerms, highlightTerms) => { 62 | const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; 63 | const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; 64 | const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; 65 | const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; 66 | const contentRoot = document.documentElement.dataset.content_root; 67 | 68 | const [docName, title, anchor, descr, score, _filename, kind] = item; 69 | 70 | let listItem = document.createElement("li"); 71 | // Add a class representing the item's type: 72 | // can be used by a theme's CSS selector for styling 73 | // See SearchResultKind for the class names. 74 | listItem.classList.add(`kind-${kind}`); 75 | let requestUrl; 76 | let linkUrl; 77 | if (docBuilder === "dirhtml") { 78 | // dirhtml builder 79 | let dirname = docName + "/"; 80 | if (dirname.match(/\/index\/$/)) 81 | dirname = dirname.substring(0, dirname.length - 6); 82 | else if (dirname === "index/") dirname = ""; 83 | requestUrl = contentRoot + dirname; 84 | linkUrl = requestUrl; 85 | } else { 86 | // normal html builders 87 | requestUrl = contentRoot + docName + docFileSuffix; 88 | linkUrl = docName + docLinkSuffix; 89 | } 90 | let linkEl = listItem.appendChild(document.createElement("a")); 91 | linkEl.href = linkUrl + anchor; 92 | linkEl.dataset.score = score; 93 | linkEl.innerHTML = title; 94 | if (descr) { 95 | listItem.appendChild(document.createElement("span")).innerHTML = 96 | " (" + descr + ")"; 97 | // highlight search terms in the description 98 | if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js 99 | highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); 100 | } 101 | else if (showSearchSummary) 102 | fetch(requestUrl) 103 | .then((responseData) => responseData.text()) 104 | .then((data) => { 105 | if (data) 106 | listItem.appendChild( 107 | Search.makeSearchSummary(data, searchTerms, anchor) 108 | ); 109 | // highlight search terms in the summary 110 | if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js 111 | highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); 112 | }); 113 | Search.output.appendChild(listItem); 114 | }; 115 | const _finishSearch = (resultCount) => { 116 | Search.stopPulse(); 117 | Search.title.innerText = _("Search Results"); 118 | if (!resultCount) 119 | Search.status.innerText = Documentation.gettext( 120 | "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." 121 | ); 122 | else 123 | Search.status.innerText = Documentation.ngettext( 124 | "Search finished, found one page matching the search query.", 125 | "Search finished, found ${resultCount} pages matching the search query.", 126 | resultCount, 127 | ).replace('${resultCount}', resultCount); 128 | }; 129 | const _displayNextItem = ( 130 | results, 131 | resultCount, 132 | searchTerms, 133 | highlightTerms, 134 | ) => { 135 | // results left, load the summary and display it 136 | // this is intended to be dynamic (don't sub resultsCount) 137 | if (results.length) { 138 | _displayItem(results.pop(), searchTerms, highlightTerms); 139 | setTimeout( 140 | () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), 141 | 5 142 | ); 143 | } 144 | // search finished, update title and status message 145 | else _finishSearch(resultCount); 146 | }; 147 | // Helper function used by query() to order search results. 148 | // Each input is an array of [docname, title, anchor, descr, score, filename, kind]. 149 | // Order the results by score (in opposite order of appearance, since the 150 | // `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. 151 | const _orderResultsByScoreThenName = (a, b) => { 152 | const leftScore = a[4]; 153 | const rightScore = b[4]; 154 | if (leftScore === rightScore) { 155 | // same score: sort alphabetically 156 | const leftTitle = a[1].toLowerCase(); 157 | const rightTitle = b[1].toLowerCase(); 158 | if (leftTitle === rightTitle) return 0; 159 | return leftTitle > rightTitle ? -1 : 1; // inverted is intentional 160 | } 161 | return leftScore > rightScore ? 1 : -1; 162 | }; 163 | 164 | /** 165 | * Default splitQuery function. Can be overridden in ``sphinx.search`` with a 166 | * custom function per language. 167 | * 168 | * The regular expression works by splitting the string on consecutive characters 169 | * that are not Unicode letters, numbers, underscores, or emoji characters. 170 | * This is the same as ``\W+`` in Python, preserving the surrogate pair area. 171 | */ 172 | if (typeof splitQuery === "undefined") { 173 | var splitQuery = (query) => query 174 | .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) 175 | .filter(term => term) // remove remaining empty strings 176 | } 177 | 178 | /** 179 | * Search Module 180 | */ 181 | const Search = { 182 | _index: null, 183 | _queued_query: null, 184 | _pulse_status: -1, 185 | 186 | htmlToText: (htmlString, anchor) => { 187 | const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); 188 | for (const removalQuery of [".headerlink", "script", "style"]) { 189 | htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); 190 | } 191 | if (anchor) { 192 | const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); 193 | if (anchorContent) return anchorContent.textContent; 194 | 195 | console.warn( 196 | `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` 197 | ); 198 | } 199 | 200 | // if anchor not specified or not found, fall back to main content 201 | const docContent = htmlElement.querySelector('[role="main"]'); 202 | if (docContent) return docContent.textContent; 203 | 204 | console.warn( 205 | "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." 206 | ); 207 | return ""; 208 | }, 209 | 210 | init: () => { 211 | const query = new URLSearchParams(window.location.search).get("q"); 212 | document 213 | .querySelectorAll('input[name="q"]') 214 | .forEach((el) => (el.value = query)); 215 | if (query) Search.performSearch(query); 216 | }, 217 | 218 | loadIndex: (url) => 219 | (document.body.appendChild(document.createElement("script")).src = url), 220 | 221 | setIndex: (index) => { 222 | Search._index = index; 223 | if (Search._queued_query !== null) { 224 | const query = Search._queued_query; 225 | Search._queued_query = null; 226 | Search.query(query); 227 | } 228 | }, 229 | 230 | hasIndex: () => Search._index !== null, 231 | 232 | deferQuery: (query) => (Search._queued_query = query), 233 | 234 | stopPulse: () => (Search._pulse_status = -1), 235 | 236 | startPulse: () => { 237 | if (Search._pulse_status >= 0) return; 238 | 239 | const pulse = () => { 240 | Search._pulse_status = (Search._pulse_status + 1) % 4; 241 | Search.dots.innerText = ".".repeat(Search._pulse_status); 242 | if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); 243 | }; 244 | pulse(); 245 | }, 246 | 247 | /** 248 | * perform a search for something (or wait until index is loaded) 249 | */ 250 | performSearch: (query) => { 251 | // create the required interface elements 252 | const searchText = document.createElement("h2"); 253 | searchText.textContent = _("Searching"); 254 | const searchSummary = document.createElement("p"); 255 | searchSummary.classList.add("search-summary"); 256 | searchSummary.innerText = ""; 257 | const searchList = document.createElement("ul"); 258 | searchList.setAttribute("role", "list"); 259 | searchList.classList.add("search"); 260 | 261 | const out = document.getElementById("search-results"); 262 | Search.title = out.appendChild(searchText); 263 | Search.dots = Search.title.appendChild(document.createElement("span")); 264 | Search.status = out.appendChild(searchSummary); 265 | Search.output = out.appendChild(searchList); 266 | 267 | const searchProgress = document.getElementById("search-progress"); 268 | // Some themes don't use the search progress node 269 | if (searchProgress) { 270 | searchProgress.innerText = _("Preparing search..."); 271 | } 272 | Search.startPulse(); 273 | 274 | // index already loaded, the browser was quick! 275 | if (Search.hasIndex()) Search.query(query); 276 | else Search.deferQuery(query); 277 | }, 278 | 279 | _parseQuery: (query) => { 280 | // stem the search terms and add them to the correct list 281 | const stemmer = new Stemmer(); 282 | const searchTerms = new Set(); 283 | const excludedTerms = new Set(); 284 | const highlightTerms = new Set(); 285 | const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); 286 | splitQuery(query.trim()).forEach((queryTerm) => { 287 | const queryTermLower = queryTerm.toLowerCase(); 288 | 289 | // maybe skip this "word" 290 | // stopwords array is from language_data.js 291 | if ( 292 | stopwords.indexOf(queryTermLower) !== -1 || 293 | queryTerm.match(/^\d+$/) 294 | ) 295 | return; 296 | 297 | // stem the word 298 | let word = stemmer.stemWord(queryTermLower); 299 | // select the correct list 300 | if (word[0] === "-") excludedTerms.add(word.substr(1)); 301 | else { 302 | searchTerms.add(word); 303 | highlightTerms.add(queryTermLower); 304 | } 305 | }); 306 | 307 | if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js 308 | localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) 309 | } 310 | 311 | // console.debug("SEARCH: searching for:"); 312 | // console.info("required: ", [...searchTerms]); 313 | // console.info("excluded: ", [...excludedTerms]); 314 | 315 | return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; 316 | }, 317 | 318 | /** 319 | * execute search (requires search index to be loaded) 320 | */ 321 | _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { 322 | const filenames = Search._index.filenames; 323 | const docNames = Search._index.docnames; 324 | const titles = Search._index.titles; 325 | const allTitles = Search._index.alltitles; 326 | const indexEntries = Search._index.indexentries; 327 | 328 | // Collect multiple result groups to be sorted separately and then ordered. 329 | // Each is an array of [docname, title, anchor, descr, score, filename, kind]. 330 | const normalResults = []; 331 | const nonMainIndexResults = []; 332 | 333 | _removeChildren(document.getElementById("search-progress")); 334 | 335 | const queryLower = query.toLowerCase().trim(); 336 | for (const [title, foundTitles] of Object.entries(allTitles)) { 337 | if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { 338 | for (const [file, id] of foundTitles) { 339 | const score = Math.round(Scorer.title * queryLower.length / title.length); 340 | const boost = titles[file] === title ? 1 : 0; // add a boost for document titles 341 | normalResults.push([ 342 | docNames[file], 343 | titles[file] !== title ? `${titles[file]} > ${title}` : title, 344 | id !== null ? "#" + id : "", 345 | null, 346 | score + boost, 347 | filenames[file], 348 | SearchResultKind.title, 349 | ]); 350 | } 351 | } 352 | } 353 | 354 | // search for explicit entries in index directives 355 | for (const [entry, foundEntries] of Object.entries(indexEntries)) { 356 | if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { 357 | for (const [file, id, isMain] of foundEntries) { 358 | const score = Math.round(100 * queryLower.length / entry.length); 359 | const result = [ 360 | docNames[file], 361 | titles[file], 362 | id ? "#" + id : "", 363 | null, 364 | score, 365 | filenames[file], 366 | SearchResultKind.index, 367 | ]; 368 | if (isMain) { 369 | normalResults.push(result); 370 | } else { 371 | nonMainIndexResults.push(result); 372 | } 373 | } 374 | } 375 | } 376 | 377 | // lookup as object 378 | objectTerms.forEach((term) => 379 | normalResults.push(...Search.performObjectSearch(term, objectTerms)) 380 | ); 381 | 382 | // lookup as search terms in fulltext 383 | normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); 384 | 385 | // let the scorer override scores with a custom scoring function 386 | if (Scorer.score) { 387 | normalResults.forEach((item) => (item[4] = Scorer.score(item))); 388 | nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); 389 | } 390 | 391 | // Sort each group of results by score and then alphabetically by name. 392 | normalResults.sort(_orderResultsByScoreThenName); 393 | nonMainIndexResults.sort(_orderResultsByScoreThenName); 394 | 395 | // Combine the result groups in (reverse) order. 396 | // Non-main index entries are typically arbitrary cross-references, 397 | // so display them after other results. 398 | let results = [...nonMainIndexResults, ...normalResults]; 399 | 400 | // remove duplicate search results 401 | // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept 402 | let seen = new Set(); 403 | results = results.reverse().reduce((acc, result) => { 404 | let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); 405 | if (!seen.has(resultStr)) { 406 | acc.push(result); 407 | seen.add(resultStr); 408 | } 409 | return acc; 410 | }, []); 411 | 412 | return results.reverse(); 413 | }, 414 | 415 | query: (query) => { 416 | const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); 417 | const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); 418 | 419 | // for debugging 420 | //Search.lastresults = results.slice(); // a copy 421 | // console.info("search results:", Search.lastresults); 422 | 423 | // print the results 424 | _displayNextItem(results, results.length, searchTerms, highlightTerms); 425 | }, 426 | 427 | /** 428 | * search for object names 429 | */ 430 | performObjectSearch: (object, objectTerms) => { 431 | const filenames = Search._index.filenames; 432 | const docNames = Search._index.docnames; 433 | const objects = Search._index.objects; 434 | const objNames = Search._index.objnames; 435 | const titles = Search._index.titles; 436 | 437 | const results = []; 438 | 439 | const objectSearchCallback = (prefix, match) => { 440 | const name = match[4] 441 | const fullname = (prefix ? prefix + "." : "") + name; 442 | const fullnameLower = fullname.toLowerCase(); 443 | if (fullnameLower.indexOf(object) < 0) return; 444 | 445 | let score = 0; 446 | const parts = fullnameLower.split("."); 447 | 448 | // check for different match types: exact matches of full name or 449 | // "last name" (i.e. last dotted part) 450 | if (fullnameLower === object || parts.slice(-1)[0] === object) 451 | score += Scorer.objNameMatch; 452 | else if (parts.slice(-1)[0].indexOf(object) > -1) 453 | score += Scorer.objPartialMatch; // matches in last name 454 | 455 | const objName = objNames[match[1]][2]; 456 | const title = titles[match[0]]; 457 | 458 | // If more than one term searched for, we require other words to be 459 | // found in the name/title/description 460 | const otherTerms = new Set(objectTerms); 461 | otherTerms.delete(object); 462 | if (otherTerms.size > 0) { 463 | const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); 464 | if ( 465 | [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) 466 | ) 467 | return; 468 | } 469 | 470 | let anchor = match[3]; 471 | if (anchor === "") anchor = fullname; 472 | else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; 473 | 474 | const descr = objName + _(", in ") + title; 475 | 476 | // add custom score for some objects according to scorer 477 | if (Scorer.objPrio.hasOwnProperty(match[2])) 478 | score += Scorer.objPrio[match[2]]; 479 | else score += Scorer.objPrioDefault; 480 | 481 | results.push([ 482 | docNames[match[0]], 483 | fullname, 484 | "#" + anchor, 485 | descr, 486 | score, 487 | filenames[match[0]], 488 | SearchResultKind.object, 489 | ]); 490 | }; 491 | Object.keys(objects).forEach((prefix) => 492 | objects[prefix].forEach((array) => 493 | objectSearchCallback(prefix, array) 494 | ) 495 | ); 496 | return results; 497 | }, 498 | 499 | /** 500 | * search for full-text terms in the index 501 | */ 502 | performTermsSearch: (searchTerms, excludedTerms) => { 503 | // prepare search 504 | const terms = Search._index.terms; 505 | const titleTerms = Search._index.titleterms; 506 | const filenames = Search._index.filenames; 507 | const docNames = Search._index.docnames; 508 | const titles = Search._index.titles; 509 | 510 | const scoreMap = new Map(); 511 | const fileMap = new Map(); 512 | 513 | // perform the search on the required terms 514 | searchTerms.forEach((word) => { 515 | const files = []; 516 | const arr = [ 517 | { files: terms[word], score: Scorer.term }, 518 | { files: titleTerms[word], score: Scorer.title }, 519 | ]; 520 | // add support for partial matches 521 | if (word.length > 2) { 522 | const escapedWord = _escapeRegExp(word); 523 | if (!terms.hasOwnProperty(word)) { 524 | Object.keys(terms).forEach((term) => { 525 | if (term.match(escapedWord)) 526 | arr.push({ files: terms[term], score: Scorer.partialTerm }); 527 | }); 528 | } 529 | if (!titleTerms.hasOwnProperty(word)) { 530 | Object.keys(titleTerms).forEach((term) => { 531 | if (term.match(escapedWord)) 532 | arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); 533 | }); 534 | } 535 | } 536 | 537 | // no match but word was a required one 538 | if (arr.every((record) => record.files === undefined)) return; 539 | 540 | // found search word in contents 541 | arr.forEach((record) => { 542 | if (record.files === undefined) return; 543 | 544 | let recordFiles = record.files; 545 | if (recordFiles.length === undefined) recordFiles = [recordFiles]; 546 | files.push(...recordFiles); 547 | 548 | // set score for the word in each file 549 | recordFiles.forEach((file) => { 550 | if (!scoreMap.has(file)) scoreMap.set(file, {}); 551 | scoreMap.get(file)[word] = record.score; 552 | }); 553 | }); 554 | 555 | // create the mapping 556 | files.forEach((file) => { 557 | if (!fileMap.has(file)) fileMap.set(file, [word]); 558 | else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); 559 | }); 560 | }); 561 | 562 | // now check if the files don't contain excluded terms 563 | const results = []; 564 | for (const [file, wordList] of fileMap) { 565 | // check if all requirements are matched 566 | 567 | // as search terms with length < 3 are discarded 568 | const filteredTermCount = [...searchTerms].filter( 569 | (term) => term.length > 2 570 | ).length; 571 | if ( 572 | wordList.length !== searchTerms.size && 573 | wordList.length !== filteredTermCount 574 | ) 575 | continue; 576 | 577 | // ensure that none of the excluded terms is in the search result 578 | if ( 579 | [...excludedTerms].some( 580 | (term) => 581 | terms[term] === file || 582 | titleTerms[term] === file || 583 | (terms[term] || []).includes(file) || 584 | (titleTerms[term] || []).includes(file) 585 | ) 586 | ) 587 | break; 588 | 589 | // select one (max) score for the file. 590 | const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); 591 | // add result to the result list 592 | results.push([ 593 | docNames[file], 594 | titles[file], 595 | "", 596 | null, 597 | score, 598 | filenames[file], 599 | SearchResultKind.text, 600 | ]); 601 | } 602 | return results; 603 | }, 604 | 605 | /** 606 | * helper function to return a node containing the 607 | * search summary for a given text. keywords is a list 608 | * of stemmed words. 609 | */ 610 | makeSearchSummary: (htmlText, keywords, anchor) => { 611 | const text = Search.htmlToText(htmlText, anchor); 612 | if (text === "") return null; 613 | 614 | const textLower = text.toLowerCase(); 615 | const actualStartPosition = [...keywords] 616 | .map((k) => textLower.indexOf(k.toLowerCase())) 617 | .filter((i) => i > -1) 618 | .slice(-1)[0]; 619 | const startWithContext = Math.max(actualStartPosition - 120, 0); 620 | 621 | const top = startWithContext === 0 ? "" : "..."; 622 | const tail = startWithContext + 240 < text.length ? "..." : ""; 623 | 624 | let summary = document.createElement("p"); 625 | summary.classList.add("context"); 626 | summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; 627 | 628 | return summary; 629 | }, 630 | }; 631 | 632 | _ready(Search.init); 633 | -------------------------------------------------------------------------------- /doc/_build/html/_static/sphinx_highlight.js: -------------------------------------------------------------------------------- 1 | /* Highlighting utilities for Sphinx HTML documentation. */ 2 | "use strict"; 3 | 4 | const SPHINX_HIGHLIGHT_ENABLED = true 5 | 6 | /** 7 | * highlight a given string on a node by wrapping it in 8 | * span elements with the given class name. 9 | */ 10 | const _highlight = (node, addItems, text, className) => { 11 | if (node.nodeType === Node.TEXT_NODE) { 12 | const val = node.nodeValue; 13 | const parent = node.parentNode; 14 | const pos = val.toLowerCase().indexOf(text); 15 | if ( 16 | pos >= 0 && 17 | !parent.classList.contains(className) && 18 | !parent.classList.contains("nohighlight") 19 | ) { 20 | let span; 21 | 22 | const closestNode = parent.closest("body, svg, foreignObject"); 23 | const isInSVG = closestNode && closestNode.matches("svg"); 24 | if (isInSVG) { 25 | span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); 26 | } else { 27 | span = document.createElement("span"); 28 | span.classList.add(className); 29 | } 30 | 31 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 32 | const rest = document.createTextNode(val.substr(pos + text.length)); 33 | parent.insertBefore( 34 | span, 35 | parent.insertBefore( 36 | rest, 37 | node.nextSibling 38 | ) 39 | ); 40 | node.nodeValue = val.substr(0, pos); 41 | /* There may be more occurrences of search term in this node. So call this 42 | * function recursively on the remaining fragment. 43 | */ 44 | _highlight(rest, addItems, text, className); 45 | 46 | if (isInSVG) { 47 | const rect = document.createElementNS( 48 | "http://www.w3.org/2000/svg", 49 | "rect" 50 | ); 51 | const bbox = parent.getBBox(); 52 | rect.x.baseVal.value = bbox.x; 53 | rect.y.baseVal.value = bbox.y; 54 | rect.width.baseVal.value = bbox.width; 55 | rect.height.baseVal.value = bbox.height; 56 | rect.setAttribute("class", className); 57 | addItems.push({ parent: parent, target: rect }); 58 | } 59 | } 60 | } else if (node.matches && !node.matches("button, select, textarea")) { 61 | node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); 62 | } 63 | }; 64 | const _highlightText = (thisNode, text, className) => { 65 | let addItems = []; 66 | _highlight(thisNode, addItems, text, className); 67 | addItems.forEach((obj) => 68 | obj.parent.insertAdjacentElement("beforebegin", obj.target) 69 | ); 70 | }; 71 | 72 | /** 73 | * Small JavaScript module for the documentation. 74 | */ 75 | const SphinxHighlight = { 76 | 77 | /** 78 | * highlight the search words provided in localstorage in the text 79 | */ 80 | highlightSearchWords: () => { 81 | if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight 82 | 83 | // get and clear terms from localstorage 84 | const url = new URL(window.location); 85 | const highlight = 86 | localStorage.getItem("sphinx_highlight_terms") 87 | || url.searchParams.get("highlight") 88 | || ""; 89 | localStorage.removeItem("sphinx_highlight_terms") 90 | url.searchParams.delete("highlight"); 91 | window.history.replaceState({}, "", url); 92 | 93 | // get individual terms from highlight string 94 | const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); 95 | if (terms.length === 0) return; // nothing to do 96 | 97 | // There should never be more than one element matching "div.body" 98 | const divBody = document.querySelectorAll("div.body"); 99 | const body = divBody.length ? divBody[0] : document.querySelector("body"); 100 | window.setTimeout(() => { 101 | terms.forEach((term) => _highlightText(body, term, "highlighted")); 102 | }, 10); 103 | 104 | const searchBox = document.getElementById("searchbox"); 105 | if (searchBox === null) return; 106 | searchBox.appendChild( 107 | document 108 | .createRange() 109 | .createContextualFragment( 110 | '" 114 | ) 115 | ); 116 | }, 117 | 118 | /** 119 | * helper function to hide the search marks again 120 | */ 121 | hideSearchWords: () => { 122 | document 123 | .querySelectorAll("#searchbox .highlight-link") 124 | .forEach((el) => el.remove()); 125 | document 126 | .querySelectorAll("span.highlighted") 127 | .forEach((el) => el.classList.remove("highlighted")); 128 | localStorage.removeItem("sphinx_highlight_terms") 129 | }, 130 | 131 | initEscapeListener: () => { 132 | // only install a listener if it is really needed 133 | if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; 134 | 135 | document.addEventListener("keydown", (event) => { 136 | // bail for input elements 137 | if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; 138 | // bail with special keys 139 | if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; 140 | if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { 141 | SphinxHighlight.hideSearchWords(); 142 | event.preventDefault(); 143 | } 144 | }); 145 | }, 146 | }; 147 | 148 | _ready(() => { 149 | /* Do not call highlightSearchWords() when we are on the search page. 150 | * It will highlight words from the *previous* search query. 151 | */ 152 | if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); 153 | SphinxHighlight.initEscapeListener(); 154 | }); 155 | -------------------------------------------------------------------------------- /doc/_build/html/diPLSlib.utils.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | diPLSlib.utils subpackage — diPLSlib 2.5.0 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 65 | 66 |
70 | 71 |
72 |
73 |
74 | 82 |
83 |
84 |
85 |
86 | 87 |
88 |

diPLSlib.utils subpackage

89 |
90 |

diPLSlib.utils.misc module

91 |

Some helper functions for diPLSlib

92 |
93 |
94 | diPLSlib.utils.misc.calibrateAnalyticGaussianMechanism(epsilon, delta, GS, tol=1e-12)[source]
95 |

Calibrate a Gaussian perturbation for differential privacy using the analytic Gaussian mechanism of [Balle and Wang, ICML’18]

96 |
97 |
Parameters:
98 |
99 |
epsilonfloat

Privacy parameter epsilon

100 |
101 |
deltafloat

Desired privacy failure probability

102 |
103 |
GSfloat

Upper bound on the L2-sensitivity of the function to which the mechanism is applied

104 |
105 |
tolfloat

Error tolerance for binary search

106 |
107 |
108 |
109 |
Returns:
110 |
111 |
sigmafloat

Standard deviation of Gaussian noise needed to achieve (epsilon,delta)-DP under global sensitivity GS

112 |
113 |
114 |
115 |
116 |

References

117 |
    118 |
  • Balle, B., & Wang, Y. X. (2018, July). Improving the gaussian mechanism for differential privacy: Analytical calibration and optimal denoising. In International Conference on Machine Learning (pp. 394-403). PMLR.

  • 119 |
120 |

Examples

121 |
>>> from diPLSlib.utils.misc import calibrateAnalyticGaussianMechanism
122 | >>> calibrateAnalyticGaussianMechanism(1.0, 1e-5, 1.0)
123 | 3.730631634944469
124 | 
125 |
126 |
127 | 128 |
129 |
130 | diPLSlib.utils.misc.gengaus(length, mu, sigma, mag, noise=0)[source]
131 |

Generate a Gaussian spectrum-like signal with optional random noise.

132 |
133 |
Parameters:
134 |
135 |
lengthint

Length of the generated signal.

136 |
137 |
mufloat

Mean of the Gaussian function.

138 |
139 |
sigmafloat

Standard deviation of the Gaussian function.

140 |
141 |
magfloat

Magnitude of the Gaussian signal.

142 |
143 |
noisefloat, optional (default=0)

Standard deviation of the Gaussian noise to be added to the signal.

144 |
145 |
146 |
147 |
Returns:
148 |
149 |
signalndarray of shape (length,)

The generated Gaussian signal with noise.

150 |
151 |
152 |
153 |
154 |

Examples

155 |
>>> from diPLSlib.utils.misc import gengaus
156 | >>> import numpy as np
157 | >>> import scipy.stats
158 | >>> signal = gengaus(100, 50, 10, 5, noise=0.1)
159 | 
160 |
161 |
162 | 163 |
164 |
165 | diPLSlib.utils.misc.hellipse(X, alpha=0.05)[source]
166 |

Compute the 95% confidence interval ellipse for a 2D scatter plot.

167 |
168 |
Parameters:
169 |
170 |
Xndarray of shape (n_samples, 2)

Matrix of data points.

171 |
172 |
alphafloat, optional (default=0.05)

Significance level for the confidence interval.

173 |
174 |
175 |
176 |
Returns:
177 |
178 |
elndarray of shape (2, 100)

Coordinates of the ellipse’s points. To plot, use plt.plot(el[0, :], el[1, :]).

179 |
180 |
181 |
182 |
183 |

Examples

184 |
>>> import matplotlib.pyplot as plt
185 | >>> import numpy as np
186 | >>> from diPLSlib.utils.misc import hellipse
187 | >>> X = np.random.random((100, 2))
188 | >>> el = hellipse(X)
189 | >>> plt.scatter(X[:,0], X[:,1], label='Data points')            
190 | <matplotlib.collections.PathCollection object at ...>
191 | >>> plt.plot(el[0,:], el[1,:], label='95% Confidence Ellipse')  
192 | [<matplotlib.lines.Line2D object at ...>]
193 | >>> plt.legend()                                                
194 | <matplotlib.legend.Legend object at ...>
195 | 
196 |
197 |
198 | 199 |
200 |
201 | diPLSlib.utils.misc.rmse(y, yhat)[source]
202 |

Compute the Root Mean Squared Error (RMSE) between two arrays.

203 |
204 |
Parameters:
205 |
206 |
yndarray of shape (n_samples,)

True values.

207 |
208 |
yhatndarray of shape (n_samples,)

Predicted values.

209 |
210 |
211 |
212 |
Returns:
213 |
214 |
errorndarray of shape (n_samples,)

The RMSE between y and yhat.

215 |
216 |
217 |
218 |
219 |

Examples

220 |
>>> import numpy as np
221 | >>> from diPLSlib.utils.misc import rmse
222 | >>> x = np.array([1, 2, 3])
223 | >>> y = np.array([2, 3, 4])
224 | >>> error = rmse(x, y)
225 | >>> print(error)
226 | 1.0
227 | 
228 |
229 |
230 | 231 |
232 |
233 |

Module contents

234 |
235 |
236 | 237 | 238 |
239 |
240 |
243 | 244 |
245 | 246 |
247 |

© Copyright 2025, Ramin Nikzad-Langerodi.

248 |
249 | 250 | Built with Sphinx using a 251 | theme 252 | provided by Read the Docs. 253 | 254 | 255 |
256 |
257 |
258 |
259 |
260 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /doc/_build/html/genindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Index — diPLSlib 2.5.0 documentation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 50 | 51 |
55 | 56 |
57 |
58 |
59 |
    60 |
  • 61 | 62 |
  • 63 |
  • 64 |
65 |
66 |
67 |
68 |
69 | 70 | 71 |

Index

72 | 73 |
74 | C 75 | | D 76 | | E 77 | | F 78 | | G 79 | | H 80 | | K 81 | | M 82 | | P 83 | | R 84 | | S 85 | | T 86 | 87 |
88 |

C

89 | 90 | 94 | 98 |
99 | 100 |

D

101 | 102 | 122 | 145 |
    123 |
  • 124 | diPLSlib.models 125 | 126 |
  • 130 |
  • 131 | diPLSlib.utils 132 | 133 |
  • 137 |
  • 138 | diPLSlib.utils.misc 139 | 140 |
  • 144 |
146 | 147 |

E

148 | 149 | 153 | 157 |
158 | 159 |

F

160 | 161 | 173 |
174 | 175 |

G

176 | 177 | 181 | 185 |
186 | 187 |

H

188 | 189 | 193 |
194 | 195 |

K

196 | 197 | 201 | 205 |
206 | 207 |

M

208 | 209 | 226 |
227 | 228 |

P

229 | 230 | 240 |
241 | 242 |

R

243 | 244 | 248 |
249 | 250 |

S

251 | 252 | 264 | 276 |
277 | 278 |

T

279 | 280 | 284 |
285 | 286 | 287 | 288 |
289 |
290 |
291 | 292 |
293 | 294 |
295 |

© Copyright 2025, Ramin Nikzad-Langerodi.

296 |
297 | 298 | Built with Sphinx using a 299 | theme 300 | provided by Read the Docs. 301 | 302 | 303 |
304 |
305 |
306 |
307 |
308 | 313 | 314 | 315 | -------------------------------------------------------------------------------- /doc/_build/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | diPLSlib documentation — diPLSlib 2.5.0 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 53 | 54 |
58 | 59 |
60 |
61 |
62 | 69 |
70 |
71 |
72 |
73 | 74 |
75 |

diPLSlib documentation

76 |
77 |

Introduction

78 |

diPLSlib is a Python library designed for domain adaptation in multivariate calibration, with a focus on privacy-preserving regression and calibration model maintenance. It provides a scikit-learn compatible API and implements advanced methods for aligning data distributions across different domains, enabling robust and transferable regression models.

79 |

The library features several state-of-the-art algorithms, including:

80 |
    81 |
  • Domain-Invariant Partial Least Squares (di-PLS/mdi-PLS): Aligns feature distributions between source and target domains to improve model generalization.

  • 82 |
  • Graph-based Calibration Transfer (GCT-PLS): Minimizes discrepancies between paired samples from different domains in the latent variable space.

  • 83 |
  • Kernel Domain Adaptive PLS (KDAPLS): Projects data into a reproducing kernel Hilbert space for non-parametric domain adaptation.

  • 84 |
  • Differentially Private PLS (EDPLS): Ensures privacy guarantees for sensitive data using the \((\epsilon, \delta)\)-differential privacy framework.

  • 85 |
86 |

diPLSlib is suitable for chemometrics, analytical chemistry, and other fields where robust calibration transfer and privacy-preserving modeling are required. For more details, usage examples, and API documentation, please refer to the sections below.

87 |
88 |

Contents:

89 | 98 |
99 |
100 |
101 | 102 | 103 |
104 |
105 |
108 | 109 |
110 | 111 |
112 |

© Copyright 2025, Ramin Nikzad-Langerodi.

113 |
114 | 115 | Built with Sphinx using a 116 | theme 117 | provided by Read the Docs. 118 | 119 | 120 |
121 |
122 |
123 |
124 |
125 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /doc/_build/html/modules.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | diPLSlib — diPLSlib 2.5.0 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 52 | 53 |
57 | 58 |
59 |
60 |
61 | 68 |
69 |
70 |
71 |
72 | 73 |
74 |

diPLSlib

75 | 129 |
130 | 131 | 132 |
133 |
134 |
135 | 136 |
137 | 138 |
139 |

© Copyright 2025, Ramin Nikzad-Langerodi.

140 |
141 | 142 | Built with Sphinx using a 143 | theme 144 | provided by Read the Docs. 145 | 146 | 147 |
148 |
149 |
150 |
151 |
152 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /doc/_build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/B-Analytics/diPLSlib/f11e224dd0e4dc3975555be54af6b7a9ae7b8819/doc/_build/html/objects.inv -------------------------------------------------------------------------------- /doc/_build/html/py-modindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Python Module Index — diPLSlib 2.5.0 documentation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 53 | 54 |
58 | 59 |
60 |
61 |
62 |
    63 |
  • 64 | 65 |
  • 66 |
  • 67 |
68 |
69 |
70 |
71 |
72 | 73 | 74 |

Python Module Index

75 | 76 |
77 | d 78 |
79 | 80 | 81 | 82 | 84 | 85 | 87 | 90 | 91 | 92 | 95 | 96 | 97 | 100 | 101 | 102 | 105 | 106 | 107 | 110 |
 
83 | d
88 | diPLSlib 89 |
    93 | diPLSlib.functions 94 |
    98 | diPLSlib.models 99 |
    103 | diPLSlib.utils 104 |
    108 | diPLSlib.utils.misc 109 |
111 | 112 | 113 |
114 |
115 |
116 | 117 |
118 | 119 |
120 |

© Copyright 2025, Ramin Nikzad-Langerodi.

121 |
122 | 123 | Built with Sphinx using a 124 | theme 125 | provided by Read the Docs. 126 | 127 | 128 |
129 |
130 |
131 |
132 |
133 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /doc/_build/html/search.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Search — diPLSlib 2.5.0 documentation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 53 | 54 |
58 | 59 |
60 |
61 |
62 |
    63 |
  • 64 | 65 |
  • 66 |
  • 67 |
68 |
69 |
70 |
71 |
72 | 73 | 80 | 81 | 82 |
83 | 84 |
85 | 86 |
87 |
88 |
89 | 90 |
91 | 92 |
93 |

© Copyright 2025, Ramin Nikzad-Langerodi.

94 |
95 | 96 | Built with Sphinx using a 97 | theme 98 | provided by Read the Docs. 99 | 100 | 101 |
102 |
103 |
104 |
105 |
106 | 111 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /doc/_build/html/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({"alltitles": {"Contents:": [[2, null]], "Introduction": [[2, "introduction"]], "Module contents": [[0, "module-diPLSlib"], [1, "module-diPLSlib.utils"]], "diPLSlib": [[3, null]], "diPLSlib documentation": [[2, null]], "diPLSlib package": [[0, null]], "diPLSlib.functions module": [[0, "module-diPLSlib.functions"]], "diPLSlib.models module": [[0, "module-diPLSlib.models"]], "diPLSlib.utils subpackage": [[0, "diplslib-utils-subpackage"], [1, null]], "diPLSlib.utils.misc module": [[1, "module-diPLSlib.utils.misc"]]}, "docnames": ["diPLSlib", "diPLSlib.utils", "index", "modules"], "envversion": {"sphinx": 64, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.viewcode": 1}, "filenames": ["diPLSlib.rst", "diPLSlib.utils.rst", "index.rst", "modules.rst"], "indexentries": {}, "objects": {"": [[0, 0, 0, "-", "diPLSlib"]], "diPLSlib": [[0, 0, 0, "-", "functions"], [0, 0, 0, "-", "models"], [1, 0, 0, "-", "utils"]], "diPLSlib.functions": [[0, 1, 1, "", "convex_relaxation"], [0, 1, 1, "", "dipals"], [0, 1, 1, "", "edpls"], [0, 1, 1, "", "kdapls"], [0, 1, 1, "", "transfer_laplacian"]], "diPLSlib.models": [[0, 2, 1, "", "DIPLS"], [0, 2, 1, "", "EDPLS"], [0, 2, 1, "", "GCTPLS"], [0, 2, 1, "", "KDAPLS"]], "diPLSlib.models.DIPLS": [[0, 3, 1, "", "fit"], [0, 3, 1, "", "predict"], [0, 3, 1, "", "set_fit_request"], [0, 3, 1, "", "set_score_request"]], "diPLSlib.models.EDPLS": [[0, 3, 1, "", "fit"], [0, 3, 1, "", "predict"], [0, 3, 1, "", "set_predict_request"], [0, 3, 1, "", "set_score_request"]], "diPLSlib.models.GCTPLS": [[0, 3, 1, "", "fit"], [0, 3, 1, "", "set_fit_request"], [0, 3, 1, "", "set_score_request"]], "diPLSlib.models.KDAPLS": [[0, 3, 1, "", "fit"], [0, 3, 1, "", "predict"], [0, 3, 1, "", "set_fit_request"], [0, 3, 1, "", "set_score_request"]], "diPLSlib.utils": [[1, 0, 0, "-", "misc"]], "diPLSlib.utils.misc": [[1, 1, 1, "", "calibrateAnalyticGaussianMechanism"], [1, 1, 1, "", "gengaus"], [1, 1, 1, "", "hellipse"], [1, 1, 1, "", "rmse"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"], "2": ["py", "class", "Python class"], "3": ["py", "method", "Python method"]}, "objtypes": {"0": "py:module", "1": "py:function", "2": "py:class", "3": "py:method"}, "terms": {"": [0, 1], "0": [0, 1], "0001": 0, "001": 0, "01": 0, "05": [0, 1], "1": [0, 1], "10": [0, 1], "100": [0, 1], "103986": 0, "12": 1, "1299": 0, "1319": 0, "18": 1, "1998": 0, "1e": 1, "2": [0, 1], "2006": 0, "201": 0, "2014": 0, "2018": [0, 1], "2019": 0, "2020": 0, "2021": 0, "2023": 0, "2024": 0, "2d": 1, "3": [0, 1], "35": 0, "394": [0, 1], "4": [0, 1], "403": [0, 1], "5": [0, 1], "50": [0, 1], "6": 0, "7": 0, "730631634944469": 1, "8": 0, "80": 0, "9": 0, "95": 1, "A": 0, "For": [0, 2], "If": 0, "In": [0, 1], "It": [0, 2], "The": [0, 1, 2], "To": 1, "_2": 0, "about": 0, "accept": 0, "accord": 0, "achiev": 1, "across": [0, 2], "ad": [0, 1], "adapt": [0, 2], "addit": 0, "adjust": [], "advanc": 2, "aim": 0, "al": 0, "algorithm": [0, 2], "alia": 0, "align": [0, 2], "all": 0, "allow": 0, "alpha": 1, "an": 0, "analysi": 0, "analyt": [0, 1, 2], "ani": 0, "api": 2, "appli": [0, 1], "ar": [0, 2], "argument": 0, "arrai": [0, 1], "art": 2, "associ": 0, "assumpt": 0, "attribut": 0, "automat": 0, "averag": 0, "b": [0, 1], "b0": [], "b0_": 0, "b_": 0, "balanc": 0, "ball": [0, 1], "base": [0, 2], "baseestim": 0, "been": 0, "beer": 0, "befor": 0, "belong": 0, "below": 2, "betwe": [], "between": [0, 1, 2], "biggl": 0, "biggr": 0, "binari": 1, "bool": 0, "both": 0, "bound": [0, 1], "bst": 0, "build": 0, "c": 0, "c_": 0, "calcul": 0, "calibr": [0, 1, 2], "calibrateanalyticgaussianmechan": [0, 1], "call": 0, "can": 0, "cdf": 0, "cdot": 0, "center": 0, "centering_": 0, "chang": 0, "chemistri": [0, 2], "chemometr": [0, 2], "chen": 0, "choos": [], "class": 0, "coef_": 0, "coeffici": 0, "collect": 1, "column": 0, "combin": 0, "compat": 2, "compon": 0, "comput": [0, 1], "confer": [0, 1], "confid": 1, "construct": 0, "contain": 0, "content": 3, "contrast": 0, "control": 0, "convex": 0, "convex_relax": [0, 3], "coordin": 1, "correspond": 0, "count": 0, "covari": 0, "crucial": [], "d": 0, "data": [0, 1, 2], "decomposit": 0, "default": [0, 1], "defin": 0, "delta": [0, 1, 2], "denois": [0, 1], "denot": 0, "design": [0, 2], "desir": 1, "detail": 2, "determin": 0, "deviat": 1, "devic": 0, "di": [0, 2], "dict": 0, "dictionari": 0, "differ": [0, 2], "differenti": [0, 1, 2], "dipal": [0, 3], "dipl": [0, 3], "discrep": [0, 2], "discrepancy_": 0, "distanc": 0, "distribut": [0, 2], "domain": [0, 2], "dp": 1, "dwork": 0, "e": 0, "e3319": 0, "e_": 0, "each": 0, "edpl": [0, 2, 3], "effect": 0, "ei": 0, "eigenvalu": 0, "el": 1, "ellips": 1, "enabl": 2, "enable_metadata_rout": 0, "end": [], "ensur": 2, "epsilon": [0, 1, 2], "equal": 0, "error": [0, 1], "es_": 0, "est": 0, "estim": 0, "et": 0, "et_": 0, "exampl": [0, 1, 2], "exist": 0, "ey_": 0, "f": 0, "failur": [0, 1], "fals": 0, "featur": [0, 2], "field": 2, "find": 0, "first": 0, "fit": [0, 3], "float": [0, 1], "focu": 2, "follow": 0, "frac": 0, "framework": 2, "from": [0, 1, 2], "function": [1, 2, 3], "g": [0, 1], "gamma": 0, "gaussian": [0, 1], "gct": [0, 2], "gctpl": [0, 3], "gener": [0, 1, 2], "gengau": [0, 1], "given": 0, "global": 1, "graph": [0, 2], "guarante": [0, 2], "guid": 0, "h": 0, "ha": 0, "handl": 0, "hellips": [0, 1], "helper": 1, "heurist": 0, "hilbert": [0, 2], "how": 0, "huang": 0, "i": [0, 1, 2], "icml": 1, "icmla": 0, "ignor": 0, "ij": 0, "implement": [0, 2], "import": [0, 1], "improv": [0, 1, 2], "includ": 2, "indic": 0, "inform": 0, "input": 0, "insid": 0, "instanc": 0, "instead": 0, "int": [0, 1], "intellig": 0, "intercept": 0, "intern": [0, 1], "interv": 1, "invari": [0, 2], "invert": 0, "involv": 0, "is_fitted_": 0, "j": 0, "journal": 0, "juli": [0, 1], "k": 0, "kda": 0, "kdapl": [0, 2, 3], "kei": 0, "kernel": [0, 2], "kernel_param": 0, "keyword": 0, "knowledg": 0, "kwarg": 0, "l": 0, "l2": 1, "l_": 0, "label": [0, 1], "laboratori": 0, "lambert": 0, "langerodi": 0, "laplacian": 0, "latent": [0, 2], "law": 0, "learn": [0, 1, 2], "least": [0, 2], "left": 0, "legend": 1, "len": [], "length": [0, 1], "leq": 0, "level": 1, "li": 0, "librari": 2, "like": 1, "line": 1, "line2d": 1, "linear": 0, "list": 0, "load": 0, "loss": 0, "lv": 0, "m": 0, "machin": [0, 1], "mag": 1, "magnitud": 1, "mainten": 2, "make": 0, "match": 0, "math": [], "mathbf": 0, "mathcal": 0, "mathemat": 0, "mathrm": 0, "matplotlib": 1, "matrix": [0, 1], "max_": 0, "maxim": 0, "mdi": 2, "mean": [0, 1], "mechan": [0, 1], "meta": 0, "metadata": 0, "metadata_rout": 0, "method": [0, 2], "mikulasek": 0, "minim": [0, 2], "misc": [0, 3], "model": [2, 3], "modul": [2, 3], "more": 2, "mu": 1, "mu_": 0, "mu_s_": 0, "mu_t_": 0, "multipl": 0, "multivari": 2, "must": 0, "m\u00fcller": 0, "n": 0, "n_": 0, "n_compon": 0, "n_domain": [], "n_featur": 0, "n_features_": [], "n_features_in_": 0, "n_sampl": [0, 1], "n_sample_pair": 0, "n_samples_sourc": 0, "n_samples_target": 0, "n_samples_test": 0, "n_source_sampl": 0, "n_target": 0, "n_target_sampl": 0, "name": 0, "ndarrai": [0, 1], "need": 1, "neg": 0, "neural": 0, "nikzad": 0, "nois": [0, 1], "non": [0, 2], "none": 0, "nonlinear": 0, "note": 0, "np": [0, 1], "ns_": 0, "nt_": 0, "number": 0, "numpi": [0, 1], "object": [0, 1], "onli": 0, "oper": 0, "opt_l": 0, "opt_l_": 0, "optim": [0, 1], "option": [0, 1], "origin": 0, "other": [0, 2], "otherwis": 0, "output": 0, "p": 0, "p_": 0, "packag": [2, 3], "pair": [0, 2], "paramet": [0, 1], "parametr": [0, 2], "partial": [0, 2], "pass": 0, "pathcollect": 1, "per": 0, "perform": 0, "perturb": 1, "phi": 0, "pipelin": 0, "pl": [0, 2], "pleas": [0, 2], "plot": 1, "pls1": 0, "plt": 1, "pmlr": [0, 1], "point": 1, "potenti": 0, "pp": [0, 1], "predict": [0, 1, 3], "preserv": 2, "primal": 0, "print": [0, 1], "privaci": [0, 1, 2], "privat": [0, 2], "probabl": [0, 1], "problem": 0, "proc": 0, "project": [0, 2], "propos": 0, "provid": [0, 2], "ps_": 0, "pst": 0, "pt": 0, "pt_": 0, "purpos": 0, "py": 0, "pyplot": 1, "python": 2, "q": 0, "qualiti": 0, "quantiti": 0, "r": 0, "rais": 0, "ramin": 0, "rand": 0, "random": [0, 1], "random_st": 0, "randomst": 0, "rbf": 0, "reconstruct": 0, "refer": [0, 1, 2], "regress": [0, 2], "regressormixin": 0, "regular": 0, "relat": 0, "relax": 0, "releas": 0, "relev": 0, "repres": 0, "represent": 0, "reproduc": [0, 2], "request": 0, "requir": 2, "rescal": 0, "reshap": 0, "residu": 0, "respect": 0, "respons": 0, "retain": 0, "return": [0, 1], "right": 0, "rkh": 0, "rmse": [0, 1], "rng": 0, "robust": 2, "root": 1, "rout": 0, "same": 0, "sampl": [0, 2], "sample_weight": 0, "satisfi": 0, "scatter": 1, "sch\u00f6lkopf": 0, "scikit": 2, "scipi": 1, "score": 0, "search": 1, "section": 2, "see": 0, "select": 0, "self": 0, "sensit": [0, 1, 2], "set": 0, "set_config": 0, "set_fit_request": [0, 3], "set_predict_request": [0, 3], "set_score_request": [0, 3], "sever": 2, "shape": [0, 1], "shi": 0, "should": 0, "sigma": [0, 1], "sign": 0, "signal": 1, "signific": 1, "singl": 0, "sklearn": 0, "smola": 0, "so": 0, "sobieczki": 0, "some": [0, 1], "sourc": [0, 1, 2], "space": [0, 2], "specif": 0, "specifi": 0, "spectrum": 1, "squar": [0, 1, 2], "st": 0, "standard": [0, 1], "stat": 1, "state": 2, "store": 0, "str": 0, "sub": 0, "subpackag": [2, 3], "suitabl": 2, "sup_": 0, "support": 0, "symmetr": 0, "system": 0, "t": 0, "t_": 0, "target": [0, 2], "target_domain": 0, "test": 0, "th": 0, "thi": 0, "through": 0, "thu": 0, "tol": 1, "toler": 1, "train": 0, "transfer": [0, 2], "transfer_laplacian": [0, 3], "transform": 0, "true": [0, 1], "ts_": 0, "tst": 0, "tt": 0, "tt_": 0, "tupl": 0, "two": 1, "type": 0, "unchang": 0, "under": [0, 1], "underli": 0, "union": 0, "univari": 0, "unlabel": 0, "unpublish": 0, "updat": 0, "upper": [0, 1], "us": [0, 1, 2], "usag": 2, "user": 0, "usual": 0, "util": [2, 3], "valu": [0, 1], "variabl": [0, 2], "varianc": 0, "vector": 0, "version": 0, "w": 0, "w_": 0, "wai": 0, "wang": [0, 1], "weight": 0, "well": 0, "where": [0, 2], "wherea": 0, "whether": 0, "which": [0, 1], "while": 0, "work": 0, "x": [0, 1], "x_": 0, "x_loadings_": 0, "x_mean_": 0, "x_residu": [], "x_residuals_": 0, "x_scores_": 0, "x_t": 0, "x_weights_": 0, "xs_": 0, "xt": 0, "xt_": 0, "xtest": 0, "y": [0, 1], "y_loadings_": 0, "y_mean_": 0, "y_residu": [], "y_residuals_": 0, "yhat": [0, 1], "you": 0, "yuan": 0}, "titles": ["diPLSlib package", "diPLSlib.utils subpackage", "diPLSlib documentation", "diPLSlib"], "titleterms": {"content": [0, 1, 2], "diplslib": [0, 1, 2, 3], "document": 2, "function": 0, "introduct": 2, "misc": 1, "model": 0, "modul": [0, 1], "packag": 0, "subpackag": [0, 1], "util": [0, 1]}}) -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | import os 7 | import sys 8 | sys.path.insert(0, os.path.abspath('../')) 9 | 10 | # -- Project information ----------------------------------------------------- 11 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 12 | 13 | project = 'diPLSlib' 14 | copyright = '2025, Ramin Nikzad-Langerodi' 15 | author = 'Ramin Nikzad-Langerodi' 16 | release = '2.5.0' 17 | 18 | # -- General configuration --------------------------------------------------- 19 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 20 | 21 | extensions = [ 22 | 'sphinx.ext.autodoc', 23 | 'numpydoc', 24 | 'sphinx.ext.viewcode', 25 | 'sphinx.ext.mathjax'] 26 | #'sphinx.ext.napoleon'] 27 | 28 | templates_path = ['_templates'] 29 | exclude_patterns = [] 30 | 31 | 32 | 33 | # -- Options for HTML output ------------------------------------------------- 34 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 35 | 36 | html_theme = 'sphinx_rtd_theme' 37 | html_static_path = ['_static'] 38 | -------------------------------------------------------------------------------- /doc/diPLSlib.rst: -------------------------------------------------------------------------------- 1 | diPLSlib package 2 | ================ 3 | 4 | 5 | diPLSlib.functions module 6 | ------------------------- 7 | 8 | .. automodule:: diPLSlib.functions 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | diPLSlib.models module 14 | ---------------------- 15 | 16 | .. automodule:: diPLSlib.models 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | 21 | diPLSlib.utils subpackage 22 | ------------------------- 23 | 24 | .. toctree:: 25 | :maxdepth: 4 26 | 27 | diPLSlib.utils 28 | 29 | Module contents 30 | --------------- 31 | 32 | .. automodule:: diPLSlib 33 | :members: 34 | :undoc-members: 35 | :show-inheritance: 36 | -------------------------------------------------------------------------------- /doc/diPLSlib.utils.rst: -------------------------------------------------------------------------------- 1 | diPLSlib.utils subpackage 2 | ========================= 3 | 4 | 5 | diPLSlib.utils.misc module 6 | -------------------------- 7 | 8 | .. automodule:: diPLSlib.utils.misc 9 | :members: 10 | :undoc-members: 11 | :show-inheritance: 12 | 13 | Module contents 14 | --------------- 15 | 16 | .. automodule:: diPLSlib.utils 17 | :members: 18 | :undoc-members: 19 | :show-inheritance: 20 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. diPLSlib documentation master file, created by 2 | sphinx-quickstart on Sun Nov 3 00:13:47 2024. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | diPLSlib documentation 7 | ====================== 8 | 9 | Introduction 10 | ------------ 11 | 12 | **diPLSlib** is a Python library designed for domain adaptation in multivariate calibration, with a focus on privacy-preserving regression and calibration model maintenance. It provides a scikit-learn compatible API and implements advanced methods for aligning data distributions across different domains, enabling robust and transferable regression models. 13 | 14 | The library features several state-of-the-art algorithms, including: 15 | 16 | - **Domain-Invariant Partial Least Squares (di-PLS/mdi-PLS):** Aligns feature distributions between source and target domains to improve model generalization. 17 | - **Graph-based Calibration Transfer (GCT-PLS):** Minimizes discrepancies between paired samples from different domains in the latent variable space. 18 | - **Kernel Domain Adaptive PLS (KDAPLS):** Projects data into a reproducing kernel Hilbert space for non-parametric domain adaptation. 19 | - **Differentially Private PLS (EDPLS):** Ensures privacy guarantees for sensitive data using the :math:`(\epsilon, \delta)`-differential privacy framework. 20 | 21 | diPLSlib is suitable for chemometrics, analytical chemistry, and other fields where robust calibration transfer and privacy-preserving modeling are required. For more details, usage examples, and API documentation, please refer to the sections below. 22 | 23 | .. toctree:: 24 | :maxdepth: 2 25 | :caption: Contents: 26 | 27 | diPLSlib 28 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /doc/modules.rst: -------------------------------------------------------------------------------- 1 | diPLSlib 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | diPLSlib 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib==3.9.2 2 | numpy==2.1.3 3 | scikit_learn==1.5.2 4 | scipy==1.14.1 5 | setuptools==75.1.0 6 | numpydoc==1.8.0 7 | sphinx==8.1.3 8 | sphinx_rtd_theme==3.0.1 9 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r", encoding="utf-8") as fh: 4 | long_description = fh.read() 5 | 6 | setuptools.setup( 7 | name="diPLSlib", 8 | version="2.5.0", 9 | author="Ramin Nikzad-Langerodi", 10 | author_email="ramin.nikzad-langerodi@scch.at", 11 | description="Python package for domain adaptation in multivariate regression", 12 | long_description=long_description, 13 | long_description_content_type="text/markdown", 14 | url="https://github.com/B-Analytics/di-PLS", 15 | packages=setuptools.find_packages(), 16 | classifiers=[ 17 | "Programming Language :: Python :: 3", 18 | 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 19 | "Operating System :: OS Independent", 20 | ], 21 | python_requires='>=3.6', 22 | install_requires=[ 23 | 'numpy', 24 | 'matplotlib', 25 | 'scipy', 26 | 'scikit-learn', 27 | ] 28 | ) -------------------------------------------------------------------------------- /tests/test_doctests.py: -------------------------------------------------------------------------------- 1 | import doctest 2 | import unittest 3 | import diPLSlib.models 4 | import diPLSlib.functions 5 | import diPLSlib.utils.misc 6 | from sklearn.utils.estimator_checks import check_estimator 7 | from diPLSlib.models import DIPLS, GCTPLS, EDPLS, KDAPLS 8 | import nbformat 9 | from nbconvert.preprocessors import ExecutePreprocessor 10 | import os 11 | 12 | class TestDocstrings(unittest.TestCase): 13 | 14 | # Test if all docstring examples run without errors 15 | def test_docstrings(self): 16 | 17 | # Run doctests across all modules in your_package 18 | doctest.testmod(diPLSlib.models) 19 | doctest.testmod(diPLSlib.functions) 20 | doctest.testmod(diPLSlib.utils.misc) 21 | 22 | # Test if diPLSlib.model classes pass check_estimator 23 | def test_check_estimator(self): 24 | 25 | models = [ 26 | DIPLS(), 27 | GCTPLS(), 28 | EDPLS(A=2, epsilon=1.0, delta=0.05), # Add required parameters for EDPLS 29 | KDAPLS() 30 | ] 31 | 32 | for model in models: 33 | check_estimator(model) 34 | 35 | 36 | # Test if all notebooks run without errors 37 | def test_notebooks(self): 38 | # List of notebooks to test 39 | notebooks = [ 40 | './notebooks/demo_diPLS.ipynb', 41 | './notebooks/demo_mdiPLS.ipynb', 42 | './notebooks/demo_gctPLS.ipynb', 43 | './notebooks/demo_edPLS.ipynb', 44 | './notebooks/demo_daPLS.ipynb', 45 | ] 46 | 47 | for notebook in notebooks: 48 | with open(notebook) as f: 49 | nb = nbformat.read(f, as_version=4) 50 | ep = ExecutePreprocessor(timeout=600, kernel_name='python3') 51 | 52 | # Set the working directory to the root of the project 53 | root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) 54 | os.chdir(root_dir) 55 | 56 | ep.preprocess(nb, {'metadata': {'path': './notebooks/'}}) 57 | 58 | 59 | if __name__ == '__main__': 60 | unittest.main() --------------------------------------------------------------------------------