112 const std::vector<T>& alpha,
double c,
113 const std::vector<T>& arrRate,
const std::vector<T>& sf) {
115 const std::size_t p = D0.
rows();
117 throw InputError(
"ldqbd_mphc: needs at least one level above the empty one");
118 const std::size_t Nlev = arrRate.size() - 1;
120 throw InputError(
"ldqbd_mphc: needs at least one level above the empty one");
121 if (D0.
cols() != p || D1.
rows() != p || D1.
cols() != p || alpha.size() != p)
122 throw InputError(
"ldqbd_mphc: D0, D1 and alpha must all have the same order");
123 if (!sf.empty() && sf.size() < Nlev)
124 throw InputError(
"ldqbd_mphc: sf must give one total-service-rate factor per level");
128 const std::size_t cmax =
129 !std::isfinite(c) ? Nlev
130 : std::min(std::max<std::size_t>(1,
static_cast<std::size_t
>(
134 std::vector<std::vector<std::vector<int> > > cfg(cmax + 1);
135 std::vector<std::map<std::vector<int>, std::size_t> > pos(cmax + 1);
136 std::vector<std::size_t> nCfg(cmax + 1, 0);
137 for (std::size_t k = 0; k <= cmax; ++k) {
139 for (std::size_t r = 0; r < cfg[k].size(); ++r) pos[k][cfg[k][r]] = r;
140 nCfg[k] = cfg[k].size();
145 "ldqbd_mphc: the exact M/PH/c chain needs " + std::to_string(nCfg[cmax]) +
146 " configurations per level for " + std::to_string(cmax) +
" servers and " +
149 " the level-by-level inverses can carry. Use fewer phases (a lower-order fit), "
150 "fewer servers, or SolverCTMC/SolverLDES on this model");
153 std::vector<T> t(p, zero);
154 for (std::size_t i = 0; i < p; ++i)
155 for (std::size_t j = 0; j < p; ++j) t[i] += D1(i, j);
160 std::vector<Matrix<T> > LOC(cmax + 1), UP(cmax + 1), DN(cmax + 1);
161 for (std::size_t k = 0; k <= cmax; ++k) {
162 const std::vector<std::vector<int> >& Ck = cfg[k];
163 LOC[k] =
Matrix<T>(nCfg[k], nCfg[k], zero);
164 for (std::size_t row = 0; row < nCfg[k]; ++row) {
165 const std::vector<int>& m = Ck[row];
166 for (std::size_t i = 0; i < p; ++i) {
167 if (m[i] == 0)
continue;
169 for (std::size_t j = 0; j < p; ++j) {
170 if (j == i)
continue;
171 std::vector<int> mm = m;
174 LOC[k](row, pos[k][mm]) += T(mult * D0(i, j));
177 LOC[k](row, row) += T(mult * D0(i, i));
182 UP[k] =
Matrix<T>(nCfg[k], nCfg[k + 1], zero);
183 for (std::size_t row = 0; row < nCfg[k]; ++row) {
184 const std::vector<int>& m = Ck[row];
185 for (std::size_t j = 0; j < p; ++j) {
186 std::vector<int> mm = m;
188 UP[k](row, pos[k + 1][mm]) += alpha[j];
194 DN[k] =
Matrix<T>(nCfg[k], nCfg[k - 1], zero);
195 for (std::size_t row = 0; row < nCfg[k]; ++row) {
196 const std::vector<int>& m = Ck[row];
197 for (std::size_t i = 0; i < p; ++i) {
198 if (m[i] == 0)
continue;
199 std::vector<int> mm = m;
209 Matrix<T> CDEP(nCfg[cmax], nCfg[cmax], zero);
210 for (std::size_t row = 0; row < nCfg[cmax]; ++row) {
211 const std::vector<int>& m = cfg[cmax][row];
212 for (std::size_t i = 0; i < p; ++i) {
213 if (m[i] == 0)
continue;
215 for (std::size_t j = 0; j < p; ++j) {
216 std::vector<int> mm = m;
219 CDEP(row, pos[cmax][mm]) += T(mult * D1(i, j));
229 std::vector<T> speed(Nlev + 1, one);
231 for (std::size_t n = 1; n <= Nlev; ++n) {
232 const std::size_t b = std::min(n, cmax);
234 if (!(sf[n - 1] == bt)) speed[n] = T(sf[n - 1] / bt);
244 for (std::size_t n = 1; n <= Nlev; ++n) {
245 const std::size_t b = std::min(n, cmax);
247 for (std::size_t i = 0; i < nCfg[b]; ++i) {
248 for (std::size_t j = 0; j < nCfg[b]; ++j) B(i, j) = T(speed[n] * LOC[b](i, j));
249 B(i, i) -= arrRate[n];
254 for (std::size_t n = 0; n + 1 <= Nlev; ++n) {
258 for (std::size_t i = 0; i < nCfg[n]; ++i)
259 for (std::size_t j = 0; j < nCfg[n + 1]; ++j) B(i, j) = T(arrRate[n] * UP[n](i, j));
263 Matrix<T> B(nCfg[cmax], nCfg[cmax], zero);
264 for (std::size_t i = 0; i < nCfg[cmax]; ++i) B(i, i) = arrRate[n];
269 for (std::size_t n = 1; n <= Nlev; ++n) {
272 for (std::size_t i = 0; i < nCfg[n]; ++i)
273 for (std::size_t j = 0; j < nCfg[n - 1]; ++j) B(i, j) = T(speed[n] * DN[n](i, j));
276 Matrix<T> B(nCfg[cmax], nCfg[cmax], zero);
277 for (std::size_t i = 0; i < nCfg[cmax]; ++i)
278 for (std::size_t j = 0; j < nCfg[cmax]; ++j) B(i, j) = T(speed[n] * CDEP(i, j));