LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
moment_housematrix.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_MOMENT_MOMENT_HOUSEMATRIX_H
6#define LINE_API_MOMENT_MOMENT_HOUSEMATRIX_H
7
8/**
9 * @file
10 * @ingroup api_moment
11 * Conversion matrix of one edge of the house of moments.
12 *
13 * Templated port of matlab/src/api/moment/moment_housematrix.m. The house of
14 * moments collects the raw, factorial, upper-factorial, binomial,
15 * negative-binomial and tail sequences of a discrete law; every edge of it is a
16 * linear map with an integer or rational table, so the exact instantiation
17 * returns the transform with no rounding at all.
18 *
19 * The tail edges are the only UPPER triangular ones, so a caller must apply the
20 * table with a full matrix-vector product and not with the lower-triangular
21 * apply_table helper.
22 *
23 * Reference:
24 * A. Heindl and A. van de Liefvoort. Moment conversions for discrete
25 * distributions. PMCCS, 2003.
26 */
27
28#include <string>
29#include <vector>
30
35#include "line/num/number.h"
36#include "line/util/error.h"
37#include "line/util/matrix.h"
39
40namespace line {
41namespace moment {
42
43/** Edge labels of the house of moments, one per MATLAB edge string. */
60
61/** Parses the MATLAB edge string into its label. */
62inline MomentEdge moment_edge_from_string(const std::string& edge) {
63 if (edge == "factorial_from_raw") return MomentEdge::FactorialFromRaw;
64 if (edge == "raw_from_factorial") return MomentEdge::RawFromFactorial;
65 if (edge == "upfactorial_from_raw") return MomentEdge::UpfactorialFromRaw;
66 if (edge == "raw_from_upfactorial") return MomentEdge::RawFromUpfactorial;
67 if (edge == "binomial_from_factorial") return MomentEdge::BinomialFromFactorial;
68 if (edge == "negbinomial_from_upfactorial") return MomentEdge::NegbinomialFromUpfactorial;
69 if (edge == "factorial_from_binomial") return MomentEdge::FactorialFromBinomial;
70 if (edge == "upfactorial_from_negbinomial") return MomentEdge::UpfactorialFromNegbinomial;
71 if (edge == "factorial_from_upfactorial") return MomentEdge::FactorialFromUpfactorial;
72 if (edge == "upfactorial_from_factorial") return MomentEdge::UpfactorialFromFactorial;
73 if (edge == "negbinomial_from_binomial") return MomentEdge::NegbinomialFromBinomial;
74 if (edge == "binomial_from_negbinomial") return MomentEdge::BinomialFromNegbinomial;
75 if (edge == "binomial_from_tail") return MomentEdge::BinomialFromTail;
76 if (edge == "tail_from_binomial") return MomentEdge::TailFromBinomial;
77 throw InputError("moment_housematrix: unknown edge " + edge);
78}
79
80/** (n+1)x(n+1) conversion table of the given edge. */
81template <class T>
83 if (n < 0)
84 throw InputError("moment_housematrix: the maximum order n must be a nonnegative integer");
85 const T zero = num_traits<T>::from_int(0);
86 const T one = num_traits<T>::from_int(1);
87 Matrix<T> Tm(static_cast<std::size_t>(n) + 1, static_cast<std::size_t>(n) + 1, zero);
88 switch (edge) {
90 return moment_stirling1<T>(n);
92 return moment_stirling2<T>(n);
97 for (int i = 0; i <= n; ++i)
98 for (int j = 0; j <= i; ++j)
99 Tm(i, j) = ((i - j) % 2 == 0) ? S(i, j) : -S(i, j);
100 return Tm;
101 }
104 for (int i = 0; i <= n; ++i)
105 Tm(i, i) = one / num_factorial<T>(static_cast<unsigned>(i));
106 return Tm;
109 for (int i = 0; i <= n; ++i) Tm(i, i) = num_factorial<T>(static_cast<unsigned>(i));
110 return Tm;
114 Tm(0, 0) = one;
115 for (int i = 1; i <= n; ++i)
116 for (int k = 1; k <= i; ++k)
117 Tm(i, k) = (edge == MomentEdge::UpfactorialFromFactorial || (i - k) % 2 == 0)
118 ? L(i, k)
119 : -L(i, k);
120 return Tm;
121 }
124 Tm(0, 0) = one;
125 for (int i = 1; i <= n; ++i)
126 for (int k = 1; k <= i; ++k) {
127 const T c = num_nck<T>(i - 1, k - 1);
128 Tm(i, k) = (edge == MomentEdge::NegbinomialFromBinomial || (i - k) % 2 == 0)
129 ? c
130 : -c;
131 }
132 return Tm;
135 Tm(0, 0) = one;
136 for (int i = 1; i <= n; ++i)
137 for (int k = i; k <= n; ++k) {
138 const T c = num_nck<T>(k - 1, i - 1);
139 Tm(i, k) =
140 (edge == MomentEdge::BinomialFromTail || (k - i) % 2 == 0) ? c : -c;
141 }
142 return Tm;
143 }
144 throw InputError("moment_housematrix: unknown edge");
145}
146
147/** String overload matching the MATLAB call signature. */
148template <class T>
149Matrix<T> moment_housematrix(const std::string& edge, int n) {
151}
152
153/** Full matrix-vector product, needed because the tail edges are upper triangular. */
154template <class T>
155std::vector<T> moment_apply_full(const Matrix<T>& A, const std::vector<T>& v) {
156 std::vector<T> r(v.size(), num_traits<T>::from_int(0));
157 for (std::size_t i = 0; i < v.size(); ++i)
158 for (std::size_t j = 0; j < v.size(); ++j) r[i] += A(i, j) * v[j];
159 return r;
160}
161
162} // namespace moment
163} // namespace line
164
165#endif
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Dense matrix and non-owning view.
Unsigned Lah numbers.
Signed Stirling numbers of the first kind.
Stirling numbers of the second kind.
Unsigned Stirling numbers of the first kind (cycle numbers), orders 0..n.
Matrix< T > moment_housematrix(MomentEdge edge, int n)
(n+1)x(n+1) conversion table of the given edge.
std::vector< T > moment_apply_full(const Matrix< T > &A, const std::vector< T > &v)
Full matrix-vector product, needed because the tail edges are upper triangular.
Matrix< T > moment_stirling2(int n)
S(i,j) = j S(i-1,j) + S(i-1,j-1), S(0,0) = 1.
MomentEdge
Edge labels of the house of moments, one per MATLAB edge string.
Matrix< T > moment_lah(int n)
L(i,j) = L(i-1,j-1) + (i+j-1) L(i-1,j), L(0,0) = 1.
Definition moment_lah.h:31
Matrix< T > moment_stirling1(int n)
s(i,j) = (-1)^(i-j) sigma(i,j).
MomentEdge moment_edge_from_string(const std::string &edge)
Parses the MATLAB edge string into its label.
Matrix< T > moment_stirlingcycle(int n)
sigma(i,j), (n+1) x (n+1) lower triangular, sigma(0,0) = 1.
T num_factorial(unsigned n)
Factorial as a value of T.
Definition number.h:184
T num_nck(int n, int k)
Binomial coefficient as a value of T, by the Pascal recurrence.
Definition population.h:87
Number-type abstraction for the templated API port.
Population-vector enumeration and combinatorics.