LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
fes_map_aggregate.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_FES_MAP_AGGREGATE_H
6#define LINE_API_FES_MAP_AGGREGATE_H
7
8/**
9 * @file
10 * @ingroup api_fes
11 * Recursive MAP flow-equivalent server for a station subset.
12 *
13 * Templated port of matlab/src/api/fes/fes_map_aggregate.m, mirrored by the JAR
14 * and native Python. Implements the recursion of Section 5.2.1 of Casale, Mi,
15 * Cherkasova and Smirni, IEEE Trans. Soft. Eng. 37(5), 2011.
16 *
17 * The first station seeds the flow-equivalent server; every further station is
18 * folded against the running server by building the inter-departure MAP of the
19 * resulting pair at each population level and fitting a MAP(2) to its first three
20 * moments and index of dispersion. The result is one MAP per level, the service
21 * process of a single load-dependent station replacing the whole subnetwork.
22 * Unlike the classic flow-equivalent server, which keeps only the mean throughput
23 * of the subnetwork, this one also carries the burstiness of its departure
24 * stream, so a bottleneck switch across the aggregated resources stays visible to
25 * the rest of the model.
26 *
27 * Levels are evaluated on a grid and the four descriptors are interpolated
28 * between grid points, as MAPs fitted at neighbouring populations are similar.
29 * The MAP is refitted at every level from the interpolated descriptors, never
30 * interpolated entrywise.
31 *
32 * ARITHMETIC: transcendental, inherited from map2_fit_idc.
33 */
34
35#include <cstddef>
36#include <string>
37#include <vector>
38
45#include "line/num/number.h"
46#include "line/util/error.h"
47
48namespace line {
49namespace fes {
50
51/** The load-dependent MAP that replaces a subnetwork, with its descriptors. */
52template <class T>
54 /** Service process of the flow-equivalent server, index k-1 holding k jobs. */
55 std::vector<mam::Map<T>> fes;
56 /** Throughput of the subnetwork at each population. */
57 std::vector<T> throughput;
58 /** Descriptors e1, e2, e3 and the index of dispersion at each population. */
59 std::vector<std::vector<T>> moments;
60 /** Fit status at each population, see map2_fit_idc. */
61 std::vector<int> status;
62 /** Populations at which the inter-departure MAP was evaluated. */
63 std::vector<std::size_t> grid;
64};
65
66/**
67 * @brief Recursive MAP flow-equivalent server for a station subset.
68 *
69 * @param maps service process of each station, already scaled by its visit ratio
70 * @param servers number of servers of each station, infinite for a delay
71 * @param n largest population the flow-equivalent server must serve
72 * @param grid populations at which the inter-departure MAP is evaluated
73 * @param method moment evaluation method, "ssolve" or "euler"
74 */
75template <class T>
77 const std::vector<double>& servers, std::size_t n,
78 const std::vector<std::size_t>& grid,
79 const std::string& method = "ssolve") {
81 "fes_map_aggregate inherits map2_fit_idc's arithmetic");
82 const std::size_t M = maps.size();
83 if (M < 1) throw InputError("fes_map_aggregate: at least one station is required");
84 if (servers.size() != M)
85 throw InputError("fes_map_aggregate: one server count per station is required");
86
88 out.grid = grid;
89 out.status.assign(n, 0);
90 out.moments.assign(4, std::vector<T>(n, num_traits<T>::from_int(0)));
91
92 std::vector<mam::Map<T>> fes = fes_map_levels(maps[0], n, servers[0]);
93 for (std::size_t k = 0; k < n; ++k) {
94 out.moments[0][k] = mam::map_moment(fes[k], 1);
95 out.moments[1][k] = mam::map_moment(fes[k], 2);
96 out.moments[2][k] = mam::map_moment(fes[k], 3);
97 out.moments[3][k] = mam::map_idc(fes[k]);
98 }
99
100 for (std::size_t i = 1; i < M; ++i) {
101 const std::vector<mam::Map<T>> stationLev = fes_map_levels(maps[i], n, servers[i]);
102 std::vector<std::vector<T>> gmom(4, std::vector<T>(grid.size()));
103 for (std::size_t g = 0; g < grid.size(); ++g) {
104 const mam::Map<T> T01 = fes_map_interdeparture(stationLev, fes, grid[g]);
105 const FesMapMoments<T> mom = fes_map_moments(T01, method);
106 gmom[0][g] = mom.e1;
107 gmom[1][g] = mom.e2;
108 gmom[2][g] = mom.e3;
109 gmom[3][g] = mom.idc;
110 }
111
112 if (grid.size() < n) {
113 std::vector<T> xs(grid.size()), xq(n);
114 for (std::size_t g = 0; g < grid.size(); ++g)
115 xs[g] = num_traits<T>::from_int(static_cast<long>(grid[g]));
116 for (std::size_t k = 0; k < n; ++k)
117 xq[k] = num_traits<T>::from_int(static_cast<long>(k + 1));
118 for (std::size_t r = 0; r < 4; ++r) out.moments[r] = fes_map_interp(xs, gmom[r], xq);
119 } else {
120 out.moments = gmom;
121 }
122
123 std::vector<mam::Map<T>> newFes;
124 newFes.reserve(n);
125 for (std::size_t k = 0; k < n; ++k) {
127 out.moments[0][k], out.moments[1][k], out.moments[2][k], out.moments[3][k]);
128 newFes.push_back(fit.map);
129 out.status[k] = fit.status;
130 }
131 fes = newFes;
132 }
133
134 out.fes = fes;
135 out.throughput.assign(n, num_traits<T>::from_int(0));
136 for (std::size_t k = 0; k < n; ++k)
137 out.throughput[k] = num_traits<T>::from_int(1) / out.moments[0][k];
138 return out;
139}
140
141/** Aggregation on the default population grid. */
142template <class T>
144 const std::vector<double>& servers, std::size_t n) {
145 return fes_map_aggregate(maps, servers, n, fes_map_grid(n), "ssolve");
146}
147
148} // namespace fes
149} // namespace line
150
151#endif // LINE_API_FES_MAP_AGGREGATE_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
Inter-departure MAP of a closed subnetwork made of one MAP station and one MAP flow-equivalent server...
Shape-preserving interpolation of the flow-equivalent descriptors, and the population grid they are e...
Per-level processes of a load-dependent flow-equivalent server.
Moments and index of dispersion of an inter-departure MAP.
Fit a MAP(2) to three moments and an asymptotic index of dispersion.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
std::vector< mam::Map< T > > fes_map_levels(const mam::Map< T > &map, std::size_t n, double mi=1.0)
Replicate a load independent MAP over n levels, scaling level k by min(k, mi).
FesMapMoments< T > fes_map_moments(const mam::Map< T > &map, const std::string &method="ssolve", double step_safety=0.1, double tol=1e-12, std::size_t iter_max=1000000)
Moments and index of dispersion of an inter-departure MAP.
mam::Map< T > fes_map_interdeparture(const std::vector< mam::Map< T > > &maps, const std::vector< mam::Map< T > > &fes, std::size_t n)
Inter-departure MAP of a closed subnetwork made of one MAP station and one MAP flow-equivalent server...
FesMapAggregateResult< T > fes_map_aggregate(const std::vector< mam::Map< T > > &maps, const std::vector< double > &servers, std::size_t n, const std::vector< std::size_t > &grid, const std::string &method="ssolve")
Recursive MAP flow-equivalent server for a station subset.
std::vector< T > fes_map_interp(const std::vector< T > &x, const std::vector< T > &y, const std::vector< T > &xq)
Monotone piecewise cubic Hermite interpolation of one series.
std::vector< std::size_t > fes_map_grid(std::size_t n, std::size_t nhead=FES_MAP_GRID_NHEAD, std::size_t ntail=FES_MAP_GRID_NTAIL)
Populations at which the inter-departure MAP is evaluated.
T map_idc(const Map< T > &m)
Index of dispersion for counts, I = 1 + 2(lambda - pie (Q + e pi)^-1 D1 e).
Definition map_moment.h:196
Map2FitIdcResult< T > map2_fit_idc(const T &e1, const T &e2, const T &e3, const T &I)
Fit a MAP(2) to three moments and an asymptotic index of dispersion.
T map_moment(const Map< T > &m, unsigned k)
Raw moment of order k of the inter-arrival time: k!
Definition map_moment.h:118
Number-type abstraction for the templated API port.
The load-dependent MAP that replaces a subnetwork, with its descriptors.
std::vector< mam::Map< T > > fes
Service process of the flow-equivalent server, index k-1 holding k jobs.
std::vector< int > status
Fit status at each population, see map2_fit_idc.
std::vector< std::vector< T > > moments
Descriptors e1, e2, e3 and the index of dispersion at each population.
std::vector< std::size_t > grid
Populations at which the inter-departure MAP was evaluated.
std::vector< T > throughput
Throughput of the subnetwork at each population.
Descriptors a MAP(2) is fitted against.
The fitted process and which of the reference's five outcomes produced it.
int status
0 all four descriptors matched, 1 exponential because the burstiness is not representable,...
A MAP as the pair of matrices (D0, D1).
Definition map_moment.h:53