ds2-toolkit 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.
- ds2_toolkit-0.1.0/LICENSE +28 -0
- ds2_toolkit-0.1.0/PKG-INFO +127 -0
- ds2_toolkit-0.1.0/README.md +85 -0
- ds2_toolkit-0.1.0/pyproject.toml +67 -0
- ds2_toolkit-0.1.0/setup.cfg +4 -0
- ds2_toolkit-0.1.0/src/ds2/__init__.py +70 -0
- ds2_toolkit-0.1.0/src/ds2/cascade.py +138 -0
- ds2_toolkit-0.1.0/src/ds2/compiler.py +137 -0
- ds2_toolkit-0.1.0/src/ds2/core.py +166 -0
- ds2_toolkit-0.1.0/src/ds2/correction.py +174 -0
- ds2_toolkit-0.1.0/src/ds2/domains.py +211 -0
- ds2_toolkit-0.1.0/src/ds2/phase.py +142 -0
- ds2_toolkit-0.1.0/src/ds2/thermo.py +140 -0
- ds2_toolkit-0.1.0/src/ds2_toolkit.egg-info/PKG-INFO +127 -0
- ds2_toolkit-0.1.0/src/ds2_toolkit.egg-info/SOURCES.txt +23 -0
- ds2_toolkit-0.1.0/src/ds2_toolkit.egg-info/dependency_links.txt +1 -0
- ds2_toolkit-0.1.0/src/ds2_toolkit.egg-info/requires.txt +18 -0
- ds2_toolkit-0.1.0/src/ds2_toolkit.egg-info/top_level.txt +1 -0
- ds2_toolkit-0.1.0/tests/test_cascade.py +59 -0
- ds2_toolkit-0.1.0/tests/test_compiler.py +44 -0
- ds2_toolkit-0.1.0/tests/test_core.py +107 -0
- ds2_toolkit-0.1.0/tests/test_correction.py +92 -0
- ds2_toolkit-0.1.0/tests/test_domains.py +103 -0
- ds2_toolkit-0.1.0/tests/test_phase.py +63 -0
- ds2_toolkit-0.1.0/tests/test_thermo.py +68 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, David Tom Foss
|
|
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,127 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ds2-toolkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Algebraic toolkit for 2x2 doubly stochastic matrices: cascade, entropy, correction, phase recovery, and compilation
|
|
5
|
+
Author-email: David Tom Foss <david@foss.com.de>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/davidtomfoss/ds2
|
|
8
|
+
Project-URL: Documentation, https://ds2.readthedocs.io
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/davidtomfoss/ds2/issues
|
|
10
|
+
Project-URL: Paper (Foundations), https://doi.org/TBD
|
|
11
|
+
Project-URL: Paper (Toolkit), https://doi.org/TBD
|
|
12
|
+
Keywords: doubly stochastic,scattering matrix,cascade analysis,Birkhoff polytope,insertion loss,Landauer principle,error correction,two-port network
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: numpy>=1.24
|
|
28
|
+
Provides-Extra: rf
|
|
29
|
+
Requires-Dist: scikit-rf>=0.30; extra == "rf"
|
|
30
|
+
Provides-Extra: test
|
|
31
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
32
|
+
Requires-Dist: pytest-cov>=4.0; extra == "test"
|
|
33
|
+
Provides-Extra: docs
|
|
34
|
+
Requires-Dist: sphinx>=7.0; extra == "docs"
|
|
35
|
+
Requires-Dist: sphinx-book-theme; extra == "docs"
|
|
36
|
+
Requires-Dist: myst-nb; extra == "docs"
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: ds2[docs,rf,test]; extra == "dev"
|
|
39
|
+
Requires-Dist: ruff; extra == "dev"
|
|
40
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
# DS2 — Algebraic Toolkit for 2x2 Doubly Stochastic Matrices
|
|
44
|
+
|
|
45
|
+
[](https://pypi.org/project/ds2/)
|
|
46
|
+
[](https://pypi.org/project/ds2/)
|
|
47
|
+
[](https://github.com/davidtomfoss/ds2/blob/main/LICENSE)
|
|
48
|
+
[]()
|
|
49
|
+
|
|
50
|
+
**One scalar replaces four complex scattering parameters.**
|
|
51
|
+
|
|
52
|
+
Every 2x2 doubly stochastic matrix is uniquely determined by a single eigenvalue
|
|
53
|
+
`lambda in [-1, 1]`, and `P(a) * P(b) = P(a*b)`. This monoid structure reduces
|
|
54
|
+
cascade analysis to scalar multiplication — no matrix algebra needed.
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install ds2
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import ds2
|
|
66
|
+
|
|
67
|
+
# Build a P(lambda) matrix
|
|
68
|
+
P = ds2.matrix(0.7)
|
|
69
|
+
# array([[0.85, 0.15],
|
|
70
|
+
# [0.15, 0.85]])
|
|
71
|
+
|
|
72
|
+
# Cascade 4 devices: just multiply eigenvalues
|
|
73
|
+
result = ds2.cascade([0.9, 0.8, -0.5, 0.95])
|
|
74
|
+
print(result.eigenvalue) # -0.342
|
|
75
|
+
print(result.insertion_loss_db) # 3.33 dB
|
|
76
|
+
|
|
77
|
+
# Analog error correction (k=3 repetition code)
|
|
78
|
+
ds2.correct(0.3, k=3) # 0.4365 — repels from 0
|
|
79
|
+
|
|
80
|
+
# Compile a target IL from standard components
|
|
81
|
+
r = ds2.compile(target_il=7.0)
|
|
82
|
+
print(r.chain) # ('6dB', '1dB')
|
|
83
|
+
print(r.error_db) # 0.0
|
|
84
|
+
|
|
85
|
+
# Landauer efficiency (quasistatic erasure)
|
|
86
|
+
ds2.landauer_efficiency(delta_0=0.9, delta_f=0.1, k=100)
|
|
87
|
+
# {'eta': 0.982, 'delta_h': 0.469, 'dissipation': 0.009, ...}
|
|
88
|
+
|
|
89
|
+
# 13-domain universality
|
|
90
|
+
ds2.domains.bsc(epsilon=0.1) # 0.8
|
|
91
|
+
ds2.domains.beam_splitter(reflectance=0.3) # -0.4
|
|
92
|
+
ds2.domains.scattering(s11_sq=0.3) # -0.4
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Five Tools
|
|
96
|
+
|
|
97
|
+
| Tool | What it does | Key result |
|
|
98
|
+
|------|-------------|------------|
|
|
99
|
+
| **Cascade** | `lambda_total = prod(lambda_i)` | Error < 10^-16 |
|
|
100
|
+
| **Thermodynamics** | Entropy budget + Landauer cost | eta -> 1 as k -> inf |
|
|
101
|
+
| **Correction** | `f_3(lambda) = (3*lambda - lambda^3)/2` | 26.5x capacity gain |
|
|
102
|
+
| **Phase recovery** | Interferometric S-matrix reconstruction | 100% on 1000 unitaries |
|
|
103
|
+
| **Compiler** | Target IL -> device chain | 0.00 dB error |
|
|
104
|
+
|
|
105
|
+
## Thirteen Domains
|
|
106
|
+
|
|
107
|
+
The DS2 monoid appears in: microwave scattering, quantum gates, Markov chains,
|
|
108
|
+
softmax/neural networks, optical beam splitters, population genetics, resistor
|
|
109
|
+
dividers, polarization (Malus's law), IIR filters, binary symmetric channels,
|
|
110
|
+
synaptic transmission, gene regulation, and epidemic transmission.
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from ds2.domains import DOMAIN_TABLE
|
|
114
|
+
for d in DOMAIN_TABLE:
|
|
115
|
+
print(f"{d['domain']:30s} lambda = {d['lambda']}")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## References
|
|
119
|
+
|
|
120
|
+
- D. T. Foss, "Algebraic Structure of Doubly Stochastic Power Matrices in
|
|
121
|
+
Electromagnetic Scattering," Proc. ICEAA/APWC, Toyama, Japan, Sep. 2026.
|
|
122
|
+
- D. T. Foss, "The DS2 Toolkit: Algebraic Methods for Two-Port Network Analysis
|
|
123
|
+
Across Thirteen Domains," Proc. ICEAA/APWC, Toyama, Japan, Sep. 2026.
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
BSD 3-Clause. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# DS2 — Algebraic Toolkit for 2x2 Doubly Stochastic Matrices
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/ds2/)
|
|
4
|
+
[](https://pypi.org/project/ds2/)
|
|
5
|
+
[](https://github.com/davidtomfoss/ds2/blob/main/LICENSE)
|
|
6
|
+
[]()
|
|
7
|
+
|
|
8
|
+
**One scalar replaces four complex scattering parameters.**
|
|
9
|
+
|
|
10
|
+
Every 2x2 doubly stochastic matrix is uniquely determined by a single eigenvalue
|
|
11
|
+
`lambda in [-1, 1]`, and `P(a) * P(b) = P(a*b)`. This monoid structure reduces
|
|
12
|
+
cascade analysis to scalar multiplication — no matrix algebra needed.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install ds2
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import ds2
|
|
24
|
+
|
|
25
|
+
# Build a P(lambda) matrix
|
|
26
|
+
P = ds2.matrix(0.7)
|
|
27
|
+
# array([[0.85, 0.15],
|
|
28
|
+
# [0.15, 0.85]])
|
|
29
|
+
|
|
30
|
+
# Cascade 4 devices: just multiply eigenvalues
|
|
31
|
+
result = ds2.cascade([0.9, 0.8, -0.5, 0.95])
|
|
32
|
+
print(result.eigenvalue) # -0.342
|
|
33
|
+
print(result.insertion_loss_db) # 3.33 dB
|
|
34
|
+
|
|
35
|
+
# Analog error correction (k=3 repetition code)
|
|
36
|
+
ds2.correct(0.3, k=3) # 0.4365 — repels from 0
|
|
37
|
+
|
|
38
|
+
# Compile a target IL from standard components
|
|
39
|
+
r = ds2.compile(target_il=7.0)
|
|
40
|
+
print(r.chain) # ('6dB', '1dB')
|
|
41
|
+
print(r.error_db) # 0.0
|
|
42
|
+
|
|
43
|
+
# Landauer efficiency (quasistatic erasure)
|
|
44
|
+
ds2.landauer_efficiency(delta_0=0.9, delta_f=0.1, k=100)
|
|
45
|
+
# {'eta': 0.982, 'delta_h': 0.469, 'dissipation': 0.009, ...}
|
|
46
|
+
|
|
47
|
+
# 13-domain universality
|
|
48
|
+
ds2.domains.bsc(epsilon=0.1) # 0.8
|
|
49
|
+
ds2.domains.beam_splitter(reflectance=0.3) # -0.4
|
|
50
|
+
ds2.domains.scattering(s11_sq=0.3) # -0.4
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Five Tools
|
|
54
|
+
|
|
55
|
+
| Tool | What it does | Key result |
|
|
56
|
+
|------|-------------|------------|
|
|
57
|
+
| **Cascade** | `lambda_total = prod(lambda_i)` | Error < 10^-16 |
|
|
58
|
+
| **Thermodynamics** | Entropy budget + Landauer cost | eta -> 1 as k -> inf |
|
|
59
|
+
| **Correction** | `f_3(lambda) = (3*lambda - lambda^3)/2` | 26.5x capacity gain |
|
|
60
|
+
| **Phase recovery** | Interferometric S-matrix reconstruction | 100% on 1000 unitaries |
|
|
61
|
+
| **Compiler** | Target IL -> device chain | 0.00 dB error |
|
|
62
|
+
|
|
63
|
+
## Thirteen Domains
|
|
64
|
+
|
|
65
|
+
The DS2 monoid appears in: microwave scattering, quantum gates, Markov chains,
|
|
66
|
+
softmax/neural networks, optical beam splitters, population genetics, resistor
|
|
67
|
+
dividers, polarization (Malus's law), IIR filters, binary symmetric channels,
|
|
68
|
+
synaptic transmission, gene regulation, and epidemic transmission.
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from ds2.domains import DOMAIN_TABLE
|
|
72
|
+
for d in DOMAIN_TABLE:
|
|
73
|
+
print(f"{d['domain']:30s} lambda = {d['lambda']}")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## References
|
|
77
|
+
|
|
78
|
+
- D. T. Foss, "Algebraic Structure of Doubly Stochastic Power Matrices in
|
|
79
|
+
Electromagnetic Scattering," Proc. ICEAA/APWC, Toyama, Japan, Sep. 2026.
|
|
80
|
+
- D. T. Foss, "The DS2 Toolkit: Algebraic Methods for Two-Port Network Analysis
|
|
81
|
+
Across Thirteen Domains," Proc. ICEAA/APWC, Toyama, Japan, Sep. 2026.
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
BSD 3-Clause. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ds2-toolkit"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Algebraic toolkit for 2x2 doubly stochastic matrices: cascade, entropy, correction, phase recovery, and compilation"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "BSD-3-Clause"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "David Tom Foss", email = "david@foss.com.de"},
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"doubly stochastic",
|
|
17
|
+
"scattering matrix",
|
|
18
|
+
"cascade analysis",
|
|
19
|
+
"Birkhoff polytope",
|
|
20
|
+
"insertion loss",
|
|
21
|
+
"Landauer principle",
|
|
22
|
+
"error correction",
|
|
23
|
+
"two-port network",
|
|
24
|
+
]
|
|
25
|
+
classifiers = [
|
|
26
|
+
"Development Status :: 3 - Alpha",
|
|
27
|
+
"Intended Audience :: Science/Research",
|
|
28
|
+
"Operating System :: OS Independent",
|
|
29
|
+
"Programming Language :: Python :: 3",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
"Programming Language :: Python :: 3.13",
|
|
34
|
+
"Topic :: Scientific/Engineering :: Physics",
|
|
35
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
36
|
+
"Typing :: Typed",
|
|
37
|
+
]
|
|
38
|
+
dependencies = [
|
|
39
|
+
"numpy>=1.24",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.optional-dependencies]
|
|
43
|
+
rf = ["scikit-rf>=0.30"]
|
|
44
|
+
test = ["pytest>=7.0", "pytest-cov>=4.0"]
|
|
45
|
+
docs = ["sphinx>=7.0", "sphinx-book-theme", "myst-nb"]
|
|
46
|
+
dev = ["ds2[rf,test,docs]", "ruff", "pre-commit"]
|
|
47
|
+
|
|
48
|
+
[project.urls]
|
|
49
|
+
Homepage = "https://github.com/davidtomfoss/ds2"
|
|
50
|
+
Documentation = "https://ds2.readthedocs.io"
|
|
51
|
+
"Bug Tracker" = "https://github.com/davidtomfoss/ds2/issues"
|
|
52
|
+
"Paper (Foundations)" = "https://doi.org/TBD"
|
|
53
|
+
"Paper (Toolkit)" = "https://doi.org/TBD"
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.packages.find]
|
|
56
|
+
where = ["src"]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
testpaths = ["tests"]
|
|
60
|
+
addopts = "--cov=ds2 --cov-report=term-missing -v"
|
|
61
|
+
|
|
62
|
+
[tool.ruff]
|
|
63
|
+
target-version = "py310"
|
|
64
|
+
line-length = 88
|
|
65
|
+
|
|
66
|
+
[tool.ruff.lint]
|
|
67
|
+
select = ["E", "F", "W", "I", "UP", "NPY"]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""DS2: Algebraic toolkit for 2x2 doubly stochastic matrices.
|
|
2
|
+
|
|
3
|
+
The DS2 monoid: every 2x2 doubly stochastic matrix is P(lambda) for a unique
|
|
4
|
+
lambda in [-1, 1], and P(a) * P(b) = P(ab). This single-scalar parameterization
|
|
5
|
+
replaces four complex scattering parameters for power-level two-port analysis.
|
|
6
|
+
|
|
7
|
+
Five core tools:
|
|
8
|
+
1. Cascade-by-multiplication (cascade)
|
|
9
|
+
2. Thermodynamic analysis (thermo)
|
|
10
|
+
3. Analog error correction (correction)
|
|
11
|
+
4. Phase recovery (phase)
|
|
12
|
+
5. Cascade compiler (compiler)
|
|
13
|
+
|
|
14
|
+
Universal across 13 domains (domains).
|
|
15
|
+
|
|
16
|
+
Example::
|
|
17
|
+
|
|
18
|
+
>>> import ds2
|
|
19
|
+
>>> P = ds2.matrix(0.7)
|
|
20
|
+
>>> ds2.cascade([0.9, 0.8, -0.5, 0.95])
|
|
21
|
+
CascadeResult(eigenvalue=-0.342, insertion_loss_db=...)
|
|
22
|
+
>>> ds2.correct(0.3, k=3)
|
|
23
|
+
0.4365...
|
|
24
|
+
|
|
25
|
+
References:
|
|
26
|
+
D. T. Foss, "Algebraic Structure of Doubly Stochastic Power Matrices
|
|
27
|
+
in Electromagnetic Scattering," Proc. ICEAA/APWC, Toyama, 2026.
|
|
28
|
+
|
|
29
|
+
D. T. Foss, "The DS2 Toolkit: Algebraic Methods for Two-Port Network
|
|
30
|
+
Analysis Across Thirteen Domains," Proc. ICEAA/APWC, Toyama, 2026.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
__version__ = "0.1.0"
|
|
34
|
+
|
|
35
|
+
from ds2.core import matrix, eigenvalue, insertion_loss, from_insertion_loss
|
|
36
|
+
from ds2.cascade import cascade, CascadeResult
|
|
37
|
+
from ds2.thermo import entropy, entropy_change, landauer_cost, landauer_efficiency
|
|
38
|
+
from ds2.correction import correct, correction_polynomial, duality_fixed_points
|
|
39
|
+
from ds2.phase import recover_phase_2port
|
|
40
|
+
from ds2.compiler import compile, CompilerResult, STANDARD_LIBRARY
|
|
41
|
+
from ds2 import domains
|
|
42
|
+
|
|
43
|
+
__all__ = [
|
|
44
|
+
"__version__",
|
|
45
|
+
# core
|
|
46
|
+
"matrix",
|
|
47
|
+
"eigenvalue",
|
|
48
|
+
"insertion_loss",
|
|
49
|
+
"from_insertion_loss",
|
|
50
|
+
# cascade
|
|
51
|
+
"cascade",
|
|
52
|
+
"CascadeResult",
|
|
53
|
+
# thermo
|
|
54
|
+
"entropy",
|
|
55
|
+
"entropy_change",
|
|
56
|
+
"landauer_cost",
|
|
57
|
+
"landauer_efficiency",
|
|
58
|
+
# correction
|
|
59
|
+
"correct",
|
|
60
|
+
"correction_polynomial",
|
|
61
|
+
"duality_fixed_points",
|
|
62
|
+
# phase
|
|
63
|
+
"recover_phase_2port",
|
|
64
|
+
# compiler
|
|
65
|
+
"compile",
|
|
66
|
+
"CompilerResult",
|
|
67
|
+
"STANDARD_LIBRARY",
|
|
68
|
+
# domains
|
|
69
|
+
"domains",
|
|
70
|
+
]
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""Cascade-by-multiplication: reduce k-device chain to scalar arithmetic.
|
|
2
|
+
|
|
3
|
+
The DS2 monoid product P(a) * P(b) = P(ab) means cascading k lossless
|
|
4
|
+
two-port devices with eigenvalues lambda_1, ..., lambda_k gives:
|
|
5
|
+
|
|
6
|
+
lambda_total = prod(lambda_i)
|
|
7
|
+
IL_total = sum(IL_i) [in dB]
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from dataclasses import dataclass, field
|
|
13
|
+
from typing import Sequence
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
|
|
17
|
+
from ds2.core import insertion_loss, matrix
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class CascadeResult:
|
|
22
|
+
"""Result of cascading multiple DS2 devices.
|
|
23
|
+
|
|
24
|
+
Attributes
|
|
25
|
+
----------
|
|
26
|
+
eigenvalue : float
|
|
27
|
+
Product eigenvalue of the cascade.
|
|
28
|
+
insertion_loss_db : float
|
|
29
|
+
Total insertion loss in dB.
|
|
30
|
+
matrix : np.ndarray
|
|
31
|
+
The 2x2 doubly stochastic matrix P(eigenvalue).
|
|
32
|
+
individual : tuple[float, ...]
|
|
33
|
+
Individual eigenvalues in cascade order.
|
|
34
|
+
cumulative : tuple[float, ...]
|
|
35
|
+
Cumulative eigenvalue after each stage.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
eigenvalue: float
|
|
39
|
+
insertion_loss_db: float
|
|
40
|
+
matrix: np.ndarray = field(repr=False)
|
|
41
|
+
individual: tuple[float, ...] = field(repr=False)
|
|
42
|
+
cumulative: tuple[float, ...] = field(repr=False)
|
|
43
|
+
|
|
44
|
+
def __repr__(self) -> str:
|
|
45
|
+
return (
|
|
46
|
+
f"CascadeResult(eigenvalue={self.eigenvalue:.6f}, "
|
|
47
|
+
f"insertion_loss_db={self.insertion_loss_db:.4f}, "
|
|
48
|
+
f"stages={len(self.individual)})"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def cascade(eigenvalues: Sequence[float]) -> CascadeResult:
|
|
53
|
+
"""Cascade k devices by multiplying their eigenvalues.
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
eigenvalues : sequence of float
|
|
58
|
+
Eigenvalues lambda_i in [-1, 1] for each device.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
CascadeResult
|
|
63
|
+
Contains product eigenvalue, total IL, cumulative trace.
|
|
64
|
+
|
|
65
|
+
Raises
|
|
66
|
+
------
|
|
67
|
+
ValueError
|
|
68
|
+
If any eigenvalue is outside [-1, 1] or sequence is empty.
|
|
69
|
+
|
|
70
|
+
Examples
|
|
71
|
+
--------
|
|
72
|
+
>>> r = cascade([0.9, 0.8, 0.7])
|
|
73
|
+
>>> abs(r.eigenvalue - 0.9 * 0.8 * 0.7) < 1e-15
|
|
74
|
+
True
|
|
75
|
+
"""
|
|
76
|
+
evs = list(eigenvalues)
|
|
77
|
+
if not evs:
|
|
78
|
+
raise ValueError("Need at least one eigenvalue")
|
|
79
|
+
for i, lam in enumerate(evs):
|
|
80
|
+
if not -1.0 <= lam <= 1.0:
|
|
81
|
+
raise ValueError(f"eigenvalue[{i}] = {lam} outside [-1, 1]")
|
|
82
|
+
|
|
83
|
+
cum = []
|
|
84
|
+
prod = 1.0
|
|
85
|
+
for lam in evs:
|
|
86
|
+
prod *= lam
|
|
87
|
+
cum.append(prod)
|
|
88
|
+
|
|
89
|
+
lam_total = cum[-1]
|
|
90
|
+
il_db = insertion_loss(lam_total)
|
|
91
|
+
P = matrix(lam_total)
|
|
92
|
+
|
|
93
|
+
return CascadeResult(
|
|
94
|
+
eigenvalue=lam_total,
|
|
95
|
+
insertion_loss_db=il_db,
|
|
96
|
+
matrix=P,
|
|
97
|
+
individual=tuple(evs),
|
|
98
|
+
cumulative=tuple(cum),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def link_budget(
|
|
103
|
+
devices: Sequence[tuple[str, float]],
|
|
104
|
+
) -> list[dict[str, float | str]]:
|
|
105
|
+
"""Compute a link budget table for named devices.
|
|
106
|
+
|
|
107
|
+
Parameters
|
|
108
|
+
----------
|
|
109
|
+
devices : sequence of (name, eigenvalue) tuples
|
|
110
|
+
Each device with its name and eigenvalue.
|
|
111
|
+
|
|
112
|
+
Returns
|
|
113
|
+
-------
|
|
114
|
+
list of dict
|
|
115
|
+
Each dict has keys: 'device', 'eigenvalue', 'cumulative_eigenvalue',
|
|
116
|
+
'cumulative_il_db'.
|
|
117
|
+
|
|
118
|
+
Examples
|
|
119
|
+
--------
|
|
120
|
+
>>> budget = link_budget([("coupler", -0.002), ("mismatch", -0.589)])
|
|
121
|
+
>>> budget[1]['cumulative_il_db'] # doctest: +SKIP
|
|
122
|
+
3.01...
|
|
123
|
+
"""
|
|
124
|
+
rows = []
|
|
125
|
+
prod = 1.0
|
|
126
|
+
for name, lam in devices:
|
|
127
|
+
if not -1.0 <= lam <= 1.0:
|
|
128
|
+
raise ValueError(f"eigenvalue for '{name}' = {lam} outside [-1, 1]")
|
|
129
|
+
prod *= lam
|
|
130
|
+
rows.append(
|
|
131
|
+
{
|
|
132
|
+
"device": name,
|
|
133
|
+
"eigenvalue": lam,
|
|
134
|
+
"cumulative_eigenvalue": prod,
|
|
135
|
+
"cumulative_il_db": insertion_loss(prod),
|
|
136
|
+
}
|
|
137
|
+
)
|
|
138
|
+
return rows
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""Cascade compiler: find exact device chains for target insertion loss.
|
|
2
|
+
|
|
3
|
+
Since IL values add in dB under cascade (log|lambda| is additive),
|
|
4
|
+
cascade design reduces to subset-sum on IL values.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import Sequence
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Standard component library (name, IL in dB)
|
|
16
|
+
STANDARD_LIBRARY: list[tuple[str, float]] = [
|
|
17
|
+
("20dB", 20.0),
|
|
18
|
+
("10dB", 10.0),
|
|
19
|
+
("6dB", 6.0),
|
|
20
|
+
("3dB", 3.0),
|
|
21
|
+
("1dB", 1.0),
|
|
22
|
+
("0.5dB", 0.5),
|
|
23
|
+
("0.1dB", 0.1),
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class CompilerResult:
|
|
29
|
+
"""Result of cascade compilation.
|
|
30
|
+
|
|
31
|
+
Attributes
|
|
32
|
+
----------
|
|
33
|
+
chain : tuple[str, ...]
|
|
34
|
+
Device names in the compiled chain.
|
|
35
|
+
target_il_db : float
|
|
36
|
+
Requested insertion loss.
|
|
37
|
+
achieved_il_db : float
|
|
38
|
+
Achieved insertion loss.
|
|
39
|
+
error_db : float
|
|
40
|
+
|target - achieved| in dB.
|
|
41
|
+
eigenvalue : float
|
|
42
|
+
Equivalent eigenvalue of the chain.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
chain: tuple[str, ...]
|
|
46
|
+
target_il_db: float
|
|
47
|
+
achieved_il_db: float
|
|
48
|
+
error_db: float
|
|
49
|
+
eigenvalue: float
|
|
50
|
+
|
|
51
|
+
def __repr__(self) -> str:
|
|
52
|
+
chain_str = " + ".join(self.chain)
|
|
53
|
+
return (
|
|
54
|
+
f"CompilerResult(chain=[{chain_str}], "
|
|
55
|
+
f"target={self.target_il_db:.2f}dB, "
|
|
56
|
+
f"achieved={self.achieved_il_db:.2f}dB, "
|
|
57
|
+
f"error={self.error_db:.2f}dB)"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def compile(
|
|
62
|
+
target_il: float,
|
|
63
|
+
library: Sequence[tuple[str, float]] | None = None,
|
|
64
|
+
tolerance: float = 0.05,
|
|
65
|
+
) -> CompilerResult:
|
|
66
|
+
"""Find a device chain achieving the target insertion loss.
|
|
67
|
+
|
|
68
|
+
Uses a greedy algorithm on a sorted library. For practical libraries
|
|
69
|
+
(< 20 component types), this achieves exact solutions.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
target_il : float
|
|
74
|
+
Target insertion loss in dB (> 0).
|
|
75
|
+
library : sequence of (name, IL_dB) tuples, optional
|
|
76
|
+
Component library. Defaults to STANDARD_LIBRARY.
|
|
77
|
+
tolerance : float
|
|
78
|
+
Acceptable error in dB.
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
CompilerResult
|
|
83
|
+
Compiled chain with achieved IL and error.
|
|
84
|
+
|
|
85
|
+
Examples
|
|
86
|
+
--------
|
|
87
|
+
>>> r = compile(7.0)
|
|
88
|
+
>>> r.chain
|
|
89
|
+
('6dB', '1dB')
|
|
90
|
+
>>> r.error_db
|
|
91
|
+
0.0
|
|
92
|
+
"""
|
|
93
|
+
if target_il <= 0.0:
|
|
94
|
+
raise ValueError(f"target_il must be > 0, got {target_il}")
|
|
95
|
+
if library is None:
|
|
96
|
+
library = STANDARD_LIBRARY
|
|
97
|
+
|
|
98
|
+
# Sort by IL descending
|
|
99
|
+
lib = sorted(library, key=lambda x: x[1], reverse=True)
|
|
100
|
+
|
|
101
|
+
chain: list[str] = []
|
|
102
|
+
current_il = 0.0
|
|
103
|
+
|
|
104
|
+
while abs(current_il - target_il) > tolerance:
|
|
105
|
+
remaining = target_il - current_il
|
|
106
|
+
if remaining <= 0:
|
|
107
|
+
break
|
|
108
|
+
|
|
109
|
+
# Find best component
|
|
110
|
+
best_name = None
|
|
111
|
+
best_il = 0.0
|
|
112
|
+
best_gap = float("inf")
|
|
113
|
+
|
|
114
|
+
for name, il in lib:
|
|
115
|
+
if il <= remaining + tolerance:
|
|
116
|
+
gap = abs(remaining - il)
|
|
117
|
+
if gap < best_gap:
|
|
118
|
+
best_gap = gap
|
|
119
|
+
best_name = name
|
|
120
|
+
best_il = il
|
|
121
|
+
|
|
122
|
+
if best_name is None:
|
|
123
|
+
break
|
|
124
|
+
|
|
125
|
+
chain.append(best_name)
|
|
126
|
+
current_il += best_il
|
|
127
|
+
|
|
128
|
+
error = abs(current_il - target_il)
|
|
129
|
+
lam = 1.0 - 2.0 * 10.0 ** (-current_il / 10.0) if current_il > 0 else 1.0
|
|
130
|
+
|
|
131
|
+
return CompilerResult(
|
|
132
|
+
chain=tuple(chain),
|
|
133
|
+
target_il_db=target_il,
|
|
134
|
+
achieved_il_db=round(current_il, 10),
|
|
135
|
+
error_db=round(error, 10),
|
|
136
|
+
eigenvalue=lam,
|
|
137
|
+
)
|