ROL
ROL_PrimalDualInteriorPointResidual.hpp
Go to the documentation of this file.
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 #ifndef ROL_PRIMALDUALINTERIORPOINTRESIDUAL_H
45 #define ROL_PRIMALDUALINTERIORPOINTRESIDUAL_H
46 
47 #include "ROL_BoundConstraint.hpp"
48 #include "ROL_Constraint.hpp"
49 #include "ROL_Objective.hpp"
51 #include "ROL_RandomVector.hpp"
52 
53 #include <iostream>
54 
75 namespace ROL {
76 
77 template<class Real>
78 class PrimalDualInteriorPointResidual : public Constraint<Real> {
79 
80  typedef ROL::ParameterList PL;
81 
82  typedef Vector<Real> V;
87 
88  typedef Elementwise::ValueSet<Real> ValueSet;
89 
90  typedef typename PV::size_type size_type;
91 
92 private:
93 
94  static const size_type OPT = 0;
95  static const size_type EQUAL = 1;
96  static const size_type LOWER = 2;
97  static const size_type UPPER = 3;
98 
99  const ROL::Ptr<OBJ> obj_;
100  const ROL::Ptr<CON> con_;
101  const ROL::Ptr<BND> bnd_;
102 
103  ROL::Ptr<const V> x_; // Optimization vector
104  ROL::Ptr<const V> l_; // constraint multiplier
105  ROL::Ptr<const V> zl_; // Lower bound multiplier
106  ROL::Ptr<const V> zu_; // Upper bound multiplier
107 
108  ROL::Ptr<const V> xl_; // Lower bound
109  ROL::Ptr<const V> xu_; // Upper bound
110 
111  const ROL::Ptr<const V> maskL_;
112  const ROL::Ptr<const V> maskU_;
113 
114  ROL::Ptr<V> scratch_; // Scratch vector the same dimension as x
115 
116  Real mu_;
117 
119 
120  Real one_;
121  Real zero_;
122 
123  int nfval_;
124  int ngrad_;
125  int ncval_;
126 
127  Elementwise::Multiply<Real> mult_;
128 
129  class SafeDivide : public Elementwise::BinaryFunction<Real> {
130  public:
131  Real apply( const Real &x, const Real &y ) const {
132  return y != 0 ? x/y : 0;
133  }
134  };
135 
137 
138  class SetZeros : public Elementwise::BinaryFunction<Real> {
139  public:
140  Real apply( const Real &x, const Real &y ) const {
141  return y==1.0 ? 0 : x;
142  }
143  };
144 
146 
147  // Fill in zeros of x with corresponding values of y
148  class InFill : public Elementwise::BinaryFunction<Real> {
149  public:
150  Real apply( const Real &x, const Real &y ) const {
151  return x == 0 ? y : x;
152  }
153  };
154 
156 
157  // Extract the optimization and lagrange multiplier
158  ROL::Ptr<V> getOptMult( V &vec ) {
159  PV &vec_pv = dynamic_cast<PV&>(vec);
160 
161  return CreatePartitioned(vec_pv.get(OPT),vec_pv.get(EQUAL));
162  }
163 
164  // Extract the optimization and lagrange multiplier
165  ROL::Ptr<const V> getOptMult( const V &vec ) {
166  const PV &vec_pv = dynamic_cast<const PV&>(vec);
167 
168  return CreatePartitioned(vec_pv.get(OPT),vec_pv.get(EQUAL));
169  }
170 
171 
172 
173 
174 public:
175 
176  PrimalDualInteriorPointResidual( const ROL::Ptr<OBJ> &obj,
177  const ROL::Ptr<CON> &con,
178  const ROL::Ptr<BND> &bnd,
179  const V &x,
180  const ROL::Ptr<const V> &maskL,
181  const ROL::Ptr<const V> &maskU,
182  ROL::Ptr<V> &scratch,
183  Real mu, bool symmetrize ) :
184  obj_(obj), con_(con), bnd_(bnd), xl_(bnd->getLowerBound()),
185  xu_(bnd->getUpperBound()), maskL_(maskL), maskU_(maskU), scratch_(scratch),
186  mu_(mu), symmetrize_(symmetrize), one_(1.0), zero_(0.0), nfval_(0),
187  ngrad_(0), ncval_(0) {
188 
189  // Get access to the four components
190  const PV &x_pv = dynamic_cast<const PV&>(x);
191 
192  x_ = x_pv.get(OPT);
193  l_ = x_pv.get(EQUAL);
194  zl_ = x_pv.get(LOWER);
195  zu_ = x_pv.get(UPPER);
196 
197  }
198 
199 
200  void update( const Vector<Real> &x, bool flag = true, int iter = -1 ) {
201 
202  // Get access to the four components
203  const PV &x_pv = dynamic_cast<const PV&>(x);
204 
205  x_ = x_pv.get(OPT);
206  l_ = x_pv.get(EQUAL);
207  zl_ = x_pv.get(LOWER);
208  zu_ = x_pv.get(UPPER);
209 
210  obj_->update(*x_,flag,iter);
211  con_->update(*x_,flag,iter);
212 
213  }
214 
215 
216  // Evaluate the gradient of the Lagrangian
217  void value( V &c, const V &x, Real &tol ) {
218 
219 
220 
221  Elementwise::Shift<Real> subtract_mu(-mu_);
222  Elementwise::Fill<Real> fill_minus_mu(-mu_);
223 
224  const PV &x_pv = dynamic_cast<const PV&>(x);
225  PV &c_pv = dynamic_cast<PV&>(c);
226 
227  x_ = x_pv.get(OPT);
228  l_ = x_pv.get(EQUAL);
229  zl_ = x_pv.get(LOWER);
230  zu_ = x_pv.get(UPPER);
231 
232  ROL::Ptr<V> cx = c_pv.get(OPT);
233  ROL::Ptr<V> cl = c_pv.get(EQUAL);
234  ROL::Ptr<V> czl = c_pv.get(LOWER);
235  ROL::Ptr<V> czu = c_pv.get(UPPER);
236 
237  /********************************************************************************/
238  /* Optimization Components */
239  /********************************************************************************/
240  obj_->gradient(*cx,*x_,tol);
241  ngrad_++;
242 
243  con_->applyAdjointJacobian(*scratch_,*l_,*x_,tol);
244 
245  cx->plus(*scratch_);
246 
247  cx->axpy(-one_,*zl_);
248  cx->plus(*zu_); // cx = g+J'l-zl+zu
249 
250  /********************************************************************************/
251  /* Constraint Components */
252  /********************************************************************************/
253 
254  con_->value(*cl,*x_,tol);
255  ncval_++;
256 
257  /********************************************************************************/
258  /* Lower Bound Components */
259  /********************************************************************************/
260  if( symmetrize_ ) { // -(x-l)+mu/zl
261 
262  czl->applyUnary(fill_minus_mu);
263  czl->applyBinary(div_,*zl_);
264 
265  scratch_->set(*x_);
266  scratch_->axpy(-1.0,*xl_);
267 
268  czl->plus(*scratch_);
269  czl->scale(-1.0);
270  }
271  else { // czl = zl*(x-l)-mu*e
272  czl->set(*x_); // czl = x
273  czl->axpy(-1.0,*xl_); // czl = x-l
274  czl->applyBinary(mult_,*zl_); // czl = zl*(x-l)
275  czl->applyUnary(subtract_mu); // czl = zl*(x-l)-mu*e
276  }
277 
278  // Zero out elements corresponding to infinite lower bounds
279  czl->applyBinary(mult_,*maskL_);
280 
281  /********************************************************************************/
282  /* Upper Bound Components */
283  /********************************************************************************/
284  if( symmetrize_ ) { // -(u-x)+mu/zu
285 
286  czu->applyUnary(fill_minus_mu);
287  czu->applyBinary(div_,*zu_);
288 
289  scratch_->set(*xu_);
290  scratch_->axpy(-1.0, *x_);
291 
292  czu->plus(*scratch_);
293  czu->scale(-1.0);
294  }
295  else { // zu*(u-x)-mu*e
296  czu->set(*xu_); // czu = u
297  czu->axpy(-1.0,*x_); // czu = u-x
298  czu->applyBinary(mult_,*zu_); // czu = zu*(u-x)
299  czu->applyUnary(subtract_mu); // czu = zu*(u-x)-mu*e
300  }
301 
302  // Zero out elements corresponding to infinite upper bounds
303  czu->applyBinary(mult_,*maskU_);
304 
305  }
306 
307  // Evaluate the action of the Hessian of the Lagrangian on a vector
308  //
309  // [ J11 J12 J13 J14 ] [ vx ] [ jvx ] [ J11*vx + J12*vl + J13*vzl + J14*vzu ]
310  // [ J21 0 0 0 ] [ vl ] = [ jvl ] = [ J21*vx ]
311  // [ J31 0 J33 0 ] [ vzl ] [ jvzl ] [ J31*vx + J33*vzl ]
312  // [ J41 0 0 J44 ] [ vzu ] [ jvzu ] [ J41*vx + J44*vzu ]
313  //
314  void applyJacobian( V &jv, const V &v, const V &x, Real &tol ) {
315 
316 
317 
318  PV &jv_pv = dynamic_cast<PV&>(jv);
319  const PV &v_pv = dynamic_cast<const PV&>(v);
320  const PV &x_pv = dynamic_cast<const PV&>(x);
321 
322  // output vector components
323  ROL::Ptr<V> jvx = jv_pv.get(OPT);
324  ROL::Ptr<V> jvl = jv_pv.get(EQUAL);
325  ROL::Ptr<V> jvzl = jv_pv.get(LOWER);
326  ROL::Ptr<V> jvzu = jv_pv.get(UPPER);
327 
328  // input vector components
329  ROL::Ptr<const V> vx = v_pv.get(OPT);
330  ROL::Ptr<const V> vl = v_pv.get(EQUAL);
331  ROL::Ptr<const V> vzl = v_pv.get(LOWER);
332  ROL::Ptr<const V> vzu = v_pv.get(UPPER);
333 
334  x_ = x_pv.get(OPT);
335  l_ = x_pv.get(EQUAL);
336  zl_ = x_pv.get(LOWER);
337  zu_ = x_pv.get(UPPER);
338 
339 
340  /********************************************************************************/
341  /* Optimization Components */
342  /********************************************************************************/
343 
344  obj_->hessVec(*jvx,*vx,*x_,tol);
345  con_->applyAdjointHessian(*scratch_,*l_,*vx,*x_,tol);
346  jvx->plus(*scratch_);
347  con_->applyAdjointJacobian(*scratch_,*vl,*x_,tol);
348  jvx->plus(*scratch_);
349 
350  // H_13 = -I for l_i > -infty
351  scratch_->set(*vzl);
352  scratch_->applyBinary(mult_,*maskL_);
353  jvx->axpy(-1.0,*scratch_);
354 
355  // H_14 = I for u_i < infty
356  scratch_->set(*vzu);
357  scratch_->applyBinary(mult_,*maskU_);
358  jvx->plus(*scratch_);
359 
360  /********************************************************************************/
361  /* Constraint Components */
362  /********************************************************************************/
363 
364  con_->applyJacobian(*jvl,*vx,*x_,tol);
365 
366  /********************************************************************************/
367  /* Lower Bound Components */
368  /********************************************************************************/
369 
370  if( symmetrize_ ) {
371  // czl = x-l-mu/zl
372  // jvzl = -vx - inv(Zl)*(X-L)*vzl
373 
374  jvzl->set(*x_);
375  jvzl->axpy(-1.0,*xl_);
376  jvzl->applyBinary(mult_,*vzl);
377  jvzl->applyBinary(div_,*zl_);
378 
379  jvzl->plus(*vx);
380  jvzl->scale(-1.0);
381 
382  }
383 
384  else {
385  // czl = zl*(x-l)-mu*e
386  // jvzl = Zl*vx + (X-L)*vzl
387 
388  // H_31 = Zl
389  jvzl->set(*vx);
390  jvzl->applyBinary(mult_,*zl_);
391 
392  // H_33 = X-L
393  scratch_->set(*x_);
394  scratch_->axpy(-1.0,*xl_);
395  scratch_->applyBinary(mult_,*vzl);
396 
397  jvzl->plus(*scratch_);
398 
399  }
400 
401  // jvzl[i] = vzl[i] if l[i] = -inf
402  jvzl->applyBinary(mult_,*maskL_);
403  jvzl->applyBinary(inFill_,*vzl);
404 
405  /********************************************************************************/
406  /* Upper Bound Components */
407  /********************************************************************************/
408 
409  if( symmetrize_ ) {
410  // czu = u-x-mu/zu
411  // jvzu = vx - inv(Zu)*(U-X)*vzu
412 
413  jvzu->set(*xu_);
414  jvzu->axpy(-1.0,*x_);
415  jvzu->applyBinary(mult_,*vzu);
416  jvzu->applyBinary(div_,*zu_);
417  jvzu->scale(-1.0);
418  jvzu->plus(*vx);
419 
420  }
421  else {
422  // czu = zu*(u-x)-mu*e
423  // jvzu = -Zu*vx + (U-X)*vzu
424 
425  // H_41 = -Zu
426  scratch_->set(*zu_);
427  scratch_->applyBinary(mult_,*vx);
428 
429  // H_44 = U-X
430  jvzu->set(*xu_);
431  jvzu->axpy(-1.0,*x_);
432  jvzu->applyBinary(mult_,*vzu);
433 
434  jvzu->axpy(-1.0,*scratch_);
435 
436  }
437 
438  // jvzu[i] = vzu[i] if u[i] = inf
439  jvzu->applyBinary(mult_,*maskU_);
440  jvzu->applyBinary(inFill_,*vzu);
441 
442  }
443 
444  // Call this whenever mu changes
445  void reset( const Real mu ) {
446  mu_ = mu;
447  nfval_ = 0;
448  ngrad_ = 0;
449  ncval_ = 0;
450  }
451 
453  return nfval_;
454  }
455 
457  return ngrad_;
458  }
459 
461  return ncval_;
462  }
463 
464 }; // class PrimalDualInteriorPointResidual
465 
466 } // namespace ROL
467 
468 #endif // ROL_PRIMALDUALINTERIORPOINTRESIDUAL_H
Provides the interface to evaluate objective functions.
void value(V &c, const V &x, Real &tol)
Evaluate the constraint operator at .
ROL::Ptr< const Vector< Real > > get(size_type i) const
Defines the linear algebra of vector space on a generic partitioned vector.
void update(const Vector< Real > &x, bool flag=true, int iter=-1)
Update constraint functions. x is the optimization variable, flag = true if optimization variable is ...
Defines the linear algebra or vector space interface.
Definition: ROL_Vector.hpp:80
PrimalDualInteriorPointResidual(const ROL::Ptr< OBJ > &obj, const ROL::Ptr< CON > &con, const ROL::Ptr< BND > &bnd, const V &x, const ROL::Ptr< const V > &maskL, const ROL::Ptr< const V > &maskU, ROL::Ptr< V > &scratch, Real mu, bool symmetrize)
void applyJacobian(V &jv, const V &v, const V &x, Real &tol)
Apply the constraint Jacobian at , , to vector .
Provides the interface to apply upper and lower bound constraints.
std::vector< PV >::size_type size_type
Defines the general constraint operator interface.