1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
// Copyright (C) 2005, 2010 International Business Machines and others.
// All Rights Reserved.
// This code is published under the Eclipse Public License.
//
// Authors: Andreas Waechter IBM 2005-12-26
#ifndef __IPLIMMEMQUASINEWTONUPDATER_HPP__
#define __IPLIMMEMQUASINEWTONUPDATER_HPP__
#include "IpHessianUpdater.hpp"
#include "IpLowRankUpdateSymMatrix.hpp"
#include "IpMultiVectorMatrix.hpp"
#include "IpDenseVector.hpp"
#include "IpDenseGenMatrix.hpp"
#include "IpDenseSymMatrix.hpp"
namespace Ipopt
{
/** Implementation of the HessianUpdater for limit-memory
* quasi-Newton approximation of the Lagrangian Hessian.
*/
class LimMemQuasiNewtonUpdater: public HessianUpdater
{
public:
/**@name Constructors / Destructors */
///@{
/** Default Constructor */
LimMemQuasiNewtonUpdater(
bool update_for_resto
);
/** Destructor */
virtual ~LimMemQuasiNewtonUpdater()
{ }
///@}
virtual bool InitializeImpl(
const OptionsList& options,
const std::string& prefix
);
/** Update the Hessian based on the current information in IpData. */
virtual void UpdateHessian();
/** Methods for OptionsList */
///@{
static void RegisterOptions(
SmartPtr<RegisteredOptions> roptions
);
///@}
private:
/**@name Default Compiler Generated Methods
* (Hidden to avoid implicit creation/calling).
*
* These methods are not implemented and
* we do not want the compiler to implement
* them for us, so we declare them private
* and do not define them. This ensures that
* they will not be implicitly created/called.
*/
///@{
/** Copy Constructor */
LimMemQuasiNewtonUpdater(
const LimMemQuasiNewtonUpdater&
);
/** Default Assignment Operator */
void operator=(
const LimMemQuasiNewtonUpdater&
);
///@}
/** Matrix space for the low-rank Hessian approximation. */
SmartPtr<const LowRankUpdateSymMatrixSpace> h_space_;
/** @name Algorithmic parameters */
///@{
/** Size of memory for limited memory update. */
Index limited_memory_max_history_;
/** enumeration for the Hessian update type. */
enum LMUpdateType
{
BFGS = 0,
SR1
};
/** Type of Hessian update. */
LMUpdateType limited_memory_update_type_;
/** enumeration for the Hessian initialization. */
enum LMInitialization
{
SCALAR1 = 0,
SCALAR2,
SCALAR3,
SCALAR4,
CONSTANT
};
/** How to choose B0 in the low-rank update. */
LMInitialization limited_memory_initialization_;
/** Value of B0 (as this multiple of the identity in certain situations). */
Number limited_memory_init_val_;
/** Number of successive iterations of skipped updates after which
* the approximation is reset.
*/
Index limited_memory_max_skipping_;
/** Minimal safeguard value for sigma */
Number sigma_safe_min_;
/** Maximal safeguard value for sigma */
Number sigma_safe_max_;
/** Flag indicating if Hessian approximation should be done in a
* special manner for the restoration phase.
*/
bool limited_memory_special_for_resto_;
///@}
/** Flag indicating if the update is to be done for the original
* NLP or for the restoration phase NLP.
*
* In the latter case, we are performing a "structured" update,
* taking into account the first explicit term in the objective
* function of the form eta*D_r*x_k.
*/
const bool update_for_resto_;
/** Most recent value for eta in the restoration phase objective
* function (only for update_for_resto_ = true)
*/
Number last_eta_;
/** Current DR_x scaling factors in the restoration phase
* objective function (only for update_for_resto_ = true).
*
* This should not change throughout one restoration phase.
*/
SmartPtr<const Vector> curr_DR_x_;
/** Tag for curr_DR_x_ */
TaggedObject::Tag curr_DR_x_tag_;
/** Current DR_x scaling factors in the restoration phase
* objective function in the smaller space for the approximation.
*
* This is only computed if the space is indeed smaller than the
* x space (only for update_for_resto_ = true)
*/
SmartPtr<const Vector> curr_red_DR_x_;
/** Current value of weighing factor eta in the restoration phase
* objective function (only for update_for_resto_ = true)
*/
Number curr_eta_;
/** Counter for successive iterations in which the update was skipped */
Index lm_skipped_iter_;
/** @name Information for the limited memory update */
///@{
/** current size of limited memory */
Index curr_lm_memory_;
/** s pairs for the recent iterations */
SmartPtr<MultiVectorMatrix> S_;
/** y pairs for the recent iterations.
*
* If update_for_resto is true, then this includes only the
* information for the constraints.
*/
SmartPtr<MultiVectorMatrix> Y_;
/** For restoration phase update: Y without the quadratic
* objective function part
*/
SmartPtr<MultiVectorMatrix> Ypart_;
/** Diagonal elements D_k for compact formulation from last
* update.
*/
SmartPtr<DenseVector> D_;
/** Matrix L_k for compact formulation from last update.*/
SmartPtr<DenseGenMatrix> L_;
/** First term (starting matrix) for the approximation. */
SmartPtr<Vector> B0_;
/** First term (starting matrix) for the approximation.
*
* If that first terms is a multiple of the identy, sigma
* give that factor. Otherwise sigma = -1.
*/
Number sigma_;
/** V in LowRankUpdateMatrix from last update */
SmartPtr<MultiVectorMatrix> V_;
/** U in LowRankUpdateMatrix from last update */
SmartPtr<MultiVectorMatrix> U_;
/** For efficient implementation, we store the pairwise products
* for s's.
*/
SmartPtr<DenseSymMatrix> SdotS_;
/** Flag indicating whether SdotS_ is update to date from most
* recent update.
*/
bool SdotS_uptodate_;
/** DR * S (only for restoration phase) */
SmartPtr<MultiVectorMatrix> DRS_;
/** For efficient implementation, we store the S^T S DR * S.
*
* Only for restoration phase.
*/
SmartPtr<DenseSymMatrix> STDRS_;
/** Primal variables x from most recent update */
SmartPtr<const Vector> last_x_;
/** Gradient of objective function w.r.t. x at x_last_ */
SmartPtr<const Vector> last_grad_f_;
/** Jacobian for equality constraints w.r.t x at x_last */
SmartPtr<const Matrix> last_jac_c_;
/** Jacobian for inequality constraints w.r.t x at x_last */
SmartPtr<const Matrix> last_jac_d_;
/** current size of limited memory */
Index curr_lm_memory_old_;
/** s pairs for the recent iterations (backup) */
SmartPtr<MultiVectorMatrix> S_old_;
/** y pairs for the recent iterations.
*
* If update_for_resto is true, then this includes only the
* information for the constraints. (backup)
*/
SmartPtr<MultiVectorMatrix> Y_old_;
/** For restoration phase update: Y without the quadratic
* objective function part (backup) */
SmartPtr<MultiVectorMatrix> Ypart_old_;
/** Diagonal elements D_k for compact formulation from last
* update (backup). */
SmartPtr<DenseVector> D_old_;
/** Matrix L_k for compact formulation from last update (backup).*/
SmartPtr<DenseGenMatrix> L_old_;
/** First term (starting matrix) for the approximation (backup). */
SmartPtr<Vector> B0_old_;
/** First term (starting matrix) for the approximation.
*
* If that first terms is a multiple of the identy, sigma give that
* factor. Otherwise sigma = -1. (backup)
*/
Number sigma_old_;
/** V in LowRankUpdateMatrix from last update (backup) */
SmartPtr<MultiVectorMatrix> V_old_;
/** U in LowRankUpdateMatrix from last update (backup) */
SmartPtr<MultiVectorMatrix> U_old_;
/** For efficient implementation, we store the pairwise products
* for s's (backup).
*/
SmartPtr<DenseSymMatrix> SdotS_old_;
/** Flag indicating whether SdotS_ is update to date from most
* recent update (backup).
*/
bool SdotS_uptodate_old_;
/** DR * S (only for restoration phase) (backup) */
SmartPtr<MultiVectorMatrix> DRS_old_;
/** For efficient implementation, we store the S^T S DR * S.
*
* Only for restoration phase. (backup)
*/
SmartPtr<DenseSymMatrix> STDRS_old_;
///@}
/** @name Auxiliary function */
///@{
/** Method deciding whether the BFGS update should be skipped.
*
* If Powell-damping is performed, the Vectors s_new and y_new
* might be adapted.
*
* @return true, if no update is to be performed this time.
*/
bool CheckSkippingBFGS(
const Vector& s_new,
const Vector& y_new
);
/** Update the internal data, such as the S, Y, L, D etc matrices
* and vectors that are required for computing the compact
* representation.
*
* @return true, if the limited memory history grew (i.e., curr_lm_memory_ was increased).
*/
bool UpdateInternalData(
const Vector& s_new,
const Vector& y_new,
SmartPtr<Vector> ypart_new
);
/** Given a MutliVector V, create a new MultiVectorSpace with one
* more column, and return V as a member of that space,
* consisting of all previous vectors, and in addition v_new in
* the last column.
*
* If V is NULL, then a new MatrixSpace with one column is created.
*/
void AugmentMultiVector(
SmartPtr<MultiVectorMatrix>& V,
const Vector& v_new
);
/** Given a DenseVector V, create a new DenseVectorSpace with one
* more row, and return V as a member of that space,
* consisting of all previous elements, and in addition v_new in
* the last row.
*
* If V is NULL, then a new DenseVectorSpace with dimension one is created.
*/
void AugmentDenseVector(
SmartPtr<DenseVector>& V,
Number v_new
);
/** Given a strictly-lower triangular square DenseGenMatrix V,
* create a new DenseGenMatrixSpace with one more dimension, and
* return V as a member of that space, consisting of all previous
* elements, and in addition elements s_i^Ty_j for (i<j), where s
* and y are the vectors in the MultiVectors S and Y.
*
* If V is NULL, then a new DenseGenMatrixSpace with dimension one
* is created.
*/
void AugmentLMatrix(
SmartPtr<DenseGenMatrix>& V,
const MultiVectorMatrix& S,
const MultiVectorMatrix& Y
);
/** Given a DenseSymMatrix V, create a new DenseGenMatrixSpace
* with one more dimension, and return V as a member of that
* space, consisting of all previous elements, and in addition
* elements s_i^Ts_j for the new entries, where s are the vectors
* in the MultiVector S.
*
* If V is NULL, then a new
* DenseGenMatrixSpace with dimension one is created.
*/
void AugmentSdotSMatrix(
SmartPtr<DenseSymMatrix>& V,
const MultiVectorMatrix& S
);
/** Given a DenseSymMatrix V, create a new DenseGenMatrixSpace
* with one more dimension, and return V as a member of that
* space, consisting of all previous elements, and in addition
* elements s_i^TDRs_j for the new entries, where s are the
* vectors in the MultiVector S, and DRs are the vectors in DRS.
*
* If V is NULL, then a new DenseGenMatrixSpace with dimension
* one is created.
*/
void AugmentSTDRSMatrix(
SmartPtr<DenseSymMatrix>& V,
const MultiVectorMatrix& S,
const MultiVectorMatrix& DRS
);
/** Given a MutliVector V, get rid of the first column, shift all
* other columns to the left, and make v_new the last column.
*
* The entity that V points to at the call, is not changed - a
* new entity is created in the method and returned as V.
*/
void ShiftMultiVector(
SmartPtr<MultiVectorMatrix>& V,
const Vector& v_new
);
/** Given a DenseVector V, get rid of the first element, shift all
* other elements one position to the top, and make v_new the
* last entry.
*
* The entity that V points to at the call, is not changed -
* a new entity is created in the method and returned as V.
*/
void ShiftDenseVector(
SmartPtr<DenseVector>& V,
Number v_new
);
/** Given a strictly-lower triangular square DenseGenMatrix V,
* shift everything one row and column up, and fill the new
* strictly lower triangular entries as s_i^Ty_j for (i<j), where
* s and y are the vectors in the MultiVectors S and Y.
*
* The entity that V points to at the call, is not changed - a new
* entity is created in the method and returned as V.
*/
void ShiftLMatrix(
SmartPtr<DenseGenMatrix>& V,
const MultiVectorMatrix& S,
const MultiVectorMatrix& Y
);
/** Given a DenseSymMatrix V, shift everything up one row and
* column, and fill the new entries as s_i^Ts_j, where s are the
* vectors in the MultiVector S.
*
* The entity that V points to at the call, is not changed -
* a new entity is created in the method and returned as V.
*/
void ShiftSdotSMatrix(
SmartPtr<DenseSymMatrix>& V,
const MultiVectorMatrix& S
);
/** Given a DenseSymMatrix V, shift everything up one row and
* column, and fill the new entries as s_i^TDRs_j, where s are
* the vectors in the MultiVector S, and DRs are the vectors in DRS.
*
* The entity that V points to at the call, is not changed -
* a new entity is created in the method and returned as V.
*/
void ShiftSTDRSMatrix(
SmartPtr<DenseSymMatrix>& V,
const MultiVectorMatrix& S,
const MultiVectorMatrix& DRS
);
/** Method for recomputing Y from scratch, using Ypart (only for
* restoration phase)
*/
void RecalcY(
Number eta,
const Vector& DR_x,
MultiVectorMatrix& S,
MultiVectorMatrix& Ypart,
SmartPtr<MultiVectorMatrix>& Y
);
/** Method for recomputing D from S and Y */
void RecalcD(
const MultiVectorMatrix& S,
const MultiVectorMatrix& Y,
SmartPtr<DenseVector>& D
);
/** Method for recomputing L from S and Y */
void RecalcL(
const MultiVectorMatrix& S,
const MultiVectorMatrix& Y,
SmartPtr<DenseGenMatrix>& L
);
/** Split the eigenvectors into negative and positive ones.
*
* Given the eigenvectors in Q and the eigenvalues (in ascending order)
* in, this returns Qminus as the negative eigenvectors times
* sqrt(-eval), and Qplus as the positive eigenvectors times
* sqrt(eval). If Qminus or Qplus is NULL, it means that there
* are no negative or positive eigenvalues, resp. Q might be changed
* during this call.
*
* @return true, if the ratio of the smallest over the largest
* eigenvalue (in absolute values) is too small; in that case,
* the update should be skipped.
*/
bool SplitEigenvalues(
DenseGenMatrix& Q,
const DenseVector& E,
SmartPtr<DenseGenMatrix>& Qminus,
SmartPtr<DenseGenMatrix>& Qplus
);
/** Store a copy of the pointers to the internal data (S, Y, D, L,
* SdotS, curr_lm_memory).
*
* This is called in case the update is
* started but skipped during the process.
*/
void StoreInternalDataBackup();
/** Restore the copy of the pointers to the internal data most
* recently stored with StoreInternalDataBackup().
*/
void RestoreInternalDataBackup();
/** Release anything that we allocated for
* StoreInternalDataBackup and is no longer needed.
*/
// void ReleaseInternalDataBackup();
/** Set the W field in IpData based on the current values of
* B0_, V_, and U_.
*/
void SetW();
///@}
};
} // namespace Ipopt
#endif