操作¶
codomain を分割する添字(start_B と concat_start_index)は、codomain
因子に沿った 1 始まり の位置です。
合成とテンソル積¶
composition() は numpy.tensordot で、受け手の
codomain と引数の domain を縮約します。プロファイルが一致しないと ValueError
です。ラベルが残るのは、両方がラベル付きのときだけです。
tensor_product() は domain と codomain を連結し、
ブロードキャストした配列を掛けます。片方がラベルなしで、かつ軸を1本以上持つと、
ラベルは落ちます。軸を持たないラベルなしスカラーは、相手のラベルを消しません。
import numpy as np
from fxtensor_salmon import FXTensor
f = FXTensor([[["a", "b"]], [["x", "y"]]], data=np.array([[0.2, 0.8], [0.6, 0.4]]))
g = FXTensor.identity_tensor([2])
assert f.tensor_product(g).labels == (None, None)
scalar = FXTensor([[], []], data=np.array(1.0))
assert f.tensor_product(scalar).labels == f.labels
left = FXTensor([[2], [2]], data=np.eye(2))
right = FXTensor([[3], [1]], data=np.ones((3, 1)))
try:
left.composition(right)
except ValueError:
pass
else:
raise AssertionError("composition requires a matching codomain and domain")
逐次合成 f ; g。¶
テンソル積 f ⊗ g。¶
周辺化¶
marginalization() は、start_B から末尾までの
codomain 軸を和で落とし、残った接頭のラベルを保ちます。start_B が
len(codomain) + 1 のときは何も和をとらず、同じオブジェクトを返します。
start_B == 1 は codomain 全体の和です。有効な範囲は 1 から
len(codomain) + 1 までです。
import numpy as np
from fxtensor_salmon import FXTensor
location_labels = ["Urban", "Rural"]
season_labels = ["Spring", "Summer", "Other"]
weather_labels = ["Sunny", "Rainy"]
process_data = np.array(
[
[[0.2, 0.1], [0.3, 0.1], [0.2, 0.1]],
[[0.1, 0.2], [0.2, 0.2], [0.1, 0.2]],
]
)
process_tensor = FXTensor(
[[location_labels], [season_labels, weather_labels]],
data=process_data,
)
season_tensor = process_tensor.marginalization(start_B=2)
assert season_tensor.labels == ([location_labels], [season_labels])
assert np.allclose(
season_tensor.data,
[
[0.3, 0.4, 0.3],
[0.3, 0.4, 0.3],
],
)
state = FXTensor(
[[], [2, 3]],
data=np.array(
[
[0.1, 0.2, 0.3],
[0.15, 0.05, 0.2],
]
),
)
assert state.marginalization(3) is state
marginal = state.marginalization(2)
assert marginal.profile == [[], [2]]
assert np.allclose(marginal.data, [0.6, 0.4])
assert state.marginalization(1).profile == [[], []]
discard_prefix() は start_B より前の
codomain 軸を和で落とし、接尾とそのラベルを残します。start_B == 1 は同じ
オブジェクトを返します。
import numpy as np
from fxtensor_salmon import FXTensor
labeled = FXTensor(
[[], [["a", "b"], ["x", "y"]]],
data=np.array(
[
[0.1, 0.2],
[0.3, 0.4],
]
),
)
assert labeled.discard_prefix(1) is labeled
prefix = labeled.discard_prefix(2)
assert prefix.labels == (None, [["x", "y"]])
assert np.allclose(prefix.data, [0.4, 0.6])
kept = labeled.marginalization(2)
assert kept.labels == (None, [["a", "b"]])
assert np.allclose(kept.data, [0.3, 0.7])
first_marginalization() と
second_marginalization() は、恒等と
exclamation() の合成で同じ分割を行います。
これらのコンストラクタは数値なので、結果はラベルなしです。first は
concat_start_index から始まる接尾を落とし、second はその前の接頭を
落とします。
import numpy as np
from fxtensor_salmon import FXTensor
labeled = FXTensor(
[[], [["a", "b"], ["x", "y"]]],
data=np.array(
[
[0.1, 0.2],
[0.3, 0.4],
]
),
)
first = labeled.first_marginalization(2)
second = labeled.second_marginalization(2)
assert first.labels == (None, None)
assert second.labels == (None, None)
assert np.allclose(first.data, labeled.marginalization(2).data)
assert np.allclose(second.data, labeled.discard_prefix(2).data)
部分合成¶
f: A → B ⊗ C と g: C → D に対し、f.partial_composition(g, k) は
1 始まりの添字 k より前の codomain を残し、接尾を g に渡します。
k == 1 は codomain 全体を渡すので、値は
composition() と一致します。実装は残す接頭に
数値の恒等を作るため、結果のラベルは消えます。
import numpy as np
from fxtensor_salmon import FXTensor
f = FXTensor(
[[2], [2, 2]],
data=np.array(
[
[[1.0, 0.0], [0.0, 1.0]],
[[0.0, 1.0], [1.0, 0.0]],
]
),
)
g = FXTensor(
[[2], [2]],
data=np.array(
[
[0.2, 0.8],
[0.6, 0.4],
]
),
)
partial = f.partial_composition(g, 2)
assert partial.profile == [[2], [2, 2]]
assert partial.labels == (None, None)
assert np.allclose(
partial.data,
[
[[0.2, 0.8], [0.6, 0.4]],
[[0.6, 0.4], [0.2, 0.8]],
],
)
whole = FXTensor([[2], [2]], data=np.array([[0.2, 0.8], [0.6, 0.4]]))
nxt = FXTensor([[2], [2]], data=np.array([[0.3, 0.7], [0.9, 0.1]]))
assert np.allclose(whole.partial_composition(nxt, 1).data, whole.composition(nxt).data)
同時化¶
jointification() は2つの状態のテンソル積です。
domain は両方とも空である必要があります。ラベルが残るのは両方がラベル付きの
ときだけで、状態の domain 側ラベルは None です。
import numpy as np
from fxtensor_salmon import FXTensor
location_labels = ["Urban", "Rural"]
traffic_labels = ["Low", "High"]
location_state = FXTensor([[], [location_labels]], data=np.array([0.6, 0.4]))
traffic_state = FXTensor([[], [traffic_labels]], data=np.array([0.7, 0.3]))
joint_state = location_state.jointification(traffic_state)
assert joint_state.labels == (None, [location_labels, traffic_labels])
assert np.allclose(
joint_state.data,
[
[0.42, 0.18],
[0.28, 0.12],
],
)
px = FXTensor([[], [["a", "b"]]], data=np.array([0.3, 0.7]))
py = FXTensor([[], [["x", "y", "z"]]], data=np.array([0.2, 0.3, 0.5]))
assert np.allclose(px.jointification(py).data, px.tensor_product(py).data)
kernel = FXTensor([[2], [2]], data=np.eye(2))
try:
location_state.jointification(kernel)
except ValueError:
pass
else:
raise AssertionError("jointification requires two states")