LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
fj_dag_makespan.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_FJ_DAG_MAKESPAN_H
6#define LINE_API_FJ_DAG_MAKESPAN_H
7
8/**
9 * @file
10 * @ingroup api_fj
11 * Makespan of a task system with precedence constraints.
12 *
13 * Templated port of matlab/src/api/fj/fj_dag_makespan.m.
14 *
15 * Because the precedence relation is acyclic, so is the chain whose state is
16 * the SET of completed tasks, and the makespan is swept level by level instead
17 * of solved as a linear system. In a state with completed set S the eligible
18 * tasks are those all of whose predecessors lie in S; task i among the k of
19 * them completes at rate rate(i,k), so the state is held for M(S) = 1/T(S) and
20 * moves to S + {i} with probability b(S,i) = rate(i,k)/T(S). Making the rate
21 * depend on the concurrency is what couples the task system to the queueing
22 * network underneath it.
23 *
24 * p(R) = sum_{S -> R} p(S) b(S,R),
25 * D(R) = M(R) p(R) + sum_{S -> R} b(S,R) D(S),
26 *
27 * started at p(empty) = 1; the makespan is D at the fully completed state, and
28 * the per-task initiation and completion times accumulate over the transitions
29 * that start and that finish each task.
30 */
31
32#include <cstddef>
33#include <vector>
34
36#include "line/num/number.h"
37#include "line/util/error.h"
38#include "line/util/matrix.h"
39
40namespace line {
41namespace fj {
42
43/** [C, I, Cend, E] of fj_dag_makespan. */
44template <class T>
46 T C;
47 std::vector<T> I;
48 std::vector<T> Cend;
49 std::vector<T> E;
50};
51
52/**
53 * @brief Makespan of a task system with precedence constraints.
54 *
55 * @param pred n by n precedence relation, pred(i,j) nonzero when i precedes j
56 * @param rate n by n table whose entry (i,k) is the rate of task i at concurrency k
57 * @return the makespan with the per-task initiation, completion and execution times
58 */
59template <class T>
61 const std::size_t n = pred.rows();
62 if (pred.cols() != n) throw InputError("fj_dag_makespan: pred must be square");
63 if (n < 1) throw InputError("fj_dag_makespan: at least one task is required");
64 if (n > 20) throw InputError("fj_dag_makespan: the completed-set sweep enumerates 2^n states");
65 if (rate.rows() != n || rate.cols() != n)
66 throw InputError("fj_dag_makespan: the rate table must be n by n");
67 const T zero = num_traits<T>::from_int(0), one = num_traits<T>::from_int(1);
68 for (std::size_t i = 0; i < n; ++i)
69 for (std::size_t k = 0; k < n; ++k)
70 if (!(rate(i, k) > zero))
71 throw InputError("fj_dag_makespan: all completion rates must be positive");
72
73 // Predecessor masks, and a topological pass that rejects a cycle
74 std::vector<std::size_t> predmask(n, 0);
75 std::vector<long> indeg(n, 0);
76 for (std::size_t j = 0; j < n; ++j)
77 for (std::size_t i = 0; i < n; ++i)
78 if (!(pred(i, j) == zero)) {
79 predmask[j] |= (static_cast<std::size_t>(1) << i);
80 ++indeg[j];
81 }
82 std::vector<bool> seen(n, false);
83 std::size_t remaining = n;
84 for (std::size_t pass = 0; pass < n; ++pass) {
85 std::size_t pick = n;
86 for (std::size_t i = 0; i < n; ++i)
87 if (!seen[i] && indeg[i] == 0) { pick = i; break; }
88 if (pick == n) break;
89 seen[pick] = true;
90 indeg[pick] = -1;
91 for (std::size_t j = 0; j < n; ++j)
92 if (!(pred(pick, j) == zero) && indeg[j] > 0) --indeg[j];
93 --remaining;
94 }
95 if (remaining > 0)
96 throw InputError("fj_dag_makespan: the precedence relation contains a cycle");
97
98 const std::size_t nmask = static_cast<std::size_t>(1) << n;
99 std::vector<std::size_t> eligmask(nmask, 0);
100 std::vector<bool> closed(nmask, false);
101 for (std::size_t mask = 0; mask < nmask; ++mask) {
102 bool ok = true;
103 std::size_t em = 0;
104 for (std::size_t i = 0; i < n; ++i) {
105 const std::size_t bit = static_cast<std::size_t>(1) << i;
106 if (mask & bit) {
107 // A completed task must have all of its predecessors completed
108 if ((predmask[i] & mask) != predmask[i]) { ok = false; break; }
109 } else if ((predmask[i] & mask) == predmask[i]) {
110 em |= bit;
111 }
112 }
113 closed[mask] = ok;
114 if (ok) eligmask[mask] = em;
115 }
116
117 std::vector<T> p(nmask, zero), D(nmask, zero);
118 p[0] = one;
120 out.I.assign(n, zero);
121 out.Cend.assign(n, zero);
122 out.E.assign(n, zero);
123
124 for (std::size_t mask = 0; mask < nmask; ++mask) {
125 if (!closed[mask]) continue;
126 std::vector<std::size_t> elig;
127 for (std::size_t i = 0; i < n; ++i)
128 if (eligmask[mask] & (static_cast<std::size_t>(1) << i)) elig.push_back(i);
129 const std::size_t k = elig.size();
130 if (k == 0) continue;
131 T Ttot = zero;
132 for (std::size_t idx = 0; idx < k; ++idx) Ttot += rate(elig[idx], k - 1);
133 // Holding time of this state, weighted by the probability of reaching it
134 D[mask] += p[mask] / Ttot;
135 for (std::size_t idx = 0; idx < k; ++idx) {
136 const std::size_t i = elig[idx];
137 const T b = rate(i, k - 1) / Ttot;
138 const std::size_t nxt = mask | (static_cast<std::size_t>(1) << i);
139 const T contrib = b * D[mask];
140 p[nxt] += p[mask] * b;
141 D[nxt] += contrib;
142 // Task i completes on this transition
143 out.Cend[i] += contrib;
144 // Tasks that first become eligible on this transition start on it
145 const std::size_t fresh = eligmask[nxt] & ~eligmask[mask];
146 for (std::size_t j = 0; j < n; ++j)
147 if (fresh & (static_cast<std::size_t>(1) << j)) out.I[j] += contrib;
148 }
149 }
150
151 out.C = D[nmask - 1];
152 for (std::size_t i = 0; i < n; ++i) out.E[i] = out.Cend[i] - out.I[i];
153 return out;
154}
155
156} // namespace fj
157} // namespace line
158
159#endif // LINE_API_FJ_DAG_MAKESPAN_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.
Shared return types and arithmetic helpers for the templated fork-join port.
Dense matrix and non-owning view.
FJDagMakespanResult< T > fj_dag_makespan(const Matrix< T > &pred, const Matrix< T > &rate)
Makespan of a task system with precedence constraints.
Number-type abstraction for the templated API port.
[C, I, Cend, E] of fj_dag_makespan.