7 #ifndef JADE_QPAS_HPP__
8 #define JADE_QPAS_HPP__
10 #include "jade.matrix.hpp"
18 template <
typename TValue>
45 const std::vector<size_t> & fixed_active_set,
46 std::vector<size_t> & active_set,
49 assert(!fixed_active_set.empty() || !active_set.empty());
54 const auto inequality_constraint_count =
59 assert(fixed_active_set.size() <= K);
63 std::set<unsigned long> visited_sets;
65 const auto insert_key = [&visited_sets, &active_set]() ->
bool
68 for (
const auto i : active_set)
70 if (visited_sets.find(key) != visited_sets.end())
72 visited_sets.insert(key);
78 std::vector<size_t> merged_active_set;
79 merged_active_set.insert(
80 merged_active_set.end(),
83 merged_active_set.insert(
84 merged_active_set.end(),
85 fixed_active_set.begin(),
86 fixed_active_set.end());
89 merged_active_set.size(),
90 merged_active_set.empty() ? 0 : 1);
102 std::vector<size_t> violated_indices;
104 if (active_set.size() < K - fixed_active_set.size())
106 for (
size_t i = 0; i < inequality_constraint_count; i++)
108 if (merged_active_set.end() != std::find(
109 merged_active_set.begin(),
110 merged_active_set.end(),
114 const auto lhs = coefficients_mat
118 violated_indices.push_back(i);
122 if (violated_indices.empty())
124 delta_vec = try_delta_vec;
126 auto lagrangian_index = index_not_found;
127 for (
size_t i = 0; i < active_set.size(); i++)
129 const auto lms_i = lagrangian_vec[i];
132 if (lagrangian_index == index_not_found ||
133 lms_i > lagrangian_vec[lagrangian_index])
134 lagrangian_index = i;
137 if (lagrangian_index == index_not_found)
142 int(lagrangian_index));
146 const auto k_violated = _backtrack(
154 if (k_violated == index_not_found)
160 [k_violated](
const size_t index) ->
bool
162 return index == k_violated;
165 assert(k_violated != index_not_found);
167 active_set.push_back(k_violated);
174 static constexpr
auto index_not_found =
175 std::numeric_limits<size_t>::max();
177 static constexpr
auto epsilon =
181 static size_t _backtrack(
186 const std::vector<size_t> & violated_indices,
189 assert(violated_delta_vec.is_size(old_delta_vec));
190 assert(b_vec.get_length() == coefficients_mat.get_height());
193 violated_indices.begin(),
194 violated_indices.end(),
195 [&b_vec](
const size_t i) ->
bool
197 return i < b_vec.get_length();
200 auto min_i = index_not_found;
203 const auto diff_vec = violated_delta_vec - old_delta_vec;
205 for (
size_t i = 0; i < violated_indices.size(); i++)
207 const auto violated_index = violated_indices[i];
208 const auto b_scalar = b_vec[violated_index];
210 const auto coefficient_vec =
211 coefficients_mat.copy_row(violated_index);
213 const auto denominator =
214 (coefficient_vec * diff_vec).get_value(0, 0);
216 const auto numerator = b_scalar -
217 (coefficient_vec * old_delta_vec).get_value(0, 0);
219 if (std::fabs(denominator) < epsilon)
222 const auto t = numerator / denominator;
223 if (min_i == index_not_found || t < min_t)
230 if (min_i == index_not_found)
231 return index_not_found;
233 new_delta_vec = (min_t * diff_vec) + old_delta_vec;
234 assert(!new_delta_vec.contains_inf());
235 assert(!new_delta_vec.contains_nan());
236 return violated_indices[min_i];
240 static void _create_kkt_mat(
245 const std::vector<size_t> & active_set,
248 const auto K = hessian_mat.get_height();
249 const auto active_count = active_set.size();
251 assert(b_vec.get_length() == coefficients_mat.get_height());
252 assert(hessian_mat.is_square());
253 assert(kkt_mat.get_height() == K + active_count);
254 assert(kkt_mat.get_width() == K + active_count + 1);
255 assert(coefficients_mat.get_width() == K);
256 assert(derivative_vec.is_vector());
257 assert(derivative_vec.get_length() == K);
262 [&b_vec](
size_t i) ->
bool {
263 return i < b_vec.get_length();
269 [&coefficients_mat](
size_t i) ->
bool {
270 return i < coefficients_mat.get_height();
274 for (
size_t k1 = 0; k1 < K; k1++)
275 for (
size_t k2 = 0; k2 < K; k2++)
276 kkt_mat(k1, k2) = hessian_mat(k1, k2);
278 for (
size_t i = 0; i < active_count; i++)
279 for (
size_t k = 0; k < K; k++)
280 kkt_mat(i + K, k) = kkt_mat(k, i + K) =
281 coefficients_mat(active_set[i], k);
283 const auto right_column_index = kkt_mat.get_width() - 1;
285 for (
size_t k = 0; k < K; k++)
286 kkt_mat(k, right_column_index) = -derivative_vec[k];
288 for (
size_t i = 0; i < active_count; i++)
289 kkt_mat(K + i, right_column_index) = b_vec[active_set[i]];
298 const std::vector<size_t> & active_set,
302 const auto active_count = active_set.size();
303 const auto K = derivative_vec.get_length();
305 assert(delta_vec.is_vector());
306 assert(delta_vec.get_length() == K);
307 assert(lagrangian_vec.is_empty() || lagrangian_vec.is_vector());
308 assert(lagrangian_vec.get_length() == active_count);
310 matrix_type kkt_mat (K + active_count, K + active_count + 1);
320 { return std::isfinite(v); }));
325 { return std::isfinite(v); }));
327 const auto last_column = kkt_mat.get_width() - 1;
329 for (
size_t k = 0; k < K; k++)
330 delta_vec[k] = kkt_mat(k, last_column);
332 for (
size_t i = 0; i < active_count; i++)
333 lagrangian_vec[i] = kkt_mat(K + i, last_column);
338 #endif // JADE_QPAS_HPP__