Probabilistic properties¶
is_markov() is true when every domain point’s
codomain slice sums to 1 or to 0 (the zero rows produced by conditioning).
A state has an empty domain, so is_markov returns False. Check a
normalized state with numpy.isclose(state.data.sum(), 1).
is_deterministic() is true when every
codomain slice is a point mass: one entry 1 and the rest 0. A zero slice is
not deterministic. Identity, copy, swap, and discard are deterministic;
a generic stochastic kernel is not.
import numpy as np
from fxtensor_salmon import FXTensor
state = FXTensor([[], [2]], data=np.array([0.2, 0.8]))
assert not state.is_markov()
assert np.isclose(state.data.sum(), 1.0)
kernel = FXTensor([[2], [2]], data=np.array([[0.2, 0.8], [0.0, 0.0]]))
assert kernel.is_markov()
assert not kernel.is_deterministic()
bad = FXTensor([[2], [2]], data=np.array([[0.2, 0.2], [0.5, 0.5]]))
assert not bad.is_markov()
identity = FXTensor.identity_tensor([2])
assert identity.is_deterministic()
assert identity.is_markov()
zeros = FXTensor([[2], [2]], data=np.zeros((2, 2)))
assert not zeros.is_deterministic()
Equality and copying¶
== compares profile, labels, and data. Data uses allclose with
FXTensor._RTOL and FXTensor._ATOL. hash uses the raw bytes, so
two tensors can compare equal and still hash differently when the stored
values differ inside that tolerance. Do not use that pair as interchangeable
dictionary keys.
copy (and copy.copy) duplicates the array. Later writes to one
tensor do not change the other.
import numpy as np
from fxtensor_salmon import FXTensor
left = FXTensor([[2], [1]], data=np.array([[1.0], [1.0]]))
right = FXTensor([[2], [1]], data=np.array([[1.0], [1.0 + 1e-9]]))
assert left == right
assert hash(left) != hash(right)
labeled = FXTensor([[["a", "b"]], [["x", "y"]]], data=np.array([[0.2, 0.8], [0.6, 0.4]]))
relabeled = FXTensor([[["a", "b"]], [["y", "x"]]], data=np.array([[0.2, 0.8], [0.6, 0.4]]))
assert labeled != relabeled
cloned = labeled.copy()
cloned.data[0, 0] = 0.0
assert labeled.data[0, 0] == 0.2
assert cloned is not labeled