Input and output¶
JSON¶
to_json() returns a dictionary with
profile, data, and dtype. The profile is labeled when the tensor
has labels. from_json() rebuilds a tensor from
profile and data. A names entry, when present, is the pair of
domain and codomain axis names. JSON with no names key loads as an
unnamed tensor.
save_to_file() writes that dictionary as JSON.
load_from_file() reads it back.
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
Strands¶
from_strands() reads a map from a strand key
to a weight. A key is a Python literal of nested lists of strings or
integers, parsed without evaluating code; any other key raises
ValueError. Labeled strands name the points. Numeric strands use
1-based indices, each index wrapped in its own list. Weights may be
float or fractions.Fraction and are stored with float.
to_original_dict() goes the other way for the
numeric form: nonzero entries become 1-based index lists. The weights are the
NumPy scalars from data, and the profile is the numeric profile.
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")