Skip to main content

Markov Tensor Module

Project description

FXTensor

FXTensor is a Python library for tensor-based calculations, particularly suited for representing and manipulating probabilistic systems, such as those found in category theory-based models of systems and processes. It uses NumPy for efficient numerical computation.

Core Concepts

A tensor in FXTensor is defined by its profile and data.

  • Profile: A list [domain, codomain] specifying the dimensions of the tensor's input and output indices. For example, [[2], [3]] represents a 2x3 matrix.
  • Data: A NumPy array holding the tensor's values. The number of axes in the array must match the total number of dimensions in the profile (length of domain + length of codomain).

A Simple Example: Weather Forecast

Let's model a simple weather system where the weather can be either Sunny (0) or Rainy (1).

  • State Tensor: Represents the probability of the current weather. If we are certain it's sunny, the state is [1, 0]. This tensor has an empty domain [] and a codomain [2].

    # P(Weather=Sunny) = 1, P(Weather=Rainy) = 0
    sunny_today = FXTensor([[], [2]], data=np.array([1, 0]))
    
  • Process Tensor: Represents a probabilistic process, like a weather forecast. This is a matrix where rows are today's weather and columns are tomorrow's.

    # P(Tomorrow | Today)
    forecast_matrix = np.array([
        [0.8, 0.2], # Today is Sunny -> Tomorrow is P(Sunny)=0.8, P(Rainy)=0.2
        [0.4, 0.6]  # Today is Rainy -> Tomorrow is P(Sunny)=0.4, P(Rainy)=0.6
    ])
    forecast_tensor = FXTensor([[2], [2]], data=forecast_matrix)
    
  • Composition: We can predict tomorrow's weather by composing today's state with the forecast tensor.

    # The result is a new state tensor for tomorrow's weather probability
    sunny_tomorrow = sunny_today.composition(forecast_tensor)
    # sunny_tomorrow.data -> np.array([0.8, 0.2])
    

Advanced Example: Multi-dimensional Systems

Now, let's consider a more complex system: the joint probability of Season and Weather given a Location.

  • Domain: Location {City, Countryside} (size 2)
  • Codomain: Season {Spring, Summer, Other} (size 3) and Weather {Sunny, Rainy} (size 2)

This can be represented by a tensor P(Season, Weather | Location) with profile [[2], [3, 2]].

# A tensor representing P(Season, Weather | Location)
# The data is a 3D NumPy array of shape (2, 3, 2)
# For simplicity, we use placeholder data here.
process_data = np.random.rand(2, 3, 2)
# Normalize to make it a valid Markov tensor (sum over codomain axes is 1)
process_data /= process_data.sum(axis=(1, 2), keepdims=True)

process_tensor = FXTensor([[2], [3, 2]], data=process_data)

Key FXTensor Methods in Action

Using our process_tensor, let's see what the main methods do.

marginalization(start_B)

This method sums over the codomain axes from a given index start_B (1-based).

# Original profile: [[2], [3, 2]] -> P(Season, Weather | Location)
# We want to get P(Season | Location) by summing out Weather.
# The 'Weather' part starts at the 2nd element of the codomain.
season_tensor = process_tensor.marginalization(start_B=2)

# Resulting profile: [[2], [3]]
# Resulting data shape: (2, 3)

discard_prefix(start_B)

This method sums over the codomain axes before a given index start_B.

# Original profile: [[2], [3, 2]] -> P(Season, Weather | Location)
# We want to get P(Weather | Location) by summing out Season.
# The 'Season' part is the prefix we want to discard.
weather_tensor = process_tensor.discard_prefix(start_B=2)

# Resulting profile: [[2], [2]]
# Resulting data shape: (2, 2)

conditionalization(start_B)

Calculates conditional probability by normalizing slices of the tensor.

# Original profile: [[2], [3, 2]] -> P(Season, Weather | Location)
# We want to compute P(Weather | Location, Season).
# This requires normalizing the data for each Location and Season.
cond_tensor = process_tensor.conditionalization(start_B=2)

# Resulting profile: [[2, 3], [2]]
# Resulting data shape: (2, 3, 2)

tensor_product(other)

Combines two independent systems.

# Let's introduce another system: P(Traffic) where Traffic is {Low, High}
# This is a state tensor with profile [[], [2]]
traffic_state = FXTensor([[], [2]], data=np.array([0.7, 0.3]))

# The tensor product gives the joint probability P(Season, Weather, Traffic | Location)
joint_tensor = process_tensor.tensor_product(traffic_state)

# Resulting profile: [[2], [3, 2, 2]]
# Resulting data shape: (2, 3, 2, 2)

Theoretical Background: Relationship with Markov Categories

The design of this library, fxtensor-salmon, is deeply rooted in the concepts of Markov Categories, a framework from categorical probability theory. The terminology and ideas explained in the blog posts [1] and [2] serve as a crucial guide to understanding the library's functionality. This section explains the correspondence between the concepts described in these articles and the concrete implementation in FXTensor.

Basic Elements of Markov Categories and FXTensor

A Markov category is a mathematical structure for abstractly handling probabilistic systems. Its main components are "objects" and "morphisms."

  • Object: An "object" in a Markov category represents a state space where a random variable can take its values. More formally, it is defined as a measurable space (X, ΣX). In the context of FXTensor, we only deal with finite discrete spaces, so an object is simply represented by a list of dimensions, such as [2] or [3, 2]. [2] represents a state space with two elements, {0, 1}, while [3, 2] represents a composite state space formed by the monoidal product (tensor product) 3 ⊗ 2 of two state spaces, {0, 1, 2} and {0, 1}.

  • Morphism: A "morphism" f: A -> B represents a probabilistic transition from state space A to B, i.e., a Markov kernel. It is a function that, for each input a ∈ A, defines a probability distribution over the output space B. An FXTensor instance itself is a concrete representation of this "morphism." The tensor's profile [domain, codomain] corresponds to the source and target objects of the morphism, respectively. For example, FXTensor([[2], [3]]) is a morphism from object 2 to object 3, and its substance is stored in the data attribute as a probability matrix (Markov matrix) of shape (2, 3).

Categorical Operations and FXTensor Methods

The fundamental operations in a Markov category are implemented as methods in FXTensor.

  1. Composition: The composition f ; g of two morphisms f: A -> B and g: B -> C corresponds to executing processes sequentially. This is realized by the t1.composition(t2) method. In string diagrams, this corresponds to connecting the output wires of f to the input wires of g, which computationally performs a tensor contraction (a generalization of matrix multiplication).

  2. Monoidal Product: This operation takes two independent morphisms f: A -> B and g: C -> D and arranges them in parallel to create a new morphism f ⊗ g: A ⊗ C -> B ⊗ D. This corresponds to t1.tensor_product(t2). It allows for the modeling of larger, composite systems by combining independent ones. In string diagrams, this corresponds to placing two diagrams side-by-side.

  3. Special Morphisms: Discard and Copy

    • Discard: !: A -> I is a morphism that completely ignores the information in state space A (where I is a one-dimensional terminal object). This is none other than the operation of marginalizing a probability distribution. marginalization(start_B) and discard_prefix(start_B) implement this concept of "discard." By summing out and eliminating a part of the codomain (specific output wires), they generate a new morphism with that information discarded.
    • Copy: Δ: A -> A ⊗ A is a morphism that duplicates a state. It is generated by FXTensor.delta(dims). Crucially, this operation is deterministic. Copying a probabilistic value is generally meaningless without assuming independence. The delta tensor is a deterministic tensor that maps an input i to (i, i), having non-zero values only on its diagonal.

Probabilistic Properties and FXTensor

As emphasized in the references, morphisms in a Markov category satisfy a "normalization condition." This is the condition that for each input, the sum of probabilities over the entire output is 1.

  • is_markov(): This method checks if a given tensor satisfies this normalization condition, i.e., if it is a valid Markov kernel.
  • is_deterministic(): A morphism is deterministic if, for each input, the output is uniquely determined with probability 1. This method verifies if the tensor has this property (i.e., each row contains exactly one 1, and the rest are 0s).

Tensor Calculus and String Diagrams

The article [2] provides a detailed explanation of the correspondence between string diagrams and tensor calculus. The operations in FXTensor can be interpreted as algebraically performing these string diagram manipulations.

  • Profile's domain and codomain: These correspond to the bundles of input and output wires in a string diagram, respectively. Each number in the list represents the dimension of an individual wire.
  • composition: Connects diagrams vertically.
  • tensor_product: Places diagrams horizontally.
  • marginalization: Terminates some of the output wires, summing out their effects.

In this way, fxtensor-salmon is a library that implements the abstract concepts of the powerful theoretical framework of Markov categories as concrete tensor computations based on NumPy. It is designed as a computational tool to execute the intuitive process operations depicted in string diagrams with rigor and efficiency.

Testing

The project uses pytest for testing. The tests are organized into classes in tests/test_fxtensor.py to group related functionality.

To run the tests, execute the following command from the project root:

pytest

References

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fxtensor_salmon-0.1.4.tar.gz (15.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fxtensor_salmon-0.1.4-py3-none-any.whl (10.4 kB view details)

Uploaded Python 3

File details

Details for the file fxtensor_salmon-0.1.4.tar.gz.

File metadata

  • Download URL: fxtensor_salmon-0.1.4.tar.gz
  • Upload date:
  • Size: 15.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for fxtensor_salmon-0.1.4.tar.gz
Algorithm Hash digest
SHA256 3adfe2b0783a8e21e0f66dc4ed1aa2f0d3db795e0959f75c2f3fa2a9d1135417
MD5 759d1a153ce9e3688748c012f7aec514
BLAKE2b-256 4d0a278440165fb633ccbbb1c8348a338ba12789ac87dc6050dea8c64781d957

See more details on using hashes here.

File details

Details for the file fxtensor_salmon-0.1.4-py3-none-any.whl.

File metadata

File hashes

Hashes for fxtensor_salmon-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 4ecd09a3bffa30897c1f9fe74d3ec321c97a4f2382c27b67c7d390ac2e0fabb2
MD5 f168109f0c896c9aa7a6b35a170d82c9
BLAKE2b-256 ef3ce0cb26140d7844733d97b0e8190d792d172882d9956fe61950f186732ff8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page