rsvs3D  0.0.0
Codes for the c++ implementation of the 3D RSVS
RSVScalc_SQP.cpp
1 #include <Eigen>
2 #include <cmath>
3 #include <cstdlib>
4 #include <fstream>
5 #include <iostream>
6 
7 // #include "snake.hpp"
8 // #include "triangulate.hpp"
9 #include "RSVScalc.hpp"
10 #include "SQPstep.hpp"
11 #include "matrixtools.hpp"
12 #include "vectorarray.hpp"
13 
14 using namespace std;
15 using namespace Eigen;
16 
17 /*
18 Implementation of the core calculation functions of
19 RSVScalc, this is done to reduce the size of the objects and
20 keep compilation time manageable.
21 
22 */
23 
24 //==========================================
25 // SQP calculation functions
26 //==========================================
27 
28 bool RSVScalc::PrepareMatricesForSQP(MatrixXd &dConstrAct, MatrixXd &HConstrAct, MatrixXd &HObjAct,
29  MatrixXd_sparse &dConstrAct_sparse, MatrixXd_sparse &HConstrAct_sparse,
30  MatrixXd_sparse &HObjAct_sparse, RowVectorXd &dObjAct, VectorXd &constrAct,
31  VectorXd &lagMultAct)
32 {
33  int ii, jj, nDvAct, nConstrAct;
34 
35  this->subDvAct.reserve(nDv);
36  this->subDvAct.clear();
37  nDvAct = 0;
38  for (ii = 0; ii < nDv; ++ii)
39  {
40  nDvAct += int(isDvAct.at(ii));
41  if (isDvAct.at(ii))
42  {
43  this->subDvAct.push_back(ii);
44  }
45  }
46 
47  this->subConstrAct.reserve(nConstr);
48  this->subConstrAct.clear();
49  nConstrAct = 0;
50  for (ii = 0; ii < nConstr; ++ii)
51  {
52  nConstrAct += int(isConstrAct.at(ii));
53  if (isConstrAct.at(ii))
54  {
55  this->subConstrAct.push_back(ii);
56  }
57  }
58 
59  dObjAct.setZero(nDvAct);
60  for (jj = 0; jj < nDvAct; ++jj)
61  {
62  dObjAct[jj] = dObj[this->subDvAct[jj]];
63  }
64  constrAct.setZero(nConstrAct);
65  for (jj = 0; jj < nConstrAct; ++jj)
66  {
67  constrAct[jj] = (constr[this->subConstrAct[jj]] - constrTarg[this->subConstrAct[jj]]);
68  }
69  lagMultAct.setZero(nConstrAct);
70 
71  this->subConstrAct.GenerateHash();
72  this->subDvAct.GenerateHash();
73 
74  if (this->UseFullMath())
75  {
76  // Full maths
77  this->PrepareMatricesForSQPFull(dConstrAct, HConstrAct, HObjAct);
78  }
79  else
80  {
81  this->PrepareMatricesForSQPSparse(dConstrAct_sparse, HConstrAct_sparse, HObjAct_sparse);
82  }
83 
84  return (nDvAct > 0);
85 }
86 
87 void RSVScalc::PrepareMatricesForSQPFull(Eigen::MatrixXd &dConstrAct, Eigen::MatrixXd &HConstrAct,
88  Eigen::MatrixXd &HObjAct)
89 {
90  int ii, jj;
91  int nConstrAct = this->subConstrAct.size();
92  int nDvAct = this->subDvAct.size();
93 
94  dConstrAct.setZero(nConstrAct, nDvAct);
95  for (ii = 0; ii < nConstrAct; ++ii)
96  {
97  for (jj = 0; jj < nDvAct; ++jj)
98  {
99  dConstrAct(ii, jj) = dConstr(this->subConstrAct[ii], this->subDvAct[jj])
100  // /constrTarg[this->subConstrAct[ii]]
101  ;
102  }
103  }
104  HConstrAct.setZero(nDvAct, nDvAct);
105  for (ii = 0; ii < nDvAct; ++ii)
106  {
107  for (jj = 0; jj < nDvAct; ++jj)
108  {
109  HConstrAct(ii, jj) = HConstr(this->subDvAct[ii], this->subDvAct[jj]);
110  }
111  }
112  HObjAct.setZero(nDvAct, nDvAct);
113  for (ii = 0; ii < nDvAct; ++ii)
114  {
115  for (jj = 0; jj < nDvAct; ++jj)
116  {
117  HObjAct(ii, jj) = HObj(this->subDvAct[ii], this->subDvAct[jj]);
118  }
119  }
120 
121  this->dLag = this->dObj + this->lagMult.transpose() * this->dConstr;
122  this->HLag = HObjAct + HConstrAct;
123 }
124 void RSVScalc::PrepareMatricesForSQPSparse(MatrixXd_sparse &dConstrAct_sparse, MatrixXd_sparse &HConstrAct_sparse,
125  MatrixXd_sparse &HObjAct_sparse)
126 {
127  int ii, jj, count;
128  int nConstrAct = this->subConstrAct.size();
129  int nDvAct = this->subDvAct.size();
130  // Sparse maths
131  dConstrAct_sparse.resize(nConstrAct, nDvAct);
132  count = this->dConstr_sparse.nonZeros();
133  dConstrAct_sparse.reserve(count);
134  for (int k = 0; k < count; ++k)
135  {
136  auto it = dConstr_sparse[k];
137  if (isConstrAct[it.row()] && isDvAct[it.col()])
138  {
139  ii = subConstrAct.find(it.row());
140  jj = subDvAct.find(it.col());
141  if (ii == rsvs3d::constants::__notfound || jj == rsvs3d::constants::__notfound)
142  {
143  std::cerr << std::endl
144  << "rows " << it.row() << ", cols " << it.col() << ", value " << it.value() << std::endl;
145  RSVS3D_ERROR_LOGIC("It should not be possible to get here.");
146  }
147 
148  dConstrAct_sparse.insert(ii, jj) = it.value();
149  }
150  }
151 
152  HConstrAct_sparse.resize(nDvAct, nDvAct);
153  count = this->HConstr_sparse.nonZeros();
154  HConstrAct_sparse.reserve(count);
155  for (int k = 0; k < count; ++k)
156  {
157  auto it = HConstr_sparse[k];
158  if (isDvAct[it.row()] && isDvAct[it.col()])
159  {
160  ii = subDvAct.find(it.row());
161  jj = subDvAct.find(it.col());
162  HConstrAct_sparse.insert(ii, jj) = it.value();
163  }
164  }
165 
166  HObjAct_sparse.resize(nDvAct, nDvAct);
167  count = this->HObj_sparse.nonZeros();
168  HObjAct_sparse.reserve(count);
169  for (int k = 0; k < count; ++k)
170  {
171  auto it = HObj_sparse[k];
172  if (isDvAct[it.row()] && isDvAct[it.col()])
173  {
174  ii = subDvAct.find(it.row());
175  jj = subDvAct.find(it.col());
176  HObjAct_sparse.insert(ii, jj) = it.value();
177  }
178  }
179  this->dConstr_sparse.SetEqual(this->dConstr);
180  this->dLag = this->dObj + this->lagMult.transpose() * this->dConstr;
181  this->HLag_sparse = HObjAct_sparse + HConstrAct_sparse;
182 }
183 
184 bool RSVScalc::PrepareMatricesForSQPSensitivity(const MatrixXd &dConstrAct, const MatrixXd &HConstrAct,
185  const MatrixXd &HObjAct, MatrixXd &sensMult, MatrixXd &sensInv,
186  MatrixXd &sensRes) const
187 {
188  int nDvAct, nConstrAct;
189 
190  // Find active design variables and active constraint
191  nDvAct = this->subDvAct.size();
192  nConstrAct = this->subConstrAct.size();
193 
196 
197  sensInv.resize(nDvAct + nConstrAct, nDvAct + nConstrAct);
198  sensMult.resize(nDvAct + nConstrAct, nConstrAct);
199  sensRes.resize(nDvAct + nConstrAct, nConstrAct);
200 
201  sensInv << HConstrAct + HObjAct, dConstrAct.transpose(), dConstrAct, MatrixXd::Zero(nConstrAct, nConstrAct);
202 
203  sensMult.setZero();
204  for (int i = 0; i < nConstrAct; ++i)
205  {
206  sensMult(nDvAct + i, i) = this->lagMult[this->subConstrAct[i]];
207  }
208  sensRes.setZero();
209 
210  // do some size checks on the constructed matrices.
211 
212  return (nDvAct > 0 && nConstrAct > 0);
213 }
214 
215 bool RSVScalc::PrepareMatricesForSQPSensitivity(const MatrixXd_sparse &dConstrAct, const MatrixXd_sparse &HConstrAct,
216  MatrixXd_sparse &HObjAct, Eigen::MatrixXd &sensMult,
217  MatrixXd_sparse &sensInv, Eigen::MatrixXd &sensRes) const
218 {
219  int nDvAct, nConstrAct;
220 
221  // Find active design variables and active constraint
222  nDvAct = this->subDvAct.size();
223  nConstrAct = this->subConstrAct.size();
224 
227 
228  sensInv.resize(nDvAct + nConstrAct, nDvAct + nConstrAct);
229  sensMult.resize(nDvAct + nConstrAct, nConstrAct);
230  sensRes.resize(nDvAct + nConstrAct, nConstrAct);
231 
232  // Assign sensInv
233  HObjAct = HConstrAct + HObjAct;
234  MatrixXd_sparse &HlagAct = HObjAct;
235  sensInv.reserve(HlagAct.nonZeros() + 2 * dConstrAct.nonZeros());
236  for (int k = 0; k < HlagAct.outerSize(); ++k)
237  {
238  for (SparseMatrix<double>::InnerIterator it(HlagAct, k); it; ++it)
239  {
240  sensInv.insert(it.row(), it.col()) = it.value();
241  }
242  }
243  for (int k = 0; k < dConstrAct.outerSize(); ++k)
244  {
245  for (SparseMatrix<double>::InnerIterator it(dConstrAct, k); it; ++it)
246  {
247  sensInv.insert(it.col(), it.row() + nDvAct) = it.value();
248  sensInv.insert(it.row() + nDvAct, it.col()) = it.value();
249  }
250  }
251 
252  sensMult.setZero();
253  for (int i = 0; i < nConstrAct; ++i)
254  {
255  sensMult(nDvAct + i, i) = this->lagMult[this->subConstrAct[i]];
256  }
257  sensRes.setZero();
258 
259  // do some size checks on the constructed matrices.
260 
261  return (nDvAct > 0 && nConstrAct > 0);
262 }
263 
264 void RSVScalc::CheckAndCompute(int calcMethod, bool sensCalc)
265 {
266  int ii;
267  bool computeFlag;
268  MatrixXd dConstrAct, HConstrAct, HObjAct;
269  MatrixXd_sparse dConstrAct_sparse, HConstrAct_sparse, HObjAct_sparse;
270  RowVectorXd dObjAct;
271  VectorXd constrAct, lagMultAct, deltaDVAct;
272 
273  computeFlag = this->PrepareMatricesForSQP(dConstrAct, HConstrAct, HObjAct, dConstrAct_sparse, HConstrAct_sparse,
274  HObjAct_sparse, dObjAct, constrAct, lagMultAct);
275  // computeFlag=true;
276  if (computeFlag)
277  {
278  if (this->UseFullMath())
279  {
280  this->ComputeSQPstep(calcMethod, dConstrAct, dObjAct, constrAct, lagMultAct);
281  }
282  else
283  {
284  this->ComputeSQPstep(calcMethod, dConstrAct_sparse, dObjAct, constrAct, lagMultAct);
285  }
286  }
287  else
288  {
289  for (ii = 0; ii < nDv; ++ii)
290  {
291  deltaDV[ii] = 0.0;
292  }
293  }
294  if (sensCalc)
295  {
296  if (this->UseFullMath())
297  {
298  MatrixXd sensMult, sensInv, sensRes;
299  bool computeSens =
300  this->PrepareMatricesForSQPSensitivity(dConstrAct, HConstrAct, HObjAct, sensMult, sensInv, sensRes);
301  if (computeSens)
302  {
303  this->ComputeSQPsens(calcMethod, sensMult, sensInv, sensRes);
304  }
305  }
306  else
307  {
308  MatrixXd_sparse sensInv;
309  MatrixXd sensRes, sensMult;
310  bool computeSens = this->PrepareMatricesForSQPSensitivity(dConstrAct_sparse, HConstrAct_sparse,
311  HObjAct_sparse, sensMult, sensInv, sensRes);
312  if (computeSens)
313  {
314  sensInv.makeCompressed();
315  this->ComputeSQPsens(calcMethod, sensMult, sensInv, sensRes);
316  }
317  }
318  }
319 }
320 
321 void RSVScalc::ComputeSQPstep(int calcMethod, MatrixXd &dConstrAct, RowVectorXd &dObjAct, VectorXd &constrAct,
322  VectorXd &lagMultAct)
323 {
324  int ni = this->subDvAct.size();
325  VectorXd deltaDVAct(ni);
326  bool isNan, isLarge, rerunDefault = true, attemptConstrOnly;
327  int ii;
328 
329  /*
330  This while loop while expensive allows to use the most stable algorithm
331  */
332  deltaDVAct.setZero();
333  attemptConstrOnly = false;
334  if ((calcMethod % 10) != calcMethod)
335  {
336  calcMethod = calcMethod % 10;
337  attemptConstrOnly = true;
338  }
339  while (rerunDefault)
340  {
341  switch (calcMethod)
342  {
343  case 1:
344  rerunDefault = SQPstep<Eigen::HouseholderQR>(*this, dConstrAct, dObjAct, constrAct, lagMultAct, deltaDVAct,
345  isNan, isLarge, attemptConstrOnly);
346  // cout << "case 1:" << endl;
347 
348  break;
349  case 2:
350  rerunDefault = SQPstep<Eigen::ColPivHouseholderQR>(*this, dConstrAct, dObjAct, constrAct, lagMultAct,
351  deltaDVAct, isNan, isLarge, attemptConstrOnly);
352  // cout << "case 2:" << endl;
353  break;
354  case 3:
355  // Eigen::LLT is inconveniently a 2 parameter template so
356  // a full type is passed
357  rerunDefault = SQPstep<Eigen::LLT<MatrixXd>>(*this, dConstrAct, dObjAct, constrAct, lagMultAct, deltaDVAct,
358  isNan, isLarge, attemptConstrOnly);
359  // cout << "case 3:" << endl;
360  break;
361  case 4:
362  rerunDefault = SQPstep<Eigen::PartialPivLU>(*this, dConstrAct, dObjAct, constrAct, lagMultAct, deltaDVAct,
363  isNan, isLarge, attemptConstrOnly);
364  // cout << "case 4:" << endl;
365  break;
366  default:
367  SQPstep<Eigen::ColPivHouseholderQR>(*this, dConstrAct, dObjAct, constrAct, lagMultAct, deltaDVAct, isNan,
368  isLarge, true);
369  rerunDefault = false;
370  // cout << "case default:" << endl;
371  break;
372  }
373  if (attemptConstrOnly)
374  {
375  rerunDefault = false;
376  }
377  if (rerunDefault)
378  {
379  calcMethod = 0;
380  }
381  }
382 
383  ni = this->subDvAct.size();
384  for (ii = 0; ii < ni; ++ii)
385  {
386  this->deltaDV[subDvAct[ii]] = deltaDVAct[ii];
387  }
388 
389  ni = this->subConstrAct.size();
390  this->lagMult.setZero(nConstr);
391  if (isLarge)
392  {
393  for (ii = 0; ii < nConstr; ++ii)
394  {
395  lagMult[subConstrAct[ii]] = 0;
396  }
397  }
398  else
399  {
400  for (ii = 0; ii < ni; ++ii)
401  {
402  this->lagMult[this->subConstrAct[ii]] = lagMultAct[ii];
403  isNan = isNan || isnan(lagMultAct[ii]);
404  }
405  }
406  if (false)
407  {
408  Print2Screen(3);
409  DisplayVector(isConstrAct);
410  DisplayVector(isDvAct);
411  }
412 }
413 
414 void RSVScalc::ComputeSQPstep(int calcMethod, MatrixXd_sparse &dConstrAct, RowVectorXd &dObjAct, VectorXd &constrAct,
415  VectorXd &lagMultAct)
416 {
417  int ni = this->subDvAct.size();
418  VectorXd deltaDVAct(ni);
419  bool isNan, isLarge, rerunDefault = true, attemptConstrOnly;
420  int ii;
421 
422  /*
423  This while loop while expensive allows to use the most stable algorithm
424  */
425  deltaDVAct.setZero();
426  attemptConstrOnly = false;
427  if ((calcMethod % 10) != calcMethod)
428  {
429  calcMethod = calcMethod % 10;
430  attemptConstrOnly = true;
431  }
432  this->HLag_sparse.makeCompressed();
433  dConstrAct.makeCompressed();
434  while (rerunDefault)
435  {
436  switch (calcMethod)
437  {
438  default:
439  SQPstep_sparse<Eigen::SparseLU<MatrixXd_sparse>>(*this, dConstrAct, dObjAct, constrAct, lagMultAct,
440  deltaDVAct, isNan, isLarge, true);
441  rerunDefault = false;
442  break;
443  }
444  if (attemptConstrOnly)
445  {
446  rerunDefault = false;
447  }
448  if (rerunDefault)
449  {
450  calcMethod = 0;
451  }
452  }
453 
454  ni = this->subDvAct.size();
455  for (ii = 0; ii < ni; ++ii)
456  {
457  this->deltaDV[subDvAct[ii]] = deltaDVAct[ii];
458  }
459 
460  ni = this->subConstrAct.size();
461  this->lagMult.setZero(nConstr);
462  if (isLarge)
463  {
464  for (ii = 0; ii < nConstr; ++ii)
465  {
466  lagMult[subConstrAct[ii]] = 0;
467  }
468  }
469  else
470  {
471  for (ii = 0; ii < ni; ++ii)
472  {
473  this->lagMult[this->subConstrAct[ii]] = lagMultAct[ii];
474  isNan = isNan || isnan(lagMultAct[ii]);
475  }
476  }
477  if (false)
478  {
479  Print2Screen(3);
480  DisplayVector(isConstrAct);
481  DisplayVector(isDvAct);
482  }
483 }
484 
485 void RSVScalc::ComputeSQPsens(int calcMethod, const Eigen::MatrixXd &sensMult, const Eigen::MatrixXd &sensInv,
486  Eigen::MatrixXd &sensRes)
487 {
488  switch (calcMethod)
489  {
490  case 1:
491  SQPsens<Eigen::HouseholderQR>(sensMult, sensInv, sensRes);
492  break;
493  case 2:
494  SQPsens<Eigen::ColPivHouseholderQR>(sensMult, sensInv, sensRes);
495  break;
496  case 3:
497  // Eigen::LLT is inconveniently a 2 parameter template so
498  // a full type is passed
499  SQPsens<Eigen::LLT<MatrixXd>>(sensMult, sensInv, sensRes);
500  break;
501  case 4:
502  SQPsens<Eigen::PartialPivLU>(sensMult, sensInv, sensRes);
503  break;
504  default:
505  SQPsens<Eigen::ColPivHouseholderQR>(sensMult, sensInv, sensRes);
506  break;
507  }
508 
509  this->sensDv.setZero(this->nDv, this->nConstr);
510  int nConstrAct, nDvAct;
511  nConstrAct = this->subConstrAct.size();
512  nDvAct = this->subDvAct.size();
513  for (int i = 0; i < nDvAct; ++i)
514  {
515  for (int j = 0; j < nConstrAct; ++j)
516  {
517  this->sensDv(this->subDvAct[i], this->subConstrAct[j]) = sensRes(i, j);
518  }
519  }
520 }
521 
522 bool SQPsens_sparse2(const Eigen::MatrixXd &sensMult, const MatrixXd_sparse &sensInv, Eigen::MatrixXd &sensRes)
523 {
524  Eigen::SparseLU<MatrixXd_sparse> HLagSystem;
525  HLagSystem.compute(sensInv);
526  if (HLagSystem.info() != Eigen::Success)
527  {
528  // decomposition failed
529  RSVS3D_ERROR_NOTHROW("Failed to decompose sensitivity system.");
530  return (false);
531  }
532 
533  sensRes = -(HLagSystem.solve(sensMult));
534 
535  return (true);
536 }
537 
538 void RSVScalc::ComputeSQPsens(int calcMethod, Eigen::MatrixXd &sensMult, MatrixXd_sparse &sensInv,
539  Eigen::MatrixXd &sensRes)
540 {
541  switch (calcMethod)
542  {
543  default:
544  SQPsens_sparse<Eigen::SparseLU<MatrixXd_sparse>>(sensMult, sensInv, sensRes);
545  break;
546  }
547 
548  this->sensDv.setZero(this->nDv, this->nConstr);
549  int nConstrAct, nDvAct;
550  nConstrAct = this->subConstrAct.size();
551  nDvAct = this->subDvAct.size();
552  for (int i = 0; i < nDvAct; ++i)
553  {
554  for (int j = 0; j < nConstrAct; ++j)
555  {
556  this->sensDv(this->subDvAct[i], this->subConstrAct[j]) = sensRes(i, j);
557  }
558  }
559 }
Provides the infrastructure for calculation of the RSVS equations.
Provides the infrastructure for calculation of the RSVS equations.
void CheckAndCompute(int calcMethod=0, bool sensCalc=false)
Prepare the active arrays for SQP calculation and calculate the SQP step.
bool PrepareMatricesForSQP(Eigen::MatrixXd &dConstrAct, Eigen::MatrixXd &HConstrAct, Eigen::MatrixXd &HObjAct, MatrixXd_sparse &dConstrAct_sparse, MatrixXd_sparse &HConstrAct_sparse, MatrixXd_sparse &HObjAct_sparse, Eigen::RowVectorXd &dObjAct, Eigen::VectorXd &constrAct, Eigen::VectorXd &lagMultAct)
Prepares the matrices needed for the SQP step calculation.
void ComputeSQPstep(int calcMethod, Eigen::MatrixXd &dConstrAct, Eigen::RowVectorXd &dObjAct, Eigen::VectorXd &constrAct, Eigen::VectorXd &lagMultAct)
Calculates the next SQP step.
bool PrepareMatricesForSQPSensitivity(const Eigen::MatrixXd &dConstrAct, const Eigen::MatrixXd &HConstrAct, const Eigen::MatrixXd &HObjAct, Eigen::MatrixXd &sensMult, Eigen::MatrixXd &sensInv, Eigen::MatrixXd &sensRes) const
Prepares the matrices needed for the calculation of the sensitivity of the SQP.
Tools to support conversion, display and derivatives of Eigen matrices.
Provides a 2D std::vector based container.
#define RSVS3D_ERROR_LOGIC(M)
Throw a logic_error.
Definition: warning.hpp:139
#define RSVS3D_ERROR_NOTHROW(M)
Generic rsvs warning.
Definition: warning.hpp:120