Pipal  1.2.0
Penalty Interior-Point ALgorithm
Loading...
Searching...
No Matches
Direction.hxx
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
2 * Copyright (c) 2025, Davide Stocco and Enrico Bertolazzi. *
3 * *
4 * The Pipal project is distributed under the MIT License. *
5 * *
6 * Davide Stocco Enrico Bertolazzi *
7 * University of Trento University of Trento *
8 * e-mail: davide.stocco@unitn.it e-mail: enrico.bertolazzi@unitn.it *
9\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10
11#pragma once
12
13#ifndef INCLUDE_PIPAL_DIRECTION_HXX
14#define INCLUDE_PIPAL_DIRECTION_HXX
15
16namespace Pipal {
17
23 template<typename Real>
25 {
26 // Create alias for easier access
27 Input<Real> const & i{this->m_input};
28
29 // Reset all direction members
30 d.x.setZero(i.nV);
31 d.r1.setZero(i.nE);
32 d.r2.setZero(i.nE);
33 d.lE.setZero(i.nE);
34 d.s1.setZero(i.nI);
35 d.s2.setZero(i.nI);
36 d.lI.setZero(i.nI);
37 d.x_norm = d.l_norm = 0;
38 d.x_norm_ = std::numeric_limits<Real>::infinity();
39 d.lred0 = d.ltred0 = d.ltred = d.qtred = d.m = 0;
40 }
41
52 template<typename Real>
54 Direction<Real> const & d3, Real const a1, Real const a2, Real const a3)
55 {
56 // Create alias for easier access
57 Input<Real> & i{this->m_input};
59
60 // Evaluate linear combinations
61 d.x = a1*d1.x + a2*d2.x + a3*d3.x;
62 if (i.nE > 0) {
63 d.r1 = a1*d1.r1 + a2*d2.r1 + a3*d3.r1;
64 d.r2 = a1*d1.r2 + a2*d2.r2 + a3*d3.r2;
65 d.lE = a1*d1.lE + a2*d2.lE + a3*d3.lE;
66 }
67 if (i.nI > 0) {
68 d.s1 = a1*d1.s1 + a2*d2.s1 + a3*d3.s1;
69 d.s2 = a1*d1.s2 + a2*d2.s2 + a3*d3.s2;
70 d.lI = a1*d1.lI + a2*d2.lI + a3*d3.lI;
71 }
72
73 // Evaluate primal direction norm
74 d.x_norm = d.x.norm();
75
76 // Evaluate dual direction norm
77 d.l_norm = std::sqrt(d.lE.matrix().squaredNorm() + d.lI.matrix().squaredNorm());
78 }
79
84 template<typename Real>
86 {
87 // Create alias for easier access
88 Input<Real> & i{this->m_input};
89 Iterate<Real> & z{this->m_iterate};
91
92 // Evaluate reduction in linear model of penalty-interior-point objective for zero penalty parameter
93 d.lred0 = 0;
94 if (i.nE > 0) {
95 d.lred0 -= ((1.0 - z.mu / z.r1) * d.r1).sum();
96 d.lred0 -= ((1.0 - z.mu / z.r2) * d.r2).sum();
97 }
98 if (i.nI > 0) {
99 d.lred0 -= (((-z.mu) / z.s1) * d.s1).sum();
100 d.lred0 -= ((1.0 - z.mu / z.s2) * d.s2).sum();
101 }
102
103 // Evaluate remaining quantities only for nonzero penalty parameter
104 if (z.rho > 0)
105 {
106 // Evaluate reduction in linear model of merit function for zero penalty parameter
107 d.ltred0 = 0;
108 if (i.nE > 0) {
109 Array<Real> sqrt_term((z.cE.square() + z.mu*z.mu).sqrt());
110 d.ltred0 -= 0.5*(((1.0 - z.mu/z.r1) * (-1.0 + z.cE/sqrt_term) + (1.0 - z.mu/z.r2) *
111 (1.0 + z.cE/sqrt_term)) * (z.JE * d.x).array()).sum();
112 }
113 if (i.nI > 0) {
114 Array<Real> sqrt_term((z.cI.square() + 4.0*z.mu*z.mu).sqrt());
115 d.ltred0 -= 0.5*((((-z.mu)/z.s1) * (-1.0 + z.cI/sqrt_term) + (1.0 - z.mu/z.s2) *
116 (1.0 + z.cI/sqrt_term)) * (z.JI * d.x).array()).sum();
117 }
118
119 // Evaluate reduction in linear model of merit function
120 d.ltred = -z.rho*z.g.transpose()*d.x + d.ltred0;
121
122 // Evaluate reduction in quadratic model of merit function
123 d.qtred = d.ltred - 0.5*d.x.transpose()*z.H*d.x;
124 if (i.nE > 0) {
125 Array<Real> Jd(z.JE*d.x);
126 Array<Real> Dinv((z.r1/(1.0+z.lE) + z.r2/(1.0-z.lE)).matrix());
127 d.qtred -= 0.5*Jd.matrix().transpose() * ((Jd/Dinv).matrix());
128 }
129 if (i.nI > 0) {
130 Array<Real> Jd(z.JI*d.x);
131 Array<Real> Dinv((z.s1/(0.0+z.lI) + z.s2/(1.0-z.lI)).matrix());
132 d.qtred -= 0.5*Jd.matrix().transpose() * ((Jd/Dinv).matrix());
133 }
134
135 // Initialize quality function vector
136 Array<Real> vec(i.nV+2*i.nE+2*i.nI);
137 vec.setZero();
138
139 // Set gradient of objective
140 vec.head(i.nV) = z.rho*z.g;
141
142 // Set gradient of Lagrangian for constraints
143 if (i.nE > 0) {vec.head(i.nV) += ((z.lE+d.lE).matrix().transpose()*z.JE).transpose().array();}
144 if (i.nI > 0) {vec.head(i.nV) += ((z.lI+d.lI).matrix().transpose()*z.JI).transpose().array();}
145
146 // Set complementarity for constraint slacks
147 if (i.nE > 0) {
148 vec.segment(i.nV, 2*i.nE) <<
149 (z.r1+d.r1)*(1.0 + (z.lE+d.lE)), (z.r2+d.r2)*(1.0 - (z.lE+d.lE));
150 }
151 if (i.nI > 0) {
152 vec.segment(i.nV+2*i.nE, 2*i.nI) <<
153 (z.s1+d.s1)*(z.lI+d.lI), (z.s2+d.s2)*(1.0 - (z.lI+d.lI));
154 }
155
156 // Evaluate quality function
157 d.m = vec.matrix().template lpNorm<Eigen::Infinity>();
158 }
159 }
160
165 template<typename Real>
167 {
168 // Create alias for easier access
169 Input<Real> const & i{this->m_input};
170 Iterate<Real> const & z{this->m_iterate};
171 Direction<Real> & d{this->m_direction};
172
173 // Evaluate direction
174 Vector<Real> dir(z.ldlt.solve(-z.b));
175
176 // Parse direction
177 d.x = dir.head(i.nV);
178 if (i.nE > 0) {
179 d.r1 = dir.segment(i.nV, i.nE);
180 d.r2 = dir.segment(i.nV+i.nE, i.nE);
181 d.lE = dir.segment(i.nV+i.nE+i.nE+i.nI+i.nI, i.nE);
182 }
183 if (i.nI > 0) {
184 d.s1 = dir.segment(i.nV+i.nE+i.nE, i.nI);
185 d.s2 = dir.segment(i.nV+i.nE+i.nE+i.nI, i.nI);
186 d.lI = dir.segment(i.nV+i.nE+i.nE+i.nI+i.nI+i.nE, i.nI);
187 }
188
189 // Evaluate primal direction norm
190 d.x_norm = d.x.norm();
191
192 // Evaluate dual direction norm
193 d.l_norm = std::sqrt(d.lE.matrix().squaredNorm() + d.lI.matrix().squaredNorm());
194 }
195
200 template <typename Real>
202 {
203 // Create alias for easier access
204 Parameter<Real> & p{this->m_parameter};
205 Iterate<Real> & z{this->m_iterate};
206 Direction<Real> & d{this->m_direction};
207
208 // Reset maximum exponent for interior-point parameter increases
209 this->resetMuMaxExp();
210
211 // Update penalty-interior-point parameters based on KKT errors
212 this->updateParameters();
213
214 // Evaluate Hessian and Newton matrices
215 if (!this->m_bfgs) {this->evalHessian();}
216 this->evalNewtonMatrix();
217
218 // Set last penalty parameter
219 this->setRhoLast(z.rho);
220
221 // Check for aggressive algorithm
222 if (p.algorithm == Algorithm::ADAPTIVE)
223 {
224 // Check KKT memory for potential mu increase limit
225 if (z.kkt(1) > z.kkt_.maxCoeff()) {this->setMuMaxExpZero();}
226
227 // Store current penalty and interior-point parameters
228 Real rho_curr{z.rho}, mu_curr{z.mu};
229
230 // Evaluate trial steps
231 Direction<Real> d1, d2, d3;
232 this->resetDirection(d1);
233 this->resetDirection(d2);
234 this->resetDirection(d3);
235 this->evalTrialSteps(d1, d2, d3);
236
237 // Set trial interior-point parameter values
239 Array<Real> Mu((mu_curr * exponents.unaryExpr(
240 [&p] (Real e) {return std::pow(p.mu_factor, e);})
241 ).min(p.mu_max).max(p.mu_min));
242
243 // Initialize feasibility direction data
244 Vector<Real> lred0_0_mu(p.mu_trials);
245 lred0_0_mu.setZero();
246
247 // Loop through interior-point parameter values
248 for (Integer j{0}; j < p.mu_trials; ++j)
249 {
250 // Set penalty and interior-point parameters
251 this->setRho(0.0);
252 this->setMu(Mu(j));
253
254 // Evaluate direction
255 this->evalLinearCombination(d1, d2, d3,
256 z.rho/rho_curr+z.mu/mu_curr-1.0, 1.0-z.mu/mu_curr, 1.0-z.rho/rho_curr);
257
258 // Cut length
259 d.x *= std::min(d.x_norm_/std::max(d.x_norm, 1.0), 1.0);
260
261 // Run fraction-to-boundary
262 this->fractionToBoundary();
263
264 // Cut length
265 this->evalTrialStepCut();
266
267 // Evaluate models
268 this->evalModels();
269
270 // Set feasibility direction data
271 lred0_0_mu(j) = d.lred0;
272 }
273
274 // Initialize updating data
275 Vector<Real> ltred0_rho_mu(p.mu_trials), qtred_rho_mu(p.mu_trials), m_rho_mu(p.mu_trials);
276 ltred0_rho_mu.setZero(); qtred_rho_mu.setZero(); m_rho_mu.setZero();
277
278 // Initialize check
279 bool check{false};
280
281 // Loop through penalty parameter values
282 for (Integer k{0}; k < p.rho_trials; ++k)
283 {
284 // Set penalty parameter
285 this->setRho(std::max(p.rho_min, std::pow(p.rho_factor, k)*rho_curr) );
286
287 // Set last penalty parameter
288 if (rho_curr > z.kkt(0)*z.kkt(0)) {this->setRhoLast(z.rho );}
289
290 // Loop through interior-point parameter values
291 for (Integer j{0}; j < p.mu_trials; ++j)
292 {
293 // Set interior-point parameter
294 this->setMu(Mu(j));
295
296 // Evaluate direction
298 d1, d2, d3,
299 z.rho/rho_curr+z.mu/mu_curr-1.0,
300 1.0-z.mu/mu_curr,
301 1.0-z.rho/rho_curr
302 );
303
304 // Run fraction-to-boundary
305 this->fractionToBoundary();
306
307 // Cut steps
308 this->evalTrialStepCut();
309
310 // Evaluate models
311 this->evalModels();
312
313 // Set updating data
314 ltred0_rho_mu(j) = d.ltred0;
315 qtred_rho_mu(j) = d.qtred;
316 m_rho_mu(j) = d.m;
317
318 // Check updating conditions for infeasible points
319 if (z.v > p.opt_err_tol && (ltred0_rho_mu(j) < p.update_con_1*lred0_0_mu(j) ||
320 qtred_rho_mu(j) < p.update_con_2*lred0_0_mu(j) || z.rho > z.kkt(0)*z.kkt(0))) {
321 m_rho_mu(j) = std::numeric_limits<Real>::infinity();
322 }
323
324 // Check updating conditions for feasible points
325 if (z.v <= p.opt_err_tol && qtred_rho_mu(j) < 0.0) {
326 m_rho_mu(j) = std::numeric_limits<Real>::infinity();
327 }
328 }
329
330 // Find minimum m for current rho
331 Real m_min{m_rho_mu.minCoeff()};
332
333 // Check for finite minimum
334 if (m_min < std::numeric_limits<Real>::infinity())
335 {
336 // Loop through mu values
337 for (Integer j{0}; j < p.mu_trials; ++j)
338 {
339 // Check condition
340 if (m_rho_mu(j) <= p.update_con_3*m_min) {this->setMu(Mu(j));}
341 }
342
343 // Set condition check
344 check = true;
345
346 // Break loop
347 break;
348 }
349 }
350
351 // Check conditions
352 if (check == false) {this->setRho(rho_curr); this->setMu(mu_curr);}
353
354 // Evaluate merit
355 this->evalMerit();
356 }
357
358 // Evaluate primal-dual right-hand side vector
359 this->evalNewtonRhs();
360
361 // Evaluate search direction
362 this->evalNewtonStep();
363
364 // Evaluate models
365 this->evalModels();
366
367 // Store last direction norm
368 d.x_norm_ = d.x_norm;
369 }
370
376 template<typename Real>
378 {
379 Input<Real> const & i{this->m_input};
380 Direction<Real> const & d{this->m_direction};
381 // Set direction components
382 v.x = d.x;
383 if (i.nE > 0) {v.r1 = d.r1; v.r2 = d.r2; v.lE = d.lE;}
384 if (i.nI > 0) {v.s1 = d.s1; v.s2 = d.s2; v.lI = d.lI;}
385 }
386
391 template<typename Real>
393 {
394 // Create alias for easier access
395 Input<Real> & i{this->m_input};
396 Direction<Real> & d{this->m_direction};
398
399 // Set direction components
400 d.x = a.p*d.x ;
401 if (i.nE > 0) {d.r1 = a.p*d.r1; d.r2 = a.p*d.r2; d.lE = a.d*d.lE;}
402 if (i.nI > 0) {d.s1 = a.p*d.s1; d.s2 = a.p*d.s2; d.lI = a.d*d.lI;}
403 }
404
412 template<typename Real>
414 {
415 // Create alias for easier access
416 Iterate<Real> const & z{this->m_iterate};
417
418 // Store current penalty and interior-point parameters
419 Real rho_curr{z.rho}, mu_curr{z.mu};
420
421 // Evaluate direction for current penalty and interior-point parameters
422 this->setRho(rho_curr);
423 this->setMu(mu_curr);
424 this->evalNewtonRhs();
425 this->evalNewtonStep();
426 this->evalTrialStep(d1);
427
428 // Evaluate direction for zero interior-point parameter
429 this->setRho(rho_curr);
430 this->setMu(0.0);
431 this->evalNewtonRhs();
432 this->evalNewtonStep();
433 this->evalTrialStep(d2);
434
435 // Evaluate direction for zero penalty parameter
436 this->setRho(0.0);
437 this->setMu(mu_curr);
438 this->evalNewtonRhs();
439 this->evalNewtonStep();
440 this->evalTrialStep(d3);
441 }
442
456 template<typename Real>
457 void Solver<Real>::setDirection(Vector<Real> const & dx, Vector<Real> const & dr1, Vector<Real> const & dr2,
458 Vector<Real> const & ds1, Vector<Real> const & ds2, Vector<Real> const & dlE, Vector<Real> const & dlI,
459 Real const dx_norm, Real const dl_norm)
460 {
461 // Create alias for easier access
462 Input<Real> const & i{this->m_input};
463 Direction<Real> & d{this->m_direction};
464
465 // Set primal variables
466 d.x = dx;
467 if (i.nE > 0) {d.r1 = dr1; d.r2 = dr2; d.lE = dlE;}
468 if (i.nI > 0) {d.s1 = ds1; d.s2 = ds2; d.lI = dlI;}
469 d.x_norm = dx_norm;
470 d.l_norm = dl_norm;
471 }
472
473} // namespace Pipal
474
475#endif // INCLUDE_PIPAL_DIRECTION_HXX
void evalMerit()
Compute the merit function value for the current iterate.
Definition Iterate.hxx:524
void evalTrialStep(Direction< Real > &v) const
Store a trial step into another direction object.
Definition Direction.hxx:377
void setRho(Real const rho)
Set penalty parameter rho.
Definition Solver.hxx:132
Acceptance< Real > m_acceptance
Definition Solver.hxx:43
void resetMuMaxExp()
Reset maximum exponent used for mu increases to its default.
Definition Solver.hxx:114
void setRhoLast(Real const rho)
Set last (previous) penalty parameter value.
Definition Solver.hxx:139
Input< Real > m_input
Definition Solver.hxx:44
void evalTrialSteps(Direction< Real > &d1, Direction< Real > &d2, Direction< Real > &d3)
Compute and store directions for a few parameter combinations.
Definition Direction.hxx:413
void evalLinearCombination(Direction< Real > const &d1, Direction< Real > const &d2, Direction< Real > const &d3, Real const a1, Real const a2, Real const a3)
Evaluate a linear combination of up to three directions.
Definition Direction.hxx:53
void evalStep()
Compute the search direction for the current iterate.
Definition Direction.hxx:201
void resetDirection(Direction< Real > &d) const
Reset a search direction to zero and initialize norms.
Definition Direction.hxx:24
Direction< Real > m_direction
Definition Solver.hxx:45
void evalNewtonRhs()
Build the right-hand side vector for the Newton system.
Definition Iterate.hxx:647
void setMu(Real const mu)
Set interior-point parameter mu.
Definition Solver.hxx:146
Iterate< Real > m_iterate
Definition Solver.hxx:46
bool m_bfgs
Definition Solver.hxx:53
void evalNewtonMatrix()
Assemble and (attempt to) factorize the Newton system matrix.
Definition Iterate.hxx:549
void setMuMaxExpZero()
Force mu exponent increases to use zero as maximum exponent.
Definition Solver.hxx:125
void evalModels()
Evaluate model reductions and quality metric for a direction.
Definition Direction.hxx:85
Parameter< Real > m_parameter
Definition Solver.hxx:48
void evalNewtonStep()
Recover direction components from the Newton system solution.
Definition Direction.hxx:166
void fractionToBoundary()
Fraction-to-boundary rule for primal and dual variables.
Definition Acceptance.hxx:100
void setDirection(Vector< Real > const &dx, Vector< Real > const &dr1, Vector< Real > const &dr2, Vector< Real > const &ds1, Vector< Real > const &ds2, Vector< Real > const &dlE, Vector< Real > const &dlI, Real const dx_norm, Real const dl_norm)
Populate a Direction object from its component vectors.
Definition Direction.hxx:457
void evalHessian()
Evaluate the Hessian of the Lagrangian and assemble internal H.
Definition Iterate.hxx:350
void evalTrialStepCut()
Scale a trial step by the fraction-to-boundary values.
Definition Direction.hxx:392
void updateParameters()
Update penalty and interior-point parameters based on KKT errors.
Definition Iterate.hxx:959
Namespace for the Pipal library.
Definition Acceptance.hxx:16
PIPAL_DEFAULT_INTEGER_TYPE Integer
The Integer type as used for the API.
Definition Types.hxx:110
Eigen::Array< Real, Eigen::Dynamic, 1 > Array
Definition Types.hxx:115
Eigen::Vector< Real, Eigen::Dynamic > Vector
Definition Types.hxx:112
Class for managing the acceptance criteria of the solver.
Definition Types.hxx:486
Real d
Definition Types.hxx:489
Real p
Definition Types.hxx:488
Class for managing the current search direction of the solver.
Definition Types.hxx:446
Real l_norm
Definition Types.hxx:456
Array< Real > s2
Definition Types.hxx:454
Real qtred
Definition Types.hxx:460
Real ltred0
Definition Types.hxx:458
Real x_norm
Definition Types.hxx:448
Array< Real > lI
Definition Types.hxx:455
Real m
Definition Types.hxx:461
Array< Real > r2
Definition Types.hxx:451
Array< Real > r1
Definition Types.hxx:450
Array< Real > lE
Definition Types.hxx:452
Real ltred
Definition Types.hxx:459
Real x_norm_
Definition Types.hxx:449
Vector< Real > x
Definition Types.hxx:447
Real lred0
Definition Types.hxx:457
Array< Real > s1
Definition Types.hxx:453
Input structure holding all the data defining the optimization problem.
Definition Types.hxx:316
Integer nV
Definition Types.hxx:348
Integer nI
Definition Types.hxx:349
Integer nE
Definition Types.hxx:350
Class for managing the current iterate of the solver.
Definition Types.hxx:377
Real rho
Definition Types.hxx:381
Array< Real > cE
Definition Types.hxx:389
Real v
Definition Types.hxx:401
Real mu
Definition Types.hxx:383
Array< Real > lI
Definition Types.hxx:398
SparseMatrix< Real > H
Definition Types.hxx:399
Array< Real > r1
Definition Types.hxx:387
SparseMatrix< Real > JE
Definition Types.hxx:390
Array< Real > s2
Definition Types.hxx:394
Array< Real > lE
Definition Types.hxx:392
Array< Real > cI
Definition Types.hxx:395
Vector< Real > b
Definition Types.hxx:408
SparseMatrix< Real > JI
Definition Types.hxx:396
LDLT ldlt
Definition Types.hxx:405
Vector< Real > kkt_
Definition Types.hxx:410
Vector< Real > kkt
Definition Types.hxx:409
Array< Real > s1
Definition Types.hxx:393
Array< Real > r2
Definition Types.hxx:388
Vector< Real > g
Definition Types.hxx:386
Internal parameters for the solver algorithm.
Definition Types.hxx:229
static constexpr Real rho_min
Definition Types.hxx:244
static constexpr Real rho_factor
Definition Types.hxx:245
static constexpr Integer mu_trials
Definition Types.hxx:251
Algorithm algorithm
Definition Types.hxx:260
static constexpr Real mu_min
Definition Types.hxx:248
Real mu_max_exp
Definition Types.hxx:261
static constexpr Real mu_max
Definition Types.hxx:252
static constexpr Real update_con_1
Definition Types.hxx:254
static constexpr Real update_con_2
Definition Types.hxx:255
static constexpr Integer rho_trials
Definition Types.hxx:246
Real opt_err_tol
Definition Types.hxx:258
static constexpr Real update_con_3
Definition Types.hxx:256