proxsuite 0.6.7
The Advanced Proximal Optimization Toolbox
Loading...
Searching...
No Matches
ruiz.hpp
Go to the documentation of this file.
1//
2// Copyright (c) 2022 INRIA
3//
6#ifndef PROXSUITE_PROXQP_SPARSE_PRECOND_RUIZ_HPP
7#define PROXSUITE_PROXQP_SPARSE_PRECOND_RUIZ_HPP
8
10
11namespace proxsuite {
12namespace proxqp {
13namespace sparse {
14
15namespace preconditioner {
16enum struct Symmetry
17{
18 LOWER,
19 UPPER,
20};
21
22namespace detail {
23template<typename T, typename I>
24void
26{
27 using namespace proxsuite::linalg::sparse::util;
28
29 I const* mi = m.row_indices();
30 T const* mx = m.values();
31
32 for (usize j = 0; j < usize(m.ncols()); ++j) {
33 auto col_start = m.col_start(j);
34 auto col_end = m.col_end(j);
35
36 for (usize p = col_start; p < col_end; ++p) {
37 usize i = zero_extend(mi[p]);
38 T mij = fabs(mx[p]);
39 row_norm[i] = std::max(row_norm[i], mij);
40 }
41 }
42}
43
44template<typename T, typename I>
45void
47{
48 using namespace proxsuite::linalg::sparse::util;
49
50 I const* hi = h.row_indices();
51 T const* hx = h.values();
52
53 for (usize j = 0; j < usize(h.ncols()); ++j) {
54 auto col_start = h.col_start(j);
55 auto col_end = h.col_end(j);
56
57 T norm_j = 0;
58
59 for (usize p = col_start; p < col_end; ++p) {
60 usize i = zero_extend(hi[p]);
61 if (i > j) {
62 break;
63 }
64
65 T hij = fabs(hx[p]);
66 norm_j = std::max(norm_j, hij);
67 col_norm[i] = std::max(col_norm[i], hij);
68 }
69
70 col_norm[j] = norm_j;
71 }
72}
73
74template<typename T, typename I>
75void
77{
78 using namespace proxsuite::linalg::sparse::util;
79
80 I const* hi = h.row_indices();
81 T const* hx = h.values();
82
83 for (usize j = 0; j < usize(h.ncols()); ++j) {
84 auto col_start = h.col_start(j);
85 auto col_end = h.col_end(j);
86
87 T norm_j = 0;
88
89 if (col_end > col_start) {
90 usize p = col_end;
91 while (true) {
92 --p;
93 usize i = zero_extend(hi[p]);
94 if (i < j) {
95 break;
96 }
97
98 T hij = fabs(hx[p]);
99 norm_j = std::max(norm_j, hij);
100 col_norm[i] = std::max(col_norm[i], hij);
101
102 if (p <= col_start) {
103 break;
104 }
105 }
106 }
107 col_norm[j] = std::max(col_norm[j], norm_j);
108 }
109}
110
111template<typename T, typename I>
112auto
116 T epsilon,
117 isize max_iter,
119 Symmetry sym,
121{
122
123 T c = 1;
124 auto S = delta_.to_eigen();
125
126 isize n = qp.H.nrows();
127 isize n_eq = qp.AT.ncols();
128 isize n_in = qp.CT.ncols();
129
130 T gamma = 1;
131 i64 iter = 1;
132
133 LDLT_TEMP_VEC(T, delta, n + n_eq + n_in, stack);
134
135 I* Hi = qp.H.row_indices_mut();
136 T* Hx = qp.H.values_mut();
137
138 I* ATi = qp.AT.row_indices_mut();
139 T* ATx = qp.AT.values_mut();
140
141 I* CTi = qp.CT.row_indices_mut();
142 T* CTx = qp.CT.values_mut();
143
144 T const machine_eps = std::numeric_limits<T>::epsilon();
145
146 while (infty_norm((1 - delta.array()).matrix()) > epsilon) {
147 if (iter == max_iter) {
148 break;
149 } else {
150 ++iter;
151 }
152
153 // norm_infty of each column of A (resp. C), i.e.,
154 // each row of AT (resp. CT)
155 {
156 auto _a_infty_norm = stack.make_new(proxsuite::linalg::veg::Tag<T>{}, n);
157 auto _c_infty_norm = stack.make_new(proxsuite::linalg::veg::Tag<T>{}, n);
158 auto _h_infty_norm = stack.make_new(proxsuite::linalg::veg::Tag<T>{}, n);
159 T* a_infty_norm = _a_infty_norm.ptr_mut();
160 T* c_infty_norm = _c_infty_norm.ptr_mut();
161 T* h_infty_norm = _h_infty_norm.ptr_mut();
162
165 switch (sym) {
166 case Symmetry::LOWER: {
168 break;
169 }
170 case Symmetry::UPPER: {
172 break;
173 }
174 }
175
176 for (isize j = 0; j < n; ++j) {
177 delta(j) = T(1) / (machine_eps + sqrt(std::max({
181 })));
182 }
183 }
184 using namespace proxsuite::linalg::sparse::util;
186 delta.tail(n_eq + n_in).setOnes();
187 } else {
188 for (usize j = 0; j < usize(n_eq); ++j) {
189 T a_row_norm = 0;
190 qp.AT.to_eigen();
191 usize col_start = qp.AT.col_start(j);
192 usize col_end = qp.AT.col_end(j);
193
194 for (usize p = col_start; p < col_end; ++p) {
195 T aji = fabs(ATx[p]);
196 a_row_norm = std::max(a_row_norm, aji);
197 }
198 delta(n + isize(j)) = T(1) / (machine_eps + sqrt(a_row_norm));
199 }
200
201 for (usize j = 0; j < usize(n_in); ++j) {
202 T c_row_norm = 0;
203 usize col_start = qp.CT.col_start(j);
204 usize col_end = qp.CT.col_end(j);
205
206 for (usize p = col_start; p < col_end; ++p) {
207 T cji = fabs(CTx[p]);
208 c_row_norm = std::max(c_row_norm, cji);
209 }
210 delta(n + n_eq + isize(j)) = T(1) / (machine_eps + sqrt(c_row_norm));
211 }
212 }
213
214 // removed as non deterministic when using avx
215 // https://gitlab.com/libeigen/eigen/-/issues/1728
216 // if (preconditioning_for_infeasible_problems) {
217 // T mean = delta.segment(n, n_eq_in).mean();
218 // delta.segment(n,n_eq_in).setConstant(mean);
219 // }
220
221 // normalize A
222 for (usize j = 0; j < usize(n_eq); ++j) {
223 usize col_start = qp.AT.col_start(j);
224 usize col_end = qp.AT.col_end(j);
225
226 T delta_j = delta(n + isize(j));
227
228 for (usize p = col_start; p < col_end; ++p) {
229 usize i = zero_extend(ATi[p]);
230 T& aji = ATx[p];
231 T delta_i = delta(isize(i));
232 aji = delta_i * (aji * delta_j);
233 }
234 }
235
236 // normalize C
237 for (usize j = 0; j < usize(n_in); ++j) {
238 usize col_start = qp.CT.col_start(j);
239 usize col_end = qp.CT.col_end(j);
240
241 T delta_j = delta(n + n_eq + isize(j));
242
243 for (usize p = col_start; p < col_end; ++p) {
244 usize i = zero_extend(CTi[p]);
245 T& cji = CTx[p];
246 T delta_i = delta(isize(i));
247 cji = delta_i * (cji * delta_j);
248 }
249 }
250
251 // normalize H
252 switch (sym) {
253 case Symmetry::LOWER: {
254 for (usize j = 0; j < usize(n); ++j) {
255 usize col_start = qp.H.col_start(j);
256 usize col_end = qp.H.col_end(j);
257 T delta_j = delta(isize(j));
258
259 if (col_end > col_start) {
260 usize p = col_end;
261 while (true) {
262 --p;
263 usize i = zero_extend(Hi[p]);
264 if (i < j) {
265 break;
266 }
267 Hx[p] = delta_j * Hx[p] * delta(isize(i));
268
269 if (p <= col_start) {
270 break;
271 }
272 }
273 }
274 }
275 break;
276 }
277 case Symmetry::UPPER: {
278 for (usize j = 0; j < usize(n); ++j) {
279 usize col_start = qp.H.col_start(j);
280 usize col_end = qp.H.col_end(j);
281 T delta_j = delta(isize(j));
282
283 for (usize p = col_start; p < col_end; ++p) {
284 usize i = zero_extend(Hi[p]);
285 if (i > j) {
286 break;
287 }
288 Hx[p] = delta_j * Hx[p] * delta(isize(i));
289 }
290 }
291 break;
292 }
293 }
294
295 // normalize vectors
296 qp.g.to_eigen().array() *= delta.head(n).array();
297 qp.b.to_eigen().array() *= delta.segment(n, n_eq).array();
298 qp.l.to_eigen().array() *= delta.tail(n_in).array();
299 qp.u.to_eigen().array() *= delta.tail(n_in).array();
300
301 // additional normalization
302 auto _h_infty_norm = stack.make_new(proxsuite::linalg::veg::Tag<T>{}, n);
303 T* h_infty_norm = _h_infty_norm.ptr_mut();
304
305 switch (sym) {
306 case Symmetry::LOWER: {
308 break;
309 }
310 case Symmetry::UPPER: {
312 break;
313 }
314 }
315
316 T avg = 0;
317 for (isize i = 0; i < n; ++i) {
318 avg += h_infty_norm[i];
319 }
320 avg /= T(n);
321
322 gamma = 1 / std::max(avg, T(1));
323
324 qp.g.to_eigen() *= gamma;
325 qp.H.to_eigen() *= gamma;
326
327 S.array() *= delta.array();
328 c *= gamma;
329 }
330 return c;
331}
332} // namespace detail
333
334template<typename T, typename I>
336{
338 isize n;
339 T c;
343
344 std::ostream* logger_ptr = nullptr;
345
347 isize n_eq_in,
348 T epsilon_ = T(1e-3),
349 i64 max_iter_ = 10,
351 std::ostream* logger = nullptr)
352 : delta(Vec<T>::Ones(n_ + n_eq_in))
353 , n(n_)
354 , c(1)
357 , sym(sym_)
359 {
360 delta.setOnes();
361 }
362
364 isize n,
365 isize n_eq,
366 isize n_in)
368 {
369 return proxsuite::linalg::dense::temp_vec_req(tag, n + n_eq + n_in) &
371 }
372
376 const isize max_iter,
377 const T epsilon,
379 {
381 delta.setOnes();
383 { proxqp::from_eigen, delta },
384 qp,
385 epsilon,
386 max_iter,
388 sym,
389 stack);
390 } else {
391 using proxsuite::linalg::sparse::util::zero_extend;
392 isize n = qp.H.nrows();
393 isize n_eq = qp.AT.ncols();
394 isize n_in = qp.CT.ncols();
395
396 I* Hi = qp.H.row_indices_mut();
397 T* Hx = qp.H.values_mut();
398
399 I* ATi = qp.AT.row_indices_mut();
400 T* ATx = qp.AT.values_mut();
401
402 I* CTi = qp.CT.row_indices_mut();
403 T* CTx = qp.CT.values_mut();
404
405 // normalize A
406 for (usize j = 0; j < usize(n_eq); ++j) {
407 usize col_start = qp.AT.col_start(j);
408 usize col_end = qp.AT.col_end(j);
409
410 T delta_j = delta(n + isize(j));
411
412 for (usize p = col_start; p < col_end; ++p) {
413 usize i = zero_extend(ATi[p]);
414 T& aji = ATx[p];
415 T delta_i = delta(isize(i));
416 aji = delta_i * (aji * delta_j);
417 }
418 }
419
420 // normalize C
421 for (usize j = 0; j < usize(n_in); ++j) {
422 usize col_start = qp.CT.col_start(j);
423 usize col_end = qp.CT.col_end(j);
424
425 T delta_j = delta(n + n_eq + isize(j));
426
427 for (usize p = col_start; p < col_end; ++p) {
428 usize i = zero_extend(CTi[p]);
429 T& cji = CTx[p];
430 T delta_i = delta(isize(i));
431 cji = delta_i * (cji * delta_j);
432 }
433 }
434
435 // normalize H
436 switch (sym) {
437 case Symmetry::LOWER: {
438 for (usize j = 0; j < usize(n); ++j) {
439 usize col_start = qp.H.col_start(j);
440 usize col_end = qp.H.col_end(j);
441 T delta_j = delta(isize(j));
442
443 if (col_end > col_start) {
444 usize p = col_end;
445 while (true) {
446 --p;
447 usize i = zero_extend(Hi[p]);
448 if (i < j) {
449 break;
450 }
451 Hx[p] = delta_j * Hx[p] * delta(isize(i));
452
453 if (p <= col_start) {
454 break;
455 }
456 }
457 }
458 }
459 break;
460 }
461 case Symmetry::UPPER: {
462 for (usize j = 0; j < usize(n); ++j) {
463 usize col_start = qp.H.col_start(j);
464 usize col_end = qp.H.col_end(j);
465 T delta_j = delta(isize(j));
466
467 for (usize p = col_start; p < col_end; ++p) {
468 usize i = zero_extend(Hi[p]);
469 if (i > j) {
470 break;
471 }
472 Hx[p] = delta_j * Hx[p] * delta(isize(i));
473 }
474 }
475 break;
476 }
477 }
478
479 // normalize vectors
480 qp.g.to_eigen().array() *= delta.head(n).array();
481 qp.b.to_eigen().array() *= delta.segment(n, n_eq).array();
482 qp.l.to_eigen().array() *= delta.tail(n_in).array();
483 qp.u.to_eigen().array() *= delta.tail(n_in).array();
484
485 qp.g.to_eigen() *= c;
486 qp.H.to_eigen() *= c;
487 }
488 }
489
490 // modifies variables in place
492 {
493 primal.to_eigen().array() /= delta.array().head(n);
494 }
496 {
497 dual.to_eigen().array() = dual.as_const().to_eigen().array() /
498 delta.tail(delta.size() - n).array() * c;
499 }
500
502 {
503 dual.to_eigen().array() =
504 dual.as_const().to_eigen().array() /
505 delta.middleRows(n, dual.to_eigen().size()).array() * c;
506 }
508 {
509 dual.to_eigen().array() = dual.as_const().to_eigen().array() /
510 delta.tail(dual.to_eigen().size()).array() * c;
511 }
512
514 {
515 primal.to_eigen().array() *= delta.array().head(n);
516 }
518 {
519 dual.to_eigen().array() = dual.as_const().to_eigen().array() *
520 delta.tail(delta.size() - n).array() / c;
521 }
522
524 {
525 dual.to_eigen().array() =
526 dual.as_const().to_eigen().array() *
527 delta.middleRows(n, dual.to_eigen().size()).array() / c;
528 }
529
531 {
532 dual.to_eigen().array() = dual.as_const().to_eigen().array() *
533 delta.tail(dual.to_eigen().size()).array() / c;
534 }
535 // modifies residuals in place
537 {
538 primal.to_eigen().array() *= delta.tail(delta.size() - n).array();
539 }
540
542 {
543 primal_eq.to_eigen().array() *=
544 delta.middleRows(n, primal_eq.to_eigen().size()).array();
545 }
547 {
548 primal_in.to_eigen().array() *=
549 delta.tail(primal_in.to_eigen().size()).array();
550 }
552 {
553 dual.to_eigen().array() *= delta.head(n).array() * c;
554 }
556 {
557 primal.to_eigen().array() /= delta.tail(delta.size() - n).array();
558 }
560 {
561 primal_eq.to_eigen().array() /=
562 delta.middleRows(n, primal_eq.to_eigen().size()).array();
563 }
565 {
566 primal_in.to_eigen().array() /=
567 delta.tail(primal_in.to_eigen().size()).array();
568 }
570 {
571 dual.to_eigen().array() /= delta.head(n).array() * c;
572 }
573};
574
575} // namespace preconditioner
576
577} // namespace sparse
578} // namespace proxqp
579} // namespace proxsuite
580
581#endif /* end of include guard PROXSUITE_PROXQP_SPARSE_PRECOND_RUIZ_HPP */
#define LDLT_TEMP_VEC(Type, Name, Rows, Stack)
Definition core.hpp:74
auto temp_vec_req(proxsuite::linalg::veg::Tag< T >, isize rows) noexcept -> proxsuite::linalg::veg::dynstack::StackReq
Definition core.hpp:862
void colwise_infty_norm_symhi(T *col_norm, proxsuite::linalg::sparse::MatRef< T, I > h)
Definition ruiz.hpp:46
void rowwise_infty_norm(T *row_norm, proxsuite::linalg::sparse::MatRef< T, I > m)
Definition ruiz.hpp:25
auto ruiz_scale_qp_in_place(VectorViewMut< T > delta_, QpViewMut< T, I > qp, T epsilon, isize max_iter, bool preconditioning_for_infeasible_problems, Symmetry sym, proxsuite::linalg::veg::dynstack::DynStackMut stack) -> T
Definition ruiz.hpp:113
void colwise_infty_norm_symlo(T *col_norm, proxsuite::linalg::sparse::MatRef< T, I > h)
Definition ruiz.hpp:76
Eigen::Matrix< T, DYN, 1 > Vec
Definition fwd.hpp:38
decltype(sizeof(0)) usize
Definition views.hpp:24
static constexpr auto with_len(proxsuite::linalg::veg::Tag< T >, isize len) noexcept -> StackReq
void scale_dual_in_place_in(VectorViewMut< T > dual) const
Definition ruiz.hpp:507
void unscale_primal_residual_in_place_in(VectorViewMut< T > primal_in) const
Definition ruiz.hpp:564
void unscale_dual_residual_in_place(VectorViewMut< T > dual) const
Definition ruiz.hpp:569
void scale_dual_residual_in_place(VectorViewMut< T > dual) const
Definition ruiz.hpp:551
void unscale_dual_in_place_in(VectorViewMut< T > dual) const
Definition ruiz.hpp:530
void unscale_primal_residual_in_place(VectorViewMut< T > primal) const
Definition ruiz.hpp:555
void scale_primal_residual_in_place_eq(VectorViewMut< T > primal_eq) const
Definition ruiz.hpp:541
void scale_primal_in_place(VectorViewMut< T > primal) const
Definition ruiz.hpp:491
void scale_dual_in_place_eq(VectorViewMut< T > dual) const
Definition ruiz.hpp:501
void unscale_primal_in_place(VectorViewMut< T > primal) const
Definition ruiz.hpp:513
RuizEquilibration(isize n_, isize n_eq_in, T epsilon_=T(1e-3), i64 max_iter_=10, Symmetry sym_=Symmetry::UPPER, std::ostream *logger=nullptr)
Definition ruiz.hpp:346
void unscale_dual_in_place(VectorViewMut< T > dual) const
Definition ruiz.hpp:517
static auto scale_qp_in_place_req(proxsuite::linalg::veg::Tag< T > tag, isize n, isize n_eq, isize n_in) -> proxsuite::linalg::veg::dynstack::StackReq
Definition ruiz.hpp:363
void unscale_primal_residual_in_place_eq(VectorViewMut< T > primal_eq) const
Definition ruiz.hpp:559
void unscale_dual_in_place_eq(VectorViewMut< T > dual) const
Definition ruiz.hpp:523
void scale_primal_residual_in_place_in(VectorViewMut< T > primal_in) const
Definition ruiz.hpp:546
void scale_qp_in_place(QpViewMut< T, I > qp, bool execute_preconditioner, bool preconditioning_for_infeasible_problems, const isize max_iter, const T epsilon, proxsuite::linalg::veg::dynstack::DynStackMut stack)
Definition ruiz.hpp:373
void scale_primal_residual_in_place(VectorViewMut< T > primal) const
Definition ruiz.hpp:536