LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
pfqn_unique.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_PFQN_UNIQUE_H
6
#define LINE_API_PFQN_UNIQUE_H
7
8
/**
9
* @file
10
* @ingroup api_pfqn
11
* Station consolidation and its inverse: merge identical demand rows into one
12
* station with a multiplicity, and expand per-station results back.
13
*
14
* Templated port of matlab/src/api/pfqn/pfqn_unique.m and pfqn_expand.m, plus
15
* the load-dependent rate shift pfqn_mushift.m.
16
*
17
* One deliberate divergence from MATLAB, the same one already taken in
18
* pfqn_recal: MATLAB compares rows within GlobalConstants.Zero() (1e-14), so it
19
* merges stations whose demands only nearly agree. A tolerance-based merge
20
* perturbs the normalizing constant, which is unacceptable for an
21
* exact-capable algorithm and has no meaning at all in the rational field. The
22
* port merges on exact equality. Callers that want tolerant merging should
23
* round their demands before calling, where the rounding is visible.
24
*/
25
26
#include <cstddef>
27
#include <vector>
28
29
#include "
line/num/number.h
"
30
#include "
line/util/error.h
"
31
#include "
line/util/matrix.h
"
32
33
namespace
line
{
34
namespace
pfqn
{
35
36
template
<
class
T>
37
struct
UniqueResult
{
38
Matrix<T>
L
;
///< consolidated demands (Mu x R)
39
Matrix<T>
mu
;
///< consolidated LD rates, empty if none
40
Matrix<T>
gamma
;
///< consolidated CD scalings, empty if none
41
std::vector<int>
mi
;
///< multiplicity of each consolidated station
42
std::vector<std::size_t>
mapping
;
///< original station -> consolidated index
43
};
44
45
/** Merge stations whose (L, mu, gamma) rows are exactly equal. */
46
template
<
class
T>
47
UniqueResult<T>
pfqn_unique
(
const
Matrix<T>
& L,
const
Matrix<T>
& mu,
const
Matrix<T>
& gamma) {
48
const
std::size_t M = L.
rows
(), R = L.
cols
();
49
if
(!mu.
empty
() && mu.
rows
() != M)
throw
InputError
(
"pfqn_unique: mu has the wrong row count"
);
50
if
(!gamma.
empty
() && gamma.
rows
() != M)
51
throw
InputError
(
"pfqn_unique: gamma has the wrong row count"
);
52
53
UniqueResult<T>
r;
54
r.
mapping
.assign(M, 0);
55
std::vector<std::size_t> reps;
// representative original index per group
56
57
const
auto
rows_equal = [&](std::size_t a, std::size_t b) {
58
for
(std::size_t j = 0; j < R; ++j)
59
if
(L(a, j) != L(b, j))
return
false
;
60
for
(std::size_t j = 0; j < mu.
cols
(); ++j)
61
if
(mu(a, j) != mu(b, j))
return
false
;
62
for
(std::size_t j = 0; j < gamma.
cols
(); ++j)
63
if
(gamma(a, j) != gamma(b, j))
return
false
;
64
return
true
;
65
};
66
67
for
(std::size_t i = 0; i < M; ++i) {
68
bool
merged =
false
;
69
for
(std::size_t g = 0; g < reps.size(); ++g) {
70
if
(rows_equal(i, reps[g])) {
71
r.
mapping
[i] = g;
72
r.
mi
[g] += 1;
73
merged =
true
;
74
break
;
75
}
76
}
77
if
(!merged) {
78
r.
mapping
[i] = reps.size();
79
reps.push_back(i);
80
r.
mi
.push_back(1);
81
}
82
}
83
84
r.
L
=
Matrix<T>
(reps.size(), R);
85
for
(std::size_t g = 0; g < reps.size(); ++g)
86
for
(std::size_t j = 0; j < R; ++j) r.
L
(g, j) = L(reps[g], j);
87
if
(!mu.
empty
()) {
88
r.
mu
=
Matrix<T>
(reps.size(), mu.
cols
());
89
for
(std::size_t g = 0; g < reps.size(); ++g)
90
for
(std::size_t j = 0; j < mu.
cols
(); ++j) r.
mu
(g, j) = mu(reps[g], j);
91
}
92
if
(!gamma.
empty
()) {
93
r.
gamma
=
Matrix<T>
(reps.size(), gamma.
cols
());
94
for
(std::size_t g = 0; g < reps.size(); ++g)
95
for
(std::size_t j = 0; j < gamma.
cols
(); ++j) r.
gamma
(g, j) = gamma(reps[g], j);
96
}
97
return
r;
98
}
99
100
template
<
class
T>
101
UniqueResult<T>
pfqn_unique
(
const
Matrix<T>
& L) {
102
return
pfqn_unique
(L,
Matrix<T>
(),
Matrix<T>
());
103
}
104
105
/**
106
* Fold a caller-supplied multiplicity vector along a consolidation mapping.
107
*
108
* Port of pfqn_combine_mi in
109
* jar/src/main/java/jline/api/pfqn/Pfqn_replicas.java, the third member of the
110
* replica trio alongside pfqn_unique and pfqn_expand. MATLAB has no
111
* counterpart.
112
*
113
* When the caller already carries its own per-station multiplicities mi (a
114
* station standing for mi(i) identical replicas) and pfqn_unique then merges
115
* further stations, the two multiplicities must COMPOSE: the consolidated
116
* station g represents sum over the original stations mapped to g of mi(i).
117
* The result is therefore a SUM along the mapping, not a count of the group,
118
* which is what makes it different from the group sizes pfqn_unique itself
119
* returns.
120
*
121
* Arithmetic: EXACT-CAPABLE. Integer addition only.
122
*
123
* @param mi (M) multiplicity of each original station
124
* @param mapping (M) original station -> consolidated index, as pfqn_unique
125
* returns it
126
* @param M_unique number of consolidated stations
127
* @return (M_unique) combined multiplicities
128
*/
129
inline
std::vector<int>
pfqn_combine_mi
(
const
std::vector<int>& mi,
130
const
std::vector<std::size_t>& mapping,
131
std::size_t M_unique) {
132
if
(mi.size() != mapping.size())
133
throw
InputError
(
"pfqn_combine_mi: mi and mapping have different lengths"
);
134
std::vector<int> combined(M_unique, 0);
135
for
(std::size_t i = 0; i < mapping.size(); ++i) {
136
if
(mapping[i] >= M_unique)
137
throw
InputError
(
"pfqn_combine_mi: mapping index out of range"
);
138
combined[mapping[i]] += mi[i];
139
}
140
return
combined;
141
}
142
143
// pfqn_expand and pfqn_mushift live in their own headers, matching the 1:1
144
// file-per-function convention: see pfqn_expand.h and pfqn_mushift.h.
145
146
}
// namespace pfqn
147
}
// namespace line
148
149
#endif
// LINE_API_PFQN_UNIQUE_H
line::InputError::InputError
InputError(const std::string &what)
Definition
error.h:39
line::Matrix
Definition
matrix.h:56
line::Matrix::cols
std::size_t cols() const
Definition
matrix.h:90
line::Matrix::Matrix
Matrix()
Definition
matrix.h:58
line::Matrix::rows
std::size_t rows() const
Definition
matrix.h:89
line::Matrix::empty
bool empty() const
Definition
matrix.h:92
error.h
The exception types the port throws.
matrix.h
Dense matrix and non-owning view.
line::pfqn
Definition
cd_peak_scaling.h:43
line::pfqn::pfqn_combine_mi
std::vector< int > pfqn_combine_mi(const std::vector< int > &mi, const std::vector< std::size_t > &mapping, std::size_t M_unique)
Fold a caller-supplied multiplicity vector along a consolidation mapping.
Definition
pfqn_unique.h:129
line::pfqn::pfqn_unique
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
line
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
line::pfqn::UniqueResult
Definition
pfqn_unique.h:37
line::pfqn::UniqueResult::mi
std::vector< int > mi
multiplicity of each consolidated station
Definition
pfqn_unique.h:41
line::pfqn::UniqueResult::mu
Matrix< T > mu
consolidated LD rates, empty if none
Definition
pfqn_unique.h:39
line::pfqn::UniqueResult::L
Matrix< T > L
consolidated demands (Mu x R)
Definition
pfqn_unique.h:38
line::pfqn::UniqueResult::gamma
Matrix< T > gamma
consolidated CD scalings, empty if none
Definition
pfqn_unique.h:40
line::pfqn::UniqueResult::mapping
std::vector< std::size_t > mapping
original station -> consolidated index
Definition
pfqn_unique.h:42
include
line
api
pfqn
pfqn_unique.h
Generated by
1.18.0