81 const std::vector<T>& Z) {
83 "pfqn_propfair requires transcendental arithmetic (logarithmic objective)");
85 const std::size_t M = L.
rows(), R = L.
cols();
86 if (N.size() != R)
throw InputError(
"pfqn_propfair: L and N disagree on the class count");
87 if (!Z.empty() && Z.size() != R)
throw InputError(
"pfqn_propfair: Z has the wrong length");
89 const std::vector<T> Zv = Z.empty() ? std::vector<T>(R, zero) : Z;
94 for (std::size_t m = 0; m < M; ++m) {
96 for (std::size_t r = 0; r < R; ++r) s += L(m, r);
97 if (s > rowmax) rowmax = s;
99 if (rowmax <= zero)
throw InputError(
"pfqn_propfair: every demand is zero");
102 const auto objective = [&](
const std::vector<T>& x) {
104 for (std::size_t r = 0; r < R; ++r) f += T(N[r] - x[r] * Zv[r]) * log(T(x[r] + eps));
107 const auto feasible = [&](
const std::vector<T>& x) {
108 for (std::size_t r = 0; r < R; ++r)
109 if (!(x[r] > zero))
return false;
110 for (std::size_t m = 0; m < M; ++m) {
112 for (std::size_t r = 0; r < R; ++r) s += L(m, r) * x[r];
113 if (!(s < one))
return false;
120 for (
int outer = 0; outer < 60; ++outer) {
122 for (
int inner = 0; inner < 100; ++inner) {
123 std::vector<T> slack(M);
124 for (std::size_t m = 0; m < M; ++m) {
126 for (std::size_t r = 0; r < R; ++r) s += L(m, r) * X[r];
127 slack[m] = T(one - s);
129 std::vector<T> grad(R, zero);
131 for (std::size_t r = 0; r < R; ++r) {
132 const T d = T(X[r] + eps);
133 const T num = T(N[r] - X[r] * Zv[r]);
134 grad[r] = T(t * T(T(-Zv[r] * log(d)) + T(num / d)));
137 grad[r] += T(one / X[r]);
138 H(r, r) -= T(one / T(X[r] * X[r]));
140 for (std::size_t m = 0; m < M; ++m) {
141 for (std::size_t r = 0; r < R; ++r) {
142 grad[r] -= T(L(m, r) / slack[m]);
143 for (std::size_t s = 0; s < R; ++s)
144 H(r, s) -= T(L(m, r) * L(m, s) / T(slack[m] * slack[m]));
148 std::vector<T> rhs(R);
149 for (std::size_t r = 0; r < R; ++r) rhs[r] = T(-grad[r]);
157 for (std::size_t r = 0; r < R; ++r) dec -= grad[r] * dx[r];
161 std::vector<T> Xn(R);
163 const T f0 = T(t * objective(X));
164 for (
int b = 0; b < 80; ++b) {
165 for (std::size_t r = 0; r < R; ++r) Xn[r] = T(X[r] + step * dx[r]);
166 if (feasible(Xn) && T(t * objective(Xn)) >= f0) {
176 if (gap < gaptol)
break;
183 for (std::size_t r = 0; r < R; ++r) {
184 if (X[r] <= zero)
throw NumericError(
"pfqn_propfair: non-positive asymptotic throughput");
185 lG += T(N[r] - X[r] * Zv[r]) * log(T(one / X[r]));
186 lG -= detail::num_factln<T>(T(X[r] * Zv[r]));
PropfairResult< T > pfqn_propfair(const Matrix< T > &L, const std::vector< T > &N, const std::vector< T > &Z)
Proportionally fair allocation estimate of the normalizing constant (Schweitzer 1979; Walton,...
std::vector< T > solve(const Matrix< T > &A, const std::vector< T > &b)
Convenience: solve Ax = b, leaving A and b untouched.