LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
fes_validate.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_VALIDATE_H
6#define LINE_API_FES_VALIDATE_H
7
8/**
9 * @file
10 * @ingroup api_fes
11 * Input validation for Flow-Equivalent Server (FES) aggregation.
12 *
13 * Templated port of matlab/src/api/fes/fes_validate.m.
14 *
15 * Checks that the network structure and the station subset admit an FES
16 * aggregation:
17 * - the model is closed (Norton's theorem is a closed-network result);
18 * - the subset is non-empty and a PROPER subset of the stations;
19 * - every index in the subset is a valid station;
20 * - every station in the subset is a Queue or a Delay, so that the isolated
21 * subnetwork has a load-dependent throughput table at all;
22 * - the subset holds no duplicates.
23 *
24 * The reference returns (isValid, errorMsg) rather than raising, because the
25 * caller (ModelAdapter.aggregateFES) reports the message to the user; the port
26 * keeps that contract. THE ORDER OF THE CHECKS IS PART OF THE CONTRACT: a
27 * subset that is both too large and holds a Source would report the first
28 * failure, and callers key on the message.
29 *
30 * NOTE the closed-model test is `sn_is_open_model`, which is true only when
31 * EVERY class is open. A MIXED model therefore passes this validator; that is
32 * the reference's behaviour and is reproduced rather than tightened, since
33 * changing it would silently refuse models the MATLAB path accepts.
34 *
35 * Arithmetic: EXACT-CAPABLE. Structural checks only; no arithmetic on T.
36 */
37
38#include <cstddef>
39#include <set>
40#include <string>
41#include <vector>
42
45#include "line/num/number.h"
46#include "line/util/error.h"
47
48namespace line {
49namespace fes {
50
51/** The reference's (isValid, errorMsg) pair. */
53 bool isValid = false;
54 std::string errorMsg;
55};
56
57/** NodeType.toText, so that the refusal messages read as the reference's do. */
58inline std::string fes_node_type_text(qn::NodeType t) {
59 switch (t) {
60 case qn::NodeType::Region: return "Region";
61 case qn::NodeType::Transition: return "Transition";
62 case qn::NodeType::Place: return "Place";
63 case qn::NodeType::Fork: return "Fork";
64 case qn::NodeType::Router: return "Router";
65 case qn::NodeType::Cache: return "Cache";
66 case qn::NodeType::Logger: return "Logger";
67 case qn::NodeType::ClassSwitch: return "ClassSwitch";
68 case qn::NodeType::Delay: return "Delay";
69 case qn::NodeType::Source: return "Source";
70 case qn::NodeType::Queue: return "Queue";
71 case qn::NodeType::Join: return "Join";
72 case qn::NodeType::Sink: return "Sink";
73 }
74 throw InputError("fes_validate: unrecognized node type");
75}
76
77/**
78 * @brief Input validation for Flow-Equivalent Server (FES) aggregation.
79 *
80 * @param sn the network structure
81 * @param subsetIndices 1-based station indices to aggregate, matching the
82 * reference's index base so that the messages agree
83 */
84template <class T>
86 const std::vector<std::size_t>& subsetIndices) {
88
89 if (subsetIndices.empty()) {
90 res.errorMsg = "Station subset cannot be empty.";
91 return res;
92 }
94 res.errorMsg =
95 "FES aggregation only applies to closed queueing networks. Model contains open "
96 "classes.";
97 return res;
98 }
99
100 const std::size_t M = sn.nstations;
101 if (subsetIndices.size() >= M) {
102 res.errorMsg =
103 "Cannot aggregate all stations. The subset must be a proper subset of the network.";
104 return res;
105 }
106
107 for (std::size_t i = 0; i < subsetIndices.size(); ++i) {
108 const std::size_t stationIdx = subsetIndices[i];
109 if (stationIdx < 1 || stationIdx > M) {
110 res.errorMsg = "Station index " + std::to_string(stationIdx) +
111 " is invalid. Must be an integer between 1 and " + std::to_string(M) +
112 ".";
113 return res;
114 }
115 const std::size_t nodeIdx = sn.station_to_node.at(stationIdx - 1);
116 const qn::NodeType nodeType = sn.nodes.at(nodeIdx - 1).nodetype;
117 if (nodeType != qn::NodeType::Queue && nodeType != qn::NodeType::Delay) {
118 res.errorMsg = "Station " + std::to_string(stationIdx) + " has type " +
119 fes_node_type_text(nodeType) +
120 ". FES aggregation only supports Queue and Delay stations.";
121 return res;
122 }
123 }
124
125 const std::set<std::size_t> uniq(subsetIndices.begin(), subsetIndices.end());
126 if (uniq.size() != subsetIndices.size()) {
127 res.errorMsg = "Station subset contains duplicate stations.";
128 return res;
129 }
130
131 res.isValid = true;
132 return res;
133}
134
135} // namespace fes
136} // namespace line
137
138#endif // LINE_API_FES_VALIDATE_H
InputError(const std::string &what)
Definition error.h:39
A network plus its refreshed NetworkStruct.
The exception types the port throws.
bool sn_is_open_model(const qn::NetworkStruct< T > &sn)
all(isinf(sn.njobs)): EVERY class is open, which a mixed model fails.
std::string fes_node_type_text(qn::NodeType t)
NodeType.toText, so that the refusal messages read as the reference's do.
FesValidateResult fes_validate(const qn::NetworkStruct< T > &sn, const std::vector< std::size_t > &subsetIndices)
Input validation for Flow-Equivalent Server (FES) aggregation.
NodeType
Node kinds, with the values of MATLAB NodeType.
Definition lang_types.h:324
A queueing network and its refreshed NetworkStruct.
Number-type abstraction for the templated API port.
Ports of the sn_has_* / sn_is_* predicate family of matlab/src/api/sn.
The reference's (isValid, errorMsg) pair.