1function [piTimeAvg,piExit,kmax]=ctmc_timeaverage(pi0,Q,t,tol,maxiter)
2% [PITIMEAVG,PIEXIT,KMAX]=CTMC_TIMEAVERAGE(PI0,Q,T,TOL,MAXITER)
4% Time-averaged transient distribution of a CTMC with generator Q over [0,T],
5% starting from
the (arbitrary) initial distribution PI0, via Jensen
's
6% uniformization. Companion of CTMC_UNIFORMIZATION, which returns only the
7% endpoint PI0*exp(Q*T); this function additionally returns the time average
9% PITIMEAVG = PI0 * (1/T) * \int_0^T exp(Q*tau) d(tau)
11% as well as the endpoint PIEXIT = PI0*exp(Q*T) (computed from the same series).
12% Both are obtained without forming any dense matrix exponential.
14% Uniformization: with q = 1.1*max|diag(Q)| and P = I + Q/q (row-stochastic),
15% PI0*exp(Q*T) = sum_j w_j(qT) * (PI0*P^j)
16% PI0*\int_0^T exp(Q*tau) = (1/q) * sum_j (1 - W_j(qT)) * (PI0*P^j)
17% where w_j and W_j are the Poisson(qT) PMF and CDF. The time average divides
18% the integral by T (equivalently the integral sum by q*T).
20% Copyright (c) 2012-2026, Imperial College London
30q = 1.1*max(abs(diag(Q)));
31% Split the horizon into equal segments with q*tSeg below the underflow
32% bound (exp(-745)==0): the integral over [0,t] is the sum of segment
33% integrals, each started from the previous segment's endpoint
36 nSeg = ceil(q*t/MAXQT);
39 integral = zeros(1,size(Q,1));
41 [avgSeg,piCur,kmax] = ctmc_timeaverage(piCur,Q,tSeg,tol,maxiter);
42 integral = integral + tSeg*avgSeg(:)
';
44 piTimeAvg = integral/t;
49 % The Poisson(q*t) mass concentrates around q*t with spread O(sqrt(q*t));
50 % a fixed cap silently truncates the series for large horizons
51 maxiter = max(100, ceil(q*t+10*sqrt(q*t)+20));
53Qs = speye(size(Q)) + sparse(Q)/q;
56% Number of Poisson terms needed (right-tail below tol), as in ctmc_uniformization
57k = 0; s = 1; r = 1; iter = 0; kmax = 1;
63 if (1 - exp(-qt)*s) <= tol
67 % Best-effort truncation depth if the loop exhausts maxiter
71% Accumulate endpoint and integral over the shared PI0*P^j sequence
72w = exp(-qt); % Poisson PMF w_0
73W = w; % Poisson CDF W_0
76piIntSum = max(1 - W, 0) * P;
81 piExit = piExit + w * P;
82 piIntSum = piIntSum + max(1 - W, 0) * P;
85piTimeAvg = piIntSum / qt; % (1/q)*sum / t = sum/(q*t)