MOOCHO (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NLPInterfacePack_NLPDirectThyraModelEvaluator.cpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Moocho: Multi-functional Object-Oriented arCHitecture for Optimization
5 // Copyright (2003) 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 Roscoe A. Bartlett (rabartl@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
55 #include "Thyra_ModelEvaluatorHelpers.hpp"
56 #include "Thyra_DetachedVectorView.hpp"
57 #include "Thyra_VectorStdOps.hpp"
58 #include "Thyra_MultiVectorStdOps.hpp"
60 #include "Teuchos_Assert.hpp"
61 #include "Teuchos_dyn_cast.hpp"
62 
63 namespace NLPInterfacePack {
64 
66  :DfDp_is_const_(false)
67 {}
68 
70  const Teuchos::RCP<Thyra::ModelEvaluator<value_type> > &model
71  ,const int p_idx
72  ,const int g_idx
73  ,const objDirecFiniteDiffCalculator_ptr_t objDirecFiniteDiffCalculator
74  ,const conDirecFiniteDiffCalculator_ptr_t conDirecFiniteDiffCalculator
75  )
76  :DfDp_is_const_(false)
77 {
78  initialize(
79  model,p_idx,g_idx
80  ,objDirecFiniteDiffCalculator,conDirecFiniteDiffCalculator
81  );
82 }
83 
85  const Teuchos::RCP<Thyra::ModelEvaluator<value_type> > &model
86  ,const int p_idx
87  ,const int g_idx
88  ,const objDirecFiniteDiffCalculator_ptr_t objDirecFiniteDiffCalculator
89  ,const conDirecFiniteDiffCalculator_ptr_t conDirecFiniteDiffCalculator
90  )
91 {
92  typedef Thyra::ModelEvaluatorBase MEB;
93  if(objDirecFiniteDiffCalculator.get())
94  this->set_objDirecFiniteDiffCalculator(objDirecFiniteDiffCalculator);
95  if(conDirecFiniteDiffCalculator.get())
96  this->set_conDirecFiniteDiffCalculator(conDirecFiniteDiffCalculator);
97  initializeBase(model,p_idx,g_idx);
98  Thyra::ModelEvaluatorBase::OutArgs<double> model_outArgs = model->createOutArgs();
99  MEB::DerivativeProperties model_W_properties = model_outArgs.get_W_properties();
100  if( p_idx >= 0 ) {
102  (conDirecFiniteDiffCalculator_.get()==0 && !model_outArgs.supports(MEB::OUT_ARG_DfDp,p_idx).supports(MEB::DERIV_MV_BY_COL))
103  ,std::invalid_argument
104  ,"Error, model must support computing DfDp("<<p_idx<<") as a"
105  " column-oriented multi-vector if not using finite differences!"
106  );
107  }
108  DfDp_is_const_ = false;
109 }
110 
111 // Overridden public members from NLP
112 
114 {
115  if(initialized_) {
116  NLPDirect::initialize(test_setup);
117  return;
118  }
120  NLPDirect::initialize(test_setup);
121 }
122 
124 {
126 }
127 
128 // Overridden public members from NLPObjGrad
129 
131 {
132  if(objDirecFiniteDiffCalculator_.get())
133  return false;
134  return true;
135  // ToDo: Change this to false when only the operator for model_DgDx is
136  // supported!
137 }
138 
140 {
141  return ( objDirecFiniteDiffCalculator_.get() != NULL );
142 }
143 
145  const Vector& x, const Vector& d, bool newx
146  ) const
147 {
148  TEUCHOS_TEST_FOR_EXCEPT(objDirecFiniteDiffCalculator_.get()==0);
149  typedef Thyra::ModelEvaluatorBase MEB;
150  MEB::InArgs<value_type> basePoint = model_->createInArgs();
151  MEB::InArgs<value_type> directions = model_->createInArgs();
152  MEB::OutArgs<value_type> baseFunc = model_->createOutArgs();
153  MEB::OutArgs<value_type> variations = model_->createOutArgs();
154  set_x(x,&basePoint);
155  set_x(d,&directions);
156  variations.set_g(g_idx_,createMember(model_->get_g_space(g_idx_)));
157  objDirecFiniteDiffCalculator_->calcVariations(
158  *model_,basePoint,directions,baseFunc,variations
159  );
160  return Thyra::get_ele(*variations.get_g(g_idx_),0);
161 }
162 
163 // Overridden public members from NLPDirect
164 
166 {
167  return basis_sys_->var_dep();
168 }
169 
171 {
172  return basis_sys_->var_indep();
173 }
174 
177 {
178  return basis_sys_->factory_D();
179 }
180 
183 {
184  return basis_sys_->factory_S();
185 }
186 
188  const Vector &x
189  ,value_type *f
190  ,VectorMutable *c
191  ,bool recalc_c
192  ,VectorMutable *Gf
193  ,VectorMutable *py
194  ,VectorMutable *rGf
195  ,MatrixOp *GcU
196  ,MatrixOp *D
197  ,MatrixOp *Uz
198  ) const
199 {
200  using Teuchos::FancyOStream;
201  using Teuchos::OSTab;
202  using Teuchos::dyn_cast;
203  using Teuchos::RCP;
204  using Teuchos::rcp;
205  using Teuchos::rcp_const_cast;
206  using Teuchos::rcp_dynamic_cast;
212  typedef Thyra::ModelEvaluatorBase MEB;
214  typedef MEB::DerivativeMultiVector<value_type> DerivMV;
215  typedef MEB::Derivative<value_type> Deriv;
216  //
217  // Get output and verbosity
218  //
220  out = this->getOStream();
222  verbLevel = ( showModelEvaluatorTrace() ? this->getVerbLevel() : Teuchos::VERB_NONE );
223  Teuchos::OSTab tab(out);
225  VOTSME modelOutputTempState(model_,out,verbLevel);
227  VOTSDFDC objDirecFiniteDiffCalculatorOutputTempState(objDirecFiniteDiffCalculator_,out,verbLevel);
228  VOTSDFDC conDirecFiniteDiffCalculatorOutputTempState(conDirecFiniteDiffCalculator_,out,verbLevel);
229  const bool trace = static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW);
230  if(out.get() && trace)
231  *out << "\nEntering MoochoPack::NLPDirectThyraModelEvaluator::calc_point(...) ...\n";
232  //
233  // Validate input
234  //
235  TEUCHOS_TEST_FOR_EXCEPT(GcU!=NULL); // Can't handle these yet!
236  TEUCHOS_TEST_FOR_EXCEPT(Uz!=NULL);
238  objDirecFiniteDiffCalculator_.get()!=NULL && Gf!=NULL, std::logic_error
239  ,"Error, can not compute full gradient vector Gf when using directional finite differences!"
240  );
241  //
242  // Compute using derivative objects that come from the underlying model.
243  //
244  // Set the input and output arguments
245  //
246  // ToDo: Disallow computation Gf and instead just compute
247  // the operators for this!
248  //
249  MEB::InArgs<value_type> model_inArgs = model_->createInArgs();
250  MEB::OutArgs<value_type> model_outArgs = model_->createOutArgs();
252  obj_grad_info.Gf = Gf;
253  obj_grad_info.f = f;
254  if(recalc_c) obj_grad_info.c = c;
256  x,true,NULL,&obj_grad_info,NULL
257  ,&model_inArgs,&model_outArgs,NULL,NULL,NULL,NULL
258  );
259  if( py || rGf || D ) {
260  if(thyra_C_.get()==NULL)
261  thyra_C_ = model_->create_W();
262  model_outArgs.set_W(thyra_C_.assert_not_null());
263  }
264  bool new_thyra_N = false;
265  if( rGf || D ) {
266  if(thyra_N_.get()==NULL) {
267  thyra_N_ = Thyra::create_DfDp_mv(*model_,p_idx_,MEB::DERIV_MV_BY_COL).getMultiVector();
268  new_thyra_N = true;
269  }
270  if(
271  !conDirecFiniteDiffCalculator_.get()
272  &&
273  ( new_thyra_N
274  || model_outArgs.get_DfDp_properties(p_idx_).linearity!=MEB::DERIV_LINEARITY_CONST )
275  )
276  {
277  model_outArgs.set_DfDp(p_idx_,DerivMV(thyra_N_.assert_not_null(),MEB::DERIV_MV_BY_COL));
278  }
279  }
280  if ( !is_null(model_outArgs.get_W()) || !is_null(model_outArgs.get_W_op()) ) {
281  if (model_inArgs.supports(MEB::IN_ARG_alpha))
282  model_inArgs.set_alpha(0.0);
283  if (model_inArgs.supports(MEB::IN_ARG_beta))
284  model_inArgs.set_beta(1.0);
285  }
286  //
287  // Evaluate the functions
288  //
289  model_->evalModel(model_inArgs,model_outArgs);
290  //
291  // Postprocess the evaluation
292  //
293  postprocessBaseOutArgs(&model_outArgs,Gf,f,recalc_c?c:NULL);
294  // Setup solve components
295  const VectorSpaceThyra *space_c;
296  const VectorSpaceThyra *space_xD;
299  RCP<MatrixOp> D_used = rcp(D,false);
300  RCP<Thyra::MultiVectorBase<value_type> > thyra_D;
301 
302  if( py || ( ( rGf || D ) && conDirecFiniteDiffCalculator_.get() ) ) {
303  space_c = &dyn_cast<const VectorSpaceThyra>(c->space()),
304  space_xD = &dyn_cast<const VectorSpaceThyra>(py->space());
305  get_thyra_vector(*space_c,*c,&thyra_c);
306  get_thyra_vector(*space_xD,py,&thyra_py);
307  }
308 
309  if( D || rGf ) {
310  if(!D) D_used = this->factory_D()->create();
311  thyra_D =
312  rcp_const_cast<Thyra::MultiVectorBase<value_type> >(
313  rcp_dynamic_cast<const Thyra::MultiVectorBase<value_type> >(
314  dyn_cast<MultiVectorMutableThyra>(*D_used).thyra_multi_vec()
315  )
316  );
317  }
318 
319  if(
320  ( rGf || D )
321  &&
322  !is_null(conDirecFiniteDiffCalculator_)
323  &&
324  ( new_thyra_N || !DfDp_is_const() )
325  )
326  {
327  if(out.get() && trace)
328  *out << "\nComputing thyra_N using directional finite differences ...\n";
329  // !
330  if(thyra_c.get())
331  model_outArgs.set_f(rcp_const_cast<Thyra::VectorBase<value_type> >(thyra_c)); // Okay, will not be changed!
332  typedef Thyra::DirectionalFiniteDiffCalculator<value_type>::SelectedDerivatives SelectedDerivatives;
333  MEB::OutArgs<value_type>
334  model_fdOutArgs = conDirecFiniteDiffCalculator_->createOutArgs(
335  *model_,SelectedDerivatives().supports(MEB::OUT_ARG_DfDp,0)
336  );
337  model_fdOutArgs.set_DfDp(p_idx_,DerivMV(thyra_N_.assert_not_null(),MEB::DERIV_MV_BY_COL));
338  conDirecFiniteDiffCalculator_->calcDerivatives(
339  *model_
340  ,model_inArgs // The base point to compute the derivatives at
341  ,model_outArgs // The base function values
342  ,model_fdOutArgs // The derivatives that we want to compute
343  );
344  }
345  // Perform solve
346  if( ( D || rGf ) && py ) {
347  // Solve for py and D together
348  if(out.get() && trace)
349  *out << "\nSolving C*[py,D] = -[c,N] simultaneously ...\n";
350  const int nind = thyra_N_->domain()->dim();
351  RCP<Thyra::MultiVectorBase<value_type> >
352  thyra_cN = Thyra::createMembers(thyra_N_->range(),nind+1);
353  Thyra::assign(thyra_cN->col(0).ptr(), *thyra_c);
354  Thyra::assign(thyra_cN->subView(Teuchos::Range1D(1,nind)).ptr(), *thyra_N_);
355  RCP<Thyra::MultiVectorBase<value_type> >
356  thyra_pyD = Thyra::createMembers(thyra_D->range(),nind+1);
357  Thyra::assign(thyra_pyD.ptr(), 0.0);
358  Thyra::SolveStatus<value_type>
359  solveStatus = Thyra::solve(*thyra_C_, Thyra::NOTRANS, *thyra_cN, thyra_pyD.ptr());
360  if(out.get() && trace) {
361  *out
362  << "\nsolve status:\n";
363  OSTab(out).o() << solveStatus;
364  }
365  Thyra::scale(-1.0, thyra_pyD.ptr());
366  Thyra::assign(thyra_py.ptr(), *thyra_pyD->col(0));
367  Thyra::assign(thyra_D.ptr(), *thyra_pyD->subView(Teuchos::Range1D(1,nind)));
368  }
369  else {
370  // Solve for py or D
371  if( py ) {
372  if(out.get() && trace)
373  *out << "\nSolving C*py = -c ...\n";
374  Thyra::assign(thyra_py.ptr(), 0.0);
375  Thyra::SolveStatus<value_type> solveStatus =
376  Thyra::solve<value_type>(*thyra_C_, Thyra::NOTRANS, *thyra_c, thyra_py.ptr());
377  if (nonnull(out) && trace) {
378  *out << "\nsolve status:\n";
379  OSTab(out).o() << solveStatus;
380  }
381  Thyra::Vt_S(thyra_py.ptr(), -1.0);
382  }
383  if( D || rGf ) {
384  if(out.get() && trace)
385  *out << "\nSolving C*D = -N ...\n";
386  Thyra::assign(thyra_D.ptr(), 0.0);
387  Thyra::SolveStatus<value_type>
388  solveStatus = Thyra::solve(*thyra_C_, Thyra::NOTRANS, *thyra_N_, thyra_D.ptr());
389  if(out.get() && trace) {
390  *out
391  << "\nsolve status:\n";
392  OSTab(out).o() << solveStatus;
393  }
394  Thyra::scale(-1.0, thyra_D.ptr());
395  }
396  }
397  if(thyra_py.get()) {
398  free_thyra_vector(*space_c,*c,&thyra_c);
399  commit_thyra_vector(*space_xD,py,&thyra_py);
400  }
401  // Compute reduced gradient
402  if(rGf) {
403  // rGf = D' * Gf_xD + Gf_xI
404  const Range1D
405  var_dep = basis_sys_->var_dep(),
406  var_indep = basis_sys_->var_indep();
407  if(objDirecFiniteDiffCalculator_.get()) {
408  if(out.get() && trace)
409  *out << "\nComputing rGf using directional finite differences ...\n";
410  //
411  // Compute each component of the reduced gradient as
412  //
413  // rGf(i) = fd_product( model.g, [ D(:,i); e(i) ] )
414  //
416  TVecPtr e_i = createMember(model_->get_p_space(p_idx_));
417  Thyra::assign(e_i.ptr(), 0.0);
418  MEB::InArgs<value_type> dir = model_->createInArgs();
419  dir.set_p(p_idx_,e_i);
420  MEB::OutArgs<value_type> bfunc = model_->createOutArgs();
421  if(f) {
422  bfunc.set_g(g_idx_,createMember(model_->get_g_space(g_idx_)));
423  Thyra::set_ele(0, *f, bfunc.get_g(g_idx_).ptr());
424  }
425  MEB::OutArgs<value_type> var = model_->createOutArgs();
426  var.set_g(g_idx_,createMember(model_->get_g_space(g_idx_)));
427  const int np = var_indep.size();
428  for( int i = 0; i < np; ++i ) {
429  set_ele(i, 1.0, e_i.ptr());
430  dir.set_x(thyra_D->col(i));
431  objDirecFiniteDiffCalculator_->calcVariations(
432  *model_,model_inArgs,dir,bfunc,var
433  );
434  dir.set_x(Teuchos::null);
435  Thyra::set_ele(i, 0.0, e_i.ptr());
436  d_rGf()[i] = Thyra::get_ele(*var.get_g(g_idx_),0);
437  }
438  }
439  else {
440  LinAlgOpPack::V_MtV( rGf, *D_used, BLAS_Cpp::trans, *Gf->sub_view(var_dep) );
441  LinAlgOpPack::Vp_V( rGf, *Gf->sub_view(var_indep) );
442  // ToDo: Just compute the operators associated with Gf and not Gf directly!
443  }
444  }
445  // * ToDo: Add specialized algorithm for computing D using an inexact Jacobian
446  // * ToDo: Add in logic for inexact solves
447  if(out.get() && trace)
448  *out << "\nLeaving MoochoPack::NLPDirectThyraModelEvaluator::calc_point(...) ...\n";
449 }
450 
452  const Vector &x
453  ,VectorMutable *c
454  ,bool recalc_c
455  ,VectorMutable *py
456  ) const
457 {
458  if(recalc_c) {
459  //
460  // Recompute c
461  //
463  }
464  // Compute py = - inv(C)*c
466 }
467 
468 } // end namespace NLPInterfacePack
void unset_quantities()
Call to unset all storage quantities (both in this class and all subclasses).
virtual value_type & f()
Returns non-const *this->get_f().
virtual vec_mut_ptr_t sub_view(const Range1D &rng)
Create a mutable abstract view of a vector object.
Struct for gradient (objective), objective and constriants (pointers)
virtual const VectorSpace & space() const =0
Return the vector space that this vector belongs to.
bool is_null(const boost::shared_ptr< T > &p)
Abstract interface for immutable, finite dimensional, coordinate vectors {abstract}.
VectorMutable * c
Pointer to constraints residual c (may be NULL if not set)
void postprocessBaseOutArgs(Thyra::ModelEvaluatorBase::OutArgs< value_type > *model_outArgs_inout, VectorMutable *Gf, value_type *f, VectorMutable *c) const
Teuchos::RCP< Thyra::MultiVectorBase< value_type > > thyra_N_
void Vt_S(VectorMutable *v_lhs, const value_type &alpha)
v_lhs *= alpha
VectorMutable * Gf
Pointer to gradient of objective function Gf (may be NULL if not set)
VectorSpace adapter subclass for Thyra::VectorSpaceBase<value_type> .
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void initializeBase(const Teuchos::RCP< Thyra::ModelEvaluator< value_type > > &model, const int p_idx, const int g_idx)
Initialize given a Thyra::ModelEvaluator and a description of how to interpret it.
void assign(VectorMutable *v_lhs, const V &V_rhs)
v_lhs = V_rhs.
T * get() const
const ObjGradInfo obj_grad_info() const
Return objective gradient and zero order information.
basic_OSTab< char > OSTab
Transposed.
value_type * f
Pointer to objective function f (may be NULL if not set)
void get_thyra_vector(const VectorSpaceThyra &thyra_vec_spc, const Vector &vec, Teuchos::RCP< const Thyra::VectorBase< value_type > > *thyra_vec)
Teuchos::RCP< Thyra::LinearOpWithSolveBase< value_type > > thyra_C_
void initialize(const Teuchos::RCP< Thyra::ModelEvaluator< value_type > > &model, const int p_idx, const int g_idx, const objDirecFiniteDiffCalculator_ptr_t objDirecFiniteDiffCalculator=Teuchos::null, const conDirecFiniteDiffCalculator_ptr_t conDirecFiniteDiffCalculator=Teuchos::null)
.Initialize given a Thyra::ModelEvaluator and a description of how to interpret it.
void commit_thyra_vector(const VectorSpaceThyra &thyra_vec_spc, VectorMutable *vec, Teuchos::RCP< Thyra::VectorBase< value_type > > *thyra_vec)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void initialize(bool test_setup)
Initialize the NLP for its first use.
T_To & dyn_cast(T_From &from)
Ptr< T > ptr() const
VectorMutable adapter subclass for Thyra::VectorBase.
std::ostream * out
void preprocessBaseInOutArgs(const Vector &x, bool newx, const ZeroOrderInfo *zero_order_info, const ObjGradInfo *obj_grad_info, const NLPFirstOrder::FirstOrderInfo *first_order_info, Thyra::ModelEvaluatorBase::InArgs< value_type > *model_inArgs_inout, Thyra::ModelEvaluatorBase::OutArgs< value_type > *model_outArgs_inout, MatrixOp **Gc_out, VectorMutable **Gf_out, value_type **f_out, VectorMutable **c_out) const
value_type calc_Gf_prod(const Vector &x, const Vector &d, bool newx) const
const RCP< T > & assert_not_null() const
MatrixOp adapter subclass for Thyra::LinearOpBase.
MatrixOpNonsing adapter subclass for Thyra::Nonlin::LinearOpWithSolve.
void calc_point(const Vector &x, value_type *f, VectorMutable *c, bool recalc_c, VectorMutable *Gf, VectorMutable *py, VectorMutable *rGf, MatrixOp *GcU, MatrixOp *D, MatrixOp *Uz) const
bool nonnull(const boost::shared_ptr< T > &p)
basic_FancyOStream< char > FancyOStream
Teuchos::RCP< Thyra::ModelEvaluator< value_type > > model_
MultiVectorMutable adapter subclass for Thyra::MultiVectorBase.
void V_MtV(VectorMutable *v_lhs, const MatrixOp &M_rhs1, BLAS_Cpp::Transp trans_rhs1, const V &V_rhs2)
v_lhs = op(M_rhs1) * V_rhs2.
AbstractLinAlgPack::value_type value_type
void set_x(const Vector &x, Thyra::ModelEvaluatorBase::InArgs< value_type > *model_inArgs_inout) const
Abstract interface for mutable coordinate vectors {abstract}.
virtual obj_ptr_t create() const =0
void calc_semi_newton_step(const Vector &x, VectorMutable *c, bool recalc_c, VectorMutable *py) const
void free_thyra_vector(const VectorSpaceThyra &thyra_vec_spc, const Vector &vec, Teuchos::RCP< const Thyra::VectorBase< value_type > > *thyra_vec)
Extract a non-const DenseLinAlgPack::DVectorSlice view of a VectorMutable object. ...
virtual VectorMutable & Gf()
Returns non-const *this->get_Gf().
virtual EVerbosityLevel getVerbLevel() const
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
virtual VectorMutable & c()
Returns non-const *this->get_c().
void Vp_V(VectorMutable *v_lhs, const V &V_rhs)
v_lhs += V_rhs.