GCC Code Coverage Report


Directory: ./
File: include/pinocchio/algorithm/admm-solver.hxx
Date: 2025-02-12 21:03:38
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