LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
api_dispatch_pfqn_b.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 *
5 * --api dispatch entries for the 'pfqn_b' group (see api_dispatch_detail.h).
6 *
7 * Conventions shared by every entry below:
8 *
9 * - Argument keys are the MATLAB parameter names of matlab/src/api/pfqn/<fn>.m.
10 * Output keys are the MATLAB output names; a field the port returns beyond
11 * them keeps its C++ name.
12 *
13 * - STATION, CLASS AND NODE INDICES ARE 0-BASED, exactly as the port takes and
14 * returns them and as the rest of the --api table already carries them
15 * (mc's partitions and SCC labels). They pass through unchanged.
16 *
17 * - An open class in a population vector and an infinite server in a server
18 * count vector are written "Inf" (the MATLAB spelling) or -1 (the port's
19 * OPEN_CLASS / INF_SERVERS sentinel).
20 *
21 * - A port whose optional trailing arguments exist only as a FULL overload
22 * next to a SHORT one takes them together: absent all, the short overload
23 * runs; given some but not all, the call is refused naming what is missing.
24 * No default value is restated here.
25 *
26 * - Scalar tolerances that the port types as `double` are read as double at
27 * every arithmetic, because that is what the port consumes.
28 */
29
30#include "api_dispatch_detail.h"
31
32#include <cctype>
33#include <cmath>
34#include <cstdint>
35#include <initializer_list>
36#include <set>
37#include <string>
38#include <utility>
39#include <vector>
40
108
109namespace line {
110namespace reg {
111
112namespace {
113
114// ---------------------------------------------------------------------------
115// Shared readers
116// ---------------------------------------------------------------------------
117
118/**
119 * Integer vector in which "Inf" (any case) or -1 stands for the port's -1
120 * sentinel: OPEN_CLASS in a population, INF_SERVERS in a server count.
121 */
122std::vector<int> ints_with_inf(const Json& j, const std::string& where) {
123 std::vector<Json> flat;
124 if (!j.is_array()) {
125 flat.push_back(j);
126 } else {
127 for (const Json& e : j) {
128 if (e.is_array())
129 for (const Json& f : e) flat.push_back(f);
130 else
131 flat.push_back(e);
132 }
133 }
134 std::vector<int> out;
135 out.reserve(flat.size());
136 for (const Json& e : flat) {
137 if (e.is_string()) {
138 std::string s = e.get<std::string>();
139 for (char& c : s) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
140 if (s == "inf" || s == "+inf" || s == "infinity") {
141 out.push_back(-1);
142 continue;
143 }
144 }
145 const std::vector<int> one = int_vector_from_json(e, where);
146 if (one.size() != 1) throw InputError(where + ": expected an integer or \"Inf\"");
147 if (one[0] < -1)
148 throw InputError(where + ": a negative entry other than -1 has no meaning, got " +
149 std::to_string(one[0]));
150 out.push_back(one[0]);
151 }
152 return out;
153}
154
155std::vector<int> pop_with_open(Args& a, const char* key) {
156 return ints_with_inf(a.get(key), std::string("'") + key + "'");
157}
158
159std::vector<int> pop_with_open_or_empty(Args& a, const char* key) {
160 const Json* v = a.opt(key);
161 return v ? ints_with_inf(*v, std::string("'") + key + "'") : std::vector<int>();
162}
163
164/** Integer matrix: a list of rows (or one row, or a scalar). */
165Matrix<int> int_matrix(Args& a, const char* key) {
166 const Json& j = a.get(key);
167 const std::string where = std::string("'") + key + "'";
168 std::vector<std::vector<int> > rows;
169 if (j.is_array() && !j.empty() && j[0].is_array()) {
170 for (const Json& r : j) rows.push_back(int_vector_from_json(r, where));
171 } else if (!(j.is_array() && j.empty())) {
172 rows.push_back(int_vector_from_json(j, where));
173 }
174 const std::size_t m = rows.size(), n = m ? rows[0].size() : 0;
175 Matrix<int> M(m, n);
176 for (std::size_t i = 0; i < m; ++i) {
177 if (rows[i].size() != n) throw InputError(where + ": rows have different lengths");
178 for (std::size_t k = 0; k < n; ++k) M(i, k) = rows[i][k];
179 }
180 return M;
181}
182
183/** 0-based index list. */
184std::vector<std::size_t> indices(Args& a, const char* key) {
185 const std::vector<int> v = a.ints(key);
186 std::vector<std::size_t> out;
187 out.reserve(v.size());
188 for (int x : v) {
189 if (x < 0)
190 throw InputError(std::string("'") + key + "' holds 0-based indices and cannot be "
191 "negative, got " + std::to_string(x));
192 out.push_back(static_cast<std::size_t>(x));
193 }
194 return out;
195}
196
197std::vector<long> longs(Args& a, const char* key) {
198 const std::vector<int> v = a.ints(key);
199 return std::vector<long>(v.begin(), v.end());
200}
201
202long a_long(Args& a, const char* key) { return static_cast<long>(a.required_integer(key)); }
203
204/** Vector of doubles, "Inf" accepted (strtod reads it). */
205std::vector<double> doubles(Args& a, const char* key) { return a.vector<double>(key); }
206
207std::vector<bool> bools(Args& a, const char* key) {
208 const Json& j = a.get(key);
209 std::vector<bool> out;
210 auto push = [&](const Json& e) {
211 if (e.is_boolean()) {
212 out.push_back(e.get<bool>());
213 return;
214 }
215 const std::vector<int> v = int_vector_from_json(e, std::string("'") + key + "'");
216 for (int x : v) {
217 if (x != 0 && x != 1)
218 throw InputError(std::string("'") + key + "' entries must be true, false, 0 or 1");
219 out.push_back(x != 0);
220 }
221 };
222 if (j.is_array())
223 for (const Json& e : j) push(e);
224 else
225 push(j);
226 return out;
227}
228
229/**
230 * How many of an ordered list of trailing optional arguments are given. A key
231 * present after an absent one is refused: the port takes them positionally,
232 * and filling the gap would mean restating the port's default here.
233 */
234std::size_t given_prefix(Args& a, const char* fn, std::initializer_list<const char*> keys) {
235 std::size_t k = 0;
236 bool gap = false;
237 std::string missing;
238 for (const char* key : keys) {
239 if (a.has(key)) {
240 if (gap)
241 throw InputError(std::string(fn) + ": '" + key + "' is positional after " +
242 missing + ", which must then be given as well");
243 ++k;
244 } else {
245 if (!gap) missing = std::string("'") + key + "'";
246 gap = true;
247 }
248 }
249 return k;
250}
251
252/** All-or-nothing group of arguments taken together by the port's long form. */
253bool all_or_none(Args& a, const char* fn, std::initializer_list<const char*> keys) {
254 std::size_t n = 0;
255 std::string names, missing;
256 for (const char* key : keys) {
257 names += (names.empty() ? "'" : ", '") + std::string(key) + "'";
258 if (a.has(key))
259 ++n;
260 else
261 missing += (missing.empty() ? "'" : ", '") + std::string(key) + "'";
262 }
263 if (n == 0) return false;
264 if (n == keys.size()) return true;
265 throw InputError(std::string(fn) + ": arguments " + names +
266 " are taken together by the port's long form; missing " + missing);
267}
268
269/** An `options` object with its own unknown-key check. */
270class OptObj {
271public:
272 OptObj(Args& a, const char* key, const char* fn) : j_(a.opt(key)), fn_(fn), key_(key) {
273 if (j_ && !j_->is_object())
274 throw InputError(fn_ + ": '" + key_ + "' must be an object");
275 }
276 OptObj(const Json* j, std::string fn, std::string key) : j_(j), fn_(std::move(fn)), key_(std::move(key)) {
277 if (j_ && !j_->is_object())
278 throw InputError(fn_ + ": '" + key_ + "' must be an object");
279 }
280 bool given() const { return j_ != nullptr; }
281 bool has(const char* k) const { return j_ && j_->find(k) != j_->end(); }
282 const Json& get(const char* k) {
283 seen_.insert(k);
284 if (!has(k)) throw InputError(fn_ + ": missing required field '" + key_ + "." + k + "'");
285 return *j_->find(k);
286 }
287 const Json* sub(const char* k) {
288 seen_.insert(k);
289 return has(k) ? &*j_->find(k) : nullptr;
290 }
291 std::string where(const char* k) const { return fn_ + ": " + key_ + "." + k; }
292 template <class T>
293 T number(const char* k) {
294 return number_from_json<T>(get(k), where(k));
295 }
296 std::string text(const char* k) {
297 const Json& v = get(k);
298 if (!v.is_string()) throw InputError(where(k) + " must be a string");
299 return v.get<std::string>();
300 }
301 std::size_t count(const char* k) {
302 const std::vector<int> v = int_vector_from_json(get(k), where(k));
303 if (v.size() != 1 || v[0] < 0)
304 throw InputError(where(k) + " must be a single non-negative integer");
305 return static_cast<std::size_t>(v[0]);
306 }
307 void done() const {
308 if (!j_) return;
309 for (auto it = j_->begin(); it != j_->end(); ++it)
310 if (seen_.find(it.key()) == seen_.end())
311 throw InputError(fn_ + ": unknown field '" + key_ + "." + it.key() + "'");
312 }
313
314private:
315 const Json* j_;
316 std::string fn_;
317 std::string key_;
318 std::set<std::string> seen_;
319};
320
321/**
322 * The SolverNC option fields the pfqn_nc family reads: samples, seed and
323 * options.config.{aghq_nodes, mcmc_batches, mcmc_burnin}. Each field that is
324 * absent keeps NcOptions' own default.
325 */
326pfqn::NcOptions nc_options(OptObj& o, const char* fn) {
327 pfqn::NcOptions n;
328 if (o.has("samples")) n.samples = o.count("samples");
329 if (o.has("seed")) n.seed = static_cast<unsigned long>(o.count("seed"));
330 OptObj cfg(o.sub("config"), fn, "options.config");
331 if (cfg.has("aghq_nodes")) n.aghq_nodes = cfg.count("aghq_nodes");
332 if (cfg.has("mcmc_batches")) n.mcmc_batches = cfg.count("mcmc_batches");
333 if (cfg.has("mcmc_burnin")) n.mcmc_burnin = cfg.number<double>("mcmc_burnin");
334 cfg.done();
335 return n;
336}
337
338template <class E>
339E enum_of(const std::string& fn, const char* key, const std::string& value,
340 std::initializer_list<std::pair<const char*, E>> table) {
341 std::string low = value;
342 for (char& c : low) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
343 std::string accepted;
344 for (const auto& p : table) {
345 if (low == p.first) return p.second;
346 accepted += (accepted.empty() ? "" : ", ") + std::string(p.first);
347 }
348 throw InputError(fn + ": unknown " + key + " '" + value + "'; accepted: " + accepted);
349}
350
351std::vector<std::string> strings(Args& a, const char* key) {
352 const Json& j = a.get(key);
353 std::vector<std::string> out;
354 if (j.is_string()) {
355 out.push_back(j.get<std::string>());
356 return out;
357 }
358 if (!j.is_array()) throw InputError(std::string("'") + key + "' must be a list of strings");
359 for (const Json& e : j) {
360 if (!e.is_string()) throw InputError(std::string("'") + key + "' must be a list of strings");
361 out.push_back(e.get<std::string>());
362 }
363 return out;
364}
365
366/** Per-station discipline, "PS", "FCFS" or "INF" (SchedStrategy names). */
367std::vector<pfqn::SchedStrategy> sched_list(Args& a, const char* key, const char* fn) {
368 std::vector<pfqn::SchedStrategy> out;
369 for (const std::string& s : strings(a, key))
370 out.push_back(enum_of<pfqn::SchedStrategy>(fn, key, s,
373 {"inf", pfqn::SchedStrategy::INF}}));
374 return out;
375}
376
377std::vector<pfqn::AmvaSched> amva_sched_list(Args& a, const char* key, const char* fn) {
378 std::vector<pfqn::AmvaSched> out;
379 for (const std::string& s : strings(a, key))
380 out.push_back(enum_of<pfqn::AmvaSched>(fn, key, s,
381 {{"ps", pfqn::AmvaSched::PS},
382 {"fcfs", pfqn::AmvaSched::FCFS},
383 {"inf", pfqn::AmvaSched::INF}}));
384 return out;
385}
386
387Json enc_idx(const std::vector<std::size_t>& v) {
388 Json j = Json::array();
389 for (std::size_t x : v) j.push_back(static_cast<std::uint64_t>(x));
390 return j;
391}
392
393Json enc_bools(const std::vector<bool>& v) {
394 Json j = Json::array();
395 for (bool b : v) j.push_back(b);
396 return j;
397}
398
399/** An N-d array as {"sz": extents, "data": column-major entries}, MATLAB's layout. */
400template <class T>
401Json enc_tensor(const moment::MomentTensor<T>& t) {
402 Json j;
403 j["sz"] = enc_idx(t.sz);
404 j["data"] = encode_vector(t.data);
405 return j;
406}
407
408// ---------------------------------------------------------------------------
409// Result encoders shared by families
410// ---------------------------------------------------------------------------
411
412/** MvaResult under MATLAB's names; `lgkey` is lG or lGN as the MATLAB file says. */
413template <class T>
414Json mva_out(const pfqn::MvaResult<T>& r, const char* lgkey) {
415 Json out;
416 out["XN"] = encode_vector(r.XN);
417 out["QN"] = encode_matrix(r.QN);
418 out["UN"] = encode_matrix(r.UN);
419 out["CN"] = encode_matrix(r.CN);
420 out["G"] = encode_scalar(r.G);
421 out[lgkey] = r.lG;
422 return out;
423}
424
425template <class T>
426Json amva_out(const pfqn::AmvaResult<T>& r, const char* itkey) {
427 Json out;
428 out["XN"] = encode_vector(r.XN);
429 out["QN"] = encode_matrix(r.QN);
430 out["UN"] = encode_matrix(r.UN);
431 out["RN"] = encode_matrix(r.RN);
432 out[itkey] = encode_count(r.iterations);
433 out["converged"] = r.converged;
434 return out;
435}
436
437template <class T>
438Json linearizer_out(const pfqn::LinearizerResult<T>& r) {
439 Json out;
440 out["Q"] = encode_matrix(r.Q);
441 out["U"] = encode_matrix(r.U);
442 out["W"] = encode_matrix(r.W);
443 out["C"] = encode_vector(r.C);
444 out["X"] = encode_vector(r.X);
445 out["totiter"] = r.totiter;
446 return out;
447}
448
449template <class R>
450Json schmidt_out(const R& r) {
451 Json out;
452 out["XN"] = encode_vector(r.XN);
453 out["QN"] = encode_matrix(r.QN);
454 out["UN"] = encode_matrix(r.UN);
455 out["CN"] = encode_matrix(r.CN);
456 return out;
457}
458
459// ---------------------------------------------------------------------------
460// Normalizing constants
461// ---------------------------------------------------------------------------
462
463struct OpManjunath {
464 template <class T>
465 static Json run(Args& a) {
466 const Matrix<T> L = a.matrix<T>("L");
467 const std::vector<int> N = a.ints("N");
468 pfqn::PfqnManjunathOptions opt;
469 // MATLAB computes the per-class decomposition when a fourth output is
470 // requested; JSON has no nargout, so it is asked for by name.
471 if (a.has("stats")) opt.stats = a.boolean("stats", opt.stats);
472 const std::size_t k = given_prefix(a, "pfqn_manjunath", {"Z", "A", "b", "sense"});
473 pfqn::PfqnManjunathResult<T> r;
474 if (k == 0) {
475 a.done();
476 r = pfqn::pfqn_manjunath(L, N, opt);
477 } else if (k == 1) {
478 const Matrix<T> Z = a.matrix<T>("Z");
479 a.done();
480 r = pfqn::pfqn_manjunath(L, N, Z, opt);
481 } else {
482 if (k < 4)
483 throw InputError("pfqn_manjunath: 'A', 'b' and 'sense' describe the constraint "
484 "rows together; give all three");
485 const Matrix<T> Z = a.matrix<T>("Z");
486 const Matrix<T> A = a.matrix<T>("A");
487 const std::vector<long> b = longs(a, "b");
488 const std::string sense = a.text("sense", "");
489 a.done();
490 r = pfqn::pfqn_manjunath(L, N, Z, A, b, sense, opt);
491 }
492 Json out;
493 out["G"] = encode_scalar(r.G);
494 out["lG"] = r.lG;
495 out["peak"] = encode_count(r.peak_states);
496 if (r.has_stats) {
497 Json s;
498 s["Q"] = encode_vector(r.Q);
499 s["X"] = encode_vector(r.X);
500 s["U"] = encode_vector(r.U);
501 s["think"] = encode_vector(r.think);
502 s["blocked"] = encode_vector(r.blocked);
503 s["delay"] = encode_vector(r.delay);
504 out["stats"] = s;
505 }
506 return out;
507 }
508};
509
510/**
511 * pfqn_nc: options.method selects the algorithm. Without lambda and with no
512 * option other than the method, the port's (L, N, Z, method) form runs; any
513 * other call is its long form, whose absolute tolerance is options.tol (MATLAB
514 * reads the same field for both the filter and comomrm's tolerance).
515 */
516struct OpNc {
517 template <class T>
518 static Json run(Args& a) {
519 const std::vector<T> lambda = a.vector_or_empty<T>("lambda");
520 const Matrix<T> L = a.matrix<T>("L");
521 const std::vector<int> N = pop_with_open(a, "N");
522 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
523 OptObj o(a, "options", "pfqn_nc");
524 if (!o.given()) throw InputError("pfqn_nc: missing required argument 'options' (with field 'method')");
525 const pfqn::NcMethod method = pfqn::nc_method_of(o.text("method"));
526 const bool longform = !lambda.empty() || o.has("tol") || o.has("samples") ||
527 o.has("seed") || o.has("config");
528 pfqn::NcDispatchResult<T> r;
529 if (!longform) {
530 o.done();
531 a.done();
532 r = pfqn::pfqn_nc(L, N, Z, method);
533 } else {
534 if (!o.has("tol"))
535 throw InputError("pfqn_nc: the port's long form (open classes or sampling "
536 "options) takes the absolute tolerance options.tol explicitly");
537 const T atol = o.number<T>("tol");
538 pfqn::NcOptions nopt = nc_options(o, "pfqn_nc");
539 nopt.tol = num_traits<T>::to_double(atol);
540 o.done();
541 a.done();
542 r = pfqn::pfqn_nc(lambda, L, N, Z, method, atol, nopt);
543 }
544 Json out;
545 out["lG"] = r.lG;
546 out["G"] = encode_scalar(r.G);
547 out["X"] = encode_vector(r.X);
548 out["Q"] = encode_matrix(r.Q);
549 out["method"] = r.method;
550 out["valid"] = r.valid;
551 return out;
552 }
553};
554
555struct OpNcSanitize {
556 template <class T>
557 static Json run(Args& a) {
558 const bool lng = all_or_none(a, "pfqn_nc_sanitize", {"lambda", "atol"});
559 pfqn::NcSanitizeResult<T> r;
560 if (lng) {
561 const std::vector<T> lambda = a.vector_or_empty<T>("lambda");
562 const Matrix<T> L = a.matrix<T>("L");
563 const std::vector<int> N = pop_with_open(a, "N");
564 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
565 const T atol = a.number<T>("atol");
566 a.done();
567 r = pfqn::pfqn_nc_sanitize(lambda, L, N, Z, atol);
568 } else {
569 const Matrix<T> L = a.matrix<T>("L");
570 const std::vector<int> N = pop_with_open(a, "N");
571 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
572 a.done();
573 r = pfqn::pfqn_nc_sanitize(L, N, Z);
574 }
575 Json out;
576 out["lambda"] = encode_vector(r.lambda);
577 out["L"] = encode_matrix(r.L);
578 out["N"] = encode_ints(r.N);
579 out["Z"] = encode_matrix(r.Z);
580 out["lGremaind"] = r.lGremaind;
581 out["Gremaind"] = encode_scalar(r.Gremaind);
582 out["classIndex"] = enc_idx(r.classIndex);
583 return out;
584 }
585};
586
587struct OpNcld {
588 template <class T>
589 static Json run(Args& a) {
590 const Matrix<T> L = a.matrix<T>("L");
591 const std::vector<int> N = a.ints("N");
592 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
593 const Matrix<T> mu = a.matrix<T>("mu");
594 OptObj o(a, "options", "pfqn_ncld");
595 pfqn::NcldResult<T> r;
596 if (!o.given()) {
597 a.done();
598 r = pfqn::pfqn_ncld(L, N, Z, mu);
599 } else {
600 const std::string method = o.text("method");
601 const T atol = o.number<T>("tol");
602 pfqn::NcOptions nopt = nc_options(o, "pfqn_ncld");
603 nopt.tol = num_traits<T>::to_double(atol);
604 o.done();
605 a.done();
606 r = pfqn::pfqn_ncld(L, N, Z, mu, method, atol, nopt);
607 }
608 Json out;
609 out["lG"] = r.lG;
610 out["G"] = encode_scalar(r.G);
611 out["method"] = r.method;
612 return out;
613 }
614};
615
616struct OpNcldmx {
617 template <class T>
618 static Json run(Args& a) {
619 const std::vector<T> lambda = a.vector<T>("lambda");
620 const Matrix<T> D = a.matrix<T>("D");
621 const std::vector<int> N = pop_with_open(a, "N");
622 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
623 const Matrix<T> mu = a.matrix<T>("mu");
624 OptObj o(a, "options", "pfqn_ncldmx");
625 pfqn::NcldmxResult<T> r;
626 if (!o.given()) {
627 a.done();
628 r = pfqn::pfqn_ncldmx(lambda, D, N, Z, mu);
629 } else {
630 const std::string method = o.text("method");
631 const T atol = o.number<T>("tol");
632 pfqn::NcOptions nopt = nc_options(o, "pfqn_ncldmx");
633 nopt.tol = num_traits<T>::to_double(atol);
634 o.done();
635 a.done();
636 r = pfqn::pfqn_ncldmx(lambda, D, N, Z, mu, method, atol, nopt);
637 }
638 Json out;
639 out["lG"] = r.lG;
640 out["G"] = encode_scalar(r.G);
641 out["lGopen"] = r.lGopen;
642 out["Gopen"] = encode_scalar(r.Gopen);
643 out["XN"] = encode_vector(r.XN);
644 out["QN"] = encode_matrix(r.QN);
645 out["EC"] = encode_matrix(r.EC);
646 return out;
647 }
648};
649
650struct OpPerm {
651 template <class T>
652 static Json run(Args& a) {
653 const Matrix<T> A = a.matrix<T>("A");
654 const std::vector<int> m = a.ints("m");
655 a.done();
656 Json out;
657 out["val"] = encode_scalar(pfqn::pfqn_perm(A, m));
658 return out;
659 }
660};
661
662struct OpMmint2 {
663 template <class T>
664 static Json run(Args& a) {
665 const std::vector<T> L = a.vector<T>("L");
666 const std::vector<T> N = a.vector<T>("N");
667 const std::vector<T> Z = a.vector<T>("Z");
668 a.done();
669 const pfqn::MmintResult<T> r = pfqn::pfqn_mmint2(L, N, Z);
670 Json out;
671 out["G"] = encode_scalar(r.G);
672 out["lG"] = encode_scalar(r.lG);
673 return out;
674 }
675};
676
677/** pfqn_nre / pfqn_nrl / pfqn_nrp: lG from (L, N, Z, alpha). */
678template <class T>
679using NrFn = T (*)(const Matrix<T>&, const std::vector<T>&, const std::vector<T>&,
680 const Matrix<T>&);
681
682template <template <class> class F>
683struct OpNr {
684 template <class T>
685 static Json run(Args& a) {
686 const Matrix<T> L = a.matrix<T>("L");
687 const std::vector<T> N = a.vector<T>("N");
688 const std::vector<T> Z = a.vector<T>("Z");
689 const Matrix<T> alpha = a.matrix<T>("alpha");
690 a.done();
691 Json out;
692 out["lG"] = encode_scalar(F<T>::call(L, N, Z, alpha));
693 return out;
694 }
695};
696template <class T>
697struct NreCall {
698 static T call(const Matrix<T>& L, const std::vector<T>& N, const std::vector<T>& Z,
699 const Matrix<T>& al) {
700 return pfqn::pfqn_nre(L, N, Z, al);
701 }
702};
703template <class T>
704struct NrlCall {
705 static T call(const Matrix<T>& L, const std::vector<T>& N, const std::vector<T>& Z,
706 const Matrix<T>& al) {
707 return pfqn::pfqn_nrl(L, N, Z, al);
708 }
709};
710template <class T>
711struct NrpCall {
712 static T call(const Matrix<T>& L, const std::vector<T>& N, const std::vector<T>& Z,
713 const Matrix<T>& al) {
714 return pfqn::pfqn_nrp(L, N, Z, al);
715 }
716};
717
718struct OpOiFnc {
719 template <class T>
720 static Json run(Args& a) {
721 const std::vector<T> Phi = a.vector<T>("Phi");
722 const std::vector<int> N = a.ints("N");
723 a.unsupported("f", "the per-state function f is a callable, which has no JSON "
724 "representation; call pfqn_oi_fnc from the library for that case");
725 a.done();
726 const pfqn::OiFncResult<T> r = pfqn::pfqn_oi_fnc(Phi, N);
727 Json out;
728 out["Psi"] = encode_vector(r.Psi);
729 out["mu"] = encode_vector(r.mu);
730 out["stride"] = enc_idx(r.stride);
731 return out;
732 }
733};
734
735struct OpPanacea {
736 template <class T>
737 static Json run(Args& a) {
738 const Matrix<T> L = a.matrix<T>("L");
739 const std::vector<int> N = a.ints("N");
740 const std::vector<T> Z = a.vector<T>("Z");
741 pfqn::PanaceaResult<T> r;
742 if (a.has("terms")) {
743 const int terms = a.required_integer("terms");
744 a.done();
745 r = pfqn::pfqn_panacea(L, N, Z, terms);
746 } else {
747 a.done();
748 r = pfqn::pfqn_panacea(L, N, Z);
749 }
750 Json out;
751 out["Gn"] = encode_scalar(r.G);
752 out["lGn"] = encode_scalar(r.lG);
753 out["normalUsage"] = r.normalUsage;
754 return out;
755 }
756};
757
758struct OpPanaceald {
759 template <class T>
760 static Json run(Args& a) {
761 const Matrix<T> L = a.matrix<T>("L");
762 const std::vector<int> N = a.ints("N");
763 const std::vector<T> Z = a.vector<T>("Z");
764 const Matrix<T> mu = a.matrix<T>("mu");
765 pfqn::PanaceaLdResult<T> r;
766 if (a.has("terms")) {
767 const int terms = a.required_integer("terms");
768 a.done();
769 r = pfqn::pfqn_panaceald(L, N, Z, mu, terms);
770 } else {
771 a.done();
772 r = pfqn::pfqn_panaceald(L, N, Z, mu);
773 }
774 Json out;
775 out["Gn"] = encode_scalar(r.G);
776 out["lGn"] = encode_scalar(r.lG);
777 out["normalUsage"] = r.normalUsage;
778 out["reason"] = r.reason ? std::string(r.reason) : std::string();
779 return out;
780 }
781};
782
783struct OpPropfair {
784 template <class T>
785 static Json run(Args& a) {
786 const Matrix<T> L = a.matrix<T>("L");
787 const std::vector<T> N = a.vector<T>("N");
788 const std::vector<T> Z = a.vector<T>("Z");
789 a.done();
790 const pfqn::PropfairResult<T> r = pfqn::pfqn_propfair(L, N, Z);
791 Json out;
792 out["G"] = encode_scalar(r.G);
793 out["lG"] = encode_scalar(r.lG);
794 out["Xasy"] = encode_vector(r.Xasy);
795 return out;
796 }
797};
798
799struct OpRd {
800 template <class T>
801 static Json run(Args& a) {
802 const Matrix<T> L = a.matrix<T>("L");
803 const std::vector<int> N = a.ints("N");
804 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
805 const Matrix<T> mu = a.matrix<T>("mu");
806 OptObj o(a, "options", "pfqn_rd");
807 pfqn::RdResult<T> r;
808 if (!o.given()) {
809 a.done();
810 r = pfqn::pfqn_rd(L, N, Z, mu);
811 } else {
812 const double tol = o.number<double>("tol");
813 const pfqn::NcMethod method = pfqn::nc_method_of(o.text("method"));
814 o.done();
815 a.done();
816 r = pfqn::pfqn_rd(L, N, Z, mu, tol, method);
817 }
818 Json out;
819 out["lGN"] = r.lGN;
820 out["Cgamma"] = encode_scalar(r.Cgamma);
821 return out;
822 }
823};
824
825struct OpRgf {
826 template <class T>
827 static Json run(Args& a) {
828 const std::vector<T> L = a.vector<T>("L");
829 const int N = a.required_integer("N");
830 pfqn::RgfResult<T> r;
831 if (a.has("Z")) {
832 const T Z = a.number<T>("Z");
833 a.done();
834 r = pfqn::pfqn_rgf(L, N, Z);
835 } else {
836 a.done();
837 r = pfqn::pfqn_rgf(L, N);
838 }
839 Json out;
840 out["G"] = encode_scalar(r.G);
841 out["lG"] = encode_scalar(r.lG);
842 out["lg"] = encode_vector(r.lg);
843 return out;
844 }
845};
846
847struct OpRgfmc {
848 template <class T>
849 static Json run(Args& a) {
850 const Matrix<T> L = a.matrix<T>("L");
851 const std::vector<int> N = a.ints("N");
852 const std::vector<T> Z = a.vector<T>("Z");
853 OptObj o(a, "options", "pfqn_rgfmc");
854 pfqn::RgfmcResult<T> r;
855 if (!o.given()) {
856 a.done();
857 r = pfqn::pfqn_rgfmc(L, N, Z);
858 } else {
859 const T tol = o.number<T>("tol");
860 const std::size_t maxterms = o.count("maxterms");
861 const T maxcancel = o.number<T>("maxcancel");
862 o.done();
863 a.done();
864 r = pfqn::pfqn_rgfmc(L, N, Z, tol, maxterms, maxcancel);
865 }
866 Json out;
867 out["G"] = encode_scalar(r.G);
868 out["lG"] = encode_scalar(r.lG);
869 return out;
870 }
871};
872
873struct OpXia {
874 template <class T>
875 static Json run(Args& a) {
876 const std::vector<T> L = a.vector<T>("L");
877 const int N = a.required_integer("N");
878 const std::vector<T> s = a.vector<T>("s");
879 a.done();
880 Json out;
881 out["lGasy"] = encode_scalar(pfqn::pfqn_xia(L, N, s));
882 return out;
883 }
884};
885
886// ---------------------------------------------------------------------------
887// MVA family
888// ---------------------------------------------------------------------------
889
890struct OpMvams {
891 template <class T>
892 static Json run(Args& a) {
893 const std::vector<T> lambda = a.vector<T>("lambda");
894 const Matrix<T> L = a.matrix<T>("L");
895 const std::vector<int> N = pop_with_open(a, "N");
896 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
897 pfqn::MvaResult<T> r;
898 if (a.has("mi")) {
899 const std::vector<int> mi = a.ints("mi");
900 if (!a.has("S"))
901 throw InputError("pfqn_mvams: the port's form with 'mi' also takes 'S'");
902 const std::vector<int> S = pop_with_open(a, "S");
903 a.done();
904 r = pfqn::pfqn_mvams(lambda, L, N, Z, mi, S);
905 } else if (a.has("S")) {
906 const std::vector<int> S = pop_with_open(a, "S");
907 a.done();
908 r = pfqn::pfqn_mvams(lambda, L, N, Z, S);
909 } else {
910 a.done();
911 r = pfqn::pfqn_mvams(lambda, L, N, Z);
912 }
913 return mva_out(r, "lG");
914 }
915};
916
917struct OpMvamx {
918 template <class T>
919 static Json run(Args& a) {
920 const std::vector<T> lambda = a.vector<T>("lambda");
921 const Matrix<T> D = a.matrix<T>("D");
922 const std::vector<int> N = pop_with_open(a, "N");
923 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
924 const std::vector<int> mi = a.ints_or_empty("mi");
925 a.done();
926 return mva_out(pfqn::pfqn_mvamx(lambda, D, N, Z, mi), "lGN");
927 }
928};
929
930struct OpMvaldmx {
931 template <class T>
932 static Json run(Args& a) {
933 const std::vector<T> lambda = a.vector<T>("lambda");
934 const Matrix<T> D = a.matrix<T>("D");
935 const std::vector<int> N = pop_with_open(a, "N");
936 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
937 const Matrix<T> mu = a.matrix<T>("mu");
938 a.done();
939 return mva_out(pfqn::pfqn_mvaldmx(lambda, D, N, Z, mu), "lGN");
940 }
941};
942
943struct OpMvaldms {
944 template <class T>
945 static Json run(Args& a) {
946 const std::vector<T> lambda = a.vector<T>("lambda");
947 const Matrix<T> D = a.matrix<T>("D");
948 const std::vector<int> N = pop_with_open(a, "N");
949 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
950 const std::vector<int> S = pop_with_open(a, "S");
951 a.done();
952 return mva_out(pfqn::pfqn_mvaldms(lambda, D, N, Z, S), "lGN");
953 }
954};
955
956struct OpMvald {
957 template <class T>
958 static Json run(Args& a) {
959 const Matrix<T> L = a.matrix<T>("L");
960 const std::vector<int> N = a.ints("N");
961 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
962 const Matrix<T> mu = a.matrix<T>("mu");
963 pfqn::MvaLdResult<T> r;
964 if (a.has("stabilize")) {
965 const bool st = a.boolean("stabilize", false);
966 a.done();
967 r = pfqn::pfqn_mvald(L, N, Z, mu, st);
968 } else {
969 a.done();
970 r = pfqn::pfqn_mvald(L, N, Z, mu);
971 }
972 Json out;
973 out["XN"] = encode_vector(r.XN);
974 out["QN"] = encode_matrix(r.QN);
975 out["UN"] = encode_vector(r.UN);
976 out["CN"] = encode_vector(r.CN);
977 out["lGN"] = r.lG;
978 out["G"] = encode_scalar(r.G);
979 out["isNumStable"] = r.isNumStable;
980 out["pi"] = encode_matrix(r.PI);
981 out["WN"] = encode_matrix(r.WN);
982 return out;
983 }
984};
985
986struct OpDebemva {
987 template <class T>
988 static Json run(Args& a) {
989 const long N = a_long(a, "N");
990 const std::vector<T> S = a.vector<T>("S");
991 const Matrix<T> P = a.matrix<T>("P");
992 const std::vector<double> K = doubles(a, "K");
993 const std::vector<bool> isdelay = bools(a, "isdelay");
994 const std::size_t k = given_prefix(a, "pfqn_debemva", {"tol", "iter_max"});
995 pfqn::DebemvaResult<T> r;
996 if (k == 0) {
997 a.done();
998 r = pfqn::pfqn_debemva(N, S, P, K, isdelay);
999 } else if (k == 1) {
1000 const double tol = a.number<double>("tol");
1001 a.done();
1002 r = pfqn::pfqn_debemva(N, S, P, K, isdelay, tol);
1003 } else {
1004 const double tol = a.number<double>("tol");
1005 const long iter_max = a_long(a, "iter_max");
1006 a.done();
1007 r = pfqn::pfqn_debemva(N, S, P, K, isdelay, tol, iter_max);
1008 }
1009 Json out;
1010 out["X"] = encode_vector(r.X);
1011 out["Q"] = encode_vector(r.Q);
1012 out["U"] = encode_vector(r.U);
1013 out["R"] = encode_vector(r.R);
1014 out["BT"] = encode_vector(r.BT);
1015 out["z"] = encode_vector(r.z);
1016 out["theta"] = r.theta;
1017 out["iter"] = r.iter;
1018 out["converged"] = r.converged;
1019 return out;
1020 }
1021};
1022
1023struct OpOqnrc {
1024 static Json run(Args& a) {
1025 const std::vector<double> lam = a.vector<double>("lam");
1026 const Matrix<double> A = a.matrix<double>("A");
1027 const Matrix<double> S = a.matrix<double>("S");
1028 const Matrix<double> SCV = a.matrix<double>("SCV");
1029 const std::vector<double> nservers = doubles(a, "nservers");
1030 const std::vector<bool> isps = bools(a, "isps");
1031 const std::vector<double> poolv = doubles(a, "pool"); // 1-based, as in MATLAB
1032 const std::vector<double> Ncapv = doubles(a, "Ncap");
1033 const bool waitq = a.boolean("waitq", true);
1034 const double tol = a.has("tol") ? a.number<double>("tol") : 1e-8;
1035 const long iter_max = a.has("iter_max") ? a_long(a, "iter_max") : 1000L;
1036 a.done();
1037 std::vector<int> pool, Ncap;
1038 for (double v : poolv) pool.push_back(static_cast<int>(v) - 1);
1039 for (double v : Ncapv) Ncap.push_back(static_cast<int>(v));
1040 const pfqn::OqnrcResult r =
1041 pfqn::pfqn_oqnrc(lam, A, S, SCV, nservers, isps, pool, Ncap, waitq, tol, static_cast<int>(iter_max));
1042 Json out;
1043 out["Q"] = encode_matrix(r.Q);
1044 out["T"] = encode_matrix(r.T);
1045 out["U"] = encode_matrix(r.U);
1046 out["R"] = encode_matrix(r.R);
1047 out["X"] = encode_vector(r.X);
1048 out["Qext"] = encode_vector(r.Qext);
1049 out["Ploss"] = encode_vector(r.Ploss);
1050 out["iter"] = r.iter;
1051 return out;
1052 }
1053};
1054
1055struct OpMvablo {
1056 template <class T>
1057 static Json run(Args& a) {
1058 const long N = a_long(a, "N");
1059 const std::vector<T> S = a.vector<T>("S");
1060 const Matrix<T> P = a.matrix<T>("P");
1061 const std::vector<double> K = doubles(a, "K");
1062 const std::vector<bool> isdelay = bools(a, "isdelay");
1063 const std::size_t k = given_prefix(a, "pfqn_mvablo", {"tol", "iter_max"});
1064 pfqn::MvabloResult<T> r;
1065 if (k == 0) {
1066 a.done();
1067 r = pfqn::pfqn_mvablo(N, S, P, K, isdelay);
1068 } else if (k == 1) {
1069 const double tol = a.number<double>("tol");
1070 a.done();
1071 r = pfqn::pfqn_mvablo(N, S, P, K, isdelay, tol);
1072 } else {
1073 const double tol = a.number<double>("tol");
1074 const int iter_max = a.required_integer("iter_max");
1075 a.done();
1076 r = pfqn::pfqn_mvablo(N, S, P, K, isdelay, tol, iter_max);
1077 }
1078 Json out;
1079 out["X"] = encode_vector(r.X);
1080 out["Q"] = encode_vector(r.Q);
1081 out["U"] = encode_vector(r.U);
1082 out["R"] = encode_vector(r.R);
1083 out["BT"] = encode_matrix(r.BT);
1084 out["iter"] = r.iter;
1085 out["converged"] = r.converged;
1086 return out;
1087 }
1088};
1089
1090struct OpMvac {
1091 template <class T>
1092 static Json run(Args& a) {
1093 const Matrix<T> L = a.matrix<T>("L");
1094 const std::vector<int> N = a.ints("N");
1095 pfqn::MvacResult<T> r;
1096 if (a.has("Z")) {
1097 const Matrix<T> Z = a.matrix<T>("Z");
1098 a.done();
1099 r = pfqn::pfqn_mvac(L, N, Z);
1100 } else {
1101 a.done();
1102 r = pfqn::pfqn_mvac(L, N);
1103 }
1104 Json out;
1105 out["XN"] = encode_vector(r.X);
1106 out["QN"] = encode_matrix(r.Q);
1107 out["UN"] = encode_matrix(r.U);
1108 out["CN"] = encode_matrix(r.C);
1109 return out;
1110 }
1111};
1112
1113struct OpMvacld {
1114 template <class T>
1115 static Json run(Args& a) {
1116 const Matrix<T> L = a.matrix<T>("L");
1117 const std::vector<int> N = a.ints("N");
1118 const Matrix<T> Z = a.matrix<T>("Z");
1119 pfqn::MvacldResult<T> r;
1120 if (a.has("mu")) {
1121 const Matrix<T> mu = a.matrix<T>("mu");
1122 a.done();
1123 r = pfqn::pfqn_mvacld(L, N, Z, mu);
1124 } else {
1125 a.done();
1126 r = pfqn::pfqn_mvacld(L, N, Z);
1127 }
1128 Json out;
1129 out["XN"] = encode_vector(r.X);
1130 out["QN"] = encode_matrix(r.Q);
1131 out["UN"] = encode_vector(r.U);
1132 out["CN"] = encode_vector(r.C);
1133 out["pij"] = encode_matrix(r.pij);
1134 return out;
1135 }
1136};
1137
1138struct OpNintmva {
1139 template <class T>
1140 static Json run(Args& a) {
1141 const std::vector<T> L = a.vector<T>("L");
1142 const T N = a.number<T>("N");
1143 pfqn::NintMvaResult<T> r;
1144 if (a.has("Z")) {
1145 const T Z = a.number<T>("Z");
1146 a.done();
1147 r = pfqn::pfqn_nintmva(L, N, Z);
1148 } else {
1149 a.done();
1150 r = pfqn::pfqn_nintmva(L, N);
1151 }
1152 Json out;
1153 out["X"] = encode_scalar(r.X);
1154 out["Q"] = encode_vector(r.Q);
1155 out["U"] = encode_vector(r.U);
1156 out["R"] = encode_vector(r.R);
1157 return out;
1158 }
1159};
1160
1161struct OpMvaInterval {
1162 template <class T>
1163 static Json run(Args& a) {
1164 const Matrix<T> L = a.matrix<T>("L");
1165 const std::vector<int> N = a.ints("N");
1166 const std::vector<T> Z = a.vector<T>("Z");
1167 a.done();
1168 // MATLAB: a scalar is a thin interval [x x].
1169 if (N.size() != 1 && N.size() != 2)
1170 throw InputError("pfqn_mva_interval: 'N' must be [nlo nup] or a scalar");
1171 if (Z.size() != 1 && Z.size() != 2)
1172 throw InputError("pfqn_mva_interval: 'Z' must be [zlo zup] or a scalar");
1173 const pfqn::MvaIntervalResult<T> r =
1174 pfqn::pfqn_mva_interval(L, N.front(), N.back(), Z.front(), Z.back());
1175 Json out;
1176 out["X"] = Json::array({encode_scalar(r.Xlo), encode_scalar(r.Xup)});
1177 out["Q"] = encode_matrix(r.Q);
1178 out["U"] = encode_matrix(r.U);
1179 out["R"] = encode_matrix(r.R);
1180 out["Rtot"] = Json::array({encode_scalar(r.Rtot_lo), encode_scalar(r.Rtot_up)});
1181 out["Qtot"] = Json::array({encode_scalar(r.Qtot_lo), encode_scalar(r.Qtot_up)});
1182 return out;
1183 }
1184};
1185
1186struct OpMomlin {
1187 template <class T>
1188 static Json run(Args& a) {
1189 const Matrix<T> L = a.matrix<T>("L");
1190 const std::vector<int> N = a.ints("N");
1191 const std::vector<T> Z = a.vector<T>("Z");
1192 pfqn::MomlinResult<T> r;
1193 if (all_or_none(a, "pfqn_momlin", {"tol", "maxiter"})) {
1194 const T tol = a.number<T>("tol");
1195 const int maxiter = a.required_integer("maxiter");
1196 a.done();
1197 r = pfqn::pfqn_momlin(L, N, Z, tol, maxiter);
1198 } else {
1199 a.done();
1200 r = pfqn::pfqn_momlin(L, N, Z);
1201 }
1202 Json out;
1203 out["Q"] = encode_matrix(r.Q);
1204 out["X"] = encode_vector(r.X);
1205 out["U"] = encode_matrix(r.U);
1206 out["R"] = encode_matrix(r.R);
1207 out["QVar"] = encode_matrix(r.QVar);
1208 // (M x R x M x R) covariance, column-major as MATLAB stores it.
1209 Json qc;
1210 qc["sz"] = Json::array({r.M, r.Rc, r.M, r.Rc});
1211 qc["data"] = encode_vector(r.QCov);
1212 out["QCov"] = qc;
1213 out["dQ"] = encode_vector(r.dQ);
1214 return out;
1215 }
1216};
1217
1218// ---------------------------------------------------------------------------
1219// Approximate MVA
1220// ---------------------------------------------------------------------------
1221
1222struct OpQsa {
1223 template <class T>
1224 static Json run(Args& a) {
1225 const Matrix<T> L = a.matrix<T>("L");
1226 const std::vector<T> N = a.vector<T>("N");
1227 const std::size_t k =
1228 given_prefix(a, "pfqn_qsa", {"Z", "type", "tol", "maxiter", "levels"});
1229 pfqn::AmvaResult<T> r;
1230 if (k == 0) {
1231 a.done();
1232 r = pfqn::pfqn_qsa(L, N);
1233 } else if (k == 1) {
1234 const std::vector<T> Z = a.vector<T>("Z");
1235 a.done();
1236 r = pfqn::pfqn_qsa(L, N, Z);
1237 } else {
1238 const std::vector<T> Z = a.vector<T>("Z");
1239 const std::vector<pfqn::AmvaSched> type = amva_sched_list(a, "type", "pfqn_qsa");
1240 if (k == 2) {
1241 a.done();
1242 r = pfqn::pfqn_qsa(L, N, Z, type);
1243 } else if (k == 3) {
1244 const double tol = a.number<double>("tol");
1245 a.done();
1246 r = pfqn::pfqn_qsa(L, N, Z, type, tol);
1247 } else if (k == 4) {
1248 const double tol = a.number<double>("tol");
1249 const std::size_t maxiter = a.count("maxiter");
1250 a.done();
1251 r = pfqn::pfqn_qsa(L, N, Z, type, tol, maxiter);
1252 } else {
1253 const double tol = a.number<double>("tol");
1254 const std::size_t maxiter = a.count("maxiter");
1255 const int levels = a.required_integer("levels");
1256 a.done();
1257 r = pfqn::pfqn_qsa(L, N, Z, type, tol, maxiter, levels);
1258 }
1259 }
1260 Json out;
1261 out["Q"] = encode_matrix(r.QN);
1262 out["U"] = encode_matrix(r.UN);
1263 out["W"] = encode_matrix(r.RN);
1264 out["X"] = encode_vector(r.XN);
1265 out["totiter"] = encode_count(r.iterations);
1266 out["converged"] = r.converged;
1267 return out;
1268 }
1269};
1270
1271struct OpQdamva {
1272 template <class T>
1273 static Json run(Args& a) {
1274 const Matrix<T> L = a.matrix<T>("L");
1275 const std::vector<T> N = a.vector<T>("N");
1276 const std::vector<T> Z = a.vector<T>("Z");
1277 const Matrix<T> mu = a.matrix<T>("mu");
1278 const Matrix<T> Q0 = a.matrix<T>("Q0");
1279 const std::size_t k = given_prefix(a, "pfqn_qdamva", {"tol", "maxiter"});
1280 pfqn::QdAmvaResult<T> r;
1281 if (k == 0) {
1282 a.done();
1283 r = pfqn::pfqn_qdamva(L, N, Z, mu, Q0);
1284 } else if (k == 1) {
1285 const double tol = a.number<double>("tol");
1286 a.done();
1287 r = pfqn::pfqn_qdamva(L, N, Z, mu, Q0, tol);
1288 } else {
1289 const double tol = a.number<double>("tol");
1290 const std::size_t maxiter = a.count("maxiter");
1291 a.done();
1292 r = pfqn::pfqn_qdamva(L, N, Z, mu, Q0, tol, maxiter);
1293 }
1294 Json out;
1295 out["Q"] = encode_matrix(r.Q);
1296 out["X"] = encode_matrix(r.X);
1297 out["U"] = encode_matrix(r.U);
1298 out["iter"] = encode_count(r.iter);
1299 out["R"] = encode_matrix(r.R);
1300 return out;
1301 }
1302};
1303
1304struct OpQdlin {
1305 template <class T>
1306 static Json run(Args& a) {
1307 const Matrix<T> L = a.matrix<T>("L");
1308 const std::vector<T> N = a.vector<T>("N");
1309 const std::vector<T> Z = a.vector<T>("Z");
1310 pfqn::QdLinResult<T> r;
1311 const bool ld = all_or_none(a, "pfqn_qdlin", {"mu", "nservers"});
1312 const std::size_t k = given_prefix(a, "pfqn_qdlin", {"tol", "maxiter", "wtol"});
1313 Matrix<T> mu;
1314 std::vector<double> ns;
1315 if (ld) {
1316 mu = a.matrix<T>("mu");
1317 ns = doubles(a, "nservers");
1318 }
1319 double tol = 0, wtol = 0;
1320 std::size_t maxiter = 0;
1321 if (k >= 1) tol = a.number<double>("tol");
1322 if (k >= 2) maxiter = a.count("maxiter");
1323 if (k >= 3) wtol = a.number<double>("wtol");
1324 a.done();
1325 if (ld) {
1326 if (k == 0) r = pfqn::pfqn_qdlin(L, N, Z, mu, ns);
1327 else if (k == 1) r = pfqn::pfqn_qdlin(L, N, Z, mu, ns, tol);
1328 else if (k == 2) r = pfqn::pfqn_qdlin(L, N, Z, mu, ns, tol, maxiter);
1329 else r = pfqn::pfqn_qdlin(L, N, Z, mu, ns, tol, maxiter, wtol);
1330 } else {
1331 if (k == 0) r = pfqn::pfqn_qdlin(L, N, Z);
1332 else if (k == 1) r = pfqn::pfqn_qdlin(L, N, Z, tol);
1333 else if (k == 2) r = pfqn::pfqn_qdlin(L, N, Z, tol, maxiter);
1334 else r = pfqn::pfqn_qdlin(L, N, Z, tol, maxiter, wtol);
1335 }
1336 Json out;
1337 out["Q"] = encode_matrix(r.Q);
1338 out["U"] = encode_matrix(r.U);
1339 out["R"] = encode_matrix(r.R);
1340 out["X"] = encode_matrix(r.X);
1341 out["C"] = encode_matrix(r.C);
1342 out["iter"] = encode_count(r.iter);
1343 return out;
1344 }
1345};
1346
1347struct OpPam {
1348 template <class T>
1349 static Json run(Args& a) {
1350 const Matrix<T> L = a.matrix<T>("L");
1351 const std::vector<T> N = a.vector<T>("N");
1352 const std::size_t k = given_prefix(a, "pfqn_pam", {"Z", "variant"});
1353 pfqn::AmvaResult<T> r;
1354 if (k == 0) {
1355 a.done();
1356 r = pfqn::pfqn_pam(L, N);
1357 } else {
1358 const std::vector<T> Z = a.vector<T>("Z");
1359 if (k == 1) {
1360 a.done();
1361 r = pfqn::pfqn_pam(L, N, Z);
1362 } else {
1363 const pfqn::PamVariant v = enum_of<pfqn::PamVariant>(
1364 "pfqn_pam", "variant", a.text("variant", ""),
1365 {{"pamb", pfqn::PamVariant::Basic},
1366 {"pami", pfqn::PamVariant::Improved},
1367 {"pamt", pfqn::PamVariant::Two}});
1368 a.done();
1369 r = pfqn::pfqn_pam(L, N, Z, v);
1370 }
1371 }
1372 return amva_out(r, "iterations");
1373 }
1374};
1375
1376struct OpTay {
1377 template <class T>
1378 static Json run(Args& a) {
1379 const Matrix<T> L = a.matrix<T>("L");
1380 const std::vector<T> N = a.vector<T>("N");
1381 const std::size_t k = given_prefix(a, "pfqn_tay", {"Z", "tol", "maxiter", "QN0"});
1382 pfqn::AmvaResult<T> r;
1383 if (k == 0) {
1384 a.done();
1385 r = pfqn::pfqn_tay(L, N);
1386 } else {
1387 const std::vector<T> Z = a.vector<T>("Z");
1388 if (k == 1) {
1389 a.done();
1390 r = pfqn::pfqn_tay(L, N, Z);
1391 } else if (k == 2) {
1392 const double tol = a.number<double>("tol");
1393 a.done();
1394 r = pfqn::pfqn_tay(L, N, Z, tol);
1395 } else if (k == 3) {
1396 const double tol = a.number<double>("tol");
1397 const std::size_t maxiter = a.count("maxiter");
1398 a.done();
1399 r = pfqn::pfqn_tay(L, N, Z, tol, maxiter);
1400 } else {
1401 const double tol = a.number<double>("tol");
1402 const std::size_t maxiter = a.count("maxiter");
1403 const Matrix<T> QN0 = a.matrix<T>("QN0");
1404 a.done();
1405 r = pfqn::pfqn_tay(L, N, Z, tol, maxiter, QN0);
1406 }
1407 }
1408 return amva_out(r, "it");
1409 }
1410};
1411
1412struct OpScat {
1413 template <class T>
1414 static Json run(Args& a) {
1415 const Matrix<T> L = a.matrix<T>("L");
1416 const std::vector<int> N = a.ints("N");
1417 const bool lng = all_or_none(a, "pfqn_scat", {"type", "tol", "maxiter", "QN0"});
1418 pfqn::LinearizerResult<T> r;
1419 if (lng) {
1420 const Matrix<T> Z = a.matrix<T>("Z");
1421 const std::vector<pfqn::SchedStrategy> type = sched_list(a, "type", "pfqn_scat");
1422 const double tol = a.number<double>("tol");
1423 const int maxiter = a.required_integer("maxiter");
1424 const Matrix<T> QN0 = a.matrix_or_empty<T>("QN0");
1425 a.done();
1426 r = pfqn::pfqn_scat(L, N, Z, type, tol, maxiter, QN0);
1427 } else if (a.has("Z")) {
1428 const Matrix<T> Z = a.matrix<T>("Z");
1429 a.done();
1430 r = pfqn::pfqn_scat(L, N, Z);
1431 } else {
1432 a.done();
1433 r = pfqn::pfqn_scat(L, N);
1434 }
1435 return linearizer_out(r);
1436 }
1437};
1438
1439struct OpSchmidt {
1440 template <class T>
1441 static Json run(Args& a) {
1442 const Matrix<T> D = a.matrix<T>("D");
1443 const std::vector<int> N = a.ints("N");
1444 const Matrix<int> S = int_matrix(a, "S");
1445 const std::vector<pfqn::SchedStrategy> sched = sched_list(a, "sched", "pfqn_schmidt");
1446 pfqn::SchmidtResult<T> r;
1447 if (a.has("v")) {
1448 const Matrix<T> v = a.matrix<T>("v");
1449 a.done();
1450 r = pfqn::pfqn_schmidt(D, N, S, sched, v);
1451 } else {
1452 a.done();
1453 r = pfqn::pfqn_schmidt(D, N, S, sched);
1454 }
1455 return schmidt_out(r);
1456 }
1457};
1458
1459struct OpSchmidtExt {
1460 template <class T>
1461 static Json run(Args& a) {
1462 const Matrix<T> D = a.matrix<T>("D");
1463 const std::vector<int> N = a.ints("N");
1464 const Matrix<int> S = int_matrix(a, "S");
1465 const std::vector<pfqn::SchedStrategy> sched = sched_list(a, "sched", "pfqn_schmidt_ext");
1466 a.done();
1467 return schmidt_out(pfqn::pfqn_schmidt_ext(D, N, S, sched));
1468 }
1469};
1470
1471struct OpMarie {
1472 template <class T>
1473 static Json run(Args& a) {
1474 const Matrix<T> L = a.matrix<T>("L");
1475 const std::vector<int> N = a.ints("N");
1476 const std::vector<T> Z = a.vector<T>("Z");
1477 const Matrix<T> scv = a.matrix<T>("scv");
1478 pfqn::MarieResult<T> r;
1479 if (all_or_none(a, "pfqn_marie", {"tol", "maxiter", "nservers"})) {
1480 const double tol = a.number<double>("tol");
1481 const int maxiter = a.required_integer("maxiter");
1482 const std::vector<int> ns = a.ints("nservers");
1483 a.done();
1484 r = pfqn::pfqn_marie(L, N, Z, scv, tol, maxiter, ns);
1485 } else {
1486 a.done();
1487 r = pfqn::pfqn_marie(L, N, Z, scv);
1488 }
1489 Json out;
1490 out["X"] = encode_vector(r.X);
1491 out["Q"] = encode_matrix(r.Q);
1492 out["U"] = encode_matrix(r.U);
1493 out["C"] = encode_matrix(r.C);
1494 out["it"] = r.it;
1495 if (r.cds.empty()) {
1496 out["mu"] = encode_matrix(r.mu);
1497 } else {
1498 Json mu = Json::array();
1499 for (const auto& c : r.cds) {
1500 Json e;
1501 e["N"] = encode_ints(c.N);
1502 e["muCox"] = encode_vectors(c.muCox);
1503 e["muExp"] = encode_vectors(c.muExp);
1504 mu.push_back(e);
1505 }
1506 out["mu"] = mu;
1507 }
1508 return out;
1509 }
1510};
1511
1512/** pfqn_stdf and pfqn_stdf_heur share their signature and result. */
1513template <bool Heur>
1514struct OpStdf {
1515 template <class T>
1516 static Json run(Args& a) {
1517 const Matrix<T> L = a.matrix<T>("L");
1518 const std::vector<int> N = a.ints("N");
1519 const Matrix<T> Z = a.matrix_or_empty<T>("Z");
1520 const std::vector<int> S = a.ints("S");
1521 const std::vector<std::size_t> fcfs = indices(a, "fcfsNodes");
1522 const Matrix<T> rates = a.matrix<T>("rates");
1523 const std::vector<T> tset = a.vector<T>("tset");
1524 a.done();
1525 const pfqn::StdfResult<T> r = Heur
1526 ? pfqn::pfqn_stdf_heur(L, N, Z, S, fcfs, rates, tset)
1527 : pfqn::pfqn_stdf(L, N, Z, S, fcfs, rates, tset);
1528 Json rd = Json::array();
1529 for (const auto& row : r.RD) rd.push_back(encode_matrices(row));
1530 Json out;
1531 out["RD"] = rd;
1532 out["tset"] = encode_vector(r.tset);
1533 out["isNumStable"] = r.isNumStable;
1534 return out;
1535 }
1536};
1537
1538struct OpSqni {
1539 template <class T>
1540 static Json run(Args& a) {
1541 const std::vector<T> N = a.vector<T>("N");
1542 const std::vector<T> L = a.vector<T>("L");
1543 const std::vector<T> Z = a.vector<T>("Z");
1544 a.done();
1545 const pfqn::SqniResult<T> r = pfqn::pfqn_sqni(N, L, Z);
1546 Json out;
1547 out["Q"] = encode_vector(r.Q);
1548 out["U"] = encode_vector(r.U);
1549 out["X"] = encode_vector(r.X);
1550 return out;
1551 }
1552};
1553
1554struct OpSdr {
1555 template <class T>
1556 static Json run(Args& a) {
1557 const Matrix<T> S = a.matrix<T>("S");
1558 const Matrix<T> xi = a.matrix<T>("xi");
1559 const std::vector<std::size_t> N = indices(a, "N");
1560 OptObj o(a, "sdr", "pfqn_sdr");
1561 if (!o.given()) throw InputError("pfqn_sdr: missing required argument 'sdr'");
1562 pfqn::SdrStruct sdr;
1563 auto idx = [&](const char* k) {
1564 const std::vector<int> v = int_vector_from_json(o.get(k), o.where(k));
1565 std::vector<std::size_t> out;
1566 for (int x : v) {
1567 if (x < 0) throw InputError(o.where(k) + " cannot be negative");
1568 out.push_back(static_cast<std::size_t>(x));
1569 }
1570 return out;
1571 };
1572 sdr.entry = o.count("entry");
1573 sdr.departure = o.count("departure");
1574 {
1575 const Json& br = o.get("branch");
1576 if (!br.is_array()) throw InputError(o.where("branch") + " must be a list of index lists");
1577 for (std::size_t b = 0; b < br.size(); ++b) {
1578 std::vector<std::size_t> blk;
1579 if (!br[b].is_null())
1580 for (int x : int_vector_from_json(br[b], o.where("branch"))) {
1581 if (x < 0) throw InputError(o.where("branch") + " cannot be negative");
1582 blk.push_back(static_cast<std::size_t>(x));
1583 }
1584 sdr.branch.push_back(blk);
1585 }
1586 }
1587 sdr.entryOf = idx("entryOf");
1588 sdr.departureOf = idx("departureOf");
1589 sdr.level = idx("level");
1590 sdr.C = vector_from_json<double>(o.get("C"), o.where("C"));
1591 sdr.d = matrix_from_json<double>(o.get("d"), o.where("d"));
1592 o.done();
1593 pfqn::SdrResult<T> r;
1594 if (a.has("alpha")) {
1595 const Matrix<T> alpha = a.matrix<T>("alpha");
1596 a.done();
1597 r = pfqn::pfqn_sdr(S, xi, N, sdr, alpha);
1598 } else {
1599 a.done();
1600 r = pfqn::pfqn_sdr(S, xi, N, sdr);
1601 }
1602 Json out;
1603 out["Q"] = encode_matrix(r.QN);
1604 out["X"] = encode_matrix(r.XN);
1605 out["U"] = encode_matrix(r.UN);
1606 out["R"] = encode_matrix(r.RN);
1607 out["G"] = encode_scalar(r.G);
1608 return out;
1609 }
1610};
1611
1612// ---------------------------------------------------------------------------
1613// Bounds
1614// ---------------------------------------------------------------------------
1615
1616/** Scalar-throughput bounds of signature (L, N, Z) -> T; Key is the MATLAB output name. */
1617template <template <class> class F>
1618struct OpXzBound {
1619 template <class T>
1620 static Json run(Args& a) {
1621 const std::vector<T> L = a.vector<T>("L");
1622 const T N = a.number<T>("N");
1623 const T Z = a.number<T>("Z");
1624 a.done();
1625 Json out;
1626 out[F<T>::key] = encode_scalar(F<T>::call(L, N, Z));
1627 return out;
1628 }
1629};
1630template <class T>
1631struct XzAbaLow {
1632 static constexpr const char* key = "XN";
1633 static T call(const std::vector<T>& L, const T& N, const T& Z) { return pfqn::pfqn_xzabalow(L, N, Z); }
1634};
1635template <class T>
1636struct XzAbaUp {
1637 static constexpr const char* key = "XN";
1638 static T call(const std::vector<T>& L, const T& N, const T& Z) { return pfqn::pfqn_xzabaup(L, N, Z); }
1639};
1640template <class T>
1641struct XzGsbLow {
1642 static constexpr const char* key = "X";
1643 static T call(const std::vector<T>& L, const T& N, const T& Z) { return pfqn::pfqn_xzgsblow(L, N, Z); }
1644};
1645template <class T>
1646struct XzGsbUp {
1647 static constexpr const char* key = "X";
1648 static T call(const std::vector<T>& L, const T& N, const T& Z) { return pfqn::pfqn_xzgsbup(L, N, Z); }
1649};
1650
1651template <bool Up>
1652struct OpQzgb {
1653 template <class T>
1654 static Json run(Args& a) {
1655 const std::vector<T> L = a.vector<T>("L");
1656 const T N = a.number<T>("N");
1657 const T Z = a.number<T>("Z");
1658 const std::size_t i = a.count("i");
1659 a.done();
1660 Json out;
1661 out["Qgb"] = encode_scalar(Up ? pfqn::pfqn_qzgbup(L, N, Z, i)
1662 : pfqn::pfqn_qzgblow(L, N, Z, i));
1663 return out;
1664 }
1665};
1666
1667struct OpSsd {
1668 template <class T>
1669 static Json run(Args& a) {
1670 const std::vector<T> L = a.vector<T>("L");
1671 const T N = a.number<T>("N");
1672 const T Z = a.number<T>("Z");
1673 pfqn::SsdBounds<T> r;
1674 if (a.has("nservers")) {
1675 const std::vector<T> ns = a.vector<T>("nservers");
1676 a.done();
1677 r = pfqn::pfqn_ssd(L, N, Z, ns);
1678 } else {
1679 a.done();
1680 r = pfqn::pfqn_ssd(L, N, Z);
1681 }
1682 Json out;
1683 out["Xlo"] = encode_scalar(r.Xlo);
1684 out["Xhi"] = encode_scalar(r.Xhi);
1685 return out;
1686 }
1687};
1688
1689struct OpMcub {
1690 template <class T>
1691 static Json run(Args& a) {
1692 const Matrix<T> L = a.matrix<T>("L");
1693 const std::vector<T> N = a.vector<T>("N");
1694 pfqn::McubBounds<T> r;
1695 if (a.has("Z")) {
1696 const std::vector<T> Z = a.vector<T>("Z");
1697 a.done();
1698 r = pfqn::pfqn_mcub(L, N, Z);
1699 } else {
1700 a.done();
1701 r = pfqn::pfqn_mcub(L, N);
1702 }
1703 Json out;
1704 out["Xub"] = encode_vector(r.Xub);
1705 out["Xlb"] = encode_vector(r.Xlb);
1706 return out;
1707 }
1708};
1709
1710struct OpMwrbb {
1711 template <class T>
1712 static Json run(Args& a) {
1713 const Matrix<T> V = a.matrix<T>("V");
1714 const Matrix<T> S = a.matrix<T>("S");
1715 const std::vector<T> N = a.vector<T>("N");
1716 const std::vector<T> Z = a.vector<T>("Z");
1717 pfqn::MwrbbBounds<T> r;
1718 if (all_or_none(a, "pfqn_mwrbb", {"sched", "prio"})) {
1719 std::vector<pfqn::MwrbbSched> sched;
1720 for (int c : a.ints("sched")) {
1721 if (c < 0 || c > 4)
1722 throw InputError("pfqn_mwrbb: 'sched' codes are 0=FIFO, 1=PS, 2=non-preemptive "
1723 "priority, 3=preemptive priority, 4=ABA; got " +
1724 std::to_string(c));
1725 sched.push_back(static_cast<pfqn::MwrbbSched>(c));
1726 }
1727 const std::vector<int> prio = a.ints("prio");
1728 a.done();
1729 r = pfqn::pfqn_mwrbb(V, S, N, Z, sched, prio);
1730 } else {
1731 a.done();
1732 r = pfqn::pfqn_mwrbb(V, S, N, Z);
1733 }
1734 Json out;
1735 out["Xlo"] = encode_vector(r.Xlo);
1736 out["Xup"] = encode_vector(r.Xup);
1737 out["Wlo"] = encode_matrix(r.Wlo);
1738 return out;
1739 }
1740};
1741
1742struct OpPbh {
1743 template <class T>
1744 static Json run(Args& a) {
1745 const std::vector<T> L = a.vector<T>("L");
1746 const int N = a.required_integer("N");
1747 const T Z = a.number<T>("Z");
1748 pfqn::PbhBounds<T> r;
1749 if (a.has("level")) {
1750 const int level = a.required_integer("level");
1751 a.done();
1752 r = pfqn::pfqn_pbh(L, N, Z, level);
1753 } else {
1754 a.done();
1755 r = pfqn::pfqn_pbh(L, N, Z);
1756 }
1757 Json out;
1758 out["Xlo"] = encode_scalar(r.Xlo);
1759 out["Xhi"] = encode_scalar(r.Xhi);
1760 out["Qlo"] = encode_vector(r.Qlo);
1761 out["Qhi"] = encode_vector(r.Qhi);
1762 return out;
1763 }
1764};
1765
1766struct OpSib {
1767 template <class T>
1768 static Json run(Args& a) {
1769 const std::vector<T> L = a.vector<T>("L");
1770 const int N = a.required_integer("N");
1771 const T Z = a.number<T>("Z");
1772 pfqn::SibBounds<T> r;
1773 if (a.has("level")) {
1774 const int level = a.required_integer("level");
1775 a.done();
1776 r = pfqn::pfqn_sib(L, N, Z, level);
1777 } else {
1778 a.done();
1779 r = pfqn::pfqn_sib(L, N, Z);
1780 }
1781 Json out;
1782 out["Xlo"] = encode_scalar(r.Xlo);
1783 out["Xhi"] = encode_scalar(r.Xhi);
1784 out["Wlo"] = encode_scalar(r.Wlo);
1785 out["Whi"] = encode_scalar(r.Whi);
1786 return out;
1787 }
1788};
1789
1790struct OpScb {
1791 template <class T>
1792 static Json run(Args& a) {
1793 const std::vector<T> L = a.vector<T>("L");
1794 const long N = a_long(a, "N");
1795 a.done();
1796 const pfqn::ScbBounds<T> r = pfqn::pfqn_scb(L, N);
1797 Json out;
1798 out["Xlo"] = encode_scalar(r.Xlo);
1799 out["Xhi"] = encode_scalar(r.Xhi);
1800 out["Ulo"] = encode_vector(r.Ulo);
1801 out["Uhi"] = encode_vector(r.Uhi);
1802 return out;
1803 }
1804};
1805
1806struct OpScbgap {
1807 template <class T>
1808 static Json run(Args& a) {
1809 const long N = a_long(a, "N");
1810 const long K = a_long(a, "K");
1811 T e;
1812 if (all_or_none(a, "pfqn_scbgap", {"r", "undominated"})) {
1813 const long r = a_long(a, "r");
1814 const bool und = a.boolean("undominated", false);
1815 a.done();
1816 e = pfqn::pfqn_scbgap<T>(N, K, r, und);
1817 } else {
1818 a.done();
1819 e = pfqn::pfqn_scbgap<T>(N, K);
1820 }
1821 Json out;
1822 out["e"] = encode_scalar(e);
1823 return out;
1824 }
1825};
1826
1827struct OpUsumbound {
1828 template <class T>
1829 static Json run(Args& a) {
1830 const long R = a_long(a, "R");
1831 const long K = a_long(a, "K");
1832 const long N = a_long(a, "N");
1833 a.done();
1834 Json out;
1835 out["Umax"] = encode_scalar(pfqn::pfqn_usumbound<T>(R, K, N));
1836 return out;
1837 }
1838};
1839
1840struct OpMinclasses {
1841 template <class T>
1842 static Json run(Args& a) {
1843 const T Usum = a.number<T>("Usum");
1844 const long K = a_long(a, "K");
1845 const long N = a_long(a, "N");
1846 a.done();
1847 Json out;
1848 out["Rmin"] = static_cast<long long>(pfqn::pfqn_minclasses(Usum, K, N));
1849 return out;
1850 }
1851};
1852
1853// ---------------------------------------------------------------------------
1854// Small structural helpers
1855// ---------------------------------------------------------------------------
1856
1857struct OpUnique {
1858 template <class T>
1859 static Json run(Args& a) {
1860 const Matrix<T> L = a.matrix<T>("L");
1861 pfqn::UniqueResult<T> r;
1862 if (all_or_none(a, "pfqn_unique", {"mu", "gamma"})) {
1863 const Matrix<T> mu = a.matrix_or_empty<T>("mu");
1864 const Matrix<T> gamma = a.matrix_or_empty<T>("gamma");
1865 a.done();
1866 r = pfqn::pfqn_unique(L, mu, gamma);
1867 } else {
1868 a.done();
1869 r = pfqn::pfqn_unique(L);
1870 }
1871 Json out;
1872 out["L_unique"] = encode_matrix(r.L);
1873 out["mu_unique"] = encode_matrix(r.mu);
1874 out["gamma_unique"] = encode_matrix(r.gamma);
1875 out["mi"] = encode_ints(r.mi);
1876 out["mapping"] = enc_idx(r.mapping);
1877 return out;
1878 }
1879};
1880
1881struct OpMushift {
1882 template <class T>
1883 static Json run(Args& a) {
1884 const Matrix<T> mu = a.matrix<T>("mu");
1885 const std::vector<std::size_t> iset = indices(a, "iset");
1886 a.done();
1887 Json out;
1888 out["mushifted"] = encode_matrix(pfqn::pfqn_mushift(mu, iset));
1889 return out;
1890 }
1891};
1892
1893struct OpMuMs {
1894 template <class T>
1895 static Json run(Args& a) {
1896 const int N = a.required_integer("N");
1897 const int m = a.required_integer("m");
1898 const int c = a.required_integer("c");
1899 a.done();
1900 Json out;
1901 out["mu"] = encode_vector(pfqn::pfqn_mu_ms<T>(N, m, c));
1902 return out;
1903 }
1904};
1905
1906// ---------------------------------------------------------------------------
1907// Sensitivities and moments
1908// ---------------------------------------------------------------------------
1909
1910struct OpSens {
1911 template <class T>
1912 static Json run(Args& a) {
1913 const Matrix<T> L = a.matrix<T>("L");
1914 const std::vector<int> N = a.ints("N");
1915 const std::vector<T> Z = a.vector<T>("Z");
1916 pfqn::SensResult<T> r;
1917 if (a.has("mi")) {
1918 const std::vector<int> mi = a.ints("mi");
1919 a.done();
1920 r = pfqn::pfqn_sens(L, N, Z, mi);
1921 } else {
1922 a.done();
1923 r = pfqn::pfqn_sens(L, N, Z);
1924 }
1925 Json s;
1926 s["XN"] = encode_vector(r.XN);
1927 s["QN"] = encode_matrix(r.QN);
1928 s["UN"] = encode_matrix(r.UN);
1929 s["CN"] = encode_matrix(r.CN);
1930 Json ps = Json::array();
1931 for (const auto& p : r.params) {
1932 Json e;
1933 e["type"] = std::string(1, p.type);
1934 e["station"] = p.station;
1935 e["class"] = static_cast<std::uint64_t>(p.cls);
1936 ps.push_back(e);
1937 }
1938 s["params"] = ps;
1939 s["dX"] = encode_matrix(r.dX);
1940 s["dQ"] = encode_matrices(r.dQ);
1941 s["dU"] = encode_matrices(r.dU);
1942 s["dR"] = encode_matrices(r.dR);
1943 s["QCov"] = encode_matrix(r.QCov);
1944 s["QVar"] = encode_matrix(r.QVar);
1945 s["QTotVar"] = encode_vector(r.QTotVar);
1946 s["QCovAsym"] = encode_scalar(r.QCovAsym);
1947 Json out;
1948 out["sens"] = s;
1949 return out;
1950 }
1951};
1952
1953struct OpSensLdmxEc {
1954 template <class T>
1955 static Json run(Args& a) {
1956 const std::vector<T> lambda = a.vector<T>("lambda");
1957 const Matrix<T> D = a.matrix<T>("D");
1958 const Matrix<T> mu = a.matrix<T>("mu");
1959 a.done();
1960 const pfqn::SensLdmxEcResult<T> r = pfqn::pfqn_sens_ldmx_ec(lambda, D, mu);
1961 Json out;
1962 out["EC"] = encode_matrix(r.EC);
1963 out["E"] = encode_matrix(r.E);
1964 out["Eprime"] = encode_matrix(r.Eprime);
1965 out["Lo"] = encode_vector(r.Lo);
1966 out["dEC"] = encode_matrix(r.dEC);
1967 out["dE"] = encode_matrix(r.dE);
1968 out["dEprime"] = encode_matrix(r.dEprime);
1969 return out;
1970 }
1971};
1972
1973struct OpSensLinearizer {
1974 template <class T>
1975 static Json run(Args& a) {
1976 const Matrix<T> L = a.matrix<T>("L");
1977 const std::vector<int> N = a.ints("N");
1978 const std::vector<T> Z = a.vector<T>("Z");
1979 pfqn::SensLinearizerResult<T> r;
1980 if (all_or_none(a, "pfqn_sens_linearizer", {"tol", "maxiter"})) {
1981 const T tol = a.number<T>("tol");
1982 const unsigned maxiter = a.uinteger("maxiter");
1983 a.done();
1984 r = pfqn::pfqn_sens_linearizer(L, N, Z, &tol, maxiter);
1985 } else {
1986 a.done();
1987 r = pfqn::pfqn_sens_linearizer(L, N, Z);
1988 }
1989 Json s;
1990 s["XN"] = encode_vector(r.XN);
1991 s["QN"] = encode_matrix(r.QN);
1992 s["UN"] = encode_matrix(r.UN);
1993 s["WN"] = encode_matrix(r.WN);
1994 s["m"] = encode_vector(r.m);
1995 s["dm"] = encode_matrix(r.dm);
1996 s["d2m"] = encode_vector(r.d2m);
1997 s["Cov"] = encode_matrix(r.Cov);
1998 s["Var"] = encode_vector(r.Var);
1999 s["M2"] = encode_vector(r.M2);
2000 s["M3"] = encode_vector(r.M3);
2001 s["Skew"] = encode_vector(r.Skew);
2002 s["CovAsym"] = encode_scalar(r.CovAsym);
2003 s["iter"] = r.iter;
2004 Json out;
2005 out["res"] = s;
2006 return out;
2007 }
2008};
2009
2010struct OpSensMom {
2011 template <class T>
2012 static Json run(Args& a) {
2013 const Matrix<T> L = a.matrix<T>("L");
2014 const std::vector<int> N = a.ints("N");
2015 const std::vector<T> Z = a.vector<T>("Z");
2016 pfqn::SensMomResult<T> r;
2017 if (all_or_none(a, "pfqn_sens_mom", {"mi", "groups"})) {
2018 const std::vector<int> mi = a.ints_or_empty("mi");
2019 const std::vector<int> groups = a.ints_or_empty("groups");
2020 a.done();
2021 r = pfqn::pfqn_sens_mom(L, N, Z, mi, groups);
2022 } else {
2023 a.done();
2024 r = pfqn::pfqn_sens_mom(L, N, Z);
2025 }
2026 Json s;
2027 s["XN"] = encode_vector(r.XN);
2028 s["QN"] = encode_matrix(r.QN);
2029 s["UN"] = encode_matrix(r.UN);
2030 s["CN"] = encode_matrix(r.CN);
2031 s["m"] = encode_matrix(r.m);
2032 s["d2m"] = encode_matrix(r.d2m);
2033 s["Cov"] = encode_matrix(r.Cov);
2034 s["dm"] = encode_matrix(r.dm);
2035 s["Var"] = encode_matrix(r.Var);
2036 s["M2"] = encode_matrix(r.M2);
2037 s["M3"] = encode_matrix(r.M3);
2038 s["Skew"] = encode_matrix(r.Skew);
2039 s["CovAsym"] = encode_scalar(r.CovAsym);
2040 Json out;
2041 out["mom"] = s;
2042 return out;
2043 }
2044};
2045
2046struct OpSensMva {
2047 template <class T>
2048 static Json run(Args& a) {
2049 const Matrix<T> L = a.matrix<T>("L");
2050 const std::vector<int> N = a.ints("N");
2051 const std::vector<T> Z = a.vector<T>("Z");
2052 pfqn::SensMvaResult<T> r;
2053 if (a.has("mi")) {
2054 const std::vector<int> mi = a.ints("mi");
2055 a.done();
2056 r = pfqn::pfqn_sens_mva(L, N, Z, mi);
2057 } else {
2058 a.done();
2059 r = pfqn::pfqn_sens_mva(L, N, Z);
2060 }
2061 Json s;
2062 s["XN"] = encode_vector(r.XN);
2063 s["QN"] = encode_matrix(r.QN);
2064 s["UN"] = encode_matrix(r.UN);
2065 s["CN"] = encode_matrix(r.CN);
2066 s["QCov"] = encode_matrices(r.QCov);
2067 s["QVar"] = encode_matrix(r.QVar);
2068 s["QTotVar"] = encode_vector(r.QTotVar);
2069 s["QCovAsym"] = encode_scalar(r.QCovAsym);
2070 Json out;
2071 out["mom"] = s;
2072 return out;
2073 }
2074};
2075
2076struct OpSensMvaldmx {
2077 template <class T>
2078 static Json run(Args& a) {
2079 const std::vector<T> lambda = a.vector<T>("lambda");
2080 const Matrix<T> D = a.matrix<T>("D");
2081 const std::vector<int> N = pop_with_open(a, "N");
2082 const std::vector<T> Z = a.vector<T>("Z");
2083 const Matrix<T> mu = a.matrix<T>("mu");
2084 a.done();
2085 const pfqn::SensMvaldmxResult<T> r = pfqn::pfqn_sens_mvaldmx(lambda, D, N, Z, mu);
2086 Json s;
2087 s["XN"] = encode_vector(r.XN);
2088 s["QN"] = encode_matrix(r.QN);
2089 s["UN"] = encode_matrix(r.UN);
2090 s["CN"] = encode_matrix(r.CN);
2091 s["QCov"] = encode_matrices(r.QCov);
2092 s["QCovFull"] = encode_matrix(r.QCovFull);
2093 s["QVar"] = encode_matrix(r.QVar);
2094 s["QTotVar"] = encode_vector(r.QTotVar);
2095 s["QCovAsym"] = encode_scalar(r.QCovAsym);
2096 Json out;
2097 out["mom"] = s;
2098 return out;
2099 }
2100};
2101
2102struct OpSensMomldmx {
2103 template <class T>
2104 static Json run(Args& a) {
2105 const std::vector<T> lambda = a.vector<T>("lambda");
2106 const Matrix<T> D = a.matrix<T>("D");
2107 const std::vector<int> N = pop_with_open(a, "N");
2108 const std::vector<T> Z = a.vector<T>("Z");
2109 const Matrix<T> mu = a.matrix<T>("mu");
2110 const std::vector<int> groups = a.ints_or_empty("groups");
2111 a.done();
2112 const pfqn::SensMomResult<T> r = pfqn::pfqn_sens_momldmx(lambda, D, N, Z, mu, groups);
2113 Json s;
2114 s["XN"] = encode_vector(r.XN);
2115 s["QN"] = encode_matrix(r.QN);
2116 s["UN"] = encode_matrix(r.UN);
2117 s["CN"] = encode_matrix(r.CN);
2118 s["m"] = encode_matrix(r.m);
2119 s["d2m"] = encode_matrix(r.d2m);
2120 s["Cov"] = encode_matrix(r.Cov);
2121 s["dm"] = encode_matrix(r.dm);
2122 s["Var"] = encode_matrix(r.Var);
2123 s["M2"] = encode_matrix(r.M2);
2124 s["M3"] = encode_matrix(r.M3);
2125 s["Skew"] = encode_matrix(r.Skew);
2126 s["CovAsym"] = encode_scalar(r.CovAsym);
2127 Json out;
2128 out["mom"] = s;
2129 return out;
2130 }
2131};
2132
2133struct OpSensRespt {
2134 template <class T>
2135 static Json run(Args& a) {
2136 const std::vector<T> S = a.vector<T>("S");
2137 const Matrix<T> V = a.matrix<T>("V");
2138 const std::vector<int> N = a.ints("N");
2139 const std::vector<T> Z = a.vector<T>("Z");
2140 pfqn::SensResptResult<T> r;
2141 if (all_or_none(a, "pfqn_sens_respt", {"b", "tmax"})) {
2142 const std::vector<int> b = a.ints("b");
2143 const int tmax = a.required_integer("tmax");
2144 a.done();
2145 r = pfqn::pfqn_sens_respt(S, V, N, Z, b, tmax);
2146 } else {
2147 a.done();
2148 r = pfqn::pfqn_sens_respt(S, V, N, Z);
2149 }
2150 Json s;
2151 s["XN"] = encode_vector(r.XN);
2152 s["QN"] = encode_matrix(r.QN);
2153 s["UN"] = encode_matrix(r.UN);
2154 s["W"] = encode_matrix(r.W);
2155 s["WM"] = encode_matrices(r.WM);
2156 s["WVar"] = encode_matrix(r.WVar);
2157 s["WSkew"] = encode_matrix(r.WSkew);
2158 s["m"] = encode_vector(r.m);
2159 s["Var"] = encode_vector(r.Var);
2160 s["p"] = encode_matrix(r.p);
2161 s["Wresid"] = encode_matrix(r.Wresid);
2162 Json out;
2163 out["res"] = s;
2164 return out;
2165 }
2166};
2167
2168struct OpQlenJointMoments {
2169 template <class T>
2170 static Json run(Args& a) {
2171 const Matrix<T> L = a.matrix<T>("L");
2172 const std::vector<int> N = a.ints("N");
2173 const std::vector<T> Z = a.vector<T>("Z");
2174 a.unsupported("lGsrc", "the injected log G source is a callable, which has no JSON "
2175 "representation; omit it to have pfqn_nc supply log G");
2176 std::vector<std::pair<std::size_t, std::size_t> > pairs;
2177 if (a.has("pairs")) {
2178 const Matrix<int> P = int_matrix(a, "pairs");
2179 if (!P.empty() && P.cols() != 2)
2180 throw InputError("pfqn_qlen_joint_moments: 'pairs' must be a P x 2 matrix of "
2181 "0-based (station, class) indices");
2182 for (std::size_t p = 0; p < P.rows(); ++p) {
2183 if (P(p, 0) < 0 || P(p, 1) < 0)
2184 throw InputError("pfqn_qlen_joint_moments: 'pairs' holds 0-based indices");
2185 pairs.emplace_back(static_cast<std::size_t>(P(p, 0)),
2186 static_cast<std::size_t>(P(p, 1)));
2187 }
2188 }
2189 const bool lng = all_or_none(a, "pfqn_qlen_joint_moments", {"route", "options"});
2190 pfqn::QlenJointMomentsResult<T> r;
2191 if (lng) {
2192 const pfqn::QlenJointRoute route = enum_of<pfqn::QlenJointRoute>(
2193 "pfqn_qlen_joint_moments", "route", a.text("route", ""),
2194 {{"auto", pfqn::QlenJointRoute::Auto},
2195 {"tail", pfqn::QlenJointRoute::Tail},
2196 {"pmf", pfqn::QlenJointRoute::Pmf}});
2197 OptObj o(a, "options", "pfqn_qlen_joint_moments");
2198 const pfqn::NcMethod method = pfqn::nc_method_of(o.text("method"));
2199 pfqn::NcOptions nopt = nc_options(o, "pfqn_qlen_joint_moments");
2200 if (o.has("tol")) nopt.tol = o.number<double>("tol");
2201 o.done();
2202 a.done();
2203 r = pfqn::pfqn_qlen_joint_moments(L, N, Z, pairs, route,
2204 pfqn::QlenJointLgSource<T>(), method, nopt);
2205 } else {
2206 a.done();
2207 r = a.has("pairs") ? pfqn::pfqn_qlen_joint_moments(L, N, Z, pairs)
2208 : pfqn::pfqn_qlen_joint_moments(L, N, Z);
2209 }
2210 Json out;
2211 out["tail"] = enc_tensor(r.tail);
2212 out["binomial"] = enc_tensor(r.binomial);
2213 out["factorial"] = enc_tensor(r.factorial);
2214 out["raw"] = enc_tensor(r.raw);
2215 out["central"] = enc_tensor(r.central);
2216 out["cumulant"] = enc_tensor(r.cumulant);
2217 out["mean"] = encode_vector(r.mean);
2218 out["cov"] = encode_matrix(r.cov);
2219 Json info;
2220 info["route"] = r.route;
2221 info["points"] = encode_count(r.points);
2222 info["served"] = encode_count(r.served);
2223 info["evals"] = encode_count(r.evals);
2224 info["exact"] = r.exact;
2225 Json pj = Json::array();
2226 for (const auto& p : r.pairs)
2227 pj.push_back(Json::array({static_cast<std::uint64_t>(p.first),
2228 static_cast<std::uint64_t>(p.second)}));
2229 info["pairs"] = pj;
2230 info["dims"] = enc_idx(r.dims);
2231 out["info"] = info;
2232 return out;
2233 }
2234};
2235
2236struct OpResptPsMoments {
2237 template <class T>
2238 static Json run(Args& a) {
2239 const std::vector<T> S = a.vector<T>("S");
2240 const std::vector<long> N = longs(a, "N");
2241 const std::vector<T> Z = a.vector<T>("Z");
2242 pfqn::ResptPsMomentsResult<T> r;
2243 if (a.has("method")) {
2244 const pfqn::ResptPsRoute m = enum_of<pfqn::ResptPsRoute>(
2245 "pfqn_respt_ps_moments", "method", a.text("method", ""),
2246 {{"auto", pfqn::ResptPsRoute::Auto},
2247 {"exact", pfqn::ResptPsRoute::Exact},
2248 {"asymptotic", pfqn::ResptPsRoute::Asymptotic}});
2249 a.done();
2250 r = pfqn::pfqn_respt_ps_moments(S, N, Z, m);
2251 } else {
2252 a.done();
2253 r = pfqn::pfqn_respt_ps_moments(S, N, Z);
2254 }
2255 Json o;
2256 Json ms = Json::array();
2257 for (pfqn::ResptPsMethod m : r.method) {
2258 switch (m) {
2259 case pfqn::ResptPsMethod::None: ms.push_back("none"); break;
2260 case pfqn::ResptPsMethod::Exact: ms.push_back("exact"); break;
2261 case pfqn::ResptPsMethod::Asymptotic: ms.push_back("asymptotic"); break;
2262 case pfqn::ResptPsMethod::Unavailable: ms.push_back("unavailable"); break;
2263 }
2264 }
2265 o["method"] = ms;
2266 o["c0"] = encode_vector(r.c0);
2267 o["c1"] = encode_vector(r.c1);
2268 o["alpha"] = encode_vector(r.alpha);
2269 o["nstates"] = encode_vector(r.nstates);
2270 o["expansionParam"] = encode_scalar(r.expansionParam);
2271 Json out;
2272 out["W"] = encode_vector(r.W);
2273 out["W2"] = encode_vector(r.W2);
2274 out["out"] = o;
2275 return out;
2276 }
2277};
2278
2279
2280// ---------------------------------------------------------------------------
2281// Seeded Monte Carlo estimators: the port draws from a caller-owned
2282// pfqn::McRng, which the JSON form names by a required seed (required_seed).
2283// ---------------------------------------------------------------------------
2284
2285/**
2286 * pfqn_mcmc(L, N, Z, s, options): MATLAB's [X, Q, ci]. options carries
2287 * samples (1e5), seed (required) and config.mcmc_batches (30) and
2288 * config.mcmc_burnin (0.1); s lists servers per station, Inf for a delay.
2289 */
2290struct OpMcmc {
2291 template <class T>
2292 static Json run(Args& a) {
2293 const Matrix<T> L = a.matrix<T>("L");
2294 const std::vector<int> N = a.ints("N");
2295 const std::vector<T> Z = a.vector_or_empty<T>("Z");
2296 const std::vector<double> sv = a.vector_or_empty<double>("s");
2297 const Json* oj = a.opt("options");
2298 a.done();
2299 if (!oj)
2300 throw InputError("pfqn_mcmc: options.seed is required; the port draws from a seeded "
2301 "generator and has no session RNG to fall back on");
2302 Args op(*oj, "pfqn_mcmc options");
2303 const std::size_t samples = op.count("samples", 100000);
2304 std::size_t nbatches = pfqn::MCMC_DEFAULT_BATCHES;
2305 double burnin = pfqn::MCMC_DEFAULT_BURNIN;
2306 if (const Json* cj = op.opt("config")) {
2307 Args cfg(*cj, "pfqn_mcmc options.config");
2308 nbatches = cfg.count("mcmc_batches", nbatches);
2309 burnin = cfg.scalar<double>("mcmc_burnin", burnin);
2310 cfg.done();
2311 }
2312 const std::uint64_t seed = required_seed(op, "pfqn_mcmc", "options.seed");
2313 op.done();
2314 pfqn::McRng rng(seed);
2315 const pfqn::McmcResult<T> r = pfqn::pfqn_mcmc(L, N, Z, sv, samples, nbatches, burnin, rng);
2316 Json ci;
2317 ci["Xse"] = encode_vector(r.Xse);
2318 ci["Xlo"] = encode_vector(r.Xlo);
2319 ci["Xhi"] = encode_vector(r.Xhi);
2320 ci["Qse"] = encode_matrix(r.Qse);
2321 ci["Qlo"] = encode_matrix(r.Qlo);
2322 ci["Qhi"] = encode_matrix(r.Qhi);
2323 ci["batches"] = encode_count(r.batches);
2324 ci["samples"] = encode_count(r.samples);
2325 ci["burnin"] = encode_count(r.burnin);
2326 Json out;
2327 out["X"] = encode_vector(r.X);
2328 out["Q"] = encode_matrix(r.Q);
2329 out["ci"] = ci;
2330 return out;
2331 }
2332};
2333
2334/**
2335 * pfqn_mci(D, N, Z, I, variant, seed): Monte Carlo integration estimate of
2336 * [G, lG]. The port returns the estimate, not MATLAB's third output lZ (the
2337 * per-sample log values), so lZ is not in the result.
2338 */
2339struct OpMci {
2340 template <class T>
2341 static Json run(Args& a) {
2342 const Matrix<T> D = a.matrix<T>("D");
2343 const std::vector<int> N = a.ints("N");
2344 const std::vector<T> Z = a.vector_or_empty<T>("Z");
2345 const std::size_t I = a.count("I", 100000);
2346 std::string v = a.text("variant", "imci");
2347 for (char& c : v) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
2348 pfqn::MciVariant variant;
2349 if (v == "imci") variant = pfqn::MciVariant::Imci;
2350 else if (v == "mci") variant = pfqn::MciVariant::Mci;
2351 else if (v == "rm") variant = pfqn::MciVariant::Rm;
2352 else if (v == "amci") variant = pfqn::MciVariant::Amci;
2353 else if (v == "lhsmci") variant = pfqn::MciVariant::Lhsmci;
2354 else throw InputError("pfqn_mci: variant must be one of imci, mci, rm, amci, lhsmci; got '" +
2355 v + "'");
2356 pfqn::McRng rng(required_seed(a, "pfqn_mci"));
2357 a.done();
2358 const pfqn::NcResult<T> r = pfqn::pfqn_mci(D, N, Z, I, variant, rng);
2359 Json out;
2360 out["G"] = encode_scalar(r.G);
2361 out["lG"] = encode_scalar(r.lG);
2362 return out;
2363 }
2364};
2365
2366/** pfqn_mmsample2(L, N, Z, samples, seed): McKenna-Mitra sampling estimate. */
2367struct OpMmsample2 {
2368 template <class T>
2369 static Json run(Args& a) {
2370 const Matrix<T> L = a.matrix<T>("L");
2371 const std::vector<int> N = a.ints("N");
2372 const std::vector<T> Z = a.vector_or_empty<T>("Z");
2373 const std::size_t samples = a.count("samples", 100000);
2374 pfqn::McRng rng(required_seed(a, "pfqn_mmsample2"));
2375 a.done();
2376 const pfqn::NcResult<T> r = pfqn::pfqn_mmsample2(L, N, Z, samples, rng);
2377 Json out;
2378 out["G"] = encode_scalar(r.G);
2379 out["lG"] = encode_scalar(r.lG);
2380 return out;
2381 }
2382};
2383
2384} // namespace
2385
2387 t["pfqn_manjunath"] = make<OpManjunath>();
2388 t["pfqn_marie"] = make<NeedsTranscendental<OpMarie> >();
2389 t["pfqn_stdf"] = make<NeedsTranscendental<OpStdf<false> > >();
2390 t["pfqn_stdf_heur"] = make<NeedsTranscendental<OpStdf<true> > >();
2391 t["pfqn_mvams"] = make<OpMvams>();
2392 t["pfqn_mvablo"] = make<OpMvablo>();
2393 t["pfqn_oqnrc"] = make<DoubleOnly<OpOqnrc> >();
2394 t["pfqn_debemva"] = make<OpDebemva>();
2395 t["pfqn_mvald"] = make<OpMvald>();
2396 t["pfqn_mvamx"] = make<OpMvamx>();
2397 t["pfqn_mvaldmx"] = make<OpMvaldmx>();
2398 t["pfqn_mvaldms"] = make<OpMvaldms>();
2399 t["pfqn_xzabalow"] = make<OpXzBound<XzAbaLow> >();
2400 t["pfqn_xzabaup"] = make<OpXzBound<XzAbaUp> >();
2401 t["pfqn_xzgsblow"] = make<NeedsTranscendental<OpXzBound<XzGsbLow> > >();
2402 t["pfqn_xzgsbup"] = make<NeedsTranscendental<OpXzBound<XzGsbUp> > >();
2403 t["pfqn_qzgblow"] = make<OpQzgb<false> >();
2404 t["pfqn_qzgbup"] = make<OpQzgb<true> >();
2405 t["pfqn_ssd"] = make<OpSsd>();
2406 t["pfqn_unique"] = make<OpUnique>();
2407 t["pfqn_mushift"] = make<OpMushift>();
2408 t["pfqn_qsa"] = make<NeedsTranscendental<OpQsa> >();
2409 t["pfqn_qdamva"] = make<NeedsTranscendental<OpQdamva> >();
2410 t["pfqn_qdlin"] = make<NeedsTranscendental<OpQdlin> >();
2411 t["pfqn_schmidt"] = make<NeedsTranscendental<OpSchmidt> >();
2412 t["pfqn_schmidt_ext"] = make<NeedsTranscendental<OpSchmidtExt> >();
2413 t["pfqn_mu_ms"] = make<OpMuMs>();
2414 t["pfqn_nc"] = make<OpNc>();
2415 t["pfqn_nc_sanitize"] = make<OpNcSanitize>();
2416 t["pfqn_ncld"] = make<OpNcld>();
2417 t["pfqn_ncldmx"] = make<OpNcldmx>();
2418 t["pfqn_perm"] = make<OpPerm>();
2419 t["pfqn_mcub"] = make<OpMcub>();
2420 t["pfqn_mmint2"] = make<NeedsTranscendental<OpMmint2> >();
2421 t["pfqn_mwrbb"] = make<OpMwrbb>();
2422 t["pfqn_nre"] = make<NeedsTranscendental<OpNr<NreCall> > >();
2423 t["pfqn_nrl"] = make<NeedsTranscendental<OpNr<NrlCall> > >();
2424 t["pfqn_nrp"] = make<NeedsTranscendental<OpNr<NrpCall> > >();
2425 t["pfqn_oi_fnc"] = make<OpOiFnc>();
2426 t["pfqn_panacea"] = make<NeedsTranscendental<OpPanacea> >();
2427 t["pfqn_panaceald"] = make<NeedsTranscendental<OpPanaceald> >();
2428 t["pfqn_pbh"] = make<OpPbh>();
2429 t["pfqn_propfair"] = make<NeedsTranscendental<OpPropfair> >();
2430 t["pfqn_sens"] = make<OpSens>();
2431 t["pfqn_sens_ldmx_ec"] = make<OpSensLdmxEc>();
2432 t["pfqn_sens_linearizer"] = make<NeedsTranscendental<OpSensLinearizer> >();
2433 t["pfqn_sens_mom"] = make<OpSensMom>();
2434 t["pfqn_sens_momldmx"] = make<OpSensMomldmx>();
2435 t["pfqn_sens_mva"] = make<NeedsTranscendental<OpSensMva> >();
2436 t["pfqn_sens_mvaldmx"] = make<OpSensMvaldmx>();
2437 t["pfqn_sens_respt"] = make<OpSensRespt>();
2438 t["pfqn_scb"] = make<OpScb>();
2439 t["pfqn_scbgap"] = make<OpScbgap>();
2440 t["pfqn_usumbound"] = make<OpUsumbound>();
2441 t["pfqn_minclasses"] = make<OpMinclasses>();
2442 t["pfqn_sib"] = make<NeedsTranscendental<OpSib> >();
2443 t["pfqn_sqni"] = make<NeedsTranscendental<OpSqni> >();
2444 t["pfqn_rd"] = make<NeedsTranscendental<OpRd> >();
2445 t["pfqn_rgf"] = make<NeedsTranscendental<OpRgf> >();
2446 t["pfqn_rgfmc"] = make<NeedsTranscendental<OpRgfmc> >();
2447 t["pfqn_nintmva"] = make<OpNintmva>();
2448 t["pfqn_qlen_joint_moments"] = make<NeedsTranscendental<OpQlenJointMoments> >();
2449 t["pfqn_respt_ps_moments"] = make<NeedsTranscendental<OpResptPsMoments> >();
2450 t["pfqn_momlin"] = make<NeedsTranscendental<OpMomlin> >();
2451 t["pfqn_mva_interval"] = make<OpMvaInterval>();
2452 t["pfqn_mvac"] = make<OpMvac>();
2453 t["pfqn_mvacld"] = make<OpMvacld>();
2454 t["pfqn_pam"] = make<OpPam>();
2455 t["pfqn_scat"] = make<NeedsTranscendental<OpScat> >();
2456 t["pfqn_sdr"] = make<OpSdr>();
2457 t["pfqn_tay"] = make<NeedsTranscendental<OpTay> >();
2458 t["pfqn_xia"] = make<NeedsTranscendental<OpXia> >();
2459 t["pfqn_mcmc"] = make<NeedsTranscendental<OpMcmc> >();
2460 t["pfqn_mci"] = make<NeedsTranscendental<OpMci> >();
2461 t["pfqn_mmsample2"] = make<NeedsTranscendental<OpMmsample2> >();
2462}
2463
2465 const std::string oirate =
2466 "the per-station service rates are callables of the station state "
2467 "(std::function), which have no JSON representation.";
2468 t["pfqn_oi_insvc"] = "the in-service rate oirate is a callable of the station state "
2469 "(std::function), which has no JSON representation.";
2470 t["pfqn_mvajd"] = oirate;
2471 t["pfqn_mvaoi"] = oirate;
2472 t["pfqn_mvaoi_marg"] = oirate;
2473 t["pfqn_ncoi"] = oirate;
2474 t["pfqn_ncjd"] = oirate;
2475 t["pfqn_pas_nc"] = oirate;
2476 t["pfqn_oi_is"] = "the per-station rates are callables (std::function), which have no JSON "
2477 "representation.";
2478 t["pfqn_pas_is"] = t["pfqn_oi_is"];
2479}
2480
2481} // namespace reg
2482} // namespace line
Internal to the –api dispatcher: what a per-domain translation unit needs to add entries to the table...
InputError(const std::string &what)
Definition error.h:105
Named-argument reader over the parsed JSON object.
Definition api_json.h:391
const std::string * get(const Element *el, const std::string &key)
el.get(key), with Python's None as a null pointer.
Definition srvn_writer.h:62
SqniResult< T > pfqn_sqni(const std::vector< T > &N, const std::vector< T > &L, const std::vector< T > &Z)
Square-root non-iterative (SQNI) approximation for a single queueing station with per-class delay.
Definition pfqn_sqni.h:57
RgfmcResult< T > pfqn_rgfmc(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const T &tol, std::size_t maxterms, const T &maxcancel)
Multiclass Recursion by Generating Functions (RGF), with think times.
Definition pfqn_rgfmc.h:465
RdResult< T > pfqn_rd(const Matrix< T > &L0, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &mu0, double tol, NcMethod method)
Reduction heuristic (RD) for the normalizing constant of a closed LOAD-DEPENDENT product-form network...
Definition pfqn_rd.h:101
MvaIntervalResult< T > pfqn_mva_interval(const Matrix< T > &L, int nlo, int nup, const T &zlo, const T &zup)
Exact interval-valued MVA for single-class closed product-form networks.
QlenJointMomentsResult< T > pfqn_qlen_joint_moments(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const std::vector< std::pair< std::size_t, std::size_t > > &pairs, QlenJointRoute route, const QlenJointLgSource< T > &lGsrc, NcMethod method, const NcOptions &nopt)
Joint moments of the queue-length vector of a closed product-form network, obtained from normalizing ...
T pfqn_xia(const std::vector< T > &L, int N, const std::vector< T > &s)
Xia's asymptotic approximation of the normalizing constant of a load-dependent (multiserver) closed n...
Definition pfqn_xia.h:90
PanaceaLdResult< T > pfqn_panaceald(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const Matrix< T > &mu, int terms)
PANACEA normal-usage asymptotic expansion for LOAD-DEPENDENT closed networks (Mitra and McKenna,...
SchmidtExtResult< T > pfqn_schmidt_ext(const Matrix< T > &D, const std::vector< int > &N, const Matrix< int > &S, const std::vector< SchedStrategy > &sched)
Extended Schmidt MVA with queue-aware alpha corrections.
SensResptResult< T > pfqn_sens_respt(const std::vector< T > &S, const Matrix< T > &V, const std::vector< int > &N, const std::vector< T > &Z, const std::vector< int > &b, int tmax)
Exact raw moments E[W^t], t = 1..3, of the sojourn time of a job at an FCFS b-server center of a clos...
LinearizerResult< T > pfqn_scat(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< SchedStrategy > &type, double tol, int maxiter, const Matrix< T > &QN0)
Neuse-Chandy SCAT (Self-Correcting Approximation Technique) approximate MVA.
Definition pfqn_scat.h:71
OqnrcResult pfqn_oqnrc(const std::vector< double > &lam, const Matrix< double > &A, const Matrix< double > &S, const Matrix< double > &SCV, const std::vector< double > &nservers, const std::vector< bool > &isps, const std::vector< int > &pool, const std::vector< int > &Ncap, bool waitq, double tol, int iter_max)
Runs OQNRC.
Definition pfqn_oqnrc.h:179
StdfResult< T > pfqn_stdf(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &S, const std::vector< std::size_t > &fcfsNodes, const Matrix< T > &rates, const std::vector< T > &tset)
Sojourn-time distribution at the listed FCFS stations.
Definition pfqn_stdf.h:322
AmvaResult< T > pfqn_pam(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, PamVariant variant=PamVariant::Basic)
Hsieh-Lam Proportional Approximation Methods (PAMB / PAMI / PAMT).
Definition pfqn_pam.h:55
NcldmxResult< T > pfqn_ncldmx(const std::vector< T > &lambda, const Matrix< T > &D, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &mu, const std::string &method, const T &atol, const NcOptions &nopt)
Normalizing constant of a MIXED open/closed network with limited load dependence.
ScbBounds< T > pfqn_scb(const std::vector< T > &L, long N)
Bracket on the throughput and the per-device utilizations of the UNKNOWN multiclass system whose sing...
Definition pfqn_scb.h:67
NcSanitizeResult< T > pfqn_nc_sanitize(const std::vector< T > &lambda, const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const T &atol)
Preprocessing shared by the normalizing-constant solvers: drop the classes that cannot contribute,...
MarieResult< T > pfqn_marie(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const Matrix< T > &scv, double tol, int maxiter, const std::vector< int > &nservers)
Marie's method for a closed network with FCFS Coxian service.
Definition pfqn_marie.h:647
SensMvaResult< T > pfqn_sens_mva(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const std::vector< int > &mi)
Exact per-station queue-length variances and covariances of a closed product-form network,...
SensLinearizerResult< T > pfqn_sens_linearizer(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const T *tol, unsigned maxiter)
Approximate moments E[Q_i], Var[Q_i], Cov[Q_i,Q_j], E[Q_i^2] and E[Q_i^3] of the per-station total qu...
long pfqn_minclasses(const T &Usum, long K, long N)
Smallest number of customer classes R consistent with an observed sum of device utilizations,...
Definition pfqn_scb.h:192
MvaResult< T > pfqn_mvams(const std::vector< T > &lambda, const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &mi, const std::vector< int > &S)
General-purpose exact MVA for mixed networks with multiserver stations.
Definition pfqn_mvams.h:862
UniqueResult< T > pfqn_unique(const Matrix< T > &L, const Matrix< T > &mu, const Matrix< T > &gamma)
Merge stations whose (L, mu, gamma) rows are exactly equal.
Definition pfqn_unique.h:47
McubBounds< T > pfqn_mcub(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Kerola's multiclass composite bound (Perf.
Definition pfqn_mcub.h:55
PropfairResult< T > pfqn_propfair(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Proportionally fair allocation estimate of the normalizing constant (Schweitzer 1979; Walton,...
NcldResult< T > pfqn_ncld(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &mu, const std::string &method_name, const T &atol, const NcOptions &nopt)
Normalizing constant of a LOAD-DEPENDENT closed network: the dispatcher.
Definition pfqn_ncld.h:167
std::function< std::vector< double >(const Matrix< T > &, const std::vector< std::vector< int > > &)> QlenJointLgSource
Injected source of log G.
MvaResult< T > pfqn_mvamx(const std::vector< T > &lambda, const Matrix< T > &D, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &mi)
Exact MVA for a mixed open/closed network of single-server stations.
Definition pfqn_mvams.h:313
T pfqn_xzabaup(const std::vector< T > &L, const T &N, const T &Z)
X <= min(1/Lmax, N/(sum(L)+Z)): capacity bound and population bound.
NcMethod nc_method_of(const std::string &s)
Map a method name to its enum; throws UnsupportedError on an unknown one.
Definition pfqn_nc.h:177
QlenJointRoute
Which survival-array identity is used.
MvabloResult< T > pfqn_mvablo(long N, const std::vector< T > &S, const Matrix< T > &P, const std::vector< double > &K, std::vector< bool > isdelay, double tol=1e-4, int iter_max=1000)
Runs MVABLO.
Definition pfqn_mvablo.h:75
T pfqn_xzabalow(const std::vector< T > &L, const T &N, const T &Z)
X >= N / (Z + N sum(L)), the ABA population bound.
MvaLdResult< T > pfqn_mvald(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &mu, bool stabilize=true)
Exact MVA for a closed network of load-dependent stations.
Definition pfqn_mvams.h:129
StdfResult< T > pfqn_stdf_heur(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &S, const std::vector< std::size_t > &fcfsNodes, const Matrix< T > &rates, const std::vector< T > &tset)
Heuristic sojourn-time distribution at the listed FCFS stations.
T pfqn_nre(const Matrix< T > &L0, const std::vector< T > &N, const std::vector< T > &Z, const Matrix< T > &alpha0)
Saddle-tilted Edgeworth approximation of log G for a limited load-dependent model.
Definition pfqn_nre.h:466
MwrbbSched
Station discipline codes, matching the MATLAB sched argument.
Definition pfqn_mwrbb.h:48
AmvaResult< T > pfqn_tay(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, double tol=1e-6, std::size_t maxiter=1000, const Matrix< T > &QN0=Matrix< T >())
Tay's arrival-instant approximate MVA.
Definition pfqn_tay.h:83
T pfqn_xzgsbup(const std::vector< T > &L, const T &N, const T &Z)
X = 2N / (R + sqrt(R^2 - 4 Z Lmax N)), R from the geometric queue bound.
MvaResult< T > pfqn_mvaldms(const std::vector< T > &lambda, const Matrix< T > &D, const std::vector< int > &N, const Matrix< T > &Z, const std::vector< int > &S)
Exact MVA for mixed open/closed networks with multiserver stations.
Definition pfqn_mvams.h:790
DebemvaResult< T > pfqn_debemva(long N, const std::vector< T > &S, const Matrix< T > &P, const std::vector< double > &K, std::vector< bool > isdelay, double tol=0.0, long iter_max=100000)
Runs debeMVA.
QdAmvaResult< T > pfqn_qdamva(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const Matrix< T > &mu, const Matrix< T > &Q0, double tol=1e-6, std::size_t maxiter=10000)
QD-AMVA: queue-dependent approximate mean value analysis.
Definition pfqn_qdamva.h:88
AmvaResult< T > pfqn_qsa(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const std::vector< AmvaSched > &type, double tol=1e-10, std::size_t maxiter=100, int levels=3)
Queue-Shift Approximation (QSA) for closed product-form networks.
Definition pfqn_qsa.h:221
T pfqn_usumbound(long R, long K, long N)
Largest value the sum of device utilizations can take in any closed product-form network with R class...
Definition pfqn_scb.h:168
SibBounds< T > pfqn_sib(const std::vector< T > &L, int N, const T &Z, int level)
Successively Improving Bounds (Srinivasan 1985/1987) on the cycle time and throughput of a single-cla...
Definition pfqn_sib.h:84
SchmidtResult< T > pfqn_schmidt(const Matrix< T > &D, const std::vector< int > &N, const Matrix< int > &S, const std::vector< SchedStrategy > &sched, const Matrix< T > &v)
Schmidt's MVA for closed networks with general scheduling disciplines and class-dependent multiserver...
SdrResult< T > pfqn_sdr(const Matrix< T > &S, const Matrix< T > &xi, const std::vector< std::size_t > &N, const SdrStruct &sdr, const Matrix< T > &alpha=Matrix< T >())
Exact product form of eq.
Definition pfqn_sdr.h:304
T pfqn_qzgbup(const std::vector< T > &L, const T &N, const T &Z, std::size_t i)
As the lower bound, with Y from the ABA upper bound and the sigma term.
Definition pfqn_qzgbup.h:34
MvaResult< T > pfqn_mvaldmx(const std::vector< T > &lambda, const Matrix< T > &D, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &mu)
Exact MVA for mixed open/closed networks with limited load dependence.
Definition pfqn_mvams.h:576
MmintResult< T > pfqn_mmint2(const std::vector< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Adaptive form (MATLAB pfqn_mmint2): Gauss-Kronrod on [0, 27.63] with absolute tolerance 1e-12.
Definition pfqn_mmint2.h:83
OiFncResult< T > pfqn_oi_fnc(const std::vector< T > &Phi, const std::vector< int > &N, const std::function< T(const std::vector< int > &)> &f)
Order-independent (OI) functional server: the balance function Psi and the rate mu_f of an auxiliary ...
Definition pfqn_oi_fnc.h:76
PanaceaResult< T > pfqn_panacea(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, int terms)
PANACEA normal-usage asymptotic expansion of the normalizing constant (Ramakrishnan and Mitra,...
T pfqn_scbgap(long N, long K, long r, bool undominated)
Demand-free bound on the relative throughput error incurred when r of the N single-customer classes a...
Definition pfqn_scb.h:135
T pfqn_nrp(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const Matrix< T > &alpha)
Norlund-Rice probit approximation of log G.
Definition pfqn_nrl.h:140
RgfResult< T > pfqn_rgf(const std::vector< T > &L, int N, const T &Z)
Recursion by Generating Functions (RGF) for the normalizing constant of a SINGLE-CLASS closed product...
Definition pfqn_rgf.h:91
MwrbbBounds< T > pfqn_mwrbb(const Matrix< T > &V, const Matrix< T > &S, const std::vector< T > &N, const std::vector< T > &Z, const std::vector< MwrbbSched > &sched, const std::vector< int > &prio)
Majumdar-Woodside robust box bounds on the per-class throughput of a closed multiclass network with m...
Definition pfqn_mwrbb.h:161
NintMvaResult< T > pfqn_nintmva(const std::vector< T > &L, const T &N, const T &Z)
Mean value analysis at a nonintegral population (fractional-base aMVA).
SensMomResult< T > pfqn_sens_mom(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const std::vector< int > &mi, const std::vector< int > &groups)
Exact moments E[Q], Var[Q], E[Q^2] and E[Q^3] of the grouped queue lengths of a closed product-form n...
PbhBounds< T > pfqn_pbh(const std::vector< T > &L, int N, const T &Z, int level)
Performance Bound Hierarchy (Eager and Sevcik 1983, ACM TOCS 1(2):99-115) for single-class closed pro...
Definition pfqn_pbh.h:114
Matrix< T > pfqn_mushift(const Matrix< T > &mu, const std::vector< std::size_t > &iset)
Shift the load-dependent service-rate lattice of selected stations.
NcMethod
The methods this port dispatches, one per compute_norm_const case.
Definition pfqn_nc.h:101
SensLdmxEcResult< T > pfqn_sens_ldmx_ec(const std::vector< T > &lambda, const Matrix< T > &D, const Matrix< T > &mu)
Effective capacity terms of the mixed load-dependent MVA of Bruell-Balbo-Afshari, together with their...
QdLinResult< T > pfqn_qdlin(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const Matrix< T > &mu, const std::vector< double > &nservers, double tol=1e-6, std::size_t maxiter=1000, double wtol=1e-4)
QD-LIN: the Linearizer arm of AMVA-LD, on a plain demand matrix.
Definition pfqn_qdlin.h:205
SensMvaldmxResult< T > pfqn_sens_mvaldmx(const std::vector< T > &lambda, const Matrix< T > &D, const std::vector< int > &N, const std::vector< T > &Z, const Matrix< T > &mu)
Exact queue-length variances and covariances of a mixed open/closed product-form network with limited...
std::vector< T > pfqn_mu_ms(int N, int m, int c)
Aggregate load-dependent rate of m identical c-server FCFS stations.
Definition pfqn_mu_ms.h:56
PamVariant
Which of the three proportional approximations to run.
Definition pfqn_pam.h:46
T pfqn_nrl(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z, const Matrix< T > &alpha)
Norlund-Rice logit approximation of log G.
Definition pfqn_nrl.h:130
T pfqn_qzgblow(const std::vector< T > &L, const T &N, const T &Z, std::size_t i)
Qgb = y/(1-y) - y^(N+1)/(1-y) with y = N L_i / (Z + sum(L) + Lmax N).
T pfqn_perm(const Matrix< T > &A, const std::vector< int > &m)
Permanent of a matrix with repeated columns, by Ryser's formula.
Definition pfqn_perm.h:52
SensMomResult< T > pfqn_sens_momldmx(const std::vector< T > &lambda, const Matrix< T > &D, const std::vector< int > &N, const std::vector< T > &Z, const Matrix< T > &mu, const std::vector< int > &groups)
Exact moments E[Q], Var[Q], E[Q^2], E[Q^3] and covariances of the grouped queue lengths of a mixed lo...
MomlinResult< T > pfqn_momlin(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const T &tol, int maxiter)
Moment linearizer: approximate first and second queue-length moments of a large closed product-form n...
Definition pfqn_momlin.h:87
SensResult< T > pfqn_sens(const Matrix< T > &L, const std::vector< int > &N, const std::vector< T > &Z, const std::vector< int > &mi)
Exact analytic derivatives of the mean performance measures {X,Q,U,R} of a closed product-form (BCMP)...
Definition pfqn_sens.h:348
T pfqn_xzgsblow(const std::vector< T > &L, const T &N, const T &Z)
X = 2N / (R + sqrt(R^2 - 4 Z Lmax (N-1))), R from the geometric queue bound.
MvacldResult< T > pfqn_mvacld(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &mu)
MVAC for networks with queue-length dependent (QLD) service centers, the Section V extension of Conwa...
NcDispatchResult< T > pfqn_nc(const std::vector< T > &lambda, const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, NcMethod method, const T &atol, const NcOptions &nopt)
Normalizing constant of a product-form queueing network: the dispatcher.
Definition pfqn_nc.h:275
MvacResult< T > pfqn_mvac(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z)
MVAC: exact mean value analysis BY CHAIN of a closed multichain product-form network (Conway,...
Definition pfqn_mvac.h:246
PfqnManjunathResult< T > pfqn_manjunath(const Matrix< T > &L, const std::vector< int > &N, const Matrix< T > &Z, const Matrix< T > &A, const std::vector< long > &b, const std::string &sense, const PfqnManjunathOptions &options={})
Exact normalizing constant of a closed multiclass product-form network whose state space carries arbi...
SsdBounds< T > pfqn_ssd(const std::vector< T > &L, const T &N, const T &Z, const std::vector< T > &nservers)
Server-Station Disaggregation bounds for a multiserver closed network (Dallery and Suri,...
Definition pfqn_ssd.h:55
nlohmann::json Json
Definition api_json.h:63
std::uint64_t required_seed(Args &a, const std::string &fn, const char *spelled="seed")
The seed of a function whose port draws from a caller-owned generator.
Json encode_vectors(const std::vector< std::vector< T > > &v)
A list of vectors, the shape a per-class or per-segment result returns.
Definition api_json.h:366
Matrix< T > matrix_from_json(const Json &j, const std::string &where)
A matrix from a JSON value: 2-D array as rows, 1-D array as a row vector, scalar as 1x1,...
Definition api_json.h:223
std::vector< int > int_vector_from_json(const Json &j, const std::string &where)
An integer vector; a non-integral entry is an error, never a truncation.
Definition api_json.h:267
Json encode_matrices(const std::vector< Matrix< T > > &v)
A list of matrices, the shape the MMAP/BMAP families return as {D0,D1,...}.
Definition api_json.h:358
T number_from_json(const Json &j, const std::string &where)
Definition api_json.h:210
std::vector< T > vector_from_json(const Json &j, const std::string &where)
A flat numeric vector: 1-D array, or a 1-row / 1-column 2-D array.
Definition api_json.h:255
Json encode_vector(const std::vector< T > &v)
Definition api_json.h:333
Json encode_matrix(const Matrix< T > &m)
Definition api_json.h:340
void register_library_only_pfqn_b(LibraryOnlyTable &t)
Json encode_scalar(const T &v)
Definition api_json.h:328
Json encode_count(std::size_t n)
A count.
Definition api_json.h:378
void register_api_pfqn_b(DispatchTable &t)
std::map< std::string, std::string > LibraryOnlyTable
name -> why the function has no named-JSON-argument form.
Json encode_ints(const std::vector< int > &v)
Definition api_json.h:350
std::map< std::string, Invoker > DispatchTable
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
debeMVA: MVA-based approximation of closed networks with finite (BAS) buffers.
Exact normalizing constant of a closed multiclass product-form network whose state space carries arbi...
Marie's iterative aggregation-decomposition for closed networks with FCFS general (Coxian) service.
Monte Carlo Integration estimate of the normalizing constant of a closed product-form network (Ross,...
Chen-O'Cinneide REGULARIZATION: a Markov chain Monte Carlo estimator of the class throughputs X(r) = ...
Kerola's multiclass composite bound (Perf.
McKenna-Mitra integral form of the normalizing constant of a repairman model (one queueing station,...
Sampled McKenna-Mitra integral form of the normalizing constant of a repairman (single-queue plus del...
Moment linearizer: approximate first and second queue-length moments of a large closed product-form n...
Aggregate load-dependent rate of m identical c-server FCFS stations.
Shift the load-dependent service-rate lattice of selected stations.
Exact interval-valued MVA for single-class closed product-form networks.
MVABLO: approximate MVA for closed networks with Blocking-After-Service (BAS).
MVAC: exact mean value analysis BY CHAIN of a closed multichain product-form network (Conway,...
MVAC for networks with queue-length dependent (QLD) service centers, the Section V extension of Conwa...
Exact Mean Value Analysis for mixed open/closed networks with multiserver stations.
Majumdar-Woodside robust box bounds on the per-class throughput of a closed multiclass network with m...
Normalizing constant of a product-form queueing network: the dispatcher.
Preprocessing shared by the normalizing-constant solvers: drop the classes that cannot contribute,...
Normalizing constant of a LOAD-DEPENDENT closed network: the dispatcher.
Normalizing constant of a MIXED open/closed network with limited load dependence.
Mean value analysis at a nonintegral population (fractional-base aMVA).
Norlund-Rice inversion of the normalizing constant on a SADDLE-TILTED contour, with a second-order Ed...
Norlund-Rice inversion of the normalizing constant, in its logistic (NRL) and probit (NRP) substituti...
Order-independent (OI) functional server: the balance function Psi and the rate mu_f of an auxiliary ...
OQNRC: approximate MVA for open queueing networks with restricted capacity.
Hsieh-Lam Proportional Approximation Methods (PAMB / PAMI / PAMT).
PANACEA normal-usage asymptotic expansion of the normalizing constant (Ramakrishnan and Mitra,...
PANACEA normal-usage asymptotic expansion for LOAD-DEPENDENT closed networks (Mitra and McKenna,...
Performance Bound Hierarchy (Eager and Sevcik 1983, ACM TOCS 1(2):99-115) for single-class closed pro...
Permanent of a matrix with repeated columns, by Ryser's formula.
Proportionally fair allocation estimate of the normalizing constant (Schweitzer 1979; Walton,...
QD-AMVA: queue-dependent approximate mean value analysis.
QD-LIN: the Linearizer arm of AMVA-LD, on a plain demand matrix.
Joint moments of the queue-length vector of a closed product-form network, obtained from normalizing ...
Queue-Shift Approximation (QSA) for closed product-form networks.
Geometric-bound lower bound on the queue length at station i.
Geometric-bound upper bound on the queue length at station i.
Reduction heuristic (RD) for the normalizing constant of a closed LOAD-DEPENDENT product-form network...
Sojourn-time moments at the processor-sharing station of a closed terminal-driven system (Mitra and M...
Recursion by Generating Functions (RGF) for the normalizing constant of a SINGLE-CLASS closed product...
Multiclass Recursion by Generating Functions (RGF), with think times.
Neuse-Chandy SCAT (Self-Correcting Approximation Technique) approximate MVA.
Dowdy-Carlson-Krantz-Tripathi (1992) single-class bounds of multi-class queueing networks,...
Schmidt's MVA for closed networks with general scheduling disciplines and class-dependent multiserver...
Extended Schmidt MVA with queue-aware alpha corrections.
Product-form state-dependent routing.
Exact analytic derivatives of the mean performance measures {X,Q,U,R} of a closed product-form (BCMP)...
Effective capacity terms of the mixed load-dependent MVA of Bruell-Balbo-Afshari, together with their...
Approximate moments E[Q_i], Var[Q_i], Cov[Q_i,Q_j], E[Q_i^2] and E[Q_i^3] of the per-station total qu...
Exact moments E[Q], Var[Q], E[Q^2] and E[Q^3] of the grouped queue lengths of a closed product-form n...
Exact higher queue-length moments (up to order three) of mixed open/closed product-form networks with...
Exact per-station queue-length variances and covariances of a closed product-form network,...
Exact queue-length variances and covariances of a mixed open/closed product-form network with limited...
Exact raw moments E[W^t], t = 1..3, of the sojourn time of a job at an FCFS b-server center of a clos...
Successively Improving Bounds (Srinivasan 1985/1987) on the cycle time and throughput of a single-cla...
Square-root non-iterative (SQNI) approximation for a single queueing station with per-class delay.
Server-Station Disaggregation bounds for a multiserver closed network (Dallery and Suri,...
Sojourn-time distribution at multiserver FCFS stations of a closed product-form network (J.
Heuristic sojourn-time distribution at multiserver FCFS stations, a variant of J.
Tay's arrival-instant approximate MVA.
Station consolidation and its inverse: merge identical demand rows into one station with a multiplici...
Xia's asymptotic approximation of the normalizing constant of a load-dependent (multiserver) closed n...
Asymptotic-bound-analysis lower bound on throughput.
Asymptotic-bound-analysis upper bound on throughput.
Geometric-square-root bound, lower bound on throughput.
Geometric-square-root bound, upper bound on throughput.