LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
sn_schedule_nominal.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2012-2026, QORE Lab, Imperial College London
3 * All rights reserved.
4 */
5#ifndef LINE_API_SN_SN_SCHEDULE_NOMINAL_H
6#define LINE_API_SN_SN_SCHEDULE_NOMINAL_H
7
8/**
9 * @file
10 * @ingroup api_sn
11 * Port of `matlab/src/api/sn/sn_schedule_nominal.m`: unpack the MAPt or PHt slot
12 * of `sn.proc` at one (station, class) into the per-segment (D0, D1) pairs and
13 * their width-weighted time average.
14 *
15 * IT IS AN ACCESSOR HERE AND A DECODER THERE, and the difference is where the
16 * conversion happens. MATLAB stores the slot as `{breakpoints, A, B, cyclic}`
17 * with A and B holding (D0, D1) for a MAPt and (alpha, S) for a PHt, so every
18 * reader must know which family it is looking at and rebuild the MAP pair
19 * (S, (-S e) alpha) itself. This port converts a PHt ONCE, in
20 * `Distrib::pht`, so what is stored is always the MAP schedule and every reader
21 * sees one representation. The nominal pair is likewise computed once, in the
22 * constructor, and lives in `Distrib::D0` / `D1` where a time-blind consumer --
23 * the phase count, `sn.rates`, the fluid layout -- already looks for it.
24 *
25 * What is left for this function is the CONTRACT: return the same eight outputs
26 * the reference returns (the width-weighted nominal pair, recomputed from the
27 * segments as the reference computes it, breakpoints, the per-segment MAP
28 * pairs, cyclic, and the marked / batch segment blocks), and refuse a (station, class) that carries no schedule
29 * rather than inventing a one-segment one. A caller that wants the nominal of an
30 * ordinary process reads `sn.service[i][r].D0` directly, which is what the
31 * reference's own `nomD0`/`nomD1` fallback does.
32 */
33
34#include <cstddef>
35#include <vector>
36
39#include "line/num/number.h"
40#include "line/util/error.h"
41#include "line/util/matrix.h"
42
43namespace line {
44namespace sn {
45
46/** What `sn_schedule_nominal` returns, in the reference's own output order. */
47template <class T>
49 Matrix<T> D0bar, D1bar; ///< the width-weighted time average
50 std::vector<T> breakpoints; ///< the boundary vector, nseg + 1 long
51 std::vector<Matrix<T> > segD0; ///< per-segment D0, already in MAP form
52 std::vector<Matrix<T> > segD1; ///< per-segment D1
53 bool cyclic = false;
54 /**
55 * The reference's 7th and 8th outputs: the per-mark blocks of a marked
56 * schedule, `segMark[c][k]` being mark c+1 in segment k, and the per-batch
57 * blocks of a batch schedule, `segBatch[c][b][k]`. Empty on an unmarked
58 * schedule, as `segMark = {}` / `segBatch = {}` are there.
59 */
60 std::vector<std::vector<Matrix<T> > > segMark;
61 std::vector<std::vector<std::vector<Matrix<T> > > > segBatch;
62};
63
64/** True when (ist, r) carries a MAPt / PHt / NHPP schedule. Both 0-based. */
65template <class T>
66bool sn_has_schedule(const qn::NetworkStruct<T>& sn, std::size_t ist, std::size_t r) {
67 if (ist >= sn.service.size() || r >= sn.service[ist].size()) return false;
68 return sn.service[ist][r].has_schedule();
69}
70
71/** Port of `sn_schedule_nominal(sn, ist, r)`; `ist` and `r` are 0-based here. */
72template <class T>
74 std::size_t r) {
75 if (!sn_has_schedule(sn, ist, r))
76 throw InputError("sn_schedule_nominal: station " + std::to_string(ist + 1) + ", class " +
77 std::to_string(r + 1) +
78 " carries no MAPt/PHt schedule; read sn.service[i][r].D0 for an "
79 "ordinary process");
80 const lang::Distrib<T>& d = sn.service[ist][r];
82 // The reference's width-weighted time average, D0bar = sum_k
83 // (widths(k)/total) * segD0{k} with widths = diff(breakpoints); the
84 // constructor stored the same pair in D0 / D1, which is the fallback when
85 // the breakpoint vector does not frame the segments.
86 const std::size_t nseg = d.sched_D0.size();
87 if (d.sched_bp.size() == nseg + 1 && d.sched_D1.size() == nseg && nseg > 0) {
88 const T zero = num_traits<T>::from_int(0);
89 T total = zero;
90 for (std::size_t k = 0; k < nseg; ++k) total += d.sched_bp[k + 1] - d.sched_bp[k];
91 out.D0bar = Matrix<T>(d.sched_D0[0].rows(), d.sched_D0[0].cols(), zero);
92 out.D1bar = Matrix<T>(d.sched_D1[0].rows(), d.sched_D1[0].cols(), zero);
93 for (std::size_t k = 0; k < nseg; ++k) {
94 const T w = T((d.sched_bp[k + 1] - d.sched_bp[k]) / total);
95 for (std::size_t a = 0; a < out.D0bar.rows(); ++a)
96 for (std::size_t b = 0; b < out.D0bar.cols(); ++b)
97 out.D0bar(a, b) = T(out.D0bar(a, b) + w * d.sched_D0[k](a, b));
98 for (std::size_t a = 0; a < out.D1bar.rows(); ++a)
99 for (std::size_t b = 0; b < out.D1bar.cols(); ++b)
100 out.D1bar(a, b) = T(out.D1bar(a, b) + w * d.sched_D1[k](a, b));
101 }
102 } else {
103 out.D0bar = d.D0;
104 out.D1bar = d.D1;
105 }
106 out.breakpoints = d.sched_bp;
107 out.segD0 = d.sched_D0;
108 out.segD1 = d.sched_D1;
109 out.cyclic = d.sched_cyclic;
110 out.segMark = d.sched_Dmark;
111 out.segBatch = d.sched_Dbatch;
112 return out;
113}
114
115} // namespace sn
116} // namespace line
117
118#endif // LINE_API_SN_SN_SCHEDULE_NOMINAL_H
InputError(const std::string &what)
Definition error.h:105
A network plus its refreshed NetworkStruct.
The exception types the port throws.
Enumerations and the minimal distribution descriptor shared by the model layer of the C++ port.
Dense matrix and non-owning view.
ScheduleNominal< T > sn_schedule_nominal(const qn::NetworkStruct< T > &sn, std::size_t ist, std::size_t r)
Port of sn_schedule_nominal(sn, ist, r); ist and r are 0-based here.
bool sn_has_schedule(const qn::NetworkStruct< T > &sn, std::size_t ist, std::size_t r)
True when (ist, r) carries a MAPt / PHt / NHPP schedule.
Conservation laws of a layered queueing network, enumerated from its structure.
Definition aoi_dist2ph.h:52
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
std::vector< std::vector< std::vector< Matrix< T > > > > sched_Dbatch
The BATCH marked schedule, sched_Dbatch[c][b][k] being the block that, in segment k,...
Definition lang_types.h:930
Matrix< T > D0
The (D0,D1) pair when the type carries one directly.
Definition lang_types.h:863
std::vector< std::vector< Matrix< T > > > sched_Dmark
The MARKED schedule, sched_Dmark[c][k] being the block of mark c+1 in segment k.
Definition lang_types.h:914
std::vector< T > sched_bp
sn.proc{i}{r} = {breakpoints, A, B, cyclic} of a MAPt / PHt / NHPP.
Definition lang_types.h:906
std::vector< Matrix< T > > sched_D1
Definition lang_types.h:907
std::vector< Matrix< T > > sched_D0
Definition lang_types.h:907
What sn_schedule_nominal returns, in the reference's own output order.
std::vector< std::vector< std::vector< Matrix< T > > > > segBatch
Matrix< T > D1bar
the width-weighted time average
std::vector< Matrix< T > > segD1
per-segment D1
std::vector< T > breakpoints
the boundary vector, nseg + 1 long
std::vector< Matrix< T > > segD0
per-segment D0, already in MAP form
std::vector< std::vector< Matrix< T > > > segMark
The reference's 7th and 8th outputs: the per-mark blocks of a marked schedule, segMark[c][k] being ma...