入出力

JSON

to_json() は profile、data、dtype を 持つ辞書を返します。ラベルがあるときはプロファイルもラベル付きです。 from_json() は profile と data から テンソルを作り直します。names があるときは、domain と codomain の 軸の名前の組です。names のない JSON は、名前のないテンソルとして読みます。

save_to_file() はその辞書を JSON として書き、 load_from_file() が読み戻します。

import numpy as np
from fxtensor_salmon import FXTensor

json_data = {
    "profile": [[["a", "b"]], [["x", "y"]]],
    "data": [[0.2, 0.8], [0.6, 0.4]],
}
tensor = FXTensor.from_json(json_data)
assert tensor.labels == ([["a", "b"]], [["x", "y"]])
payload = tensor.to_json()
assert payload["profile"] == [[["a", "b"]], [["x", "y"]]]
assert payload["dtype"] == str(tensor.data.dtype)
assert FXTensor.from_json(payload) == tensor
import tempfile
from pathlib import Path

import numpy as np
from fxtensor_salmon import FXTensor

source = FXTensor(
    [[["a", "b"]], [["x", "y"]]],
    data=np.array([[0.2, 0.8], [0.6, 0.4]]),
)
with tempfile.TemporaryDirectory() as tmp:
    filename = str(Path(tmp) / "tensor.json")
    source.save_to_file(filename)
    loaded = FXTensor.load_from_file(filename)
assert loaded == source

ストランド

from_strands() は、ストランドのキーから重みへの 対応を読みます。キーは文字列または整数の入れ子リストという Python リテラルで、 コードとしては評価しません。それ以外のキーは ValueError です。ラベル付きの ストランドは点の名前を書きます。数値のストランドは 1 始まり の添字で、 各添字をそれぞれのリストで包みます。重みは float または fractions.Fraction で、float として保存します。

to_original_dict() は数値形式の逆向きです。 非ゼロ成分を 1 始まりの添字リストにします。重みは data の NumPy スカラーで、 プロファイルは数値のプロファイルです。

import numpy as np
from fractions import Fraction
from fxtensor_salmon import FXTensor

profile = [[2], [3]]
strands = {
    "[[[1]], [[1]]]": 0.1,
    "[[[1]], [[2]]]": 0.2,
    "[[[1]], [[3]]]": 0.7,
    "[[[2]], [[1]]]": 0.3,
    "[[[2]], [[2]]]": 0.3,
    "[[[2]], [[3]]]": 0.4,
}
tensor = FXTensor.from_strands(profile, strands)
assert np.allclose(
    tensor.data,
    [
        [0.1, 0.2, 0.7],
        [0.3, 0.3, 0.4],
    ],
)

half = FXTensor.from_strands([[2], [1]], {"[[[1]], [[1]]]": Fraction(1, 2)})
assert np.isclose(half.data[0, 0], 0.5)

original = FXTensor([[2], [3]], data=np.array([[0.1, 0.0, 0.7], [0.0, 0.3, 0.0]]))
encoded = original.to_original_dict()
assert encoded["profile"] == [[2], [3]]
assert float(encoded["strands"]["[[1], [1]]"]) == 0.1
assert "[[1], [2]]" not in encoded["strands"]

try:
    FXTensor.from_strands([[["a", "b"]], [["x", "y"]]], {"not-a-list": 1.0})
except ValueError:
    pass
else:
    raise AssertionError("strand keys must be nested lists")