5#ifndef LINE_API_FJ_TSM_CAPACITY_H
6#define LINE_API_FJ_TSM_CAPACITY_H
55 std::vector<std::vector<unsigned> >
states;
62inline void tsm_states(
const std::vector<unsigned>& r,
unsigned left, std::size_t k,
63 std::vector<unsigned>& stack,
64 std::vector<std::vector<unsigned> >& out) {
66 for (std::size_t i = 0; i < stack.size(); ++i)
67 if (stack[i] > 0) { out.push_back(stack);
return; }
70 const unsigned nmax = left / r[k];
71 for (
unsigned n = 0; n <= nmax; ++n) {
73 tsm_states(r, left - n * r[k], k + 1, stack, out);
91 const std::vector<unsigned>& r,
const std::vector<T>& x) {
92 const std::size_t K = f.size();
93 if (s < 1)
throw InputError(
"fj_tsm_capacity: s must be a positive integer");
94 if (r.size() != K || x.size() != K)
95 throw InputError(
"fj_tsm_capacity: f, r and x must have the same length");
98 for (std::size_t k = 0; k < K; ++k) {
99 if (f[k] < zero)
throw InputError(
"fj_tsm_capacity: the class frequencies must be non-negative");
100 if (r[k] < 1 || r[k] > s)
101 throw InputError(
"fj_tsm_capacity: the server requirements must lie in 1..s");
102 if (!(x[k] > zero))
throw InputError(
"fj_tsm_capacity: the mean service times must be positive");
107 throw InputError(
"fj_tsm_capacity: the class frequencies must sum to one");
111 for (std::size_t k = 0; k < K; ++k)
115 std::vector<unsigned> stack(K, 0);
116 detail::tsm_states(r, s, 0, stack, out.
states);
117 const std::size_t ns = out.
states.size();
118 if (ns == 0)
throw NumericError(
"fj_tsm_capacity: no feasible execution state");
124 for (std::size_t k = 0; k < K; ++k) {
125 if (!(f[k] > zero))
continue;
127 for (std::size_t j = 0; j < ns; ++j)
133 for (std::size_t j = 0; j < ns; ++j) lpm.
row_add(j, one);
138 throw NumericError(std::string(
"fj_tsm_capacity: the capacity linear program returned ") +
141 out.
prob.assign(sol.
x.begin(), sol.
x.begin() +
static_cast<long>(ns));
146 if (s == 2 && K == 2 && ((r[0] == 1 && r[1] == 2) || (r[0] == 2 && r[1] == 1))) {
147 const std::size_t a = (r[0] == 1) ? 0 : 1, b = 1 - a;
148 const T f1 = f[a], f2 = f[b], mu1 = one / x[a], mu2 = one / x[b];
150 out.
Lfcfs = two * mu1 * mu2 /
151 (f1 * f1 * mu2 + two * f2 * f2 * mu1 + two * f1 * f2 * (mu1 + mu2));
NumericError(const std::string &what)
Sparse LP in the natural form, with per-variable bounds.
void set_maximize(bool m)
true to maximize c'x (the default), false to minimize.
void emit(LpSense sense, const T &rhs)
Emit the accumulated row with the given relation and right-hand side.
void set_cost(std::size_t j, const T &v)
void row_clear()
Discard whatever the row accumulator holds.
void row_add(std::size_t j, const T &v)
row(j) += v, the accumulation the MATLAB reference performs.
The exception types the port throws.
Shared return types and arithmetic helpers for the templated fork-join port.
FJTsmCapacityResult< T > fj_tsm_capacity(unsigned s, const std::vector< T > &f, const std::vector< unsigned > &r, const std::vector< T > &x)
Saturation throughput of the team service model.
const char * lp_status_name(LpStatus s)
LpSolution< T > simplex_solve(const LpModel< T > &model, std::size_t max_iterations=0)
Solve the model.
Number-type abstraction for the templated API port.
Templated primal simplex with Bland's rule.
[Lmax, Llp, Lfcfs, states, prob] of fj_tsm_capacity.
std::vector< std::vector< unsigned > > states
std::vector< T > x
primal solution in the ORIGINAL variable space