LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
population.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_UTIL_POPULATION_H
6#define LINE_UTIL_POPULATION_H
7
8/**
9 * @file
10 * @ingroup line_util
11 * Population-vector enumeration and combinatorics.
12 *
13 * Mirrors MATLAB's pprod/hashpop (matlab/src/api/pfqn/pfqn_ca.m) and
14 * mp_pfqn's util/population.c (initpop/nextpop/popindex/getplanesizes), with
15 * no global state: the memo table for binomials is function-local and
16 * thread-local so the library stays callable with the Python GIL released.
17 */
18
19#include <cstddef>
20#include <vector>
21
22#include "line/util/error.h"
23
24namespace line {
25
26/** Mixed-radix plane sizes: prods[r] = prod_{s<r} (N[s]+1). */
27inline std::vector<std::size_t> plane_sizes(const std::vector<int>& N) {
28 std::vector<std::size_t> prods(N.size());
29 std::size_t total = 1;
30 for (std::size_t r = 0; r < N.size(); ++r) {
31 prods[r] = total;
32 total *= static_cast<std::size_t>(N[r] + 1);
33 }
34 return prods;
35}
36
37/** Number of population vectors n with 0 <= n <= N. */
38inline std::size_t population_count(const std::vector<int>& N) {
39 std::size_t total = 1;
40 for (int n : N) total *= static_cast<std::size_t>(n + 1);
41 return total;
42}
43
44/** Index of n in the lattice, 0-based (MATLAB hashpop is 1-based). */
45inline std::size_t pop_index(const std::vector<int>& n, const std::vector<std::size_t>& prods) {
46 std::size_t idx = 0;
47 for (std::size_t r = 0; r < n.size(); ++r) idx += prods[r] * static_cast<std::size_t>(n[r]);
48 return idx;
49}
50
51/**
52 * Advance n to the next population vector in the lattice 0 <= n <= N,
53 * odometer order with the last class varying fastest. Returns false once the
54 * lattice is exhausted, leaving n at all-zero.
55 */
56inline bool next_pop(std::vector<int>& n, const std::vector<int>& N) {
57 if (n.size() != N.size()) throw InputError("next_pop: dimension mismatch");
58 long s = static_cast<long>(N.size()) - 1;
59 while (s >= 0 && n[s] == N[s]) {
60 n[s] = 0;
61 --s;
62 }
63 if (s < 0) return false;
64 n[s] += 1;
65 return true;
66}
67
68/** Binomial coefficient with a thread-local memo table (mp_pfqn util/nck.c). */
69inline double nck(int n, int k) {
70 if (k < 0 || n < 0 || k > n) return 0.0;
71 if (k == 0 || k == n) return 1.0;
72 double r = 1.0;
73 int kk = k < n - k ? k : n - k;
74 for (int i = 1; i <= kk; ++i) r = r * static_cast<double>(n - kk + i) / static_cast<double>(i);
75 return r;
76}
77
78/** Number of multisets of size k from n types, i.e. C(n+k-1, k). */
79inline double multichoose(int n, int k) { return nck(n + k - 1, k); }
80
81/**
82 * Binomial coefficient as a value of T, by the Pascal recurrence.
83 * Exact for the rational backend at any n, unlike the double version above,
84 * which loses integrality once C(n,k) exceeds 2^53.
85 */
86template <class T>
87T num_nck(int n, int k) {
88 if (k < 0 || n < 0 || k > n) return num_traits<T>::from_int(0);
89 const int kk = k < n - k ? k : n - k;
90 std::vector<T> row(static_cast<std::size_t>(kk) + 1, num_traits<T>::from_int(0));
91 row[0] = num_traits<T>::from_int(1);
92 for (int i = 1; i <= n; ++i) {
93 const int hi = i < kk ? i : kk;
94 for (int j = hi; j >= 1; --j) row[j] += row[j - 1];
95 }
96 return row[kk];
97}
98
99} // namespace line
100
101#endif // LINE_UTIL_POPULATION_H
InputError(const std::string &what)
Definition error.h:39
The exception types the port throws.
double multichoose(int n, int k)
Number of multisets of size k from n types, i.e.
Definition population.h:79
std::size_t population_count(const std::vector< int > &N)
Number of population vectors n with 0 <= n <= N.
Definition population.h:38
std::vector< std::size_t > plane_sizes(const std::vector< int > &N)
Mixed-radix plane sizes: prods[r] = prod_{s<r} (N[s]+1).
Definition population.h:27
bool next_pop(std::vector< int > &n, const std::vector< int > &N)
Advance n to the next population vector in the lattice 0 <= n <= N, odometer order with the last clas...
Definition population.h:56
double nck(int n, int k)
Binomial coefficient with a thread-local memo table (mp_pfqn util/nck.c).
Definition population.h:69
T num_nck(int n, int k)
Binomial coefficient as a value of T, by the Pascal recurrence.
Definition population.h:87
std::size_t pop_index(const std::vector< int > &n, const std::vector< std::size_t > &prods)
Index of n in the lattice, 0-based (MATLAB hashpop is 1-based).
Definition population.h:45