5#ifndef LINE_API_MC_CTMC_SADDLEPOINT_H
6#define LINE_API_MC_CTMC_SADDLEPOINT_H
126 return d == d && d != std::numeric_limits<double>::infinity() &&
127 d != -std::numeric_limits<double>::infinity();
134using detail::tx_finite;
171inline std::vector<T> saddle_solve(
Matrix<T> A, std::vector<T> b) {
172 std::vector<std::size_t> piv =
lu_factor(A);
190 const std::vector<T>& pi0,
const T& th) {
191 const std::size_t n = D0.
rows();
194 for (std::size_t i = 0; i < n; ++i)
195 for (std::size_t j = 0; j < n; ++j) {
196 W(i, j) = ex * D1(i, j);
197 A(i, j) = D0(i, j) + W(i, j);
201 for (std::size_t i = 0; i < n; ++i)
203 const std::vector<std::complex<double> > ev =
eig_values(Ad);
204 double etad = -std::numeric_limits<double>::infinity();
205 for (std::size_t i = 0; i < ev.size(); ++i)
206 if (ev[i].real() > etad) etad = ev[i].real();
210 for (std::size_t i = 0; i < n; ++i)
211 for (std::size_t j = 0; j < n; ++j)
221 const std::vector<T> v = detail::saddle_solve(M, rhs);
224 for (std::size_t i = 0; i < n; ++i)
225 for (std::size_t j = 0; j < n; ++j)
227 std::vector<T> u = detail::saddle_solve(Mt, rhs);
229 for (std::size_t i = 0; i < n; ++i) uv += u[i] * v[i];
230 for (std::size_t i = 0; i < n; ++i) u[i] /= uv;
235 for (std::size_t i = 0; i < n; ++i) {
237 for (std::size_t j = 0; j < n; ++j) inner += W(i, j) * v[j];
238 st.
deta += u[i] * inner;
246 for (std::size_t i = 0; i < n; ++i) {
247 for (std::size_t j = 0; j < n; ++j) B(i, j) = Ashift(i, j);
250 T acc = st.
deta * v[i];
251 for (std::size_t j = 0; j < n; ++j) acc -= W(i, j) * v[j];
254 const std::vector<T> sol = detail::saddle_solve(B, r);
256 for (std::size_t i = 0; i < n; ++i) {
258 for (std::size_t j = 0; j < n; ++j) inner += W(i, j) * sol[j];
259 corr2 += u[i] * inner;
264 for (std::size_t i = 0; i < n; ++i) {
282inline T saddle_root(
const Matrix<T>& D0,
const Matrix<T>& D1,
const std::vector<T>& pi0,
283 const T& r,
const T& th0,
const T& thmin,
const T& thmax,
int& iters) {
285 const int MAXIT = 200;
286 T th = std::min(std::max(th0, thmin), thmax);
288 T lo = th, hi = th, dlo = d1, dhi = d1;
298 throw InputError(
"ctmc_saddlepoint: the rate k/t is below the representable "
305 step = num_traits<T>::from_int(1);
314 throw InputError(
"ctmc_saddlepoint: the rate k/t is above the representable "
321 th = std::min(std::max(th, lo), hi);
322 const T logr = tx_log(r);
324 for (
int it = 1; it <= MAXIT; ++it) {
327 const T f = tx_log(si.deta) - logr;
329 if (f > num_traits<T>::from_int(0))
333 T thn = th - f * si.deta / si.d2eta;
334 if (!tx_finite(thn) || thn <= lo || thn >= hi)
335 thn = (lo + hi) / num_traits<T>::from_int(2);
337 TOL * std::max(num_traits<T>::from_int(1),
num_abs(th))) {
360 const std::vector<T>& t,
const std::vector<long>& k,
362 const std::vector<T>& pi0 = std::vector<T>()) {
364 "ctmc_saddlepoint is unavailable over the rational field: the saddlepoint "
365 "involves exp, log and sqrt of the Perron root, none a rational function "
367 const std::size_t nph = D0.
rows();
368 if (D0.
cols() != nph || D1.
rows() != nph || D1.
cols() != nph)
369 throw InputError(
"ctmc_saddlepoint: D0 and D1 must be square matrices of the same order");
371 T maxrate = zero, maxq = zero;
372 for (std::size_t i = 0; i < nph; ++i)
373 for (std::size_t j = 0; j < nph; ++j) {
374 if (D1(i, j) < zero)
throw InputError(
"ctmc_saddlepoint: D1 must be nonnegative");
375 maxrate = std::max(maxrate, D1(i, j));
376 maxq = std::max(maxq,
num_abs(D0(i, j) + D1(i, j)));
378 if (!(maxrate > zero))
379 throw InputError(
"ctmc_saddlepoint: D1 has no counted transitions, the counting process "
380 "is identically zero");
382 for (std::size_t i = 0; i < nph; ++i) {
384 for (std::size_t j = 0; j < nph; ++j) {
385 Q(i, j) = D0(i, j) + D1(i, j);
390 throw InputError(
"ctmc_saddlepoint: D0+D1 must be an infinitesimal generator "
394 std::vector<T> pi = pi0;
396 if (pi.size() != nph)
397 throw InputError(
"ctmc_saddlepoint: pi0 must have one entry per phase");
399 for (std::size_t i = 0; i < nph; ++i) pisum += pi[i];
401 throw InputError(
"ctmc_saddlepoint: pi0 must sum to one");
404 const std::size_t n = std::max(t.size(), k.size());
405 if ((t.size() != n && t.size() != 1) || (k.size() != n && k.size() != 1))
406 throw InputError(
"ctmc_saddlepoint: t and k must be scalars or arrays of the same size");
407 std::vector<T> tv(n);
408 std::vector<long> kv(n);
409 for (std::size_t i = 0; i < n; ++i) {
410 tv[i] = t.size() == 1 ? t[0] : t[i];
411 kv[i] = k.size() == 1 ? k[0] : k[i];
412 if (tv[i] < zero)
throw InputError(
"ctmc_saddlepoint: the horizon t must be nonnegative");
413 if (kv[i] < 0)
throw InputError(
"ctmc_saddlepoint: the count k must be nonnegative");
419 res.
p.assign(n, zero);
420 res.
logp.assign(n, ninf);
421 res.
theta.assign(n, ninf);
422 res.
eta.assign(n, nan);
423 res.
deta.assign(n, nan);
424 res.
d2eta.assign(n, nan);
425 res.
ampl.assign(n, nan);
426 res.
corr.assign(n, nan);
427 res.
k2.assign(n, nan);
428 res.
iter.assign(n, 0);
429 res.
exact.assign(n,
false);
445 std::vector<std::size_t> ord(n);
446 for (std::size_t i = 0; i < n; ++i) ord[i] = i;
447 std::vector<double> rate(n, 0.0);
448 for (std::size_t i = 0; i < n; ++i)
450 std::stable_sort(ord.begin(), ord.end(),
451 [&rate](std::size_t a, std::size_t b) { return rate[a] < rate[b]; });
454 for (std::size_t idx = 0; idx < n; ++idx) {
455 const std::size_t i = ord[idx];
457 const long ki = kv[i];
474 for (std::size_t a = 0; a < nph; ++a)
475 for (std::size_t b = 0; b < nph; ++b) acc += pi[a] * E(a, b);
477 res.
logp[i] = acc > zero ?
tx_log(acc) : ninf;
483 thmin, thmax, iters);
493 const T K2 = ti * s.
d2eta;
501 throw NumericError(
"ctmc_saddlepoint: the cumulant generating function is not "
502 "strictly convex at the saddle; D0+D1 is probably reducible");
504 const T base = ti * s.
eta - kiT * th -
522 const T d3 = (sp.
d2eta - sm.
d2eta) / (two * h);
524 const T K3 = ti * d3, K4 = ti * d4;
525 const T lam3sq = K3 * K3 / (K2 * K2 * K2);
526 const T lam4 = K4 / (K2 * K2);
527 const T gp = (sp.
ampl - sm.
ampl) / (two * h);
528 const T gpp = (sp.
ampl - two * s.
ampl + sm.
ampl) / (h * h);
534 gpp / (two * K2) + gp * K3 / (two * K2 * K2);
535 if (corr <= zero) corr = ampl;
551 return ctmc_saddlepoint(D0, D1, std::vector<T>(1, t), std::vector<long>(1, k), method).p[0];
NumericError(const std::string &what)
Steady-state distribution of a continuous-time Markov chain.
Eigenvalues and singular values, backed by LAPACK.
The exception types the port throws.
Matrix exponential by scaling and squaring with a diagonal Pade approximant.
LU factorization with partial pivoting, templated on the number type.
Dense matrix and non-owning view.
bool tx_finite(const T &x)
SaddlepointMethod
Which term of the steepest-descent expansion to stop at.
@ SADDLEPOINT_DANIELS2
second order, error O(1/K2^2) – the DEFAULT
@ SADDLEPOINT_PLAIN
bare first order, amplitude set to 1
@ SADDLEPOINT_DANIELS
first order with the Perron amplitude, O(1/K2)
std::vector< T > ctmc_solve(const Matrix< T > &Qin)
Steady-state distribution of a continuous-time Markov chain.
T tx_exp(const T &x)
exp/log/isfinite through ADL, the idiom the rest of api/mc uses: using std::exp then an unqualified c...
SaddlepointResult< T > ctmc_saddlepoint(const Matrix< T > &D0, const Matrix< T > &D1, const std::vector< T > &t, const std::vector< long > &k, SaddlepointMethod method=SADDLEPOINT_DANIELS2, const std::vector< T > &pi0=std::vector< T >())
Pr{N(t)=k} over arrays of horizons and counts.
static const double CTMC_SADDLEPOINT_K2_MIN
Below this value of K2 = t*eta''(theta*) the expansion is out of its regime.
PerronState< T > ctmc_saddlepoint_perron(const Matrix< T > &D0, const Matrix< T > &D1, const std::vector< T > &pi0, const T &th)
Perron root of A(th) = D0 + exp(th)*D1 with deta, d2eta and the amplitude.
void lu_solve(const Matrix< T > &LU, const std::vector< std::size_t > &piv, std::vector< T > &b)
Solve LUx = Pb in place on b, using the factors from lu_factor.
std::vector< std::size_t > lu_factor(Matrix< T > &A)
In-place LU of A (n x n).
std::vector< std::complex< double > > eig_values(const Matrix< double > &A)
Eigenvalues of a general real square matrix, in LAPACK's order.
Matrix< T > expm(const Matrix< T > &A)
Matrix exponential exp(A).
Number-type abstraction for the templated API port.
Perron root of A(theta) with its first two derivatives and the amplitude.
One entry per (t,k) pair.
double worst_t
horizon at which it was met
std::vector< T > eta
eta(theta*)
std::vector< T > p
approximation of Pr{N(t)=k}
std::vector< bool > exact
true where the value is exact, not approximated
std::vector< T > k2
K2 = t*eta''(theta*), the expansion parameter.
std::vector< int > iter
Newton steps taken.
std::vector< T > theta
the saddle theta*, -inf where k=0
bool out_of_regime
true when some point fell below CTMC_SADDLEPOINT_K2_MIN
T lambda
the stationary event rate eta'(0)
std::vector< T > ampl
the Perron amplitude g(theta*)
std::vector< T > deta
eta'(theta*), equal to k/t at convergence
T worst_k2
the smallest K2 met
std::vector< T > d2eta
eta''(theta*)
std::vector< T > logp
its natural logarithm, accurate below the floor
std::vector< T > corr
the bracket multiplying the leading term
long worst_k
count at which it was met