fxtensor-salmon 1.2.0__tar.gz → 1.2.1__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.
- {fxtensor_salmon-1.2.0/src/fxtensor_salmon.egg-info → fxtensor_salmon-1.2.1}/PKG-INFO +18 -1
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/README.md +17 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/pyproject.toml +1 -1
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon/operations.py +50 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1/src/fxtensor_salmon.egg-info}/PKG-INFO +18 -1
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon.egg-info/SOURCES.txt +1 -0
- fxtensor_salmon-1.2.1/tests/test_almost_surely.py +158 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/LICENSE +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/setup.cfg +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon/__init__.py +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon/core.py +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon/discopy.py +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon/io.py +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon/profile.py +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon/special.py +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon.egg-info/dependency_links.txt +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon.egg-info/requires.txt +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon.egg-info/top_level.txt +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/tests/test_axioms.py +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/tests/test_discopy.py +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/tests/test_fxtensor.py +0 -0
- {fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/tests/test_inference.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fxtensor_salmon
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: Markov Tensor Module
|
|
5
5
|
Author-email: Tadachika Oki <sakesnare@gmail.com>
|
|
6
6
|
License: Copyright 2025 Tadachika Oki
|
|
@@ -383,6 +383,8 @@ The `fxtensor-salmon` library is designed based on the **Markov Category**, a fr
|
|
|
383
383
|
| `jointification` | Joint of two states | Combine two independent states (states only) |
|
|
384
384
|
| `conditional` | Kernel `A → X ⊗ Y` → `A ⊗ X → Y` | Conditionalize a kernel (generalizes `conditionalization`) |
|
|
385
385
|
| `bayesian_inversion` | `f: X → Y` and prior `I → X` → `f†: Y → X` | Bayesian update / posterior kernel |
|
|
386
|
+
| `almost_surely_equal` | `f = g` p-a.s. | Compare kernels only where the prior has mass |
|
|
387
|
+
| `is_absolutely_continuous` | `p ≪ q` | Check support inclusion of states / kernels |
|
|
386
388
|
| `exclamation` | Discard morphism `X → I` | Build an all-ones discarding tensor |
|
|
387
389
|
| `copy_tensor` | Copy morphism `X → X^{⊗ n}` | Deterministic copy / diagonal (`n=0` is discard) |
|
|
388
390
|
| `delta_tensor` | Identity (alias of `identity_tensor`) | Build an identity kernel |
|
|
@@ -494,6 +496,20 @@ assert c.labels == ([['a'], ['x0', 'x1']], [['y0', 'y1']])
|
|
|
494
496
|
assert np.allclose(c.data, [[[0.25, 0.75], [1/3, 2/3]]])
|
|
495
497
|
```
|
|
496
498
|
|
|
499
|
+
#### `support`, `almost_surely_equal`, `is_absolutely_continuous` — a.s. reasoning
|
|
500
|
+
|
|
501
|
+
`support()` returns the 0/1 indicator of nonzero entries (same profile and labels). `f.almost_surely_equal(g, p)` checks Fritz's `p ; copy ; (id ⊗ f) = p ; copy ; (id ⊗ g)`, i.e. `f` and `g` agree on the support of `p`. `p.is_absolutely_continuous(q)` checks `p ≪ q` (zero in `q` implies zero in `p`; input-wise for kernels, cf. arXiv:2308.00651). Zero is judged with `_ATOL`; labels are not compared.
|
|
502
|
+
|
|
503
|
+
```python
|
|
504
|
+
prior = FXTensor([[], [['x0', 'x1', 'x2']]], data=np.array([0.4, 0.6, 0.0]))
|
|
505
|
+
f = FXTensor([[['x0', 'x1', 'x2']], [['y0', 'y1']]], data=np.array([[0.2, 0.8], [0.5, 0.5], [1.0, 0.0]]))
|
|
506
|
+
g = FXTensor([[['x0', 'x1', 'x2']], [['y0', 'y1']]], data=np.array([[0.2, 0.8], [0.5, 0.5], [0.3, 0.7]]))
|
|
507
|
+
assert np.array_equal(prior.support().data, [1.0, 1.0, 0.0])
|
|
508
|
+
assert f.almost_surely_equal(g, prior) # f and g differ only on the null point x2
|
|
509
|
+
assert f.is_absolutely_continuous(g) # f(·|x) ≪ g(·|x) for every x
|
|
510
|
+
assert not g.is_absolutely_continuous(f)
|
|
511
|
+
```
|
|
512
|
+
|
|
497
513
|
### Probabilistic Properties
|
|
498
514
|
|
|
499
515
|
- `is_markov()`: Verifies if the tensor satisfies the normalization condition (sum of outputs equals 1 or 0). States (empty domain) always return `False`; check `np.isclose(state.data.sum(), 1)` for a normalized state.
|
|
@@ -513,3 +529,4 @@ pytest
|
|
|
513
529
|
- [2] [檜山正幸のキマイラ飼育記 (はてなBlog), マルコフ圏におけるテンソル計算の手順とコツ](https://m-hiyama.hatenablog.com/entry/2021/04/05/153325)
|
|
514
530
|
- [3] [K. Cho and B. Jacobs, Disintegration and Bayesian Inversion via String Diagrams (arXiv:1709.00322)](https://arxiv.org/abs/1709.00322)
|
|
515
531
|
- [4] [T. Fritz, A synthetic approach to Markov kernels, conditional independence and theorems on sufficient statistics (arXiv:1908.07021)](https://arxiv.org/abs/1908.07021)
|
|
532
|
+
- [5] [T. Fritz, T. Gonda, A. Lorenzin, P. Perrone, D. Stein, Absolute continuity, supports and idempotent splitting in categorical probability (arXiv:2308.00651)](https://arxiv.org/abs/2308.00651)
|
|
@@ -354,6 +354,8 @@ The `fxtensor-salmon` library is designed based on the **Markov Category**, a fr
|
|
|
354
354
|
| `jointification` | Joint of two states | Combine two independent states (states only) |
|
|
355
355
|
| `conditional` | Kernel `A → X ⊗ Y` → `A ⊗ X → Y` | Conditionalize a kernel (generalizes `conditionalization`) |
|
|
356
356
|
| `bayesian_inversion` | `f: X → Y` and prior `I → X` → `f†: Y → X` | Bayesian update / posterior kernel |
|
|
357
|
+
| `almost_surely_equal` | `f = g` p-a.s. | Compare kernels only where the prior has mass |
|
|
358
|
+
| `is_absolutely_continuous` | `p ≪ q` | Check support inclusion of states / kernels |
|
|
357
359
|
| `exclamation` | Discard morphism `X → I` | Build an all-ones discarding tensor |
|
|
358
360
|
| `copy_tensor` | Copy morphism `X → X^{⊗ n}` | Deterministic copy / diagonal (`n=0` is discard) |
|
|
359
361
|
| `delta_tensor` | Identity (alias of `identity_tensor`) | Build an identity kernel |
|
|
@@ -465,6 +467,20 @@ assert c.labels == ([['a'], ['x0', 'x1']], [['y0', 'y1']])
|
|
|
465
467
|
assert np.allclose(c.data, [[[0.25, 0.75], [1/3, 2/3]]])
|
|
466
468
|
```
|
|
467
469
|
|
|
470
|
+
#### `support`, `almost_surely_equal`, `is_absolutely_continuous` — a.s. reasoning
|
|
471
|
+
|
|
472
|
+
`support()` returns the 0/1 indicator of nonzero entries (same profile and labels). `f.almost_surely_equal(g, p)` checks Fritz's `p ; copy ; (id ⊗ f) = p ; copy ; (id ⊗ g)`, i.e. `f` and `g` agree on the support of `p`. `p.is_absolutely_continuous(q)` checks `p ≪ q` (zero in `q` implies zero in `p`; input-wise for kernels, cf. arXiv:2308.00651). Zero is judged with `_ATOL`; labels are not compared.
|
|
473
|
+
|
|
474
|
+
```python
|
|
475
|
+
prior = FXTensor([[], [['x0', 'x1', 'x2']]], data=np.array([0.4, 0.6, 0.0]))
|
|
476
|
+
f = FXTensor([[['x0', 'x1', 'x2']], [['y0', 'y1']]], data=np.array([[0.2, 0.8], [0.5, 0.5], [1.0, 0.0]]))
|
|
477
|
+
g = FXTensor([[['x0', 'x1', 'x2']], [['y0', 'y1']]], data=np.array([[0.2, 0.8], [0.5, 0.5], [0.3, 0.7]]))
|
|
478
|
+
assert np.array_equal(prior.support().data, [1.0, 1.0, 0.0])
|
|
479
|
+
assert f.almost_surely_equal(g, prior) # f and g differ only on the null point x2
|
|
480
|
+
assert f.is_absolutely_continuous(g) # f(·|x) ≪ g(·|x) for every x
|
|
481
|
+
assert not g.is_absolutely_continuous(f)
|
|
482
|
+
```
|
|
483
|
+
|
|
468
484
|
### Probabilistic Properties
|
|
469
485
|
|
|
470
486
|
- `is_markov()`: Verifies if the tensor satisfies the normalization condition (sum of outputs equals 1 or 0). States (empty domain) always return `False`; check `np.isclose(state.data.sum(), 1)` for a normalized state.
|
|
@@ -484,3 +500,4 @@ pytest
|
|
|
484
500
|
- [2] [檜山正幸のキマイラ飼育記 (はてなBlog), マルコフ圏におけるテンソル計算の手順とコツ](https://m-hiyama.hatenablog.com/entry/2021/04/05/153325)
|
|
485
501
|
- [3] [K. Cho and B. Jacobs, Disintegration and Bayesian Inversion via String Diagrams (arXiv:1709.00322)](https://arxiv.org/abs/1709.00322)
|
|
486
502
|
- [4] [T. Fritz, A synthetic approach to Markov kernels, conditional independence and theorems on sufficient statistics (arXiv:1908.07021)](https://arxiv.org/abs/1908.07021)
|
|
503
|
+
- [5] [T. Fritz, T. Gonda, A. Lorenzin, P. Perrone, D. Stein, Absolute continuity, supports and idempotent splitting in categorical probability (arXiv:2308.00651)](https://arxiv.org/abs/2308.00651)
|
|
@@ -152,6 +152,56 @@ class OperationsMixin:
|
|
|
152
152
|
one = np.isclose(rows, 1, rtol=rtol, atol=atol)
|
|
153
153
|
return bool(np.all(zero | one) and np.all(one.sum(axis=1) == 1))
|
|
154
154
|
|
|
155
|
+
def support(self) -> 'FXTensor':
|
|
156
|
+
"""Indicator tensor of the nonzero entries (same profile and labels).
|
|
157
|
+
|
|
158
|
+
For a state ``p: I → X`` this is the support ``{x : p(x) > 0}``; for a
|
|
159
|
+
kernel ``f: A → X`` it is the support relation ``{(a, x) : f(x|a) > 0}``.
|
|
160
|
+
Entries within ``_ATOL`` of zero count as zero.
|
|
161
|
+
"""
|
|
162
|
+
rtol = type(self)._RTOL
|
|
163
|
+
atol = type(self)._ATOL
|
|
164
|
+
mask = ~np.isclose(self.data, 0, rtol=rtol, atol=atol)
|
|
165
|
+
return self._spawn(self._profile[0], self._profile[1], self._labels, mask.astype(float))
|
|
166
|
+
|
|
167
|
+
def almost_surely_equal(self, other: 'FXTensor', prior: 'FXTensor') -> bool:
|
|
168
|
+
"""Check ``self = other`` ``prior``-almost surely.
|
|
169
|
+
|
|
170
|
+
For ``f, g: X → Y`` and a state ``p: I → X`` this is Fritz's
|
|
171
|
+
``p ; copy ; (id ⊗ f) = p ; copy ; (id ⊗ g)``; for finite tensors it
|
|
172
|
+
means ``f(·|x) = g(·|x)`` for every ``x`` with ``p(x) > 0``. Only
|
|
173
|
+
profiles are compared, not labels.
|
|
174
|
+
"""
|
|
175
|
+
if self._profile != other._profile:
|
|
176
|
+
raise ValueError("Tensors must have the same profile")
|
|
177
|
+
if prior._profile[0]:
|
|
178
|
+
raise ValueError("prior must be a state (empty domain)")
|
|
179
|
+
if prior._profile[1] != self._profile[0]:
|
|
180
|
+
raise ValueError("prior codomain must match the domain of self")
|
|
181
|
+
weights = prior.data.reshape(self._profile[0] + [1] * len(self._profile[1]))
|
|
182
|
+
return bool(np.allclose(
|
|
183
|
+
weights * self.data,
|
|
184
|
+
weights * other.data,
|
|
185
|
+
rtol=type(self)._RTOL,
|
|
186
|
+
atol=type(self)._ATOL,
|
|
187
|
+
))
|
|
188
|
+
|
|
189
|
+
def is_absolutely_continuous(self, other: 'FXTensor') -> bool:
|
|
190
|
+
"""Check ``self ≪ other``: wherever ``other`` is zero, ``self`` is zero.
|
|
191
|
+
|
|
192
|
+
For states this is the usual absolute continuity of distributions;
|
|
193
|
+
for kernels ``f, g: A → X`` it holds input-wise, i.e. ``f(·|a) ≪ g(·|a)``
|
|
194
|
+
for every ``a`` (finite case of Fritz et al., arXiv:2308.00651).
|
|
195
|
+
Only profiles are compared, not labels.
|
|
196
|
+
"""
|
|
197
|
+
if self._profile != other._profile:
|
|
198
|
+
raise ValueError("Tensors must have the same profile")
|
|
199
|
+
rtol = type(self)._RTOL
|
|
200
|
+
atol = type(self)._ATOL
|
|
201
|
+
other_zero = np.isclose(other.data, 0, rtol=rtol, atol=atol)
|
|
202
|
+
self_zero = np.isclose(self.data, 0, rtol=rtol, atol=atol)
|
|
203
|
+
return bool(np.all(self_zero | ~other_zero))
|
|
204
|
+
|
|
155
205
|
def marginalization(self, start_B: int) -> 'FXTensor':
|
|
156
206
|
"""Marginalize out a part of the codomain by summing over it."""
|
|
157
207
|
domain_len = len(self._profile[0])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fxtensor_salmon
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: Markov Tensor Module
|
|
5
5
|
Author-email: Tadachika Oki <sakesnare@gmail.com>
|
|
6
6
|
License: Copyright 2025 Tadachika Oki
|
|
@@ -383,6 +383,8 @@ The `fxtensor-salmon` library is designed based on the **Markov Category**, a fr
|
|
|
383
383
|
| `jointification` | Joint of two states | Combine two independent states (states only) |
|
|
384
384
|
| `conditional` | Kernel `A → X ⊗ Y` → `A ⊗ X → Y` | Conditionalize a kernel (generalizes `conditionalization`) |
|
|
385
385
|
| `bayesian_inversion` | `f: X → Y` and prior `I → X` → `f†: Y → X` | Bayesian update / posterior kernel |
|
|
386
|
+
| `almost_surely_equal` | `f = g` p-a.s. | Compare kernels only where the prior has mass |
|
|
387
|
+
| `is_absolutely_continuous` | `p ≪ q` | Check support inclusion of states / kernels |
|
|
386
388
|
| `exclamation` | Discard morphism `X → I` | Build an all-ones discarding tensor |
|
|
387
389
|
| `copy_tensor` | Copy morphism `X → X^{⊗ n}` | Deterministic copy / diagonal (`n=0` is discard) |
|
|
388
390
|
| `delta_tensor` | Identity (alias of `identity_tensor`) | Build an identity kernel |
|
|
@@ -494,6 +496,20 @@ assert c.labels == ([['a'], ['x0', 'x1']], [['y0', 'y1']])
|
|
|
494
496
|
assert np.allclose(c.data, [[[0.25, 0.75], [1/3, 2/3]]])
|
|
495
497
|
```
|
|
496
498
|
|
|
499
|
+
#### `support`, `almost_surely_equal`, `is_absolutely_continuous` — a.s. reasoning
|
|
500
|
+
|
|
501
|
+
`support()` returns the 0/1 indicator of nonzero entries (same profile and labels). `f.almost_surely_equal(g, p)` checks Fritz's `p ; copy ; (id ⊗ f) = p ; copy ; (id ⊗ g)`, i.e. `f` and `g` agree on the support of `p`. `p.is_absolutely_continuous(q)` checks `p ≪ q` (zero in `q` implies zero in `p`; input-wise for kernels, cf. arXiv:2308.00651). Zero is judged with `_ATOL`; labels are not compared.
|
|
502
|
+
|
|
503
|
+
```python
|
|
504
|
+
prior = FXTensor([[], [['x0', 'x1', 'x2']]], data=np.array([0.4, 0.6, 0.0]))
|
|
505
|
+
f = FXTensor([[['x0', 'x1', 'x2']], [['y0', 'y1']]], data=np.array([[0.2, 0.8], [0.5, 0.5], [1.0, 0.0]]))
|
|
506
|
+
g = FXTensor([[['x0', 'x1', 'x2']], [['y0', 'y1']]], data=np.array([[0.2, 0.8], [0.5, 0.5], [0.3, 0.7]]))
|
|
507
|
+
assert np.array_equal(prior.support().data, [1.0, 1.0, 0.0])
|
|
508
|
+
assert f.almost_surely_equal(g, prior) # f and g differ only on the null point x2
|
|
509
|
+
assert f.is_absolutely_continuous(g) # f(·|x) ≪ g(·|x) for every x
|
|
510
|
+
assert not g.is_absolutely_continuous(f)
|
|
511
|
+
```
|
|
512
|
+
|
|
497
513
|
### Probabilistic Properties
|
|
498
514
|
|
|
499
515
|
- `is_markov()`: Verifies if the tensor satisfies the normalization condition (sum of outputs equals 1 or 0). States (empty domain) always return `False`; check `np.isclose(state.data.sum(), 1)` for a normalized state.
|
|
@@ -513,3 +529,4 @@ pytest
|
|
|
513
529
|
- [2] [檜山正幸のキマイラ飼育記 (はてなBlog), マルコフ圏におけるテンソル計算の手順とコツ](https://m-hiyama.hatenablog.com/entry/2021/04/05/153325)
|
|
514
530
|
- [3] [K. Cho and B. Jacobs, Disintegration and Bayesian Inversion via String Diagrams (arXiv:1709.00322)](https://arxiv.org/abs/1709.00322)
|
|
515
531
|
- [4] [T. Fritz, A synthetic approach to Markov kernels, conditional independence and theorems on sufficient statistics (arXiv:1908.07021)](https://arxiv.org/abs/1908.07021)
|
|
532
|
+
- [5] [T. Fritz, T. Gonda, A. Lorenzin, P. Perrone, D. Stein, Absolute continuity, supports and idempotent splitting in categorical probability (arXiv:2308.00651)](https://arxiv.org/abs/2308.00651)
|
|
@@ -13,6 +13,7 @@ src/fxtensor_salmon.egg-info/SOURCES.txt
|
|
|
13
13
|
src/fxtensor_salmon.egg-info/dependency_links.txt
|
|
14
14
|
src/fxtensor_salmon.egg-info/requires.txt
|
|
15
15
|
src/fxtensor_salmon.egg-info/top_level.txt
|
|
16
|
+
tests/test_almost_surely.py
|
|
16
17
|
tests/test_axioms.py
|
|
17
18
|
tests/test_discopy.py
|
|
18
19
|
tests/test_fxtensor.py
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Tests for support, almost_surely_equal and is_absolutely_continuous.
|
|
2
|
+
|
|
3
|
+
References: T. Fritz (arXiv:1908.07021), almost sure equality;
|
|
4
|
+
T. Fritz, T. Gonda, A. Lorenzin, P. Perrone, D. Stein, "Absolute continuity,
|
|
5
|
+
supports and idempotent splitting in categorical probability" (arXiv:2308.00651).
|
|
6
|
+
"""
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from fxtensor_salmon import FXTensor
|
|
11
|
+
|
|
12
|
+
from test_axioms import random_kernel
|
|
13
|
+
|
|
14
|
+
X = ["x0", "x1", "x2"]
|
|
15
|
+
Y = ["y0", "y1"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def joint(prior, f):
|
|
19
|
+
"""prior ; copy ; (id ⊗ f)"""
|
|
20
|
+
x = prior.profile[1]
|
|
21
|
+
return prior.composition(FXTensor.copy_tensor(x)).composition(
|
|
22
|
+
FXTensor.identity_tensor(x).tensor_product(f)
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.fixture
|
|
27
|
+
def prior():
|
|
28
|
+
# x2 has probability zero
|
|
29
|
+
return FXTensor([[], [X]], data=np.array([0.4, 0.6, 0.0]))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@pytest.fixture
|
|
33
|
+
def f():
|
|
34
|
+
return FXTensor([[X], [Y]], data=np.array([[0.2, 0.8], [0.5, 0.5], [1.0, 0.0]]))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.fixture
|
|
38
|
+
def g():
|
|
39
|
+
# differs from f only on the null point x2
|
|
40
|
+
return FXTensor([[X], [Y]], data=np.array([[0.2, 0.8], [0.5, 0.5], [0.3, 0.7]]))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TestSupport:
|
|
44
|
+
def test_state(self, prior):
|
|
45
|
+
s = prior.support()
|
|
46
|
+
assert s.labels == (None, [X])
|
|
47
|
+
assert np.array_equal(s.data, [1.0, 1.0, 0.0])
|
|
48
|
+
|
|
49
|
+
def test_kernel_relation(self, f):
|
|
50
|
+
s = f.support()
|
|
51
|
+
assert s.profile == f.profile
|
|
52
|
+
assert s.labels == f.labels
|
|
53
|
+
assert np.array_equal(s.data, [[1, 1], [1, 1], [1, 0]])
|
|
54
|
+
|
|
55
|
+
def test_tolerance(self):
|
|
56
|
+
p = FXTensor([[], [2]], data=np.array([1 - 1e-12, 1e-12]))
|
|
57
|
+
assert np.array_equal(p.support().data, [1.0, 0.0])
|
|
58
|
+
|
|
59
|
+
def test_support_of_composition(self, prior, f):
|
|
60
|
+
# supp(p;f) = {y : exists x in supp(p) with f(y|x) > 0}
|
|
61
|
+
expected = (prior.support().data @ f.support().data) > 0
|
|
62
|
+
assert np.array_equal(prior.composition(f).support().data, expected.astype(float))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class TestAlmostSurelyEqual:
|
|
66
|
+
def test_differs_only_on_null_set(self, prior, f, g):
|
|
67
|
+
assert f.almost_surely_equal(g, prior)
|
|
68
|
+
assert f != g
|
|
69
|
+
|
|
70
|
+
def test_matches_joint_equation(self, prior, f, g):
|
|
71
|
+
assert joint(prior, f) == joint(prior, g)
|
|
72
|
+
|
|
73
|
+
def test_differs_on_support(self, prior, f):
|
|
74
|
+
h = FXTensor([[X], [Y]], data=np.array([[0.3, 0.7], [0.5, 0.5], [1.0, 0.0]]))
|
|
75
|
+
assert not f.almost_surely_equal(h, prior)
|
|
76
|
+
assert joint(prior, f) != joint(prior, h)
|
|
77
|
+
|
|
78
|
+
def test_full_support_prior_means_equality(self, f, g):
|
|
79
|
+
uniform = FXTensor([[], [X]], data=np.full(3, 1 / 3))
|
|
80
|
+
assert not f.almost_surely_equal(g, uniform)
|
|
81
|
+
assert f.almost_surely_equal(f.copy(), uniform)
|
|
82
|
+
|
|
83
|
+
def test_double_bayesian_inversion_is_almost_surely_equal(self, prior, g):
|
|
84
|
+
# with a non-full-support prior, (g†)† differs from g on x2 but agrees a.s.
|
|
85
|
+
inv = g.bayesian_inversion(prior)
|
|
86
|
+
double = inv.bayesian_inversion(prior.composition(g))
|
|
87
|
+
assert double != g
|
|
88
|
+
assert double.almost_surely_equal(g, prior)
|
|
89
|
+
|
|
90
|
+
def test_random_multi_axis(self):
|
|
91
|
+
p = random_kernel([], [2, 3], 40)
|
|
92
|
+
data = p.data.copy()
|
|
93
|
+
data[1, 2] = 0.0
|
|
94
|
+
p = FXTensor([[], [2, 3]], data=data / data.sum())
|
|
95
|
+
f = random_kernel([2, 3], [2], 41)
|
|
96
|
+
g_data = f.data.copy()
|
|
97
|
+
g_data[1, 2] = [0.9, 0.1]
|
|
98
|
+
g = FXTensor([[2, 3], [2]], data=g_data)
|
|
99
|
+
assert f.almost_surely_equal(g, p)
|
|
100
|
+
assert joint(p, f) == joint(p, g)
|
|
101
|
+
|
|
102
|
+
def test_labels_are_ignored(self, prior, f):
|
|
103
|
+
unlabeled = FXTensor([[3], [2]], data=f.data)
|
|
104
|
+
assert f.almost_surely_equal(unlabeled, prior)
|
|
105
|
+
|
|
106
|
+
def test_errors(self, prior, f):
|
|
107
|
+
with pytest.raises(ValueError):
|
|
108
|
+
f.almost_surely_equal(FXTensor([[3], [3]], data=np.eye(3)), prior)
|
|
109
|
+
with pytest.raises(ValueError):
|
|
110
|
+
f.almost_surely_equal(f, f)
|
|
111
|
+
with pytest.raises(ValueError):
|
|
112
|
+
f.almost_surely_equal(f, FXTensor([[], [2]], data=np.array([0.5, 0.5])))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class TestAbsoluteContinuity:
|
|
116
|
+
def test_states(self):
|
|
117
|
+
p = FXTensor([[], [3]], data=np.array([0.5, 0.5, 0.0]))
|
|
118
|
+
q = FXTensor([[], [3]], data=np.array([0.2, 0.3, 0.5]))
|
|
119
|
+
assert p.is_absolutely_continuous(q)
|
|
120
|
+
assert not q.is_absolutely_continuous(p)
|
|
121
|
+
|
|
122
|
+
def test_equivalent_to_support_inclusion(self):
|
|
123
|
+
rng = np.random.default_rng(50)
|
|
124
|
+
for _ in range(20):
|
|
125
|
+
a = rng.random(4) * (rng.random(4) > 0.4)
|
|
126
|
+
b = rng.random(4) * (rng.random(4) > 0.4)
|
|
127
|
+
p, q = FXTensor([[], [4]], data=a), FXTensor([[], [4]], data=b)
|
|
128
|
+
inclusion = np.all(p.support().data <= q.support().data)
|
|
129
|
+
assert p.is_absolutely_continuous(q) == inclusion
|
|
130
|
+
|
|
131
|
+
def test_kernels_inputwise(self, f, g):
|
|
132
|
+
assert f.is_absolutely_continuous(g)
|
|
133
|
+
assert not g.is_absolutely_continuous(f)
|
|
134
|
+
|
|
135
|
+
def test_reflexive_and_transitive(self):
|
|
136
|
+
p = FXTensor([[], [3]], data=np.array([1.0, 0.0, 0.0]))
|
|
137
|
+
q = FXTensor([[], [3]], data=np.array([0.5, 0.5, 0.0]))
|
|
138
|
+
r = FXTensor([[], [3]], data=np.full(3, 1 / 3))
|
|
139
|
+
assert p.is_absolutely_continuous(p)
|
|
140
|
+
assert p.is_absolutely_continuous(q) and q.is_absolutely_continuous(r)
|
|
141
|
+
assert p.is_absolutely_continuous(r)
|
|
142
|
+
|
|
143
|
+
def test_preserved_by_composition(self, f):
|
|
144
|
+
p = FXTensor([[], [X]], data=np.array([1.0, 0.0, 0.0]))
|
|
145
|
+
q = FXTensor([[], [X]], data=np.array([0.5, 0.0, 0.5]))
|
|
146
|
+
assert p.is_absolutely_continuous(q)
|
|
147
|
+
assert p.composition(f).is_absolutely_continuous(q.composition(f))
|
|
148
|
+
|
|
149
|
+
def test_almost_sure_equality_transfers(self, prior, f, g):
|
|
150
|
+
# if p ≪ q and f = g q-a.s., then f = g p-a.s.
|
|
151
|
+
p = FXTensor([[], [X]], data=np.array([1.0, 0.0, 0.0]))
|
|
152
|
+
assert p.is_absolutely_continuous(prior)
|
|
153
|
+
assert f.almost_surely_equal(g, prior)
|
|
154
|
+
assert f.almost_surely_equal(g, p)
|
|
155
|
+
|
|
156
|
+
def test_profile_mismatch(self):
|
|
157
|
+
with pytest.raises(ValueError):
|
|
158
|
+
FXTensor([[], [2]], data=np.ones(2)).is_absolutely_continuous(FXTensor([[], [3]], data=np.ones(3)))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fxtensor_salmon-1.2.0 → fxtensor_salmon-1.2.1}/src/fxtensor_salmon.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|