LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Toggle main menu visibility
Loading...
Searching...
No Matches
pas_placement.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_PAS_PLACEMENT_H
6
#define LINE_API_PFQN_PAS_PLACEMENT_H
7
8
/**
9
* @file
10
* @ingroup api_pfqn
11
* Placement order of a pass-and-swap (P&S) order-independent network.
12
*
13
* Templated port of matlab/src/api/pfqn/pas_placement.m. An ordering
14
* c = (c_1, ..., c_l) is feasible iff class a never precedes class b whenever
15
* H(b, a) is nonzero (Comte and Dorsman, 2021, arXiv:2009.12299), so H is read
16
* as "row must be placed before column" and its transitive closure P is the
17
* full precedence relation. The closure is taken by repeated Boolean squaring
18
* against H until it stops growing, which is the reference's own iteration and
19
* terminates in at most R steps.
20
*
21
* placeable(x) returns the classes that may be placed next given the vector x
22
* of remaining per-class counts: class j is placeable iff x(j) > 0 and no
23
* still-present class must precede it, sum_i x(i) P(i, j) == 0.
24
*
25
* ARITHMETIC. The closure is Boolean and the placeable test is a sum of
26
* counts, so nothing here rounds and the header is instantiated at Rational as
27
* well as double and Real. P is returned as a 0/1 matrix of T, matching
28
* MATLAB's double(P), so it can be multiplied straight into the caller's
29
* arithmetic.
30
*
31
* EMPTY H. MATLAB returns P = [] and a placeable that admits every present
32
* class. Reproduced: an empty H yields an empty P, and placeable then ignores
33
* the precedence test.
34
*/
35
36
#include <cstddef>
37
#include <vector>
38
39
#include "
line/num/number.h
"
40
#include "
line/util/error.h
"
41
#include "
line/util/matrix.h
"
42
43
namespace
line
{
44
namespace
pfqn
{
45
46
/** Result of pas_placement. */
47
template
<
class
T>
48
struct
PasPlacement
{
49
Matrix<T>
P
;
///< precedence closure, P(i, j) = 1 iff i must precede j
50
51
/**
52
* Classes that may be placed next, given the remaining per-class counts.
53
* @return 0-based class indices, in increasing order (MATLAB's find order)
54
*/
55
std::vector<std::size_t>
placeable
(
const
std::vector<T>& x)
const
{
56
const
T zero =
num_traits<T>::from_int
(0);
57
std::vector<std::size_t> idx;
58
if
(
P
.
rows
() == 0) {
59
for
(std::size_t j = 0; j < x.size(); ++j)
60
if
(x[j] > zero) idx.push_back(j);
61
return
idx;
62
}
63
if
(x.size() !=
P
.
rows
())
throw
InputError
(
"pas_placement: x has the wrong class count"
);
64
for
(std::size_t j = 0; j <
P
.
cols
(); ++j) {
65
if
(!(x[j] > zero))
continue
;
66
T s = zero;
67
for
(std::size_t i = 0; i <
P
.
rows
(); ++i) s += x[i] *
P
(i, j);
68
if
(s == zero) idx.push_back(j);
69
}
70
return
idx;
71
}
72
};
73
74
/**
75
* Precedence closure of a swap graph.
76
*
77
* @param H (R x R) swap graph; H(b, a) nonzero forces b before a
78
*/
79
template
<
class
T>
80
PasPlacement<T>
pas_placement
(
const
Matrix<T>
& H) {
81
PasPlacement<T>
out;
82
if
(H.
rows
() == 0 || H.
cols
() == 0)
return
out;
83
if
(H.
rows
() != H.
cols
())
throw
InputError
(
"pas_placement: the swap graph is not square"
);
84
const
std::size_t R = H.
rows
();
85
const
T zero =
num_traits<T>::from_int
(0), one =
num_traits<T>::from_int
(1);
86
87
std::vector<char> P(R * R, 0), Hb(R * R, 0);
88
for
(std::size_t i = 0; i < R; ++i)
89
for
(std::size_t j = 0; j < R; ++j) {
90
const
char
b = H(i, j) != zero ? 1 : 0;
91
Hb[i * R + j] = b;
92
P[i * R + j] = b;
93
}
94
for
(std::size_t it = 0; it < R; ++it) {
95
std::vector<char> next(P);
96
for
(std::size_t i = 0; i < R; ++i)
97
for
(std::size_t k = 0; k < R; ++k) {
98
if
(!P[i * R + k])
continue
;
99
for
(std::size_t j = 0; j < R; ++j)
100
if
(Hb[k * R + j]) next[i * R + j] = 1;
101
}
102
if
(next == P)
break
;
103
P.swap(next);
104
}
105
106
out.
P
=
Matrix<T>
(R, R, zero);
107
for
(std::size_t i = 0; i < R; ++i)
108
for
(std::size_t j = 0; j < R; ++j)
109
if
(P[i * R + j]) out.
P
(i, j) = one;
110
return
out;
111
}
112
113
}
// namespace pfqn
114
}
// namespace line
115
116
#endif
// LINE_API_PFQN_PAS_PLACEMENT_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
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::pas_placement
PasPlacement< T > pas_placement(const Matrix< T > &H)
Precedence closure of a swap graph.
Definition
pas_placement.h:80
line
Definition
aoi_dist2ph.h:52
number.h
Number-type abstraction for the templated API port.
line::num_traits
Definition
number.h:111
line::pfqn::PasPlacement
Result of pas_placement.
Definition
pas_placement.h:48
line::pfqn::PasPlacement::P
Matrix< T > P
precedence closure, P(i, j) = 1 iff i must precede j
Definition
pas_placement.h:49
line::pfqn::PasPlacement::placeable
std::vector< std::size_t > placeable(const std::vector< T > &x) const
Classes that may be placed next, given the remaining per-class counts.
Definition
pas_placement.h:55
include
line
api
pfqn
pas_placement.h
Generated by
1.18.0