条件付けと推論

条件付き化

conditionalization() は同時状態を核にします。 concat_start_index は、新しい codomain の先頭になる codomain 因子の 1 始まりの位置です。それより前の因子が domain になります。codomain の和が 0 の スライスは 0 のままで、is_markov() はその行を 許容します。受け手は状態である必要があります。

import numpy as np
from fxtensor_salmon import FXTensor

location_labels = ["Urban", "Rural"]
season_labels = ["Spring", "Summer", "Other"]
weather_labels = ["Sunny", "Rainy"]
joint = FXTensor(
    [[], [location_labels, season_labels, weather_labels]],
    data=np.array(
        [
            [[0.08, 0.04], [0.12, 0.04], [0.08, 0.04]],
            [[0.06, 0.12], [0.12, 0.12], [0.06, 0.12]],
        ]
    ),
)
cond_tensor = joint.conditionalization(concat_start_index=3)
assert cond_tensor.labels == ([location_labels, season_labels], [weather_labels])
assert cond_tensor.is_markov()
assert np.allclose(
    cond_tensor.data,
    [
        [[2 / 3, 1 / 3], [0.75, 0.25], [2 / 3, 1 / 3]],
        [[1 / 3, 2 / 3], [0.50, 0.50], [1 / 3, 2 / 3]],
    ],
)

joint_state = FXTensor([[], [2, 2]], data=np.array([[0.1, 0.2], [0.0, 0.0]]))
kernel = joint_state.conditionalization(2)
assert kernel.profile == [[2], [2]]
assert kernel.is_markov()
assert np.allclose(kernel.data, [[1 / 3, 2 / 3], [0.0, 0.0]])

not_a_state = FXTensor([[2], [2]], data=np.eye(2))
try:
    not_a_state.conditionalization(1)
except ValueError:
    pass
else:
    raise AssertionError("conditionalization requires a state")

核の条件付け

conditional() は、核 f: A → X ⊗ Y に対する 同じ分割です。結果の domain は A ⊗ X です。状態に対しては conditionalization と一致します。

import numpy as np
from fxtensor_salmon import FXTensor

location_labels = ["Urban", "Rural"]
season_labels = ["Spring", "Summer", "Other"]
weather_labels = ["Sunny", "Rainy"]
joint = FXTensor(
    [[], [location_labels, season_labels, weather_labels]],
    data=np.array(
        [
            [[0.08, 0.04], [0.12, 0.04], [0.08, 0.04]],
            [[0.06, 0.12], [0.12, 0.12], [0.06, 0.12]],
        ]
    ),
)
cond_tensor = joint.conditionalization(concat_start_index=3)
assert cond_tensor.labels == ([location_labels, season_labels], [weather_labels])
assert cond_tensor.is_markov()
assert np.allclose(
    cond_tensor.data,
    [
        [[2 / 3, 1 / 3], [0.75, 0.25], [2 / 3, 1 / 3]],
        [[1 / 3, 2 / 3], [0.50, 0.50], [1 / 3, 2 / 3]],
    ],
)

joint_state = FXTensor([[], [2, 2]], data=np.array([[0.1, 0.2], [0.0, 0.0]]))
kernel = joint_state.conditionalization(2)
assert kernel.profile == [[2], [2]]
assert kernel.is_markov()
assert np.allclose(kernel.data, [[1 / 3, 2 / 3], [0.0, 0.0]])

not_a_state = FXTensor([[2], [2]], data=np.eye(2))
try:
    not_a_state.conditionalization(1)
except ValueError:
    pass
else:
    raise AssertionError("conditionalization requires a state")

ベイズ反転

事前状態 p: I → X と核 f: X → Y に対し、 bayesian_inversion() は次の f†: Y → X を 返します。

f†(x|y) = p(x) f(y|x) / Σ_x' p(x') f(y|x')

証拠が 0 の行は 0 のままです。X のラベルは、f がラベル付きなら f から、 そうでなければ事前状態から取ります。このメソッドが返すテンソルでは、有限の等式 p ; copy ; (id ⊗ f) = p ; f ; copy ; (f† ⊗ id) が成り立ちます。

上から下へ読むベイズ反転の等式

ベイズ反転: p ; copy ; (id ⊗ f) = p ; f ; copy ; (f† ⊗ id)。

import numpy as np
from fxtensor_salmon import FXTensor

health = ["Sick", "Healthy"]
result = ["Positive", "Negative"]
prior = FXTensor([[], [health]], data=np.array([0.01, 0.99]))
test = FXTensor([[health], [result]], data=np.array([[0.9, 0.1], [0.05, 0.95]]))
posterior = test.bayesian_inversion(prior)
assert posterior.labels == ([result], [health])
assert np.isclose(posterior.data[0, 0], 2 / 13)

x = prior.labels[1]
y = test.labels[1]
forward = prior.composition(FXTensor.copy_tensor(x)).composition(
    FXTensor.identity_tensor(x).tensor_product(test)
)
backward = prior.composition(test).composition(FXTensor.copy_tensor(y)).composition(
    posterior.tensor_product(FXTensor.identity_tensor(y))
)
assert forward == backward

point = FXTensor([[], [2]], data=np.array([1.0, 0.0]))
kernel = FXTensor([[2], [2]], data=np.array([[0.0, 1.0], [0.3, 0.7]]))
inverted = kernel.bayesian_inversion(point)
assert np.allclose(inverted.data[0], [0.0, 0.0])
assert np.allclose(inverted.data[1], [1.0, 0.0])

台とほとんど確実な等価

support() は、同じプロファイルとラベルを持つ 0/1 テンソルです。FXTensor._ATOL 以内の成分は 0 とみなします。

almost_surely_equal() は、事前状態が正である 点で、同じプロファイルの2つのテンソルが一致するかを見ます。ラベルは比べません。 事前状態は、codomain が domain と一致する状態である必要があります。

is_absolutely_continuous() は、other が 0 の 場所で self も 0 かを見ます。核では入力ごとに確認します。プロファイルは 一致している必要があり、ラベルは比べません。

事前状態のもとでの2つの核のほとんど確実な等価

ほとんど確実な等価: p ; copy ; (id ⊗ f) = p ; copy ; (id ⊗ g)。

import numpy as np
from fxtensor_salmon import FXTensor

prior = FXTensor([[], [["x0", "x1", "x2"]]], data=np.array([0.4, 0.6, 0.0]))
f = FXTensor(
    [[["x0", "x1", "x2"]], [["y0", "y1"]]],
    data=np.array([[0.2, 0.8], [0.5, 0.5], [1.0, 0.0]]),
)
g = FXTensor(
    [[["x0", "x1", "x2"]], [["y0", "y1"]]],
    data=np.array([[0.2, 0.8], [0.5, 0.5], [0.3, 0.7]]),
)
assert np.array_equal(prior.support().data, [1.0, 1.0, 0.0])
assert f.almost_surely_equal(g, prior)
assert not f.almost_surely_equal(g, FXTensor([[], [3]], data=np.array([0.2, 0.2, 0.6])))
assert f.is_absolutely_continuous(g)
assert not g.is_absolutely_continuous(f)

relabeled = FXTensor([[["a", "b", "c"]], [["p", "q"]]], data=np.array(f.data))
assert f.almost_surely_equal(relabeled, prior)