LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches

The M/G/1-type and GI/M/1-type fundamental-matrix solvers of MAMSolver / SMCSolver, ported from matlab/lib/thirdparty/MG1files: stat.m, MG1_EG.m, MG1_Decay.m, GIM1_Caudal.m, MG1_Shifts.m, MG1_CR.m, MG1_FI.m and GIM1_R.m. More...

#include <algorithm>
#include <cmath>
#include <complex>
#include <cstddef>
#include <limits>
#include <string>
#include <vector>
#include "line/num/complex_number.h"
#include "line/num/number.h"
#include "line/util/eig.h"
#include "line/util/error.h"
#include "line/util/fft.h"
#include "line/util/linalg.h"
#include "line/util/lstsq.h"
#include "line/util/lu.h"
#include "line/util/matrix.h"
Include dependency graph for mg1.h:

Go to the source code of this file.

Classes

struct  line::smc::Drift
 The drift of an M/G/1-type sequence, and the invariant vector it uses. More...
struct  line::smc::ShiftResult
 What MG1_Shifts returns: the shifted sequence and the drift it measured. More...
struct  line::smc::Mg1CrOptions
 Options of MG1_CR, with the reference's defaults. More...
struct  line::smc::Mg1FiOptions
 Options of MG1_FI, with the reference's defaults. More...

Namespaces

namespace  line
namespace  line::smc

Typedefs

using line::smc::Blocks = std::vector<Matrix<double>>

Functions

template<class T>
Matrix< T > line::smc::madd (const Matrix< T > &A, const Matrix< T > &B)
 A + B.
template<class T>
Matrix< T > line::smc::msub (const Matrix< T > &A, const Matrix< T > &B)
 A - B.
Matrix< double > line::smc::mscale (const Matrix< double > &A, double c)
 c * A.
std::vector< double > line::smc::rowsums (const Matrix< double > &A)
 sum(A,2), the row sums, as a column held in a vector.
double line::smc::inf_norm (const Matrix< double > &A)
 norm(A,inf), the largest absolute row sum.
double line::smc::inf_norm (const Blocks &blk, std::size_t from)
 norm(A,inf) over a whole block sequence stacked vertically.
double line::smc::max_abs_diff (const Matrix< double > &A, const Matrix< double > &B)
 max(max(abs(A-B))).
double line::smc::max_col_sum (const Matrix< double > &A)
 max(sum(A)), the largest column sum WITHOUT absolute values, as in MATLAB.
Blocks line::smc::blocks_of (const Matrix< double > &A, std::size_t m)
 Splits the wide [A0 A1 ... Amax] into its m x m blocks.
Matrix< double > line::smc::hcat (const Blocks &blk)
 Re-assembles a block sequence into the wide [A0 A1 ... Amax].
Matrix< double > line::smc::vcat (const Blocks &blk)
 Stacks a block sequence vertically, [A0; A1; ...; Amax].
Blocks line::smc::vblocks_of (const Matrix< double > &A, std::size_t r)
 Splits a vertical stack into its blocks of r rows.
std::vector< double > line::smc::stat (const Matrix< double > &A)
 Stationary distribution of a stochastic matrix: the left eigenvector for eigenvalue 1, nonnegative and summing to one.
std::vector< double > line::smc::rowvec_times (const std::vector< double > &v, const Matrix< double > &A)
 theta A, the row vector times matrix product used throughout.
double line::smc::dot (const std::vector< double > &a, const std::vector< double > &b)
 The inner product of a row vector with a column held as a vector.
Drift line::smc::mg1_drift (const Blocks &A)
 drift = theta * beta with beta = (Amax)e + (Amax+Amax-1)e + ..., the expected level increment per transition of the phase process.
std::complex< double > line::smc::max_eig (const Matrix< double > &M)
 max(eig(M)) with MATLAB's semantics on a complex spectrum: the element of largest modulus, ties broken by the larger phase angle.
Matrix< double > line::smc::poly_at (const Blocks &A, double z)
 A(z) = A0 + A1 z + ... + Amax z^max, by Horner as the reference writes it.
double line::smc::mg1_decay (const Blocks &A)
 Decay rate of a recurrent M/G/1-type chain: the unique z > 1 with PF(A(z)) = z.
double line::smc::gim1_caudal (const Blocks &A)
 Caudal characteristic of a GI/M/1-type chain: the spectral radius of R, the unique z in (0,1) with PF(A(z)) = z.
ShiftResult line::smc::mg1_shifts (const Blocks &Ain, const std::string &shift_type)
 Shift technique for the M/G/1-type sequence.
Matrix< double > line::smc::mg1_eg (const Blocks &Ain, bool &found)
 G in closed form when A0 has rank one.
Matrix< double > line::smc::mg1_cr (const Blocks &Ain, const Mg1CrOptions &opts=Mg1CrOptions())
 Cyclic reduction for M/G/1-type Markov chains [Bini, Meini].
Matrix< double > line::smc::mg1_fi (const Blocks &Ain, const Mg1FiOptions &opts=Mg1FiOptions())
 Functional iterations for M/G/1-type Markov chains [Neuts].
Matrix< double > line::smc::gim1_r (const Blocks &Ain, const std::string &dual, const std::string &algor)
 R of a GI/M/1-type Markov chain, through the G of its dual.

Detailed Description

The M/G/1-type and GI/M/1-type fundamental-matrix solvers of MAMSolver / SMCSolver, ported from matlab/lib/thirdparty/MG1files: stat.m, MG1_EG.m, MG1_Decay.m, GIM1_Caudal.m, MG1_Shifts.m, MG1_CR.m, MG1_FI.m and GIM1_R.m.

These are the third-party numerics the ETAQA aggregation sits on: MG1_CR returns the minimal nonnegative G of an M/G/1-type chain and GIM1_R the minimal nonnegative R of a GI/M/1-type one, and without them solver_mam_bmap_map_1 and solver_mam_map_bmap_1 have nothing to aggregate. The port follows the MATLAB line by line, including the block index arithmetic, the stopping tests and the constants, so that a divergence against the reference is a bug here and not a design difference.

BLOCK LAYOUT. The reference passes a block sequence as one wide matrix A = [A0 A1 A2 ... Amax], m rows by m*(max+1) columns. This port carries the same sequence as a std::vector<Matrix<double>> of m x m blocks, which is the identical object with the index arithmetic done once, in blocks_of / hcat, instead of at every use. The GI/M/1 side stacks its blocks VERTICALLY in the reference; GIM1_R_ETAQA is what transposes that stack into the horizontal one, so everything below is horizontal.

DOUBLE ONLY, and not by preference. MG1_Decay and GIM1_Caudal bisect on the Perron-Frobenius eigenvalue of A(z), which needs LAPACK; MG1_CR evaluates its polynomials at complex roots of unity through an FFT, whose twiddle factors are cos/sin; MG1_pi_ETAQA drops a column chosen by a numerical rank test, which needs an SVD. None of the three has a multiprecision or exact counterpart in this tree, so the whole family is declared on Matrix<double> and the solvers that call it refuse at any other arithmetic rather than down-converting behind the caller's back.

TWO REFERENCE BRANCHES ARE REFUSED BY NAME rather than transcribed, because they cannot run in MATLAB either. MG1_Shifts writes rowhatA(1,maxd*i:end) = uT*A(:,maxd*i:end) in three places (the drift < 1 'tau' branch and the drift > 1 'one' branch), where i is not a loop variable at that point: it is either MATLAB's imaginary unit, which makes the index complex and errors, or the leftover value 1 from the beta loop above, which addresses column maxd of a matrix whose blocks start every m columns. Either way the line does not compute "the last block", which is what the surrounding code needs. ETAQA reaches neither branch: it shifts a positive recurrent chain (drift < 1) with the default ShiftType 'one', which is the branch that is correct and is ported.

Definition in file mg1.h.