302 "mfq_general_solve calls a tolerance-terminated Riccati solver");
303 using namespace mfq_detail;
305 const std::size_t N = Q.
rows();
307 throw InputError(
"mfq_general_solve: Q and R must be square and of equal order");
311 std::vector<std::size_t> ixz, ixp, ixn;
312 for (std::size_t i = 0; i < N; ++i) {
321 const std::size_t Nz = ixz.size(), Np = ixp.size(), Nn = ixn.size();
325 "mfq_general_solve: every state has an up drift, so the fluid level grows without "
326 "bound and has no stationary law");
328 std::vector<std::size_t>
perm;
329 perm.insert(
perm.end(), ixz.begin(), ixz.end());
330 perm.insert(
perm.end(), ixp.begin(), ixp.end());
331 perm.insert(
perm.end(), ixn.begin(), ixn.end());
333 for (std::size_t i = 0; i < N; ++i) P(i,
perm[i]) = one;
336 Matrix<T> Qv(N, N, zero), Rv(N, N, zero);
337 for (std::size_t i = 0; i < N; ++i)
338 for (std::size_t j = 0; j < N; ++j) {
347 for (std::size_t i = 0; i < Nz; ++i)
348 for (std::size_t j = 0; j < Nz; ++j) negQ00(i, j) = -Qv(i, j);
353 "mfq_general_solve: the zero-drift states form a closed set, so the fluid can be "
354 "trapped at a constant level and the model has no stationary fluid law; the "
355 "MATLAB reference silently substitutes a pseudo-inverse here");
358 const std::size_t Npn = Np + Nn;
359 Matrix<T> Qbar = block(Qv, Nz, Nz, Npn, Npn);
361 const Matrix<T> L = block(Qv, Nz, 0, Npn, Nz);
362 const Matrix<T> Rt = block(Qv, 0, Nz, Nz, Npn);
366 for (std::size_t i = 0; i < Npn; ++i) absRi(i, i) = one /
num_abs(Rv(Nz + i, Nz + i));
370 mfq_fundamental(block(Qz, 0, 0, Np, Np), block(Qz, 0, Np, Np, Nn),
371 block(Qz, Np, 0, Nn, Np), block(Qz, Np, Np, Nn, Nn), prec, 150u,
379 for (std::size_t i = 0; i < Np; ++i) {
381 for (std::size_t j = 0; j < Nn; ++j) Pm(i, Np + j) = Psi(i, j);
383 const Matrix<T> iCp = block(absRi, 0, 0, Np, Np);
384 const Matrix<T> iCn = block(absRi, Np, Np, Nn, Nn);
389 const Matrix<T> Qpz = block(Qv, Nz, 0, Np, Nz);
390 const Matrix<T> Qnz = block(Qv, Nz + Np, 0, Nn, Nz);
393 for (std::size_t i = 0; i < Np; ++i)
394 for (std::size_t j = 0; j < Nz; ++j) clo(i, j) = lhs(i, j);
398 for (std::size_t i = 0; i < Np; ++i)
399 for (std::size_t j = 0; j < Npn; ++j) clo(i, Nz + j) = rhs(i, j);
404 const std::vector<T> eN =
ones<T>(N);
407 if (Q0.
rows() == 0) {
411 for (std::size_t i = 0; i < Np; ++i)
412 for (std::size_t j = 0; j < N; ++j) cloP(i,
perm[j]) = clo(i, j);
414 std::vector<T> Ua(Nn, zero);
416 const Matrix<T> Qnz = block(Qv, Nz + Np, 0, Nn, Nz);
418 for (std::size_t i = 0; i < Nn; ++i) Ua[i] += t[i];
422 for (std::size_t i = 0; i < Nn; ++i) Ua[i] += t[i];
425 const Matrix<T> Qnp = block(Qz, Np, 0, Nn, Np);
427 for (std::size_t i = 0; i < Nn; ++i) Ua[i] += t[i];
432 for (std::size_t j = 0; j < Nn; ++j)
433 for (std::size_t i = 0; i < Nn; ++i) Msys(j, i) = U(i, j);
434 for (std::size_t i = 0; i < Nn; ++i) Msys(Nn, i) = Ua[i];
435 std::vector<T> rhs(Nn + 1, zero);
437 const std::vector<T> pm = normal_equations_solve(Msys, rhs);
439 std::vector<T> m0(N, zero);
441 const std::vector<T> pmiCn =
vecmul(pm, iCn);
443 const Matrix<T> Qnz = block(Qv, Nz + Np, 0, Nn, Nz);
444 const std::vector<T> t =
vecmul(
vecmul(pmiCn, Qnz), iQv00);
445 for (std::size_t j = 0; j < Nz; ++j) m0[j] = t[j];
447 for (std::size_t j = 0; j < Nn; ++j) m0[Nz + Np + j] = pmiCn[j];
449 out.
mass0.assign(N, zero);
450 for (std::size_t j = 0; j < N; ++j) out.
mass0[
perm[j]] = m0[j];
451 out.
ini =
vecmul(pm, block(Qz, Np, 0, Nn, Np));
454 if (Q0.
rows() != N || Q0.
cols() != N)
455 throw InputError(
"mfq_general_solve: Q0 must be square and of the order of Q");
457 for (std::size_t i = 0; i < N; ++i)
458 for (std::size_t j = 0; j < N; ++j) Q0v(i, j) = Q0(
perm[i],
perm[j]);
463 for (std::size_t i = 0; i < Np; ++i)
464 for (std::size_t j = 0; j < N; ++j) Msys(j, i) = -cloRv(i, j);
465 for (std::size_t i = 0; i < Nn; ++i)
466 for (std::size_t j = 0; j < N; ++j) Msys(j, Np + i) = Q0v(Nz + Np + i, j);
467 for (std::size_t i = 0; i < Nz; ++i)
468 for (std::size_t j = 0; j < N; ++j) Msys(j, Np + Nn + i) = Q0v(i, j);
470 const std::vector<T> s =
mulvec(
matmul(negKinv, clo), eN);
471 for (std::size_t i = 0; i < Np; ++i) Msys(N, i) = s[i];
472 for (std::size_t i = Np; i < N; ++i) Msys(N, i) = one;
474 std::vector<T> rhs(N + 1, zero);
476 const std::vector<T> sol = normal_equations_solve(Msys, rhs);
478 out.
ini.assign(sol.begin(), sol.begin() + Np);
480 for (std::size_t i = 0; i < Np; ++i)
481 for (std::size_t j = 0; j < N; ++j) cloP(i,
perm[j]) = clo(i, j);
483 std::vector<T> m0(N, zero);
484 for (std::size_t j = 0; j < Nz; ++j) m0[j] = sol[Np + Nn + j];
485 for (std::size_t j = 0; j < Nn; ++j) m0[Nz + Np + j] = sol[Np + j];
486 out.
mass0.assign(N, zero);
487 for (std::size_t j = 0; j < N; ++j) out.
mass0[
perm[j]] = m0[j];