mfa-estimator 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.
- mfa_estimator-0.1.0/LICENSE +28 -0
- mfa_estimator-0.1.0/PKG-INFO +371 -0
- mfa_estimator-0.1.0/README.md +345 -0
- mfa_estimator-0.1.0/pyproject.toml +83 -0
- mfa_estimator-0.1.0/setup.cfg +4 -0
- mfa_estimator-0.1.0/src/mfa_estimator/__init__.py +7 -0
- mfa_estimator-0.1.0/src/mfa_estimator/estimator.py +309 -0
- mfa_estimator-0.1.0/src/mfa_estimator.egg-info/PKG-INFO +371 -0
- mfa_estimator-0.1.0/src/mfa_estimator.egg-info/SOURCES.txt +13 -0
- mfa_estimator-0.1.0/src/mfa_estimator.egg-info/dependency_links.txt +1 -0
- mfa_estimator-0.1.0/src/mfa_estimator.egg-info/requires.txt +2 -0
- mfa_estimator-0.1.0/src/mfa_estimator.egg-info/top_level.txt +1 -0
- mfa_estimator-0.1.0/tests/test_estimator.py +378 -0
- mfa_estimator-0.1.0/tests/test_examples.py +37 -0
- mfa_estimator-0.1.0/tests/test_import.py +13 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023, benediktfesl
|
|
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.
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mfa-estimator
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MFA-based estimator for linear inverse problems with complex-valued priors.
|
|
5
|
+
License-Expression: BSD-3-Clause
|
|
6
|
+
Project-URL: Homepage, https://github.com/benediktfesl/MFA_estimator
|
|
7
|
+
Project-URL: Repository, https://github.com/benediktfesl/MFA_estimator
|
|
8
|
+
Project-URL: Issues, https://github.com/benediktfesl/MFA_estimator/issues
|
|
9
|
+
Keywords: complex-valued,mixture of factor analyzers,MFA,linear inverse problems,MMSE,low-rank,signal processing
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: numpy>=1.23
|
|
24
|
+
Requires-Dist: cplx-mfa>=0.1.0
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# mfa-estimator
|
|
28
|
+
|
|
29
|
+
[](https://www.python.org/)
|
|
30
|
+
[](LICENSE)
|
|
31
|
+
[](https://pypi.org/project/mfa-estimator/)
|
|
32
|
+
|
|
33
|
+
MFA-based estimator for complex-valued linear inverse problems.
|
|
34
|
+
|
|
35
|
+
`mfa-estimator` provides an estimator for noisy linear observation models using a complex-valued mixture of factor analyzers (MFA) prior. The package builds on [cplx-mfa](https://pypi.org/project/cplx-mfa/) for fitting the complex-valued MFA prior and adds an estimation layer for inverse problems of the form
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
y = A h + n
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
where `h` is the unknown complex-valued vector, `A` is a known linear observation matrix, and `n` is complex Gaussian observation noise.
|
|
42
|
+
|
|
43
|
+
The estimator is domain-independent and can be used for linear inverse problems in signal processing, communications, and related applications. Channel estimation is one motivating application and is discussed in the research background section.
|
|
44
|
+
|
|
45
|
+
## ✨ Highlights
|
|
46
|
+
|
|
47
|
+
- MFA-based estimator for complex-valued linear inverse problems
|
|
48
|
+
- Supports general linear observation models of the form `y = A h + n`
|
|
49
|
+
- Uses complex-valued MFA priors fitted with [`cplx-mfa`](https://pypi.org/project/cplx-mfa/)
|
|
50
|
+
- Component-wise LMMSE estimation under the fitted mixture prior
|
|
51
|
+
- Posterior component weighting in the observation domain
|
|
52
|
+
- Supports identity and rectangular observation matrices
|
|
53
|
+
- Supports full posterior mixture estimates or truncated component sums
|
|
54
|
+
- scikit-learn-like workflow via inherited `fit(...)` and added `estimate(...)`
|
|
55
|
+
- Modern Python packaging with `pyproject.toml`, `uv`, `pytest`, and `ruff`
|
|
56
|
+
|
|
57
|
+
## 📌 Citation
|
|
58
|
+
|
|
59
|
+
If you use `mfa-estimator` in academic work, please cite the package directly:
|
|
60
|
+
|
|
61
|
+
```bibtex
|
|
62
|
+
@software{fesl_mfa_estimator,
|
|
63
|
+
author = {Fesl, Benedikt},
|
|
64
|
+
title = {{mfa-estimator}: MFA-based estimator for complex-valued linear inverse problems},
|
|
65
|
+
year = {2026},
|
|
66
|
+
url = {https://github.com/benediktfesl/MFA_estimator},
|
|
67
|
+
version = {0.1.0}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Plain-text citation:
|
|
72
|
+
|
|
73
|
+
> B. Fesl, `mfa-estimator`: MFA-based estimator for complex-valued linear inverse problems, version 0.1.0. Available: https://github.com/benediktfesl/MFA_estimator
|
|
74
|
+
|
|
75
|
+
If you use the estimator in the context of channel estimation, please also consider citing the related papers listed in the research background section.
|
|
76
|
+
|
|
77
|
+
## 📦 Installation
|
|
78
|
+
|
|
79
|
+
Install from PyPI:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install mfa-estimator
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
or with `uv`:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uv add mfa-estimator
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
For development, clone the repository and install the development environment:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
git clone https://github.com/benediktfesl/MFA_estimator.git
|
|
95
|
+
cd MFA_estimator
|
|
96
|
+
uv sync --group dev
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 🚀 Quick Start
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
import numpy as np
|
|
103
|
+
|
|
104
|
+
from mfa_estimator import MfaEstimator
|
|
105
|
+
|
|
106
|
+
rng = np.random.default_rng(0)
|
|
107
|
+
|
|
108
|
+
h_train = (
|
|
109
|
+
rng.normal(size=(1_000, 8))
|
|
110
|
+
+ 1j * rng.normal(size=(1_000, 8))
|
|
111
|
+
) / np.sqrt(2.0)
|
|
112
|
+
|
|
113
|
+
h_val = (
|
|
114
|
+
rng.normal(size=(100, 8))
|
|
115
|
+
+ 1j * rng.normal(size=(100, 8))
|
|
116
|
+
) / np.sqrt(2.0)
|
|
117
|
+
|
|
118
|
+
noise = (
|
|
119
|
+
rng.normal(size=(100, 8))
|
|
120
|
+
+ 1j * rng.normal(size=(100, 8))
|
|
121
|
+
) / np.sqrt(2.0)
|
|
122
|
+
|
|
123
|
+
# Identity observation model: y = h + n
|
|
124
|
+
noise_covariance = np.eye(8)
|
|
125
|
+
y = h_val + noise
|
|
126
|
+
|
|
127
|
+
estimator = MfaEstimator(
|
|
128
|
+
n_components=4,
|
|
129
|
+
latent_dim=2,
|
|
130
|
+
random_state=0,
|
|
131
|
+
max_iter=100,
|
|
132
|
+
verbose=False,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Fit the complex-valued MFA prior p(h).
|
|
136
|
+
estimator.fit(h_train)
|
|
137
|
+
|
|
138
|
+
# Estimate h from noisy observations y.
|
|
139
|
+
h_est = estimator.estimate(
|
|
140
|
+
y=y,
|
|
141
|
+
Cn=noise_covariance,
|
|
142
|
+
A=None,
|
|
143
|
+
n_summands_or_proba=1.0,
|
|
144
|
+
)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
The estimator follows a two-step pattern:
|
|
148
|
+
|
|
149
|
+
1. `fit(h_train)` fits the complex-valued MFA prior using the inherited `cplx-mfa` implementation.
|
|
150
|
+
2. `estimate(y, Cn, A)` estimates the unknown vector from noisy linear observations.
|
|
151
|
+
|
|
152
|
+
## 🧩 Estimation Model
|
|
153
|
+
|
|
154
|
+
The package assumes a linear observation model
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
y = A h + n
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
where:
|
|
161
|
+
|
|
162
|
+
| Symbol | Description |
|
|
163
|
+
|---|---|
|
|
164
|
+
| `h` | Unknown complex-valued vector to be estimated. |
|
|
165
|
+
| `y` | Noisy complex-valued observation. |
|
|
166
|
+
| `A` | Known linear observation matrix. |
|
|
167
|
+
| `n` | Zero-mean complex Gaussian noise with covariance `Cn`. |
|
|
168
|
+
|
|
169
|
+
The unknown vector `h` is modeled with a fitted complex-valued MFA prior:
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
p(h) = Σ_k π_k CN(h; μ_k, C_k)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
For each mixture component, the observation-domain model is
|
|
176
|
+
|
|
177
|
+
```text
|
|
178
|
+
y | k ~ CN(A μ_k, A C_k Aᴴ + Cn)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The estimator computes posterior component probabilities in the observation domain and combines component-wise LMMSE estimates.
|
|
182
|
+
|
|
183
|
+
## 🧠 Estimator API
|
|
184
|
+
|
|
185
|
+
The main class is:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
from mfa_estimator import MfaEstimator
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`MfaEstimator` inherits from [`cplx_mfa.ComplexMFA`](https://pypi.org/project/cplx-mfa/) and therefore supports the same prior-fitting API.
|
|
192
|
+
|
|
193
|
+
Core methods:
|
|
194
|
+
|
|
195
|
+
| Method | Description |
|
|
196
|
+
|---|---|
|
|
197
|
+
| `fit(X)` | Fit the complex-valued MFA prior. Inherited from `cplx-mfa`. |
|
|
198
|
+
| `predict(X)` | Predict the most likely MFA prior component. Inherited from `cplx-mfa`. |
|
|
199
|
+
| `predict_proba(X)` | Return prior-domain component probabilities. Inherited from `cplx-mfa`. |
|
|
200
|
+
| `sample(n_samples=1, rng=None)` | Draw samples from the fitted MFA prior. Inherited from `cplx-mfa`. |
|
|
201
|
+
| `estimate(y, Cn, A=None, n_summands_or_proba=1)` | Estimate unknown vectors from noisy linear observations. |
|
|
202
|
+
|
|
203
|
+
Constructor parameters are inherited from `ComplexMFA`:
|
|
204
|
+
|
|
205
|
+
| Parameter | Description |
|
|
206
|
+
|---|---|
|
|
207
|
+
| `n_components` | Number of mixture components. |
|
|
208
|
+
| `latent_dim` | Latent dimensionality of each factor analyzer. |
|
|
209
|
+
| `ppca` | If `True`, use one isotropic noise variance per component. |
|
|
210
|
+
| `lock_psis` | If `True`, use shared diagonal noise variances across components. |
|
|
211
|
+
| `rs_clip` | Lower clipping value for responsibilities during EM. |
|
|
212
|
+
| `max_condition_number` | Scaling factor used for random loading initialization. |
|
|
213
|
+
| `max_iter` | Maximum number of EM iterations. |
|
|
214
|
+
| `tol` | Relative convergence tolerance. |
|
|
215
|
+
| `random_state` | Integer seed or NumPy random generator used for initialization. |
|
|
216
|
+
| `verbose` | If `True`, print EM progress. |
|
|
217
|
+
|
|
218
|
+
The fitted prior parameters are exposed using the trailing-underscore attributes from `cplx-mfa`:
|
|
219
|
+
|
|
220
|
+
| Attribute | Description |
|
|
221
|
+
|---|---|
|
|
222
|
+
| `weights_` | Mixture weights of shape `(n_components,)`. |
|
|
223
|
+
| `means_` | Component means of shape `(n_components, n_features)`. |
|
|
224
|
+
| `loadings_` | Factor loading matrices of shape `(n_components, n_features, latent_dim)`. |
|
|
225
|
+
| `covariances_` | Full implied covariance matrices of shape `(n_components, n_features, n_features)`. |
|
|
226
|
+
| `precisions_` | Inverse covariance matrices of shape `(n_components, n_features, n_features)`. |
|
|
227
|
+
| `noise_variances_` | Diagonal noise variances of shape `(n_components, n_features)`. |
|
|
228
|
+
| `lower_bound_history_` | EM lower-bound values collected during fitting. |
|
|
229
|
+
|
|
230
|
+
## 🔎 Estimation
|
|
231
|
+
|
|
232
|
+
The main method added by this package is `estimate(...)`:
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
h_est = estimator.estimate(
|
|
236
|
+
y=y,
|
|
237
|
+
Cn=noise_covariance,
|
|
238
|
+
A=observation_matrix,
|
|
239
|
+
n_summands_or_proba=1.0,
|
|
240
|
+
)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Arguments:
|
|
244
|
+
|
|
245
|
+
| Argument | Description |
|
|
246
|
+
|---|---|
|
|
247
|
+
| `y` | Observations of shape `(n_samples, n_observations)`. |
|
|
248
|
+
| `Cn` | Observation noise covariance of shape `(n_observations, n_observations)`. |
|
|
249
|
+
| `A` | Observation matrix of shape `(n_observations, n_features)`. If `None`, the identity matrix is used. |
|
|
250
|
+
| `n_summands_or_proba` | Component-selection rule for the posterior mixture estimate. |
|
|
251
|
+
|
|
252
|
+
The component-selection parameter can be used in two ways:
|
|
253
|
+
|
|
254
|
+
| Value | Behavior |
|
|
255
|
+
|---|---|
|
|
256
|
+
| Integer, e.g. `1` or `5` | Use the corresponding number of most likely posterior components. |
|
|
257
|
+
| Float in `(0, 1]`, e.g. `0.9` | Use the fewest most likely components whose cumulative posterior probability reaches the threshold. |
|
|
258
|
+
| `1.0` | Use all components. |
|
|
259
|
+
|
|
260
|
+
## 🧪 Examples
|
|
261
|
+
|
|
262
|
+
Run the example script:
|
|
263
|
+
|
|
264
|
+
```bash
|
|
265
|
+
uv run python examples/mfa_estimator_example.py --nr 1
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Available examples:
|
|
269
|
+
|
|
270
|
+
| Number | Description |
|
|
271
|
+
|---|---|
|
|
272
|
+
| `1` | Identity observation model with component-wise diagonal noise variances. |
|
|
273
|
+
| `2` | Selection observation model with component-wise diagonal noise variances. |
|
|
274
|
+
| `3` | Identity observation model with shared diagonal noise variances. |
|
|
275
|
+
| `4` | Identity observation model with shared isotropic PPCA-style noise variances. |
|
|
276
|
+
|
|
277
|
+
Run all examples back to back:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
for nr in 1 2 3 4; do
|
|
281
|
+
uv run python examples/mfa_estimator_example.py --nr "$nr"
|
|
282
|
+
done
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Use `--help` to inspect the script interface:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
uv run python examples/mfa_estimator_example.py --help
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## 📚 Research Background
|
|
292
|
+
|
|
293
|
+
This package was originally developed in the context of low-rank structured MMSE estimation with mixture models. The implementation is domain-independent, but the motivating application is channel estimation in communication systems.
|
|
294
|
+
|
|
295
|
+
Related publications:
|
|
296
|
+
|
|
297
|
+
- B. Fesl, N. Turan, and W. Utschick, “Low-Rank Structured MMSE Channel Estimation with Mixtures of Factor Analyzers,” *57th Asilomar Conference on Signals, Systems, and Computers*, 2023.
|
|
298
|
+
[[IEEE](https://ieeexplore.ieee.org/document/10477088)] [[arXiv](https://arxiv.org/abs/2304.14809)]
|
|
299
|
+
|
|
300
|
+
- B. Fesl, N. Turan, B. Böck, and W. Utschick, “Channel Estimation for Quantized Systems based on Conditionally Gaussian Latent Models,” *IEEE Transactions on Signal Processing*, 2024.
|
|
301
|
+
[[IEEE](https://ieeexplore.ieee.org/document/10454252)] [[arXiv](https://arxiv.org/abs/2309.04014)]
|
|
302
|
+
|
|
303
|
+
- B. Fesl, “Generative Model-Aided Channel Estimation Design and Optimality Analysis,” *Ph.D. dissertation, Technical University of Munich*, 2025.
|
|
304
|
+
[[Link](https://mediatum.ub.tum.de/?id=1748775)]
|
|
305
|
+
|
|
306
|
+
## 🧪 Development
|
|
307
|
+
|
|
308
|
+
Install the development environment with `uv`:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
uv sync --group dev
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Run tests:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
uv run pytest
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Run linting:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
uv run ruff check .
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Format code:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
uv run ruff format .
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Run an example:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
uv run python examples/mfa_estimator_example.py --nr 1
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Build the package:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
uv run python -m build
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Check the package distribution:
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
uv run twine check dist/*
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## ✅ Test Coverage
|
|
351
|
+
|
|
352
|
+
The test suite covers:
|
|
353
|
+
|
|
354
|
+
- package imports
|
|
355
|
+
- integration with the `cplx-mfa` package
|
|
356
|
+
- estimation with identity observation matrices
|
|
357
|
+
- estimation with rectangular observation matrices
|
|
358
|
+
- estimation with complex-valued observation matrices
|
|
359
|
+
- real-valued input handling
|
|
360
|
+
- posterior probability normalization
|
|
361
|
+
- component-count selection
|
|
362
|
+
- cumulative-probability selection
|
|
363
|
+
- unfitted-estimator behavior
|
|
364
|
+
- invalid input validation
|
|
365
|
+
- non-finite input validation
|
|
366
|
+
- preservation of fitted prior parameters during estimation
|
|
367
|
+
- example script execution
|
|
368
|
+
|
|
369
|
+
## 📄 License
|
|
370
|
+
|
|
371
|
+
This project is licensed under the [BSD 3-Clause License](LICENSE).
|