Operations API Reference

Custom operations for use in SciStanPy Stan models.

This module provides a framework for adding mathematical operations to the model graph. Operations are built from TransformedParameter classes and can handle both immediate computation on NumPy/PyTorch data and deferred computation within model graphs. This module should be the access point to all operations available in SciStanPy–users should not need to directly interact with the underlying transformation classes.

Operation Framework

The operations module provides a framework for creating mathematical operations from TransformedParameter classes that work with both SciStanPy model components and raw numerical data (NumPy arrays/PyTorch tensors).

Core Classes:

class scistanpy.operations.MetaOperation(name, bases, attrs)[source]

Bases: type

Metaclass for dynamically creating operation classes.

This metaclass is responsible for creating operation classes from TransformedParameter classes. It validates that a DISTCLASS attribute is provided and appropriate, then automatically inherits documentation from the underlying transformation class. In general, users will not need to interact with this metaclass directly.

Parameters:
  • name (str) – Name of the class being created

  • bases (tuple) – Base classes for the new class

  • attrs (dict) – Class attributes dictionary

Raises:
  • ValueError – If DISTCLASS is not provided in class attributes

  • TypeError – If DISTCLASS is not a subclass of TransformedParameter

The metaclass performs the following validations and setup:
  • Ensures DISTCLASS attribute exists

  • Validates DISTCLASS inheritance from TransformedParameter

  • Inherits documentation from the DISTCLASS to the __call__ method

class scistanpy.operations.Operation[source]

Bases: object

Base class for SciStanPy mathematical operations.

This class provides the foundation for all mathematical operations that can be used in SciStanPy models. Operations can handle both immediate computation on numerical data and deferred computation when used with model components.

The class should never be instantiated directly. Instead, use the build_operation() function to create specific operation instances from TransformedParameter classes.

Variables:

DISTCLASS – The TransformedParameter class this operation wraps.

Note

Operations automatically detect whether they are being called with SciStanPy model components or raw numerical data and handle each case appropriately.

DISTCLASS: type[TransformedParameter]
__call__(*args, **kwargs)[source]

Apply the operation to the provided inputs.

This method provides intelligent dispatching based on the input types. When called with SciStanPy model components, it returns a new TransformedParameter instance for deferred computation. When called with raw numerical data (numpy), it performs immediate computation.

Parameters:
  • args (tuple) – Positional arguments for the operation. Can be model components or numerical data.

  • kwargs (dict) – Keyword arguments for the operation. Can contain model components or numerical data.

Returns:

Either a TransformedParameter instance (for deferred computation) or the immediate result of the operation on numerical data.

Return type:

Union[transformed_parameters.TransformedParameter, Any]

The method behavior depends on input types:

Operation Builder:

The build_operation() function allows users to create custom operations easily by wrapping a TransformedParameter subclass. This is the main interface for creating new operations from custom TransformedParameter classes and is what is used under the hood to create all built-in operations.

scistanpy.operations.build_operation(
distclass: type[TransformedParameter],
) Operation[source]

Build an operation instance from a TransformedParameter class.

This function creates a new operation class using the MetaOperation metaclass in combination with the Operation base class, then returns an instance of that class. The resulting operation inherits documentation and behavior from the provided TransformedParameter class.

Parameters:

distclass (type[transformed_parameters.TransformedParameter]) – The TransformedParameter class to build the operation from.

Returns:

A new operation instance that wraps the provided TransformedParameter class.

Return type:

Operation

Raises:
  • ValueError – If distclass is not provided

  • TypeError – If distclass is not a subclass of TransformedParameter

Example:

from scistanpy.operations import build_operation
from scistanpy.model.components.transformations.transformed_parameters import UnaryTransformedParameter

class MyTransformation(UnaryTransformedParameter):
    # Custom mathematical transformation.

    def run_np_torch_op(self, x):
        # Implementation for numerical data
        return x**2 + 1

    def write_stan_operation(self, x: str) -> str:
        # Stan code generation
        return f"square({x}) + 1"

# Create operation
my_operation = build_operation(MyTransformation)

# Use the operation
param = ssp.parameters.Normal(mu=0.0, sigma=1.0)
transformed = my_operation(param)

Operation Usage Patterns

Operations can be used in two main contexts: with SciStanPy model components (Parameter, TransformedParameter, and Constant) and with raw numerical data (NumPy arrays or PyTorch tensors). The operations automatically dispatch to the appropriate behavior based on the input type.

With Model Components:

# Operations with parameters create transformed parameters
base_param = ssp.parameters.Normal(mu=0.0, sigma=1.0)
transformed = ssp.operations.exp(base_param)

# Use in model definitions
observed = ssp.parameters.Normal(mu=transformed, sigma=0.1)

With Numerical Data:

# Operations with numerical data compute immediately
import numpy as np

data = np.array([1, 2, 3])
result = ssp.operations.exp(data)  # Returns exp([1, 2, 3])

Intelligent Dispatching:

# Operations automatically detect input types
def my_function(x):
    return ssp.operations.log(ssp.operations.exp(x) + 1)

# Works with both parameters and data
param_result = my_function(ssp.parameters.Normal(mu=0, sigma=1))
data_result = my_function(np.array([1, 2, 3]))

Available Operations

The following operations are available in the SciStanPy operations module. Each operation is documented with its usage patterns and examples.

If there’s a specific mathematical operation that you need which is not listed here (and, given that this is an evolving library, there are certainly many missing), please consider (A) raising an issue on the SciStanPy GitHub repository requesting its addition, or (B) creating a custom operation using the build_operation() function. If you take the latter approach, also consider contributing your custom operation back to the SciStanPy project for inclusion in future releases!

Mathematical Functions

Below are the basic mathematical operations provided by SciStanPy.

scistanpy.operations.abs_(*args, **kwargs)

Absolute value operation.

Computes the absolute value of the input parameter or numerical data. See also, AbsParameter.

Usage:

# With model components
param = ssp.parameters.Normal(mu=0.0, sigma=1.0)
abs_param = ssp.operations.abs_(param)

# With numerical data
result = ssp.operations.abs_([-1.0, -2.0, 3.0])  # Returns [1.0, 2.0, 3.0]
scistanpy.operations.exp(*args, **kwargs)

Exponential operation.

Computes the exponential (e^x) of the input parameter or numerical data. See also, ExpParameter.

Usage:

# Exponential transformation
log_rate = ssp.parameters.Normal(mu=0.0, sigma=1.0)
rate = ssp.operations.exp(log_rate)  # Ensures positive values
scistanpy.operations.log(*args, **kwargs)

Natural logarithm operation.

Computes the natural logarithm of the input parameter or numerical data. See also, LogParameter.

Usage:

# Natural logarithm
positive_param = ssp.parameters.LogNormal(mu=0.0, sigma=1.0)
log_param = ssp.operations.log(positive_param)
scistanpy.operations.log1p_exp(*args, **kwargs)

\(\log(1 + \exp(x))\) operation.

Computes \(\log(1 + \exp(x))\) in a numerically stable way. See also, Log1pExpParameter.

scistanpy.operations.sigmoid(*args, **kwargs)

Sigmoid operation.

Computes the sigmoid function \((1 + \exp(-x))^{-1}\) of the input. See also, SigmoidParameter.

Usage:

# Convert logits to probabilities
logits = ssp.parameters.Normal(mu=0.0, sigma=1.0)
probabilities = ssp.operations.sigmoid(logits)
scistanpy.operations.log_sigmoid(*args, **kwargs)

Log-sigmoid operation.

Computes the logarithm of the sigmoid function in a numerically stable way. See also, LogSigmoidParameter.

Normalization Operations

Normalization operations that can be used to build constrained transformed parameters from unconstrained parameters. Take care with these when sampling! It is easy to create non-identifiable models if the normalization is not used correctly.

Note

The normalization operations always operate over the last dimension of the input parameter when applied to SciStanPy parameters.

scistanpy.operations.normalize(*args, **kwargs)

Normalization operation.

Normalizes input data to unit sum. Note that when applied to SciStanPy parameters, this operation is always performed over the last dimension. See also, NormalizeParameter.

Usage:

# Normalize to unit sum (over last dimension)
weights = ssp.parameters.LogNormal(mu=0.0, sigma=1.0, shape=(3, 9))
probabilities = ssp.operations.normalize(weights) # Each row sums to 1
scistanpy.operations.normalize_log(*args, **kwargs)

Log-space normalization operation.

This function ensures that the sum of exponentials is equal to 1 over the last dimension of the input. See also, NormalizeLogParameter.

Usage:

# Normalize to unit sum (over last dimension)
weights = ssp.parameters.Normal(mu=0.0, sigma=1.0, shape=(3, 9))
probabilities = ssp.operations.exp(
    ssp.operations.normalize(weights)
) # Each row sums to 1

Reduction Operations

Reduction operations allow for aggregating values across dimensions of parameters or data. As with the normalization operations, these always operate over the last dimension of the input parameter when applied to SciStanPy parameters.

scistanpy.operations.sum_(*args, **kwargs)

Summation operation.

Computes the sum over an input parameter dimension or over numerical data. Note that for SciStanPy operations, the sum is always performed over the last dimension. See also, SumParameter.

Usage:

# Sum over last dimension
values = ssp.parameters.Normal(mu=0.0, sigma=1.0, shape=(5, 3))
total = ssp.operations.sum_(values) # Shape = (5,)

# Sum but keep dimensions
total_keepdims = ssp.operations.sum_(values, keepdims=True) # Shape = (5, 1)
scistanpy.operations.logsumexp(*args, **kwargs)

Log-sum-exp operation.

Note that for SciStanPy operations, the sum is always performed over the last dimension.

Computes log(sum(exp(x))) in a numerically stable way. See also, LogSumExpParameter.

Growth Model Operations

Growth model operations provide a set of mathematical transformations for modeling population growth and similar temporal dynamics. These operations can be used to define growth models in a probabilistic framework (e.g., for deep mutational scanning).

scistanpy.operations.exponential_growth(*args, **kwargs)

Exponential growth operation.

Models exponential growth patterns in time series data. See also, ExponentialGrowth.

Usage:

# Model exponential population growth
time_points = np.array([0, 1, 2, 3, 4])
initial_pop = ssp.parameters.LogNormal(mu=np.log(100), sigma=0.1)
growth_rate = ssp.parameters.Normal(mu=0.1, sigma=0.05)

population = ssp.operations.exponential_growth(
    t=time_points, A=initial_pop, r=growth_rate
)
scistanpy.operations.binary_exponential_growth(*args, **kwargs)

Binary exponential growth operation.

Models exponential growth over two timepoints, taking in the population size at the starting time (assumed to be at t = 0) and outputting the population size at the ending time (assumed to be at t = 1). See also, BinaryExponentialGrowth.

Usage:

# Two-timepoint exponential growth
initial_size = ssp.parameters.LogNormal(mu=np.log(50), sigma=0.2)
growth_rate = ssp.parameters.Normal(mu=0.2, sigma=0.1)

final_size = ssp.operations.binary_exponential_growth(
    A=initial_size, r=growth_rate
)
scistanpy.operations.log_exponential_growth(*args, **kwargs)

Log-exponential growth operation.

Identical to ~scistanpy.operations.exponential_growth, only models the log of the population size. See also, LogExponentialGrowth.

scistanpy.operations.binary_log_exponential_growth(*args, **kwargs)

Binary log-exponential growth operation.

Identical to binary_exponential_growth(), only models the log of the population size. See also, BinaryLogExponentialGrowth.

scistanpy.operations.sigmoid_growth(*args, **kwargs)

Sigmoid growth operation.

Models sigmoid growth patterns in time series data. See also, SigmoidGrowth.

Usage:

# Logistic growth with carrying capacity
time_points = np.array([0, 5, 10, 15, 20])
carrying_capacity = ssp.parameters.LogNormal(mu=np.log(1000), sigma=0.1)
growth_rate = ssp.parameters.Normal(mu=0.3, sigma=0.1)
inflection_time = ssp.parameters.Normal(mu=10.0, sigma=2.0)

population = ssp.operations.sigmoid_growth(
    t=time_points, A=carrying_capacity, r=growth_rate, c=inflection_time
)
scistanpy.operations.log_sigmoid_growth(*args, **kwargs)

Log-sigmoid growth operation.

Identical to log_sigmoid_growth(), only models the log of the population size. See also, LogSigmoidGrowth.

scistanpy.operations.sigmoid_growth_init_param(*args, **kwargs)

An alternate parametrization of sigmoid_growth() parametrized using initial population abundance rather than carrying capacity. See also, SigmoidGrowthInitParametrization.

Usage:

# Alternative sigmoid parametrization using initial population
time_points = np.array([0, 5, 10])
carrying_capacity = ssp.parameters.LogNormal(mu=np.log(1000), sigma=0.1)
growth_rate = ssp.parameters.Normal(mu=0.3, sigma=0.1)
init_pop = ssp.parameters.LogNormal(mu=np.log(10), sigma=0.2)

population = ssp.operations.sigmoid_growth_init_param(
    t=time_points, A=carrying_capacity, r=growth_rate, A0=init_pop
)
scistanpy.operations.log_sigmoid_growth_init_param(*args, **kwargs)

An alternative parametrization of log_sigmoid_growth() parametrized using initial population abundance rather than carrying capacity. See also, LogSigmoidGrowthInitParametrization.

Specialized Operations

Specialized operations provide additional mathematical transformations that are useful in specific modeling contexts. There is plenty of room for expansion in this category, and users are encouraged to contribute new operations as needed.

scistanpy.operations.convolve_sequence(*args, **kwargs)

Sequence convolution operation.

Performs convolution operations on sequence data. See also, ConvolveSequence.

Usage:

# Sequence convolution for pattern matching
weights = Normal(mu=0, sigma=1, shape=(motif_length, 4))  # 4 nucleotides
dna_sequence = Constant(encoded_dna)  # 0,1,2,3 for A,C,G,T

# Perform convolution of the sequence with the weights
convolved = ssp.operations.convolve_sequence(
    weights=weights, ordinals=dna_sequence
)