Project: s41467-025-58356-7 | Function: convolve_exp (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Performs convolution of piecewise step functions with exponential decay functions for PET tracer kinetic modeling. Implements mathematical convolution operations essential for analyzing blood-brain barrier permeability using time-activity curves (TACs) from PET imaging data.

**KEY TERMS:** {
  "f_t": "time-activity curve input function",
  "alpha": "exponential decay parameter",
  "convolve": "mathematical convolution operation",
  "cumtrapz": "cumulative trapezoidal integration"
}

**CONTEXT CODE:** # -*- coding: utf-8 -*-
"""
Created on Thu Oct  3 21:54:59 2024

@author: kjychung
"""
import numpy as np

from scipy.integrate import cumtrapz
from scipy.optimize import nnls

from functools import partial
from multiprocessing import Pool

import time
import os

try:
    from . mathtools import logspace_with_bounds, batch_nnls
except:
    from utils.mathtools import logspace_with_bounds, batch_nnls

def convolve_exp(t, f_t, alpha):
    """
    Performs convolution of piecewise step functions with exponential decay functions for PET tracer kinetic modeling.

    This function implements mathematical convolution operations essential for analyzing blood-brain barrier
    permeability using time-activity curves (TACs) from PET imaging data. The implementation handles convolution
    of a series of boxcar functions (scaled by f_t[i]) with exponential decay functions, which is fundamental
    to PET kinetic analysis.

    Args:
        t: Time array for the analysis
        f_t: Piecewise step function values (assumed to be Sum_{i=0}^{N-1} {f_t[i] * (H(t-t_i) - H(t-t_{i+1}))})
        alpha: Exponential decay parameter

    Returns:
        Convolution result for PET tracer kinetic modeling

    Paper reference: "Using an average ascending aorta arterial input function from our cohort, we simulated
    dispersed arterial input functions using a mono-exponential dispersion function: C_d(t) = C_a(t) ⊗ k_d*e^(-k_d*t)"

    Formula: Convolution f_t ⊗ e^(-αt) for piecewise step functions
    Implementation: Mathematical convolution using Heaviside step functions, exponential operations, and cumulative integration
    """
    # MASKED: Mathematical convolution implementation for PET tracer kinetic modeling
    raise NotImplementedError("This function is masked for testing purposes. The function performs convolution of piecewise step functions with exponential decay functions for PET tracer kinetic modeling, implementing mathematical convolution operations essential for analyzing blood-brain barrier permeability using time-activity curves from PET imaging data.")

def akaike_information_criteria(y, yp, nparams):
    """
    y and yp are ndarrays with shape (nt,) or (ncurves,nt). y and yp should 
    have the same size. 
    nparams = number of parameters in the model
    """
    
    yshape = y.shape
    nt = yshape[-1]
    rss = np.sum((y - yp)**2, axis=-1)
    aic = nt*np.log(rss / nt) + 2*nparams + (2*nparams**2 + 2*nparams) / (nt - nparams - 1)
    
    return aic


def aath_tac(t, Cwb, td, Tc, F, K1, k2, Cp=None):
    
    if Cp is None:
        Cp = Cwb
        
    aif_cdf = cumtrapz(Cwb, x=t, initial=0)
    aif_cdf_td = np.interp(t-td, t, aif_cdf)
    aif_cdf_td_Tc = np.interp(t-td-Tc, t, aif_cdf)
    
    aif_conv_exp = convolve_exp(t, Cp, k2)
    aif_conv_exp_td_Tc = np.interp(t-td-Tc, t, aif_conv_exp)
    
    q_iv = F*(aif_cdf_td - aif_cdf_td_Tc)
    q_ev = K1*aif_conv_exp_td_Tc
    
    return q_iv, q_ev


def s1tc_tac(t, Cwb, td, va, K1, k2, Cp=None):
    
    if Cp is None:
        Cp = Cwb
    
    aif_conv_exp = convolve_exp(t, Cp, k2)
    
    q_iv = va*np.interp(t-td, t, Cwb, Cwb[0], Cwb[-1])
    q_ev = (1-va)*K1*np.interp(t-td, t, aif_conv_exp)
    
    return q_iv, q_ev

def create_aath_bfm_matrix(t, Cwb, Cp=None, 
                           td_params=(0,10.25,0.25),
                           Tc_params=(3,10.25,0.25),
                           k2_params=(0.00001,0.05,100),
                           useVa=False
                           ):   
    
    t_str0 = time.time()
    
    if Cp is None:
        Cp = Cwb
        
    nt = len(t)
    
    k2_vals = logspace_with_bounds(*k2_params, prependZero=True)
    nk2 = len(k2_vals)

    td_lut, Tc_lut, k2_lut = np.meshgrid(np.arange(*td_params),
                                        np.arange(*Tc_params),
                                        k2_vals)
    
    td_lut = td_lut.flatten()
    Tc_lut = Tc_lut.flatten()
    k2_lut = k2_lut.flatten()

    ncombos = td_lut.size
    
    Cwb_cdf = cumtrapz(Cwb, x=t, initial=0)



Complete the function implementation replacing "raise NotImplementedError".