Concepts¶
Profile¶
The constructor accepts three profile forms.
Labeled.
[[domain groups], [codomain groups]]where each group is a list of strings. The dimension of a group is its length.Numeric.
[[domain lengths], [codomain lengths]]where each entry is anint.Tuple.
(domain lengths, codomain lengths). This form is unlabeled.
profile always returns numeric lengths, [[domain], [codomain]].
labels returns (domain groups, codomain groups). An empty side, or a
side that was never labeled, is None rather than [].
Axis 0 is the first domain factor. After the domain factors, axis numbers
continue into the codomain. get_label_index(axis, label) returns the
position of label on that axis. get_index_label(axis, index) is the
inverse. Both raise ValueError when the tensor has no labels, or when
label is not on that axis.
import numpy as np
from fxtensor_salmon import FXTensor
labeled = FXTensor(
[[["Urban", "Rural"]], [["Spring", "Summer", "Other"], ["Sunny", "Rainy"]]],
data=np.zeros((2, 3, 2)),
)
assert labeled.profile == [[2], [3, 2]]
assert labeled.labels == (
[["Urban", "Rural"]],
[["Spring", "Summer", "Other"], ["Sunny", "Rainy"]],
)
assert labeled.get_label_index(0, "Rural") == 1
assert labeled.get_label_index(1, "Summer") == 1
assert labeled.get_index_label(2, 0) == "Sunny"
numeric = FXTensor([[2], [3, 2]], data=np.zeros((2, 3, 2)))
assert numeric.labels == (None, None)
as_tuple = FXTensor(([2], [3]), data=np.zeros((2, 3)))
assert as_tuple.profile == [[2], [3]]
assert as_tuple.labels == (None, None)
Data¶
data is a NumPy array of shape tuple(domain_lengths + codomain_lengths).
Omitted data is all zeros. A shape that does not match the profile raises
ValueError. The empty profile [[], []] is the monoidal unit; its data
is a 0-d array.
import numpy as np
from fxtensor_salmon import FXTensor
zeros = FXTensor([[2], [2]])
assert np.array_equal(zeros.data, np.zeros((2, 2)))
scalar = FXTensor([[], []], data=np.array(1.0))
assert scalar.profile == [[], []]
assert scalar.data.shape == ()
assert float(scalar.data) == 1.0
try:
FXTensor([[2], [2]], data=np.ones((2, 3)))
except ValueError:
pass
else:
raise AssertionError("data shape must match the profile")
plain = FXTensor([[2], [2]], data=np.eye(2))
try:
plain.get_label_index(0, "a")
except ValueError:
pass
else:
raise AssertionError("unlabeled tensors have no label lookup")
States and kernels¶
A state has an empty domain. A kernel has a nonempty domain. Several methods
are restricted to states because the corresponding string diagram starts from
the monoidal unit: conditionalization(),
jointification(), and the prior argument of
bayesian_inversion() and
almost_surely_equal().
Equality uses numpy.allclose with FXTensor._RTOL (1e-05) and
FXTensor._ATOL (1e-08), and it also compares profiles and labels.
copy returns a new tensor with its own array.