5#ifndef LINE_API_PFQN_JOINTMARG_H
6#define LINE_API_PFQN_JOINTMARG_H
69namespace jointmargdetail {
72inline std::string lower(
const std::string& s) {
74 for (std::size_t i = 0; i < out.size(); ++i)
75 out[i] =
static_cast<char>(std::tolower(
static_cast<unsigned char>(out[i])));
88Matrix<T> replicate_rows(
const Matrix<T>& L,
const std::vector<int>& n) {
89 const std::size_t M = L.rows(), R = L.cols();
90 std::vector<std::size_t> rowOf;
91 for (std::size_t i = 0; i < M; ++i)
92 for (
int c = 0; c < n[i]; ++c) rowOf.push_back(i);
93 Matrix<T> A(rowOf.size(), R);
94 for (std::size_t a = 0; a < rowOf.size(); ++a)
95 for (std::size_t r = 0; r < R; ++r) A(a, r) = L(rowOf[a], r);
101Matrix<double> expand_to_double(
const Matrix<T>& A,
const std::vector<int>& N) {
102 std::vector<std::size_t> colOf;
103 for (std::size_t r = 0; r < N.size(); ++r)
104 for (
int c = 0; c < N[r]; ++c) colOf.push_back(r);
105 Matrix<double> out(A.rows(), colOf.size(), 0.0);
106 for (std::size_t i = 0; i < A.rows(); ++i)
107 for (std::size_t b = 0; b < colOf.size(); ++b)
108 out(i, b) = num_traits<T>::to_double(A(i, colOf[b]));
123Matrix<double> rows_to_double(
const Matrix<T>& A,
const std::vector<int>& N,
124 std::vector<std::size_t>* mult) {
125 std::vector<std::size_t> keep;
127 for (std::size_t r = 0; r < N.size(); ++r)
130 mult->push_back(
static_cast<std::size_t
>(N[r]));
132 Matrix<double> out(A.rows(), keep.size(), 0.0);
133 for (std::size_t i = 0; i < A.rows(); ++i)
134 for (std::size_t l = 0; l < keep.size(); ++l)
135 out(i, l) = num_traits<T>::to_double(A(i, keep[l]));
147std::pair<std::size_t, std::size_t> first_zero(
const Matrix<T>& L,
const std::vector<int>& N,
148 const std::vector<int>& n) {
149 const T zero = num_traits<T>::from_int(0);
150 for (std::size_t i = 0; i < L.rows(); ++i) {
151 if (n[i] == 0)
continue;
152 for (std::size_t r = 0; r < L.cols(); ++r)
153 if (N[r] > 0 && !(L(i, r) > zero))
return std::make_pair(i + 1, r + 1);
155 return std::make_pair(
static_cast<std::size_t
>(0),
static_cast<std::size_t
>(0));
187 const std::vector<std::size_t>& infset,
const T& G,
188 const std::string& engine =
"exact", std::uint64_t seed = 0) {
189 const std::size_t M = L.
rows(), R = L.
cols();
190 if (N.size() != R)
throw InputError(
"pfqn_jointmarg: L and N disagree on the class count");
191 if (n.size() != M)
throw InputError(
"pfqn_jointmarg: the occupancy vector has the wrong length");
193 if (G == zero)
throw NumericError(
"pfqn_jointmarg: the normalizing constant is zero");
194 for (std::size_t k = 0; k < infset.size(); ++k)
195 if (infset[k] >= M)
throw InputError(
"pfqn_jointmarg: infset indexes a station outside L");
197 long Ntot = 0, ntot = 0;
199 if (v < 0)
throw InputError(
"pfqn_jointmarg: negative population");
203 if (v < 0)
throw InputError(
"pfqn_jointmarg: negative occupancy");
207 if (ntot != Ntot)
return zero;
210 const std::string eng = jointmargdetail::lower(engine);
211 const Matrix<T> A = jointmargdetail::replicate_rows(L, n);
214 if (eng ==
"exact") {
217 const std::pair<std::size_t, std::size_t> z = jointmargdetail::first_zero(L, N, n);
219 throw InputError(
"pfqn_jointmarg: the '" + eng +
220 "' permanent engine cannot be applied: the demand of class " +
221 std::to_string(z.second) +
" at station " + std::to_string(z.first) +
222 " is zero, so the replicated matrix has no full support. "
223 "Use engine 'exact'.");
228 std::vector<std::size_t> mult;
229 const Matrix<double> Ar = jointmargdetail::rows_to_double(A, N, &mult);
232 const Matrix<double> Ad = jointmargdetail::expand_to_double(A, N);
233 if (eng ==
"bethe") {
235 }
else if (eng ==
"heur") {
237 }
else if (eng ==
"huberlaw") {
239 }
else if (eng ==
"adapart") {
242 throw InputError(
"pfqn_jointmarg: unrecognized permanent engine '" + engine +
243 "'. Use exact, spm, bethe, heur, huberlaw or adapart.");
252 for (std::size_t k = 0; k < infset.size(); ++k)
260 const std::vector<std::size_t>& infset,
const std::string& engine =
"exact",
261 std::uint64_t seed = 0) {
262 const std::size_t M = L.
rows(), R = L.
cols();
266 std::vector<bool> isinf(M,
false);
267 for (std::size_t k = 0; k < infset.size(); ++k)
268 if (infset[k] < M) isinf[infset[k]] =
true;
270 for (std::size_t i = 0; i < M; ++i)
274 for (std::size_t i = 0; i < M; ++i) {
275 if (isinf[i])
continue;
276 for (std::size_t r = 0; r < R; ++r) Lq(a, r) = L(i, r);
280 if (!infset.empty()) {
282 for (std::size_t k = 0; k < infset.size(); ++k)
283 for (std::size_t r = 0; r < R; ++r) Z(0, r) += L(infset[k], r);
NumericError(const std::string &what)
The exception types the port throws.
Dense matrix and non-owning view.
double perm_spm(const Matrix< double > &a, double tolerance=1e-11, std::size_t max_iterations=10000)
The saddle-point estimate of the permanent of a square strictly positive matrix.
double perm_heur(const Matrix< double > &m, double tolerance=1e-10, std::size_t max_iterations=1000)
The Sinkhorn heuristic.
double perm_bethe(const Matrix< double > &m, double epsilon=0.001, std::size_t max_iteration=200000)
The Bethe permanent, by sum-product message passing.
double perm_adapart(const Matrix< double > &m, std::uint64_t seed=0)
AdaPart estimate of the permanent, with the reference defaults.
double perm_huberlaw(const Matrix< double > &m, std::uint64_t seed=0)
Huber-Law estimate of the permanent, with the reference defaults.
NcResult< T > pfqn_ca(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z)
Convolution algorithm for the exact normalizing constant of a closed product-form network (Buzen 1973...
T pfqn_jointmarg(const std::vector< int > &n, const Matrix< T > &L, const std::vector< int > &N, const std::vector< std::size_t > &infset, const T &G, const std::string &engine="exact", std::uint64_t seed=0)
Joint probability of the per-station TOTAL queue lengths.
T pfqn_perm(const Matrix< T > &A, const std::vector< int > &m)
Permanent of a matrix with repeated columns, by Ryser's formula.
T num_factorial(unsigned n)
Factorial as a value of T.
Number-type abstraction for the templated API port.
APPROXIMATE permanents: the Sinkhorn heuristic, the Bethe estimate and the saddle-point expansion.
RANDOMIZED permanents: the AdaPart rejection sampler and the Huber-Law acceptance-rejection importanc...
Convolution algorithm for the exact normalizing constant of a closed product-form network (Buzen 1973...
Permanent of a matrix with repeated columns, by Ryser's formula.