GCC Code Coverage Report


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