tlmnet 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tlmnet-0.1.0/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2023 - 2026, Carlson Research, LLC
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
tlmnet-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: tlmnet
3
+ Version: 0.1.0
4
+ Summary: Ternary Linear Models via Exact MILP Solvers
5
+ Author-email: "Carlson Research, LLC" <rolf@hrolfrc.com>
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/carlson-research/tlmnet
8
+ Project-URL: Repository, https://github.com/carlson-research/tlmnet
9
+ Project-URL: Documentation, https://carlson-research.github.io/tlmnet/
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: numpy>=1.24.0
19
+ Requires-Dist: scipy>=1.10.0
20
+ Requires-Dist: scikit-learn>=1.6.0
21
+ Requires-Dist: joblib>=1.3.0
22
+ Requires-Dist: pandas
23
+ Requires-Dist: matplotlib
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
26
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
27
+ Requires-Dist: sphinx>=7.0.0; extra == "dev"
28
+ Requires-Dist: pydata-sphinx-theme>=0.15.0; extra == "dev"
29
+ Requires-Dist: sphinx-gallery; extra == "dev"
30
+ Requires-Dist: numpydoc; extra == "dev"
31
+ Requires-Dist: nbsphinx; extra == "dev"
32
+ Requires-Dist: pandoc; extra == "dev"
33
+ Requires-Dist: mypy>=1.8.0; extra == "dev"
34
+ Requires-Dist: pre-commit<3.8.0; extra == "dev"
35
+ Requires-Dist: build>=1.0.0; extra == "dev"
36
+ Requires-Dist: twine>=5.0.0; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # tlmnet
40
+
41
+ [![CI](https://github.com/carlson-research/tlmnet/actions/workflows/tests.yml/badge.svg)](https://github.com/carlson-research/tlmnet/actions)
42
+ [![PyPI Version](https://img.shields.io/pypi/v/tlmnet.svg)](https://pypi.org/project/tlmnet/)
43
+ [![Python Version](https://img.shields.io/pypi/pyversions/tlmnet.svg)](https://pypi.org/project/tlmnet/)
44
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://carlson-research.github.io/tlmnet/)
45
+ [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://github.com/carlson-research/tlmnet/blob/main/LICENSE)
46
+
47
+ `tlmnet` provides exact Mixed-Integer Linear Programming (MILP) solvers for Quantized Statistical Learning with Ternary Linear Models (TLMs).
48
+
49
+ By restricting coefficients to discrete ternary values ($w_j \in \{-1, 0, 1\}$), it constructs globally optimal, sparse, and interpretable classifiers compliant with Scikit-Learn 1.6+ API standards.
50
+
51
+ ## Features
52
+
53
+ * **Exact Discrete Weights:** Solves for ternary coefficients $w_j \in \{-1, 0, 1\}$ directly using branch-and-bound optimization via `scipy.optimize.milp`.
54
+ * **Exact $L_0$ Cardinality Constraints:** Enforces strict integer feature selection budgets ($\sum \vert{}w_j\vert{} \le k$) using `max_features`.
55
+ * **Native Sparse Data Support:** Efficiently processes high-dimensional `scipy.sparse` matrices (`CSR`, `CSC`, `COO`) using sparse block constraint assembly.
56
+ * **Scikit-Learn Compatibility:** Plugs directly into `Pipeline`, `OneVsRestClassifier`, `GridSearchCV`, and standard estimator workflows.
57
+ * **Timeout & Incumbent Recovery:** Automatically returns the best feasible integer solution found if the solver reaches `time_limit` before proving global optimality.
58
+
59
+ ## Installation
60
+
61
+ Install `tlmnet` directly from PyPI:
62
+
63
+ ```bash
64
+ pip install tlmnet
65
+ ```
66
+
67
+ ## Quick Start Example
68
+
69
+ ```python
70
+ from tlmnet import TlmMilpClassifier
71
+ from sklearn.datasets import make_classification
72
+ from sklearn.model_selection import train_test_split
73
+ from sklearn.pipeline import make_pipeline
74
+ from sklearn.preprocessing import StandardScaler
75
+
76
+ # Generate synthetic classification dataset
77
+ X, y = make_classification(
78
+ n_samples=200, n_features=15, n_informative=5, random_state=42
79
+ )
80
+ X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
81
+
82
+ # Build pipeline with standardization and exact MILP classification
83
+ clf = make_pipeline(
84
+ StandardScaler(),
85
+ TlmMilpClassifier(max_features=5, C=1.0, time_limit=30.0)
86
+ )
87
+ clf.fit(X_train, y_train)
88
+
89
+ # Inspect model properties
90
+ tlm_model = clf.named_steps["tlmmilpclassifier"]
91
+ print("Ternary Coefficients:", tlm_model.coef_)
92
+ print("Test Accuracy:", clf.score(X_test, y_test))
93
+
94
+ ```
95
+
96
+ ## License
97
+
98
+ This project is licensed under the BSD-3-Clause License.
99
+
100
+ ## Authors
101
+
102
+ * **Author & Maintainer**: Rolf Carlson (rolf@hrolfrc.com)
tlmnet-0.1.0/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # tlmnet
2
+
3
+ [![CI](https://github.com/carlson-research/tlmnet/actions/workflows/tests.yml/badge.svg)](https://github.com/carlson-research/tlmnet/actions)
4
+ [![PyPI Version](https://img.shields.io/pypi/v/tlmnet.svg)](https://pypi.org/project/tlmnet/)
5
+ [![Python Version](https://img.shields.io/pypi/pyversions/tlmnet.svg)](https://pypi.org/project/tlmnet/)
6
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://carlson-research.github.io/tlmnet/)
7
+ [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://github.com/carlson-research/tlmnet/blob/main/LICENSE)
8
+
9
+ `tlmnet` provides exact Mixed-Integer Linear Programming (MILP) solvers for Quantized Statistical Learning with Ternary Linear Models (TLMs).
10
+
11
+ By restricting coefficients to discrete ternary values ($w_j \in \{-1, 0, 1\}$), it constructs globally optimal, sparse, and interpretable classifiers compliant with Scikit-Learn 1.6+ API standards.
12
+
13
+ ## Features
14
+
15
+ * **Exact Discrete Weights:** Solves for ternary coefficients $w_j \in \{-1, 0, 1\}$ directly using branch-and-bound optimization via `scipy.optimize.milp`.
16
+ * **Exact $L_0$ Cardinality Constraints:** Enforces strict integer feature selection budgets ($\sum \vert{}w_j\vert{} \le k$) using `max_features`.
17
+ * **Native Sparse Data Support:** Efficiently processes high-dimensional `scipy.sparse` matrices (`CSR`, `CSC`, `COO`) using sparse block constraint assembly.
18
+ * **Scikit-Learn Compatibility:** Plugs directly into `Pipeline`, `OneVsRestClassifier`, `GridSearchCV`, and standard estimator workflows.
19
+ * **Timeout & Incumbent Recovery:** Automatically returns the best feasible integer solution found if the solver reaches `time_limit` before proving global optimality.
20
+
21
+ ## Installation
22
+
23
+ Install `tlmnet` directly from PyPI:
24
+
25
+ ```bash
26
+ pip install tlmnet
27
+ ```
28
+
29
+ ## Quick Start Example
30
+
31
+ ```python
32
+ from tlmnet import TlmMilpClassifier
33
+ from sklearn.datasets import make_classification
34
+ from sklearn.model_selection import train_test_split
35
+ from sklearn.pipeline import make_pipeline
36
+ from sklearn.preprocessing import StandardScaler
37
+
38
+ # Generate synthetic classification dataset
39
+ X, y = make_classification(
40
+ n_samples=200, n_features=15, n_informative=5, random_state=42
41
+ )
42
+ X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
43
+
44
+ # Build pipeline with standardization and exact MILP classification
45
+ clf = make_pipeline(
46
+ StandardScaler(),
47
+ TlmMilpClassifier(max_features=5, C=1.0, time_limit=30.0)
48
+ )
49
+ clf.fit(X_train, y_train)
50
+
51
+ # Inspect model properties
52
+ tlm_model = clf.named_steps["tlmmilpclassifier"]
53
+ print("Ternary Coefficients:", tlm_model.coef_)
54
+ print("Test Accuracy:", clf.score(X_test, y_test))
55
+
56
+ ```
57
+
58
+ ## License
59
+
60
+ This project is licensed under the BSD-3-Clause License.
61
+
62
+ ## Authors
63
+
64
+ * **Author & Maintainer**: Rolf Carlson (rolf@hrolfrc.com)
@@ -0,0 +1,99 @@
1
+ # pip install -e ".[dev]"
2
+
3
+ [build-system]
4
+ requires = ["setuptools>=61.0", "wheel"]
5
+ build-backend = "setuptools.build_meta"
6
+
7
+ [project]
8
+ name = "tlmnet"
9
+ dynamic = ["version"]
10
+ description = "Ternary Linear Models via Exact MILP Solvers"
11
+ readme = "README.md"
12
+ authors = [
13
+ {name = "Carlson Research, LLC", email = "rolf@hrolfrc.com"}
14
+ ]
15
+ license = "BSD-3-Clause"
16
+ requires-python = ">=3.11"
17
+ dependencies = [
18
+ "numpy>=1.24.0",
19
+ "scipy>=1.10.0",
20
+ "scikit-learn>=1.6.0",
21
+ "joblib>=1.3.0",
22
+ "pandas",
23
+ "matplotlib",
24
+ ]
25
+
26
+ classifiers = [
27
+ "Programming Language :: Python :: 3",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Programming Language :: Python :: 3.12",
30
+ "Intended Audience :: Science/Research",
31
+ "Topic :: Scientific/Engineering :: Information Analysis",
32
+ ]
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/carlson-research/tlmnet"
36
+ Repository = "https://github.com/carlson-research/tlmnet"
37
+ Documentation = "https://carlson-research.github.io/tlmnet/"
38
+
39
+ [project.optional-dependencies]
40
+ dev = [
41
+ "pytest>=8.0.0",
42
+ "pytest-cov>=5.0.0",
43
+ "sphinx>=7.0.0",
44
+ "pydata-sphinx-theme>=0.15.0",
45
+ "sphinx-gallery",
46
+ "numpydoc",
47
+ "nbsphinx",
48
+ "pandoc",
49
+ "mypy>=1.8.0",
50
+ "pre-commit<3.8.0",
51
+ "build>=1.0.0",
52
+ "twine>=5.0.0",
53
+ ]
54
+
55
+ [tool.coverage.run]
56
+ source = ["src/tlmnet"]
57
+ omit = [
58
+ "src/tlmnet/__main__.py",
59
+ ]
60
+
61
+ [tool.setuptools.dynamic]
62
+ version = {attr = "tlmnet._version.__version__"}
63
+
64
+ [tool.setuptools.packages.find]
65
+ where = ["src"]
66
+ include = ["tlmnet*"]
67
+
68
+ [tool.pytest.ini_options]
69
+ filterwarnings = [
70
+ "ignore:Passing a non-Collection iterable to parametrize is deprecated:pytest.PytestRemovedIn10Warning",
71
+ ]
72
+ addopts = "--doctest-modules"
73
+ pythonpath = [".", "src"]
74
+ testpaths = ["tests", "src"]
75
+
76
+ [tool.ruff]
77
+ line-length = 88
78
+ src = ["src", "tests"]
79
+
80
+ [tool.mypy]
81
+ python_version = "3.12"
82
+ exclude = ["docs/auto_examples/"]
83
+ warn_return_any = false
84
+ warn_unused_configs = true
85
+ ignore_missing_imports = true
86
+
87
+ [tool.coverage.report]
88
+ exclude_lines = [
89
+ "pragma: no cover",
90
+ "def __repr__",
91
+ "if self.debug:",
92
+ "if settings.DEBUG",
93
+ "raise AssertionError",
94
+ "raise NotImplementedError",
95
+ "if 0:",
96
+ "if __name__ == .__main__.:",
97
+ "if self.verbose:"
98
+ ]
99
+ show_missing = true
tlmnet-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,4 @@
1
+ from ._version import __version__
2
+ from .milp import TlmMilpClassifier
3
+
4
+ __all__ = ["TlmMilpClassifier", "__version__"]
@@ -0,0 +1,3 @@
1
+ """Version definition for dynamic pyproject.toml linking."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,161 @@
1
+ import numpy as np
2
+ import scipy.sparse as sp
3
+ from scipy.optimize import Bounds, LinearConstraint, milp
4
+ from sklearn.base import BaseEstimator, ClassifierMixin
5
+ from sklearn.utils.multiclass import type_of_target, unique_labels
6
+ from sklearn.utils.validation import check_is_fitted, validate_data
7
+
8
+
9
+ class TlmMilpClassifier(ClassifierMixin, BaseEstimator):
10
+ """Exact Ternary Linear Model Classifier using Mixed-Integer Linear Programming (MILP).
11
+
12
+ Solves for w_j in {-1, 0, 1} using decision variable splitting w_j = u_j - v_j.
13
+ Natively supports sparse data constraints via scipy.sparse block matrices.
14
+ """
15
+
16
+ def __init__(
17
+ self, max_features=None, C=1.0, time_limit=60.0, mip_rel_gap=1e-4, verbose=False
18
+ ):
19
+ self.max_features = max_features
20
+ self.C = C
21
+ self.time_limit = time_limit
22
+ self.mip_rel_gap = mip_rel_gap
23
+ self.verbose = verbose
24
+
25
+ def _more_tags(self):
26
+ return {"poor_score": True, "binary_only": True}
27
+
28
+ def __sklearn_tags__(self):
29
+ tags = super().__sklearn_tags__()
30
+ tags.classifier_tags.poor_score = True
31
+ tags.classifier_tags.multi_class = False
32
+ tags.input_tags.sparse = (
33
+ True # Tell Scikit-Learn we natively accept sparse matrices
34
+ )
35
+ tags.estimator_type = "classifier"
36
+ return tags
37
+
38
+ def fit(self, X, y):
39
+ if y is None:
40
+ raise ValueError("requires y to be passed, but the target y is None")
41
+
42
+ # 1. Validate data; natively accept sparse inputs (CSR/CSC/COO)
43
+ X, y = validate_data(
44
+ self, X=X, y=y, accept_sparse=["csr", "csc", "coo"], reset=True
45
+ )
46
+
47
+ # 2. Check target type
48
+ y_type = type_of_target(y)
49
+ if y_type == "unknown":
50
+ raise ValueError("Unknown label type: target y must be binary.")
51
+ if y_type != "binary":
52
+ raise ValueError(
53
+ f"Only binary classification is supported. The type of target is {y_type}."
54
+ )
55
+
56
+ self.classes_ = unique_labels(y)
57
+ if len(self.classes_) < 2:
58
+ raise ValueError(
59
+ f"This solver needs samples of at least 2 classes in the data, "
60
+ f"but the data contains only one class: {self.classes_[0]}"
61
+ )
62
+
63
+ n_samples, n_features = X.shape
64
+
65
+ # Convert y to {-1, +1}
66
+ y_binary = np.where(y == self.classes_[1], 1, -1)
67
+
68
+ # Decision Variables: 2*p (weights) + n (slacks)
69
+ c = np.zeros(2 * n_features + n_samples)
70
+ c[2 * n_features :] = self.C
71
+
72
+ integrality = np.concatenate([np.ones(2 * n_features), np.zeros(n_samples)])
73
+ lb = np.zeros(2 * n_features + n_samples)
74
+ ub = np.concatenate([np.ones(2 * n_features), np.full(n_samples, np.inf)])
75
+ bounds = Bounds(lb, ub)
76
+
77
+ constraints = []
78
+
79
+ # 1. Mutually Exclusive Ternary Constraint (Sparse)
80
+ row_exc = np.repeat(np.arange(n_features), 2)
81
+ col_exc = np.arange(2 * n_features)
82
+ data_exc = np.ones(2 * n_features)
83
+
84
+ A_exc_left = sp.coo_matrix(
85
+ (data_exc, (row_exc, col_exc)), shape=(n_features, 2 * n_features)
86
+ )
87
+ A_exc_right = sp.csr_matrix((n_features, n_samples))
88
+ A_exclusive = sp.hstack([A_exc_left, A_exc_right])
89
+ constraints.append(LinearConstraint(A_exclusive, -np.inf, 1))
90
+
91
+ # 2. Classification Margin Constraint (Sparse)
92
+ if not sp.issparse(X):
93
+ X_sparse = sp.csr_matrix(X)
94
+ else:
95
+ X_sparse = X
96
+
97
+ # Multiply rows of X by y efficiently
98
+ Y_diag = sp.diags(y_binary, dtype=float)
99
+ X_y = Y_diag @ X_sparse
100
+ X_y = X_y.tocoo()
101
+
102
+ # Interleave u and v coefficients
103
+ row_u, col_u, data_u = X_y.row, 2 * X_y.col, X_y.data
104
+ row_v, col_v, data_v = X_y.row, 2 * X_y.col + 1, -X_y.data
105
+
106
+ row_margin = np.concatenate([row_u, row_v])
107
+ col_margin = np.concatenate([col_u, col_v])
108
+ data_margin = np.concatenate([data_u, data_v])
109
+
110
+ A_margin_left = sp.coo_matrix(
111
+ (data_margin, (row_margin, col_margin)), shape=(n_samples, 2 * n_features)
112
+ )
113
+ A_margin_right = sp.eye(n_samples, format="coo")
114
+ A_margin = sp.hstack([A_margin_left, A_margin_right])
115
+
116
+ constraints.append(LinearConstraint(A_margin, 1.0, np.inf))
117
+
118
+ # 3. L0 Sparsity Budget (Sparse)
119
+ if self.max_features is not None:
120
+ A_sparse_left = sp.csr_matrix(np.ones((1, 2 * n_features)))
121
+ A_sparse_right = sp.csr_matrix((1, n_samples))
122
+ A_sparse_const = sp.hstack([A_sparse_left, A_sparse_right])
123
+ constraints.append(LinearConstraint(A_sparse_const, 0, self.max_features))
124
+
125
+ # Solve MILP with expanded options
126
+ options = {
127
+ "time_limit": self.time_limit,
128
+ "mip_rel_gap": self.mip_rel_gap,
129
+ "disp": self.verbose,
130
+ }
131
+ res = milp(
132
+ c=c,
133
+ integrality=integrality,
134
+ bounds=bounds,
135
+ constraints=constraints,
136
+ options=options,
137
+ )
138
+
139
+ # Status 0 = Optimal, Status 1 = Time Limit Reached (but res.x might exist!)
140
+ if res.status in (0, 1) and res.x is not None:
141
+ u_opt = np.round(res.x[: 2 * n_features : 2])
142
+ v_opt = np.round(res.x[1 : 2 * n_features : 2])
143
+ else:
144
+ # Only fail to all zeros if it's proven infeasible (Status 2) or unbounded (Status 3)
145
+ u_opt = np.zeros(n_features)
146
+ v_opt = np.zeros(n_features)
147
+
148
+ self.coef_ = u_opt - v_opt
149
+ self.intercept_ = 0.0
150
+
151
+ return self
152
+
153
+ def decision_function(self, X):
154
+ """Predict confidence scores for samples."""
155
+ check_is_fitted(self)
156
+ X = validate_data(self, X=X, accept_sparse=["csr", "csc", "coo"], reset=False)
157
+ return X @ self.coef_
158
+
159
+ def predict(self, X):
160
+ scores = self.decision_function(X)
161
+ return np.where(scores >= 0, self.classes_[1], self.classes_[0])
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: tlmnet
3
+ Version: 0.1.0
4
+ Summary: Ternary Linear Models via Exact MILP Solvers
5
+ Author-email: "Carlson Research, LLC" <rolf@hrolfrc.com>
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/carlson-research/tlmnet
8
+ Project-URL: Repository, https://github.com/carlson-research/tlmnet
9
+ Project-URL: Documentation, https://carlson-research.github.io/tlmnet/
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: numpy>=1.24.0
19
+ Requires-Dist: scipy>=1.10.0
20
+ Requires-Dist: scikit-learn>=1.6.0
21
+ Requires-Dist: joblib>=1.3.0
22
+ Requires-Dist: pandas
23
+ Requires-Dist: matplotlib
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
26
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
27
+ Requires-Dist: sphinx>=7.0.0; extra == "dev"
28
+ Requires-Dist: pydata-sphinx-theme>=0.15.0; extra == "dev"
29
+ Requires-Dist: sphinx-gallery; extra == "dev"
30
+ Requires-Dist: numpydoc; extra == "dev"
31
+ Requires-Dist: nbsphinx; extra == "dev"
32
+ Requires-Dist: pandoc; extra == "dev"
33
+ Requires-Dist: mypy>=1.8.0; extra == "dev"
34
+ Requires-Dist: pre-commit<3.8.0; extra == "dev"
35
+ Requires-Dist: build>=1.0.0; extra == "dev"
36
+ Requires-Dist: twine>=5.0.0; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # tlmnet
40
+
41
+ [![CI](https://github.com/carlson-research/tlmnet/actions/workflows/tests.yml/badge.svg)](https://github.com/carlson-research/tlmnet/actions)
42
+ [![PyPI Version](https://img.shields.io/pypi/v/tlmnet.svg)](https://pypi.org/project/tlmnet/)
43
+ [![Python Version](https://img.shields.io/pypi/pyversions/tlmnet.svg)](https://pypi.org/project/tlmnet/)
44
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://carlson-research.github.io/tlmnet/)
45
+ [![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://github.com/carlson-research/tlmnet/blob/main/LICENSE)
46
+
47
+ `tlmnet` provides exact Mixed-Integer Linear Programming (MILP) solvers for Quantized Statistical Learning with Ternary Linear Models (TLMs).
48
+
49
+ By restricting coefficients to discrete ternary values ($w_j \in \{-1, 0, 1\}$), it constructs globally optimal, sparse, and interpretable classifiers compliant with Scikit-Learn 1.6+ API standards.
50
+
51
+ ## Features
52
+
53
+ * **Exact Discrete Weights:** Solves for ternary coefficients $w_j \in \{-1, 0, 1\}$ directly using branch-and-bound optimization via `scipy.optimize.milp`.
54
+ * **Exact $L_0$ Cardinality Constraints:** Enforces strict integer feature selection budgets ($\sum \vert{}w_j\vert{} \le k$) using `max_features`.
55
+ * **Native Sparse Data Support:** Efficiently processes high-dimensional `scipy.sparse` matrices (`CSR`, `CSC`, `COO`) using sparse block constraint assembly.
56
+ * **Scikit-Learn Compatibility:** Plugs directly into `Pipeline`, `OneVsRestClassifier`, `GridSearchCV`, and standard estimator workflows.
57
+ * **Timeout & Incumbent Recovery:** Automatically returns the best feasible integer solution found if the solver reaches `time_limit` before proving global optimality.
58
+
59
+ ## Installation
60
+
61
+ Install `tlmnet` directly from PyPI:
62
+
63
+ ```bash
64
+ pip install tlmnet
65
+ ```
66
+
67
+ ## Quick Start Example
68
+
69
+ ```python
70
+ from tlmnet import TlmMilpClassifier
71
+ from sklearn.datasets import make_classification
72
+ from sklearn.model_selection import train_test_split
73
+ from sklearn.pipeline import make_pipeline
74
+ from sklearn.preprocessing import StandardScaler
75
+
76
+ # Generate synthetic classification dataset
77
+ X, y = make_classification(
78
+ n_samples=200, n_features=15, n_informative=5, random_state=42
79
+ )
80
+ X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
81
+
82
+ # Build pipeline with standardization and exact MILP classification
83
+ clf = make_pipeline(
84
+ StandardScaler(),
85
+ TlmMilpClassifier(max_features=5, C=1.0, time_limit=30.0)
86
+ )
87
+ clf.fit(X_train, y_train)
88
+
89
+ # Inspect model properties
90
+ tlm_model = clf.named_steps["tlmmilpclassifier"]
91
+ print("Ternary Coefficients:", tlm_model.coef_)
92
+ print("Test Accuracy:", clf.score(X_test, y_test))
93
+
94
+ ```
95
+
96
+ ## License
97
+
98
+ This project is licensed under the BSD-3-Clause License.
99
+
100
+ ## Authors
101
+
102
+ * **Author & Maintainer**: Rolf Carlson (rolf@hrolfrc.com)
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/tlmnet/__init__.py
5
+ src/tlmnet/_version.py
6
+ src/tlmnet/milp.py
7
+ src/tlmnet.egg-info/PKG-INFO
8
+ src/tlmnet.egg-info/SOURCES.txt
9
+ src/tlmnet.egg-info/dependency_links.txt
10
+ src/tlmnet.egg-info/requires.txt
11
+ src/tlmnet.egg-info/top_level.txt
@@ -0,0 +1,20 @@
1
+ numpy>=1.24.0
2
+ scipy>=1.10.0
3
+ scikit-learn>=1.6.0
4
+ joblib>=1.3.0
5
+ pandas
6
+ matplotlib
7
+
8
+ [dev]
9
+ pytest>=8.0.0
10
+ pytest-cov>=5.0.0
11
+ sphinx>=7.0.0
12
+ pydata-sphinx-theme>=0.15.0
13
+ sphinx-gallery
14
+ numpydoc
15
+ nbsphinx
16
+ pandoc
17
+ mypy>=1.8.0
18
+ pre-commit<3.8.0
19
+ build>=1.0.0
20
+ twine>=5.0.0
@@ -0,0 +1 @@
1
+ tlmnet