1 // @HEADER
2 // ************************************************************************
3 //
4 //               Rapid Optimization Library (ROL) Package
5 //                 Copyright (2014) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact lead developers:
38 //              Drew Kouri   (dpkouri@sandia.gov) and
39 //              Denis Ridzal (dridzal@sandia.gov)
40 //
41 // ************************************************************************
42 // @HEADER
43 
44 
45 #ifndef ROL_CONSTRAINT_DEF_H
46 #define ROL_CONSTRAINT_DEF_H
47 
48 #include "ROL_LinearAlgebra.hpp"
49 #include "ROL_LAPACK.hpp"
50 
51 namespace ROL {
52 
53 template <class Real>
applyJacobian(Vector<Real> & jv,const Vector<Real> & v,const Vector<Real> & x,Real & tol)54 void Constraint<Real>::applyJacobian(Vector<Real> &jv,
55                                      const Vector<Real> &v,
56                                      const Vector<Real> &x,
57                                      Real &tol) {
58   // By default we compute the finite-difference approximation.
59   const Real one(1);
60   Real ctol = std::sqrt(ROL_EPSILON<Real>());
61 
62   // Get step length.
63   Real h = std::max(one,x.norm()/v.norm())*tol;
64   //Real h = 2.0/(v.norm()*v.norm())*tol;
65 
66   // Compute constraint at x.
67   ROL::Ptr<Vector<Real> > c = jv.clone();
68   this->value(*c,x,ctol);
69 
70   // Compute perturbation x + h*v.
71   ROL::Ptr<Vector<Real> > xnew = x.clone();
72   xnew->set(x);
73   xnew->axpy(h,v);
74   this->update(*xnew);
75 
76   // Compute constraint at x + h*v.
77   jv.zero();
78   this->value(jv,*xnew,ctol);
79 
80   // Compute Newton quotient.
81   jv.axpy(-one,*c);
82   jv.scale(one/h);
83 }
84 
85 
86 template <class Real>
applyAdjointJacobian(Vector<Real> & ajv,const Vector<Real> & v,const Vector<Real> & x,Real & tol)87 void Constraint<Real>::applyAdjointJacobian(Vector<Real> &ajv,
88                                             const Vector<Real> &v,
89                                             const Vector<Real> &x,
90                                             Real &tol) {
91   applyAdjointJacobian(ajv,v,x,v.dual(),tol);
92 }
93 
94 
95 
96 
97 
98 template <class Real>
applyAdjointJacobian(Vector<Real> & ajv,const Vector<Real> & v,const Vector<Real> & x,const Vector<Real> & dualv,Real & tol)99 void Constraint<Real>::applyAdjointJacobian(Vector<Real> &ajv,
100                                             const Vector<Real> &v,
101                                             const Vector<Real> &x,
102                                             const Vector<Real> &dualv,
103                                             Real &tol) {
104   // By default we compute the finite-difference approximation.
105   // This requires the implementation of a vector-space basis for the optimization variables.
106   // The default implementation requires that the constraint space is equal to its dual.
107   const Real one(1);
108   Real h(0), ctol = std::sqrt(ROL_EPSILON<Real>());
109 
110   ROL::Ptr<Vector<Real> > xnew = x.clone();
111   ROL::Ptr<Vector<Real> > ex   = x.clone();
112   ROL::Ptr<Vector<Real> > eajv = ajv.clone();
113   ROL::Ptr<Vector<Real> > cnew = dualv.clone();  // in general, should be in the constraint space
114   ROL::Ptr<Vector<Real> > c0   = dualv.clone();  // in general, should be in the constraint space
115   this->value(*c0,x,ctol);
116 
117   ajv.zero();
118   for ( int i = 0; i < ajv.dimension(); i++ ) {
119     ex = x.basis(i);
120     eajv = ajv.basis(i);
121     h = std::max(one,x.norm()/ex->norm())*tol;
122     xnew->set(x);
123     xnew->axpy(h,*ex);
124     this->update(*xnew);
125     this->value(*cnew,*xnew,ctol);
126     cnew->axpy(-one,*c0);
127     cnew->scale(one/h);
128     ajv.axpy(cnew->dot(v.dual()),*eajv);
129   }
130 }
131 
132 
133 /*template <class Real>
134 void Constraint<Real>::applyHessian(Vector<Real> &huv,
135                                     const Vector<Real> &u,
136                                     const Vector<Real> &v,
137                                     const Vector<Real> &x,
138                                     Real &tol ) {
139   Real jtol = std::sqrt(ROL_EPSILON<Real>());
140 
141   // Get step length.
142   Real h = std::max(1.0,x.norm()/v.norm())*tol;
143   //Real h = 2.0/(v.norm()*v.norm())*tol;
144 
145   // Compute constraint Jacobian at x.
146   ROL::Ptr<Vector<Real> > ju = huv.clone();
147   this->applyJacobian(*ju,u,x,jtol);
148 
149   // Compute new step x + h*v.
150   ROL::Ptr<Vector<Real> > xnew = x.clone();
151   xnew->set(x);
152   xnew->axpy(h,v);
153   this->update(*xnew);
154 
155   // Compute constraint Jacobian at x + h*v.
156   huv.zero();
157   this->applyJacobian(huv,u,*xnew,jtol);
158 
159   // Compute Newton quotient.
160   huv.axpy(-1.0,*ju);
161   huv.scale(1.0/h);
162 }*/
163 
164 
165 template <class Real>
applyAdjointHessian(Vector<Real> & huv,const Vector<Real> & u,const Vector<Real> & v,const Vector<Real> & x,Real & tol)166 void Constraint<Real>::applyAdjointHessian(Vector<Real> &huv,
167                                            const Vector<Real> &u,
168                                            const Vector<Real> &v,
169                                            const Vector<Real> &x,
170                                            Real &tol ) {
171   // Get step length.
172   Real h = std::max(static_cast<Real>(1),x.norm()/v.norm())*tol;
173 
174   // Compute constraint Jacobian at x.
175   ROL::Ptr<Vector<Real> > aju = huv.clone();
176   applyAdjointJacobian(*aju,u,x,tol);
177 
178   // Compute new step x + h*v.
179   ROL::Ptr<Vector<Real> > xnew = x.clone();
180   xnew->set(x);
181   xnew->axpy(h,v);
182   update(*xnew);
183 
184   // Compute constraint Jacobian at x + h*v.
185   huv.zero();
186   applyAdjointJacobian(huv,u,*xnew,tol);
187 
188   // Compute Newton quotient.
189   huv.axpy(static_cast<Real>(-1),*aju);
190   huv.scale(static_cast<Real>(1)/h);
191 }
192 
193 
194 template <class Real>
solveAugmentedSystem(Vector<Real> & v1,Vector<Real> & v2,const Vector<Real> & b1,const Vector<Real> & b2,const Vector<Real> & x,Real & tol)195 std::vector<Real> Constraint<Real>::solveAugmentedSystem(Vector<Real> &v1,
196                                                          Vector<Real> &v2,
197                                                          const Vector<Real> &b1,
198                                                          const Vector<Real> &b2,
199                                                          const Vector<Real> &x,
200                                                          Real &tol) {
201 
202   /*** Initialization. ***/
203   const Real zero(0), one(1);
204   int m = 200;           // Krylov space size.
205   Real zerotol = zero;
206   int i = 0;
207   int k = 0;
208   Real temp = zero;
209   Real resnrm = zero;
210 
211   //tol = std::sqrt(b1.dot(b1)+b2.dot(b2))*1e-8;
212   tol = std::sqrt(b1.dot(b1)+b2.dot(b2))*tol;
213 
214   // Set initial guess to zero.
215   v1.zero(); v2.zero();
216 
217   // Allocate static memory.
218   ROL::Ptr<Vector<Real> > r1 = b1.clone();
219   ROL::Ptr<Vector<Real> > r2 = b2.clone();
220   ROL::Ptr<Vector<Real> > z1 = v1.clone();
221   ROL::Ptr<Vector<Real> > z2 = v2.clone();
222   ROL::Ptr<Vector<Real> > w1 = b1.clone();
223   ROL::Ptr<Vector<Real> > w2 = b2.clone();
224   std::vector<ROL::Ptr<Vector<Real> > > V1;
225   std::vector<ROL::Ptr<Vector<Real> > > V2;
226   ROL::Ptr<Vector<Real> > V2temp = b2.clone();
227   std::vector<ROL::Ptr<Vector<Real> > > Z1;
228   std::vector<ROL::Ptr<Vector<Real> > > Z2;
229   ROL::Ptr<Vector<Real> > w1temp = b1.clone();
230   ROL::Ptr<Vector<Real> > Z2temp = v2.clone();
231 
232   std::vector<Real> res(m+1, zero);
233   LA::Matrix<Real> H(m+1,m);
234   LA::Vector<Real> cs(m);
235   LA::Vector<Real> sn(m);
236   LA::Vector<Real> s(m+1);
237   LA::Vector<Real> y(m+1);
238   LA::Vector<Real> cnorm(m);
239   ROL::LAPACK<int, Real> lapack;
240 
241   // Compute initial residual.
242   applyAdjointJacobian(*r1, v2, x, zerotol);
243   r1->scale(-one); r1->axpy(-one, v1.dual()); r1->plus(b1);
244   applyJacobian(*r2, v1, x, zerotol);
245   r2->scale(-one); r2->plus(b2);
246   res[0] = std::sqrt(r1->dot(*r1) + r2->dot(*r2));
247 
248   // Check if residual is identically zero.
249   if (res[0] == zero) {
250     res.resize(0);
251     return res;
252   }
253 
254   V1.push_back(b1.clone()); (V1[0])->set(*r1); (V1[0])->scale(one/res[0]);
255   V2.push_back(b2.clone()); (V2[0])->set(*r2); (V2[0])->scale(one/res[0]);
256 
257   s(0) = res[0];
258 
259   for (i=0; i<m; i++) {
260 
261     // Apply right preconditioner.
262     V2temp->set(*(V2[i]));
263     applyPreconditioner(*Z2temp, *V2temp, x, b1, zerotol);
264     Z2.push_back(v2.clone()); (Z2[i])->set(*Z2temp);
265     Z1.push_back(v1.clone()); (Z1[i])->set((V1[i])->dual());
266 
267     // Apply operator.
268     applyJacobian(*w2, *(Z1[i]), x, zerotol);
269     applyAdjointJacobian(*w1temp, *Z2temp, x, zerotol);
270     w1->set(*(V1[i])); w1->plus(*w1temp);
271 
272     // Evaluate coefficients and orthogonalize using Gram-Schmidt.
273     for (k=0; k<=i; k++) {
274       H(k,i) = w1->dot(*(V1[k])) + w2->dot(*(V2[k]));
275       w1->axpy(-H(k,i), *(V1[k]));
276       w2->axpy(-H(k,i), *(V2[k]));
277     }
278     H(i+1,i) = std::sqrt(w1->dot(*w1) + w2->dot(*w2));
279 
280     V1.push_back(b1.clone()); (V1[i+1])->set(*w1); (V1[i+1])->scale(one/H(i+1,i));
281     V2.push_back(b2.clone()); (V2[i+1])->set(*w2); (V2[i+1])->scale(one/H(i+1,i));
282 
283     // Apply Givens rotations.
284     for (k=0; k<=i-1; k++) {
285       temp     = cs(k)*H(k,i) + sn(k)*H(k+1,i);
286       H(k+1,i) = -sn(k)*H(k,i) + cs(k)*H(k+1,i);
287       H(k,i)   = temp;
288     }
289 
290     // Form i-th rotation matrix.
291     if ( H(i+1,i) == zero ) {
292       cs(i) = one;
293       sn(i) = zero;
294     }
295     else if ( std::abs(H(i+1,i)) > std::abs(H(i,i)) ) {
296       temp = H(i,i) / H(i+1,i);
297       sn(i) = one / std::sqrt( one + temp*temp );
298       cs(i) = temp * sn(i);
299     }
300     else {
301       temp = H(i+1,i) / H(i,i);
302       cs(i) = one / std::sqrt( one + temp*temp );
303       sn(i) = temp * cs(i);
304     }
305 
306     // Approximate residual norm.
307     temp     = cs(i)*s(i);
308     s(i+1)   = -sn(i)*s(i);
309     s(i)     = temp;
310     H(i,i)   = cs(i)*H(i,i) + sn(i)*H(i+1,i);
311     H(i+1,i) = zero;
312     resnrm   = std::abs(s(i+1));
313     res[i+1] = resnrm;
314 
315     // Update solution approximation.
316     const char uplo = 'U';
317     const char trans = 'N';
318     const char diag = 'N';
319     const char normin = 'N';
320     Real scaling = zero;
321     int info = 0;
322     y = s;
323     lapack.LATRS(uplo, trans, diag, normin, i+1, H.values(), m+1, y.values(), &scaling, cnorm.values(), &info);
324     z1->zero();
325     z2->zero();
326     for (k=0; k<=i; k++) {
327       z1->axpy(y(k), *(Z1[k]));
328       z2->axpy(y(k), *(Z2[k]));
329     }
330 
331     // Evaluate special stopping condition.
332     //tol = ???;
333 
334 //    std::cout << "  " << i+1 << ": " << res[i+1]/res[0] << std::endl;
335     if (res[i+1] <= tol) {
336 //      std::cout << "  solved in " << i+1 << " iterations to " << res[i+1] << " (" << res[i+1]/res[0] << ")" << std::endl;
337       // Update solution vector.
338       v1.plus(*z1);
339       v2.plus(*z2);
340       break;
341     }
342 
343   } // for (int i=0; i++; i<m)
344 
345   res.resize(i+2);
346 
347   /*
348   std::stringstream hist;
349   hist << std::scientific << std::setprecision(8);
350   hist << "\n    Augmented System Solver:\n";
351   hist << "    Iter Residual\n";
352   for (unsigned j=0; j<res.size(); j++) {
353     hist << "    " << std::left << std::setw(14) << res[j] << "\n";
354   }
355   hist << "\n";
356   std::cout << hist.str();
357   */
358 
359   return res;
360 }
361 
362 
363 template <class Real>
checkApplyJacobian(const Vector<Real> & x,const Vector<Real> & v,const Vector<Real> & jv,const bool printToStream,std::ostream & outStream,const int numSteps,const int order)364 std::vector<std::vector<Real> > Constraint<Real>::checkApplyJacobian(const Vector<Real> &x,
365                                                                      const Vector<Real> &v,
366                                                                      const Vector<Real> &jv,
367                                                                      const bool printToStream,
368                                                                      std::ostream & outStream,
369                                                                      const int numSteps,
370                                                                      const int order) {
371   std::vector<Real> steps(numSteps);
372   for(int i=0;i<numSteps;++i) {
373     steps[i] = pow(10,-i);
374   }
375 
376   return checkApplyJacobian(x,v,jv,steps,printToStream,outStream,order);
377 }
378 
379 
380 
381 
382 template <class Real>
checkApplyJacobian(const Vector<Real> & x,const Vector<Real> & v,const Vector<Real> & jv,const std::vector<Real> & steps,const bool printToStream,std::ostream & outStream,const int order)383 std::vector<std::vector<Real> > Constraint<Real>::checkApplyJacobian(const Vector<Real> &x,
384                                                                      const Vector<Real> &v,
385                                                                      const Vector<Real> &jv,
386                                                                      const std::vector<Real> &steps,
387                                                                      const bool printToStream,
388                                                                      std::ostream & outStream,
389                                                                      const int order) {
390   ROL_TEST_FOR_EXCEPTION( order<1 || order>4, std::invalid_argument,
391                               "Error: finite difference order must be 1,2,3, or 4" );
392 
393   const Real one(1.0);
394 
395   using Finite_Difference_Arrays::shifts;
396   using Finite_Difference_Arrays::weights;
397 
398   Real tol = std::sqrt(ROL_EPSILON<Real>());
399 
400   int numSteps = steps.size();
401   int numVals = 4;
402   std::vector<Real> tmp(numVals);
403   std::vector<std::vector<Real> > jvCheck(numSteps, tmp);
404 
405   // Save the format state of the original outStream.
406   ROL::nullstream oldFormatState;
407   oldFormatState.copyfmt(outStream);
408 
409   // Compute constraint value at x.
410   ROL::Ptr<Vector<Real> > c = jv.clone();
411   this->update(x);
412   this->value(*c, x, tol);
413 
414   // Compute (Jacobian at x) times (vector v).
415   ROL::Ptr<Vector<Real> > Jv = jv.clone();
416   this->applyJacobian(*Jv, v, x, tol);
417   Real normJv = Jv->norm();
418 
419   // Temporary vectors.
420   ROL::Ptr<Vector<Real> > cdif = jv.clone();
421   ROL::Ptr<Vector<Real> > cnew = jv.clone();
422   ROL::Ptr<Vector<Real> > xnew = x.clone();
423 
424   for (int i=0; i<numSteps; i++) {
425 
426     Real eta = steps[i];
427 
428     xnew->set(x);
429 
430     cdif->set(*c);
431     cdif->scale(weights[order-1][0]);
432 
433     for(int j=0; j<order; ++j) {
434 
435        xnew->axpy(eta*shifts[order-1][j], v);
436 
437        if( weights[order-1][j+1] != 0 ) {
438            this->update(*xnew);
439            this->value(*cnew,*xnew,tol);
440            cdif->axpy(weights[order-1][j+1],*cnew);
441        }
442 
443     }
444 
445     cdif->scale(one/eta);
446 
447     // Compute norms of Jacobian-vector products, finite-difference approximations, and error.
448     jvCheck[i][0] = eta;
449     jvCheck[i][1] = normJv;
450     jvCheck[i][2] = cdif->norm();
451     cdif->axpy(-one, *Jv);
452     jvCheck[i][3] = cdif->norm();
453 
454     if (printToStream) {
455       std::stringstream hist;
456       if (i==0) {
457       hist << std::right
458            << std::setw(20) << "Step size"
459            << std::setw(20) << "norm(Jac*vec)"
460            << std::setw(20) << "norm(FD approx)"
461            << std::setw(20) << "norm(abs error)"
462            << "\n"
463            << std::setw(20) << "---------"
464            << std::setw(20) << "-------------"
465            << std::setw(20) << "---------------"
466            << std::setw(20) << "---------------"
467            << "\n";
468       }
469       hist << std::scientific << std::setprecision(11) << std::right
470            << std::setw(20) << jvCheck[i][0]
471            << std::setw(20) << jvCheck[i][1]
472            << std::setw(20) << jvCheck[i][2]
473            << std::setw(20) << jvCheck[i][3]
474            << "\n";
475       outStream << hist.str();
476     }
477 
478   }
479 
480   // Reset format state of outStream.
481   outStream.copyfmt(oldFormatState);
482 
483   return jvCheck;
484 } // checkApplyJacobian
485 
486 
487 template <class Real>
checkApplyAdjointJacobian(const Vector<Real> & x,const Vector<Real> & v,const Vector<Real> & c,const Vector<Real> & ajv,const bool printToStream,std::ostream & outStream,const int numSteps)488 std::vector<std::vector<Real> > Constraint<Real>::checkApplyAdjointJacobian(const Vector<Real> &x,
489                                                                             const Vector<Real> &v,
490                                                                             const Vector<Real> &c,
491                                                                             const Vector<Real> &ajv,
492                                                                             const bool printToStream,
493                                                                             std::ostream & outStream,
494                                                                             const int numSteps) {
495   Real tol = std::sqrt(ROL_EPSILON<Real>());
496   const Real one(1);
497 
498   int numVals = 4;
499   std::vector<Real> tmp(numVals);
500   std::vector<std::vector<Real> > ajvCheck(numSteps, tmp);
501   Real eta_factor = 1e-1;
502   Real eta = one;
503 
504   // Temporary vectors.
505   ROL::Ptr<Vector<Real> > c0   = c.clone();
506   ROL::Ptr<Vector<Real> > cnew = c.clone();
507   ROL::Ptr<Vector<Real> > xnew = x.clone();
508   ROL::Ptr<Vector<Real> > ajv0 = ajv.clone();
509   ROL::Ptr<Vector<Real> > ajv1 = ajv.clone();
510   ROL::Ptr<Vector<Real> > ex   = x.clone();
511   ROL::Ptr<Vector<Real> > eajv = ajv.clone();
512 
513   // Save the format state of the original outStream.
514   ROL::nullstream oldFormatState;
515   oldFormatState.copyfmt(outStream);
516 
517   // Compute constraint value at x.
518   this->update(x);
519   this->value(*c0, x, tol);
520 
521   // Compute (Jacobian at x) times (vector v).
522   this->applyAdjointJacobian(*ajv0, v, x, tol);
523   Real normAJv = ajv0->norm();
524 
525   for (int i=0; i<numSteps; i++) {
526 
527     ajv1->zero();
528 
529     for ( int j = 0; j < ajv.dimension(); j++ ) {
530       ex = x.basis(j);
531       eajv = ajv.basis(j);
532       xnew->set(x);
533       xnew->axpy(eta,*ex);
534       this->update(*xnew);
535       this->value(*cnew,*xnew,tol);
536       cnew->axpy(-one,*c0);
537       cnew->scale(one/eta);
538       ajv1->axpy(cnew->dot(v.dual()),*eajv);
539     }
540 
541     // Compute norms of Jacobian-vector products, finite-difference approximations, and error.
542     ajvCheck[i][0] = eta;
543     ajvCheck[i][1] = normAJv;
544     ajvCheck[i][2] = ajv1->norm();
545     ajv1->axpy(-one, *ajv0);
546     ajvCheck[i][3] = ajv1->norm();
547 
548     if (printToStream) {
549       std::stringstream hist;
550       if (i==0) {
551       hist << std::right
552            << std::setw(20) << "Step size"
553            << std::setw(20) << "norm(adj(Jac)*vec)"
554            << std::setw(20) << "norm(FD approx)"
555            << std::setw(20) << "norm(abs error)"
556            << "\n"
557            << std::setw(20) << "---------"
558            << std::setw(20) << "------------------"
559            << std::setw(20) << "---------------"
560            << std::setw(20) << "---------------"
561            << "\n";
562       }
563       hist << std::scientific << std::setprecision(11) << std::right
564            << std::setw(20) << ajvCheck[i][0]
565            << std::setw(20) << ajvCheck[i][1]
566            << std::setw(20) << ajvCheck[i][2]
567            << std::setw(20) << ajvCheck[i][3]
568            << "\n";
569       outStream << hist.str();
570     }
571 
572     // Update eta.
573     eta = eta*eta_factor;
574   }
575 
576   // Reset format state of outStream.
577   outStream.copyfmt(oldFormatState);
578 
579   return ajvCheck;
580 } // checkApplyAdjointJacobian
581 
582 template <class Real>
checkAdjointConsistencyJacobian(const Vector<Real> & w,const Vector<Real> & v,const Vector<Real> & x,const Vector<Real> & dualw,const Vector<Real> & dualv,const bool printToStream,std::ostream & outStream)583 Real Constraint<Real>::checkAdjointConsistencyJacobian(const Vector<Real> &w,
584                                                        const Vector<Real> &v,
585                                                        const Vector<Real> &x,
586                                                        const Vector<Real> &dualw,
587                                                        const Vector<Real> &dualv,
588                                                        const bool printToStream,
589                                                        std::ostream & outStream) {
590   Real tol = ROL_EPSILON<Real>();
591 
592   ROL::Ptr<Vector<Real> > Jv = dualw.clone();
593   ROL::Ptr<Vector<Real> > Jw = dualv.clone();
594 
595   this->update(x);
596   applyJacobian(*Jv,v,x,tol);
597   applyAdjointJacobian(*Jw,w,x,tol);
598 
599   Real vJw = v.dot(Jw->dual());
600   Real wJv = w.dot(Jv->dual());
601 
602   Real diff = std::abs(wJv-vJw);
603 
604   if ( printToStream ) {
605     std::stringstream hist;
606     hist << std::scientific << std::setprecision(8);
607     hist << "\nTest Consistency of Jacobian and its adjoint: \n  |<w,Jv> - <adj(J)w,v>| = "
608          << diff << "\n";
609     hist << "  |<w,Jv>|               = " << std::abs(wJv) << "\n";
610     hist << "  Relative Error         = " << diff / (std::abs(wJv)+ROL_UNDERFLOW<Real>()) << "\n";
611     outStream << hist.str();
612   }
613   return diff;
614 } // checkAdjointConsistencyJacobian
615 
616 template <class Real>
checkApplyAdjointHessian(const Vector<Real> & x,const Vector<Real> & u,const Vector<Real> & v,const Vector<Real> & hv,const bool printToStream,std::ostream & outStream,const int numSteps,const int order)617 std::vector<std::vector<Real> > Constraint<Real>::checkApplyAdjointHessian(const Vector<Real> &x,
618                                                                            const Vector<Real> &u,
619                                                                            const Vector<Real> &v,
620                                                                            const Vector<Real> &hv,
621                                                                            const bool printToStream,
622                                                                            std::ostream & outStream,
623                                                                            const int numSteps,
624                                                                            const int order) {
625   std::vector<Real> steps(numSteps);
626   for(int i=0;i<numSteps;++i) {
627     steps[i] = pow(10,-i);
628   }
629 
630   return checkApplyAdjointHessian(x,u,v,hv,steps,printToStream,outStream,order);
631 }
632 
633 
634 template <class Real>
checkApplyAdjointHessian(const Vector<Real> & x,const Vector<Real> & u,const Vector<Real> & v,const Vector<Real> & hv,const std::vector<Real> & steps,const bool printToStream,std::ostream & outStream,const int order)635 std::vector<std::vector<Real> > Constraint<Real>::checkApplyAdjointHessian(const Vector<Real> &x,
636                                                                            const Vector<Real> &u,
637                                                                            const Vector<Real> &v,
638                                                                            const Vector<Real> &hv,
639                                                                            const std::vector<Real> &steps,
640                                                                            const bool printToStream,
641                                                                            std::ostream & outStream,
642                                                                            const int order) {
643   using Finite_Difference_Arrays::shifts;
644   using Finite_Difference_Arrays::weights;
645 
646   const Real one(1);
647   Real tol = std::sqrt(ROL_EPSILON<Real>());
648 
649   int numSteps = steps.size();
650   int numVals = 4;
651   std::vector<Real> tmp(numVals);
652   std::vector<std::vector<Real> > ahuvCheck(numSteps, tmp);
653 
654   // Temporary vectors.
655   ROL::Ptr<Vector<Real> > AJdif = hv.clone();
656   ROL::Ptr<Vector<Real> > AJu = hv.clone();
657   ROL::Ptr<Vector<Real> > AHuv = hv.clone();
658   ROL::Ptr<Vector<Real> > AJnew = hv.clone();
659   ROL::Ptr<Vector<Real> > xnew = x.clone();
660 
661   // Save the format state of the original outStream.
662   ROL::nullstream oldFormatState;
663   oldFormatState.copyfmt(outStream);
664 
665   // Apply adjoint Jacobian to u.
666   this->update(x);
667   this->applyAdjointJacobian(*AJu, u, x, tol);
668 
669   // Apply adjoint Hessian at x, in direction v, to u.
670   this->applyAdjointHessian(*AHuv, u, v, x, tol);
671   Real normAHuv = AHuv->norm();
672 
673   for (int i=0; i<numSteps; i++) {
674 
675     Real eta = steps[i];
676 
677     // Apply adjoint Jacobian to u at x+eta*v.
678     xnew->set(x);
679 
680     AJdif->set(*AJu);
681     AJdif->scale(weights[order-1][0]);
682 
683     for(int j=0; j<order; ++j) {
684 
685         xnew->axpy(eta*shifts[order-1][j],v);
686 
687         if( weights[order-1][j+1] != 0 ) {
688             this->update(*xnew);
689             this->applyAdjointJacobian(*AJnew, u, *xnew, tol);
690             AJdif->axpy(weights[order-1][j+1],*AJnew);
691         }
692     }
693 
694     AJdif->scale(one/eta);
695 
696     // Compute norms of Jacobian-vector products, finite-difference approximations, and error.
697     ahuvCheck[i][0] = eta;
698     ahuvCheck[i][1] = normAHuv;
699     ahuvCheck[i][2] = AJdif->norm();
700     AJdif->axpy(-one, *AHuv);
701     ahuvCheck[i][3] = AJdif->norm();
702 
703     if (printToStream) {
704       std::stringstream hist;
705       if (i==0) {
706       hist << std::right
707            << std::setw(20) << "Step size"
708            << std::setw(20) << "norm(adj(H)(u,v))"
709            << std::setw(20) << "norm(FD approx)"
710            << std::setw(20) << "norm(abs error)"
711            << "\n"
712            << std::setw(20) << "---------"
713            << std::setw(20) << "-----------------"
714            << std::setw(20) << "---------------"
715            << std::setw(20) << "---------------"
716            << "\n";
717       }
718       hist << std::scientific << std::setprecision(11) << std::right
719            << std::setw(20) << ahuvCheck[i][0]
720            << std::setw(20) << ahuvCheck[i][1]
721            << std::setw(20) << ahuvCheck[i][2]
722            << std::setw(20) << ahuvCheck[i][3]
723            << "\n";
724       outStream << hist.str();
725     }
726 
727   }
728 
729   // Reset format state of outStream.
730   outStream.copyfmt(oldFormatState);
731 
732   return ahuvCheck;
733 } // checkApplyAdjointHessian
734 
735 } // namespace ROL
736 
737 #endif
738