GCC Code Coverage Report


Directory: ./
File: include/pinocchio/algorithm/admm-solver.hxx
Date: 2024-08-27 18:20:05
Exec Total Coverage
Lines: 0 121 0.0%
Branches: 0 0 -%

Line Branch Exec Source
1 //
2 // Copyright (c) 2022-2024 INRIA
3 //
4
5 #ifndef __pinocchio_algorithm_admm_solver_hxx__
6 #define __pinocchio_algorithm_admm_solver_hxx__
7
8 #include <limits>
9 #include <iomanip>
10 #include <iostream>
11
12 #include "pinocchio/algorithm/contact-solver-utils.hpp"
13 #include "pinocchio/algorithm/constraints/coulomb-friction-cone.hpp"
14
15 namespace pinocchio
16 {
17
18 template<typename _Scalar>
19 template<
20 typename DelassusDerived,
21 typename VectorLike,
22 typename ConstraintAllocator,
23 typename VectorLikeR>
24 bool ADMMContactSolverTpl<_Scalar>::solve(
25 DelassusOperatorBase<DelassusDerived> & _delassus,
26 const Eigen::MatrixBase<VectorLike> & g,
27 const std::vector<CoulombFrictionConeTpl<Scalar>, ConstraintAllocator> & cones,
28 const Eigen::MatrixBase<VectorLikeR> & R,
29 const boost::optional<ConstRefVectorXs> primal_guess,
30 const boost::optional<ConstRefVectorXs> dual_guess,
31 bool compute_largest_eigen_values,
32 bool stat_record)
33
34 {
35 using namespace internal;
36
37 DelassusDerived & delassus = _delassus.derived();
38
39 const Scalar mu_R = R.minCoeff();
40 PINOCCHIO_CHECK_INPUT_ARGUMENT(tau <= Scalar(1) && tau > Scalar(0), "tau should lie in ]0,1].");
41 PINOCCHIO_CHECK_INPUT_ARGUMENT(mu_prox >= 0, "mu_prox should be positive.");
42 PINOCCHIO_CHECK_INPUT_ARGUMENT(mu_R >= Scalar(0), "R should be a positive vector.");
43 PINOCCHIO_CHECK_ARGUMENT_SIZE(R.size(), problem_size);
44 // PINOCCHIO_CHECK_INPUT_ARGUMENT(math::max(R.maxCoeff(),mu_prox) >= 0,"mu_prox and mu_R
45 // cannot be both equal to zero.");
46
47 if (compute_largest_eigen_values)
48 {
49 // const Scalar L = delassus.computeLargestEigenValue(20); // Largest eigen_value
50 // estimate.
51 power_iteration_algo.run(delassus);
52 }
53 const Scalar L = power_iteration_algo.largest_eigen_value;
54 // const Scalar L = delassus.computeLargestEigenValue(20);
55 const Scalar m = mu_prox + mu_R;
56 const Scalar cond = L / m;
57 const Scalar rho_increment = std::pow(cond, rho_power_factor);
58
59 Scalar complementarity,
60 proximal_metric, // proximal metric between two successive iterates.
61 primal_feasibility, dual_feasibility_ncp, dual_feasibility;
62
63 // std::cout << std::setprecision(12);
64
65 Scalar rho;
66 rho = computeRho(L, m, rho_power);
67 // if(!is_initialized)
68 // {
69 // rho = computeRho(L,m,rho_power);
70 // }
71 // else
72 // {
73 // rho = this->rho;
74 // }
75 // rho = computeRho(L,m,rho_power);
76
77 // std::cout << "L: " << L << std::endl;
78 // std::cout << "m: " << m << std::endl;
79 // std::cout << "prox_value: " << prox_value << std::endl;
80
81 PINOCCHIO_EIGEN_MALLOC_NOT_ALLOWED();
82
83 // Update the cholesky decomposition
84 Scalar prox_value = mu_prox + tau * rho;
85 rhs = R + VectorXs::Constant(this->problem_size, prox_value);
86 delassus.updateDamping(rhs);
87 cholesky_update_count = 1;
88
89 // Initial update of the variables
90 // Init x
91 if (primal_guess)
92 {
93 x_ = primal_guess.get();
94 PINOCCHIO_CHECK_ARGUMENT_SIZE(x_.size(), problem_size);
95 }
96 else if (!is_initialized)
97 {
98 x_.setZero();
99 }
100 else
101 {
102 x_ = y_; // takes the current value stored in the solver
103 }
104
105 // Init y
106 computeConeProjection(cones, x_, y_);
107
108 // Init z
109 if (dual_guess)
110 {
111 z_ = dual_guess.get();
112 PINOCCHIO_CHECK_ARGUMENT_SIZE(z_.size(), problem_size);
113 }
114 else if (!is_initialized)
115 {
116 delassus.applyOnTheRight(y_, z_); // z = G * y
117 z_.noalias() += -prox_value * y_ + g;
118 computeComplementarityShift(cones, z_, s_);
119 z_ += s_; // Add De Saxé shift
120 computeDualConeProjection(cones, z_, z_);
121 }
122 else
123 {
124 // Keep z from the previous iteration
125 }
126
127 // std::cout << "x_: " << x_.transpose() << std::endl;
128 // std::cout << "y_: " << y_.transpose() << std::endl;
129 // std::cout << "z_: " << z_.transpose() << std::endl;
130
131 if (stat_record)
132 {
133 stats.reset();
134
135 // Compute initial problem primal and dual feasibility
136 primal_feasibility_vector = x_ - y_;
137 primal_feasibility = primal_feasibility_vector.template lpNorm<Eigen::Infinity>();
138 }
139
140 is_initialized = true;
141
142 // End of Initialization phase
143
144 bool abs_prec_reached = false, rel_prec_reached = false;
145
146 Scalar y_previous_norm_inf = y_.template lpNorm<Eigen::Infinity>();
147 int it = 1;
148 // Scalar res = 0;
149 #ifdef PINOCCHIO_WITH_HPP_FCL
150 timer.start();
151 #endif // PINOCCHIO_WITH_HPP_FCL
152 for (; it <= Base::max_it; ++it)
153 {
154 // std::cout << "---" << std::endl;
155 // std::cout << "it: " << it << std::endl;
156 // std::cout << "tau*rho: " << tau*rho << std::endl;
157
158 x_previous = x_;
159 y_previous = y_;
160 z_previous = z_;
161 complementarity = Scalar(0);
162
163 // s-update
164 computeComplementarityShift(cones, z_, s_);
165
166 // std::cout << "s_: " << s_.transpose() << std::endl;
167
168 // std::cout << "x_: " << x_.transpose() << std::endl;
169
170 // z-update
171 // const Scalar alpha = 1.;
172 // z_ -= (tau*rho) * (x_ - y_);
173 // std::cout << "intermediate z_: " << z_.transpose() << std::endl;
174
175 // x-update
176 rhs = -(g + s_ - (rho * tau) * y_ - mu_prox * x_ - z_);
177 const VectorXs rhs_copy = rhs;
178 // x_ = rhs;
179 delassus.solveInPlace(rhs);
180 // VectorXs tmp = delassus * rhs - rhs_copy;
181 // res = math::max(res,tmp.template lpNorm<Eigen::Infinity>());
182 // std::cout << "residual = " << (delassus * rhs - x_).template lpNorm<Eigen::Infinity>()
183 // << std::endl;
184 x_ = rhs;
185
186 // y-update
187 // rhs *= alpha;
188 // rhs += (1-alpha)*y_previous;
189 rhs = x_;
190 rhs -= z_ / (tau * rho);
191 computeConeProjection(cones, rhs, y_);
192 // std::cout << "y_: " << y_.transpose() << std::endl;
193
194 // z-update
195 z_ -= (tau * rho) * (x_ - y_);
196 // const Scalar gamma = Scalar(it) / Scalar(it + 300);
197
198 // z_ += gamma * (z_ - z_previous).eval();
199 // x_ += gamma * (x_ - x_previous).eval();
200 // computeConeProjection(cones, y_, y_);
201
202 // z_ -= (tau*rho) * (x_ * alpha + (1-alpha)*y_previous - y_);
203 // std::cout << "z_: " << z_.transpose() << std::endl;
204 // computeDualConeProjection(cones, z_, z_);
205
206 // check termination criteria
207 primal_feasibility_vector = x_ - y_;
208 // delassus.applyOnTheRight(x_,dual_feasibility_vector);
209 // dual_feasibility_vector.noalias() += g + s_ - prox_value * x_ - z_;
210
211 {
212 VectorXs & dy = rhs;
213 dy = y_ - y_previous;
214 proximal_metric = dy.template lpNorm<Eigen::Infinity>();
215 dual_feasibility_vector.noalias() = (tau * rho) * dy;
216 }
217
218 {
219 VectorXs & dx = rhs;
220 dx = x_ - x_previous;
221 dual_feasibility_vector.noalias() += mu_prox * dx;
222 }
223
224 // delassus.applyOnTheRight(x_,dual_feasibility_vector);
225 // dual_feasibility_vector.noalias() += g;
226 // computeComplementarityShift(cones, z_, s_);
227 // dual_feasibility_vector.noalias() += s_ - prox_value * x_ - z_;
228
229 primal_feasibility = primal_feasibility_vector.template lpNorm<Eigen::Infinity>();
230 dual_feasibility = dual_feasibility_vector.template lpNorm<Eigen::Infinity>();
231 complementarity = computeConicComplementarity(cones, z_, y_);
232 // complementarity = z_.dot(y_)/cones.size();
233
234 if (stat_record)
235 {
236 VectorXs tmp(rhs);
237 delassus.applyOnTheRight(y_, rhs);
238 rhs.noalias() += g - prox_value * y_;
239 computeComplementarityShift(cones, rhs, tmp);
240 rhs.noalias() += tmp;
241
242 internal::computeDualConeProjection(cones, rhs, tmp);
243 tmp -= rhs;
244
245 dual_feasibility_ncp = tmp.template lpNorm<Eigen::Infinity>();
246
247 stats.primal_feasibility.push_back(primal_feasibility);
248 stats.dual_feasibility.push_back(dual_feasibility);
249 stats.dual_feasibility_ncp.push_back(dual_feasibility_ncp);
250 stats.complementarity.push_back(complementarity);
251 stats.rho.push_back(rho);
252 }
253
254 // std::cout << "primal_feasibility: " << primal_feasibility << std::endl;
255 // std::cout << "dual_feasibility: " << dual_feasibility << std::endl;
256 // std::cout << "complementarity: " << complementarity << std::endl;
257
258 // Checking stopping residual
259 if (
260 check_expression_if_real<Scalar, false>(complementarity <= this->absolute_precision)
261 && check_expression_if_real<Scalar, false>(dual_feasibility <= this->absolute_precision)
262 && check_expression_if_real<Scalar, false>(primal_feasibility <= this->absolute_precision))
263 abs_prec_reached = true;
264 else
265 abs_prec_reached = false;
266
267 const Scalar y_norm_inf = y_.template lpNorm<Eigen::Infinity>();
268 if (check_expression_if_real<Scalar, false>(
269 proximal_metric
270 <= this->relative_precision * math::max(y_norm_inf, y_previous_norm_inf)))
271 rel_prec_reached = true;
272 else
273 rel_prec_reached = false;
274
275 // if(abs_prec_reached || rel_prec_reached)
276 if (abs_prec_reached)
277 break;
278
279 // Account for potential update of rho
280 bool update_delassus_factorization = false;
281 if (primal_feasibility > ratio_primal_dual * dual_feasibility)
282 {
283 rho *= rho_increment;
284 // rho *= math::pow(cond,rho_power_factor);
285 // rho_power += rho_power_factor;
286 update_delassus_factorization = true;
287 }
288 else if (dual_feasibility > ratio_primal_dual * primal_feasibility)
289 {
290 rho /= rho_increment;
291 // rho *= math::pow(cond,-rho_power_factor);
292 // rho_power -= rho_power_factor;
293 update_delassus_factorization = true;
294 }
295
296 if (update_delassus_factorization)
297 {
298 prox_value = mu_prox + tau * rho;
299 rhs = R + VectorXs::Constant(this->problem_size, prox_value);
300 delassus.updateDamping(rhs);
301 cholesky_update_count++;
302 }
303
304 y_previous_norm_inf = y_norm_inf;
305 // std::cout << "rho_power: " << rho_power << std::endl;
306 // std::cout << "rho: " << rho << std::endl;
307 // std::cout << "---" << std::endl;
308 }
309
310 PINOCCHIO_EIGEN_MALLOC_ALLOWED();
311
312 this->absolute_residual =
313 math::max(primal_feasibility, math::max(complementarity, dual_feasibility));
314 this->relative_residual = proximal_metric;
315 this->it = it;
316 // std::cout << "max linalg res: " << res << std::endl;
317 // y_sol.const_cast_derived() = y_;
318
319 // Save values
320 this->rho_power = computeRhoPower(L, m, rho);
321 this->rho = rho;
322
323 if (stat_record)
324 {
325 stats.it = it;
326 stats.cholesky_update_count = cholesky_update_count;
327 }
328
329 #ifdef PINOCCHIO_WITH_HPP_FCL
330 timer.stop();
331 #endif // PINOCCHIO_WITH_HPP_FCL
332
333 // if(abs_prec_reached || rel_prec_reached)
334 if (abs_prec_reached)
335 return true;
336
337 return false;
338 }
339 } // namespace pinocchio
340
341 #endif // ifndef __pinocchio_algorithm_admm_solver_hxx__
342