DisCoPy

fxtensor_salmon.discopy converts tensors to and from DisCoPy Markov diagrams. Importing the module requires the discopy extra and Python 3.10 or newer:

pip install "fxtensor-salmon[discopy]"

Each profile factor is one wire. to_tensor() drops labels. Pass them back to from_tensor() if you need them. to_box() stores labels in the Markov type names, and from_box() restores them. to_diagram() is the box as a diagram.

FXTensorFunctor sends DisCoPy Copy, Discard, Swap, and Id to copy_tensor(), exclamation(), swap(), and identity_tensor(). An object map sends an atomic type to an int, a label list, or a DisCoPy Dim.

import numpy as np
from discopy.markov import Copy, Discard, Id, Swap, Ty
from fxtensor_salmon import FXTensor
from fxtensor_salmon.discopy import (
    FXTensorFunctor,
    from_box,
    from_tensor,
    to_box,
    to_diagram,
    to_tensor,
)

kernel = FXTensor([[2], [2]], data=np.array([[0.8, 0.2], [0.4, 0.6]]))
assert from_tensor(to_tensor(kernel)) == kernel

weather = ["Sunny", "Rainy"]
forecast = FXTensor([[weather], [weather]], data=np.array([[0.8, 0.2], [0.4, 0.6]]))
assert from_tensor(to_tensor(forecast)).labels == (None, None)
assert from_tensor(to_tensor(forecast), labels=forecast.labels) == forecast
box = to_box(forecast, name="forecast")
assert from_box(box) == forecast
assert from_diagram(to_diagram(forecast, name="forecast")) == forecast

x, y = Ty("x"), Ty("y")
functor = FXTensorFunctor({x: 2, y: 3}, {})
assert functor(Copy(x)) == FXTensor.copy_tensor([2])
assert functor(Discard(x)) == FXTensor.exclamation([2])
assert functor(Swap(x, y)) == FXTensor.swap([2], [3])
assert functor(Id(x)) == FXTensor.identity_tensor([2])