LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
ljd_linearize.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_LJD_LINEARIZE_H
6#define LINE_API_FES_LJD_LINEARIZE_H
7
8/**
9 * @file
10 * @ingroup api_fes
11 * Linearized index of a per-class population vector, for Limited Joint
12 * Dependence (LJD) tables.
13 *
14 * Port of matlab/src/api/ljd/ljd_linearize.m,
15 *
16 * idx = 1 + n1 + n2 (N1+1) + n3 (N1+1)(N2+1) + ...
17 *
18 * with every n_k clamped to its cutoff N_k. The result is 1-BASED, exactly as
19 * in MATLAB, because the FES scaling tables it addresses are transcribed from
20 * MATLAB indices; the callers in this port subtract one when they index a
21 * std::vector. It is otherwise the mixed-radix index of line/util/population.h
22 * (pop_index over plane_sizes), with the clamp added.
23 *
24 * The header lives under api/fes because the FES functions are its only
25 * consumers in this port; when the ljd domain itself is ported it should move
26 * to api/ljd unchanged.
27 */
28
29#include <cstddef>
30#include <vector>
31
32#include "line/util/error.h"
33
34namespace line {
35namespace fes {
36
37/**
38 * @brief Linearized index of a per-class population vector, for Limited Joint
39 * Dependence (LJD) tables.
40 *
41 * @param nvec per-class populations
42 * @param cutoffs per-class cutoffs, same length as nvec
43 * @return the 1-based linearized index
44 */
45inline std::size_t ljd_linearize(const std::vector<int>& nvec, const std::vector<int>& cutoffs) {
46 if (nvec.size() != cutoffs.size())
47 throw InputError("ljd_linearize: population and cutoff vectors have different lengths");
48 std::size_t idx = 1; // 1-indexed, as in MATLAB
49 std::size_t multiplier = 1;
50 for (std::size_t k = 0; k < nvec.size(); ++k) {
51 const int nk = nvec[k] < cutoffs[k] ? nvec[k] : cutoffs[k]; // clamp to cutoff
52 if (nk > 0) idx += static_cast<std::size_t>(nk) * multiplier;
53 multiplier *= static_cast<std::size_t>(cutoffs[k] + 1);
54 }
55 return idx;
56}
57
58/**
59 * Inverse of `ljd_linearize`: the population vector behind an index.
60 *
61 * The forward map is a mixed-radix numeral with class k in radix (Nk+1), so the
62 * inverse is the digit-by-digit division that reads it back. It is what lets a
63 * caller walk a tabulated dependence in index order and still know which
64 * population each entry belongs to.
65 *
66 * @param idx the 1-based linearized index
67 * @param cutoffs per-class cutoffs
68 * @return the per-class population vector
69 */
70inline std::vector<int> ljd_delinearize(std::size_t idx, const std::vector<int>& cutoffs) {
71 std::vector<int> nvec(cutoffs.size(), 0);
72 std::size_t rem = idx - 1;
73 for (std::size_t k = 0; k < cutoffs.size(); ++k) {
74 const std::size_t radix = static_cast<std::size_t>(cutoffs[k] + 1);
75 nvec[k] = static_cast<int>(rem % radix);
76 rem /= radix;
77 }
78 return nvec;
79}
80
81} // namespace fes
82} // namespace line
83
84#endif // LINE_API_FES_LJD_LINEARIZE_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
std::vector< int > ljd_delinearize(std::size_t idx, const std::vector< int > &cutoffs)
Inverse of ljd_linearize: the population vector behind an index.
std::size_t ljd_linearize(const std::vector< int > &nvec, const std::vector< int > &cutoffs)
Linearized index of a per-class population vector, for Limited Joint Dependence (LJD) tables.