LINE Solver (C++)
Templated C++ port of the LINE queueing solver
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
43namespace line {
44namespace pfqn {
45
46/** Result of pas_placement. */
47template <class T>
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 */
79template <class T>
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
InputError(const std::string &what)
Definition error.h:39
std::size_t cols() const
Definition matrix.h:90
std::size_t rows() const
Definition matrix.h:89
The exception types the port throws.
Dense matrix and non-owning view.
PasPlacement< T > pas_placement(const Matrix< T > &H)
Precedence closure of a swap graph.
Number-type abstraction for the templated API port.
Result of pas_placement.
Matrix< T > P
precedence closure, P(i, j) = 1 iff i must precede j
std::vector< std::size_t > placeable(const std::vector< T > &x) const
Classes that may be placed next, given the remaining per-class counts.