NLPInterfacePack: C++ Interfaces and Implementation for Non-Linear Programs  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
NLPInterfacePack_NLPSerialPreprocessExplJac.cpp
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 
42 #include <assert.h>
43 
44 #include <typeinfo>
45 #include <algorithm>
46 
47 #include "NLPInterfacePack_NLPSerialPreprocessExplJac.hpp"
48 #include "AbstractLinAlgPack_MatrixPermAggr.hpp"
49 #include "AbstractLinAlgPack_BasisSystemFactory.hpp"
50 #include "AbstractLinAlgPack_MatrixComposite.hpp"
51 #include "AbstractLinAlgPack_MatrixSparseCOORSerial.hpp"
52 #include "AbstractLinAlgPack_PermutationSerial.hpp"
53 #include "AbstractLinAlgPack_VectorDenseEncap.hpp"
54 #include "DenseLinAlgPack_DVectorOp.hpp"
55 #include "DenseLinAlgPack_IVector.hpp"
56 #include "DenseLinAlgPack_PermVecMat.hpp"
57 #include "Teuchos_Assert.hpp"
58 #include "Teuchos_dyn_cast.hpp"
59 #include "Teuchos_AbstractFactoryStd.hpp"
60 #include "OptionsFromStreamPack_OptionsFromStream.hpp"
61 
62 namespace NLPInterfacePack {
63 
64 // NLPSerialPreprocessExplJac
65 
66 // Constructors / initializers
67 
69  const basis_sys_fcty_ptr_t &basis_sys_fcty
70  ,const factory_mat_ptr_t &factory_Gc_full
71  )
72  :initialized_(false),test_setup_(false)
73 {
74  this->set_basis_sys_fcty(basis_sys_fcty);
75  this->set_factory_Gc_full(factory_Gc_full);
76 }
77 
79  const factory_mat_ptr_t &factory_Gc_full
80  )
81 {
82  if(factory_Gc_full.get())
83  factory_Gc_full_ = factory_Gc_full;
84  else
85  factory_Gc_full_ = Teuchos::rcp(
88 }
89 
90 // Overridden public members from NLP
91 
92 void NLPSerialPreprocessExplJac::set_options( const options_ptr_t& options )
93 {
94  options_ = options;
95 }
96 
97 const NLP::options_ptr_t&
99 {
100  return options_;
101 }
102 
104 {
105  namespace mmp = MemMngPack;
106 
107  test_setup_ = test_setup;
108 
109  if( initialized_ && !imp_nlp_has_changed() ) {
110  // The subclass NLP has not changed so we can just
111  // slip this preprocessing.
112  NLPFirstOrder::initialize(test_setup);
113  NLPSerialPreprocess::initialize(test_setup); // Some duplication but who cares!
114  return;
115  }
116 
117  // Initialize the base object first
118  NLPFirstOrder::initialize(test_setup);
119  NLPSerialPreprocess::initialize(test_setup); // Some duplication but who cares!
120 
121  // Initialize the storage for the intermediate quanities
122  Gc_nz_orig_ = imp_Gc_nz_orig(); // Get the estimated number of nonzeros in Gc
123  Gc_val_orig_.resize(Gc_nz_orig_);
124  Gc_ivect_orig_.resize(Gc_nz_orig_);
125  Gc_jvect_orig_.resize(Gc_nz_orig_);
126  Gh_nz_orig_ = imp_Gh_nz_orig(); // Get the estimated number of nonzeros in Gh
127  Gh_val_orig_.resize(Gh_nz_orig_);
128  Gh_ivect_orig_.resize(Gh_nz_orig_);
129  Gh_jvect_orig_.resize(Gh_nz_orig_);
130 
131  Gc_perm_new_basis_updated_ = false;
132 
133  // If you get here then the initialization went Ok.
134  initialized_ = true;
135 }
136 
138  return initialized_;
139 }
140 
141 // Overridden public members from NLPFirstOrder
142 
145 {
146  return factory_Gc_;
147 }
148 
151 {
152  BasisSystemFactory &fcty = const_cast<NLPSerialPreprocessExplJac*>(this)->basis_sys_fcty();
153  fcty.set_options(options_);
154  return fcty.create();
155 }
156 
158 {
159  using Teuchos::dyn_cast;
161  if( Gc != NULL ) {
162  dyn_cast<MatrixPermAggr>(*Gc); // With throw exception if not correct type!
163  }
165 }
166 
167 // Overridden public members from NLPVarReductPerm
168 
170  Permutation* P_var, Range1D* var_dep
171  ,Permutation* P_equ, Range1D* equ_decomp
172  )
173 {
174  const bool new_basis = NLPSerialPreprocess::get_next_basis(
175  P_var,var_dep,P_equ,equ_decomp
176  );
177  if( new_basis ) {
178  Gc_perm_new_basis_updated_ = false;
179  }
180  return new_basis;
181 }
182 
184  const Permutation &P_var, const Range1D &var_dep
185  ,const Permutation *P_equ, const Range1D *equ_decomp
186  )
187 {
189  P_var,var_dep,P_equ,equ_decomp
190  );
191  Gc_perm_new_basis_updated_ = false;
192 }
193 
194 // Overridden protected members from NLPFirstOrder
195 
197  const Vector& x, bool newx
198  ,const FirstOrderInfo& first_order_info
199  ) const
200 {
201  namespace mmp = MemMngPack;
202  using Teuchos::dyn_cast;
203 
205 
206  const Range1D
207  var_dep = this->var_dep(),
208  equ_decomp = this->equ_decomp();
209  // Get the dimensions of the original NLP
210  const size_type
211  n = this->n(),
212  n_orig = this->imp_n_orig(),
213  m_orig = this->imp_m_orig(),
214  mI_orig = this->imp_mI_orig();
215  // Get the dimensions of the full matrices
216  const size_type
217  n_full = n_orig + mI_orig,
218  m_full = m_orig + mI_orig;
219  // Get the number of columns in the matrix being constructed here
220  const size_type
221  num_cols = m_full;
222 
223  //
224  // Get references to the constituent objects
225  //
226 
227  // Get the concrete type for the Jacobian matrix
228  MatrixPermAggr
229  &G_aggr = dyn_cast<MatrixPermAggr>( *first_order_info.Gc );
230  // Get smart pointers to the constituent members
232  G_full = Teuchos::rcp_const_cast<MatrixOp>( G_aggr.mat_orig() );
234  P_row = Teuchos::rcp_dynamic_cast<PermutationSerial>(
235  Teuchos::rcp_const_cast<Permutation>( G_aggr.row_perm() ) ); // variable permutation
237  P_col = Teuchos::rcp_dynamic_cast<PermutationSerial>(
238  Teuchos::rcp_const_cast<Permutation>( G_aggr.col_perm() ) ); // constraint permutation
240  G_perm = G_aggr.mat_perm();
241  // Remove references to G_full, G_perm, P_row and P_col.
242  G_aggr.set_uninitialized();
243  // Allocate the original matrix object if not done so yet
244  if( G_full.get() == NULL || G_full.total_count() > 1 )
245  G_full = factory_Gc_full_->create();
246  // Get reference to the MatrixLoadSparseElements interface
247  MatrixLoadSparseElements
248  &G_lse = dyn_cast<MatrixLoadSparseElements>(*G_full);
249 
250  //
251  // Calcuate the full explicit Jacobian
252  //
253 
254  set_x_full( VectorDenseEncap(x)(), newx, &x_full() );
255  if( m_orig )
257  if( mI_orig )
259 
260  // Now get the actual number of nonzeros
261  const size_type nz_full
262  = Gc_nz_orig_ + Gh_nz_orig_ + mI_orig; // Gc_orig, Gh_orig, -I
263 
264  // Determine if we need to set the structure and the nonzeros or just the nonzero values
265  const bool load_struct = (G_lse.nz() == 0);
266 
267  size_type G_nz_previous;
268  if( load_struct ) {
269  G_lse.reinitialize(n,num_cols,nz_full); // The actual number of nonzeros will be minus the fixed variables
270  }
271  else {
272  G_nz_previous = G_lse.nz();
273  G_lse.reset_to_load_values(); // Use row and column indexes already set (better be same insert order!)
274  }
275 
276  //
277  // Load the matrix entries where we remove variables fixed by bounds
278  //
279 
280  // Get pointers to buffers to fill with nonzero entries
281  value_type *val = NULL;
282  index_type *ivect = NULL,
283  *jvect = NULL;
284  G_lse.get_load_nonzeros_buffers(
285  nz_full // We may actually load less
286  ,&val
287  ,load_struct ? &ivect : NULL
288  ,load_struct ? &jvect : NULL
289  );
290  // Pointers to the full COOR matrix just updated
291  const value_type *val_orig = NULL;
292  const value_type *val_orig_end = NULL;
293  const index_type *ivect_orig = NULL;
294  const index_type *jvect_orig = NULL;
295 
296  index_type nz = 0;
297  if( m_orig ) {
298  // Load entries for Gc_orig
299  val_orig = &Gc_val_orig_[0];
300  val_orig_end = val_orig + Gc_nz_orig_;
301  ivect_orig = &Gc_ivect_orig_[0];
302  jvect_orig = &Gc_jvect_orig_[0];
303  imp_fill_jacobian_entries(
304  n, n_full, load_struct
305  ,0 // column offset
306  ,val_orig, val_orig_end, ivect_orig, jvect_orig
307  ,&nz // This will be incremented
308  ,val, ivect, jvect
309  );
310  }
311  if( mI_orig > 0 ) {
312  // Load entires for Gc_orig and -I
313  val_orig = &Gh_val_orig_[0];
314  val_orig_end = val_orig + Gh_nz_orig_;
315  ivect_orig = &Gh_ivect_orig_[0];
316  jvect_orig = &Gh_jvect_orig_[0];
317  imp_fill_jacobian_entries(
318  n, n_full, load_struct
319  ,m_orig // column offset (i.e. [ Gc_orig, Gh_orig ] )
320  ,val_orig, val_orig_end, ivect_orig, jvect_orig
321  ,&nz // This will be incremented
322  ,val + nz, ivect + nz, jvect + nz
323  );
324  // -I
325  value_type *val_itr = val + nz;
326  index_type *ivect_itr = ivect + nz;
327  index_type *jvect_itr = jvect + nz;
328  const IVector& var_full_to_remove_fixed = this->var_full_to_remove_fixed();
329  if( load_struct ) {
330  // Fill values and i and j
331  for( index_type k = 1; k <= mI_orig; ++k ) {
332  size_type var_idx = var_full_to_remove_fixed(n_orig+k); // Knows about slacks
333 #ifdef TEUCHOS_DEBUG
334  TEUCHOS_TEST_FOR_EXCEPT( !( 0 < var_idx && var_idx <= n_full ) );
335 #endif
336  if(var_idx <= n) {
337  // This is not a fixed variable
338  *val_itr++ = -1.0;
339  *ivect_itr++ = var_idx;
340  *jvect_itr++ = m_orig + k; // (i.e. [ 0, -I ] )
341  ++nz;
342  }
343  }
344  }
345  else {
346  // Just fill values
347  for( index_type k = 1; k <= mI_orig; ++k ) {
348  size_type var_idx = var_full_to_remove_fixed(n_orig+k); // Knows about slacks
349 #ifdef TEUCHOS_DEBUG
350  TEUCHOS_TEST_FOR_EXCEPT( !( 0 < var_idx && var_idx <= n_full ) );
351 #endif
352  if(var_idx <= n) {
353  // This is not a fixed variable
354  *val_itr++ = -1.0;
355  ++nz;
356  }
357  }
358  }
359  }
360 
361  if( !load_struct ) {
362  // Check that the number of nonzeros added matches the number of nonzeros in G
364  G_nz_previous != nz, std::runtime_error
365  ,"NLPSerialPreprocessExplJac::imp_calc_Gc(...): Error, "
366  "The number of added nonzeros does not match the number of nonzeros "
367  "in the previous matrix load!." );
368  }
369 
370  // Commit the nonzeros
371  G_lse.commit_load_nonzeros_buffers(
372  nz // The actual number of nonzeros to set
373  ,&val
374  ,load_struct ? &ivect : NULL
375  ,load_struct ? &jvect : NULL
376  );
377  G_lse.finish_construction(test_setup_);
378 
379  //
380  // Setup permuted view
381  //
382 
383  // Setup row (variable) permutation
384  if( P_row.get() == NULL || P_col.total_count() > 1 )
385  P_row = Teuchos::rcp(new PermutationSerial());
387  if( P_row->perm().get() == NULL ) var_perm = Teuchos::rcp(new IVector(n_full));
388  else var_perm = Teuchos::rcp_const_cast<IVector>(P_row->perm());
389  *var_perm = this->var_perm();
390  P_row->initialize(var_perm,Teuchos::null);
391  // Setup column (constraint) permutation
392  if( P_col.get() == NULL || P_col.total_count() > 1 )
393  P_col = Teuchos::rcp(new PermutationSerial());
394  Teuchos::RCP<IVector> con_perm;
395  if( P_col->perm().get() == NULL ) con_perm = Teuchos::rcp(new IVector(m_full));
396  else con_perm = Teuchos::rcp_const_cast<IVector>(P_col->perm());
397  *con_perm = this->equ_perm();
398  P_col->initialize(con_perm,Teuchos::null);
399  // Setup G_perm
400  int num_row_part, num_col_part;
401  index_type row_part[3], col_part[3];
402  if(var_dep.size()) {
403  num_row_part = 2;
404  row_part[0] = 1;
405  row_part[1] = (var_dep.lbound() == 1 ? var_dep.ubound()+1 : var_dep.lbound());
406  row_part[2] = n+1;
407  }
408  else {
409  num_row_part = 1;
410  row_part[0] = 1;
411  row_part[1] = n+1;
412  }
413  if(equ_decomp.size()) {
414  num_col_part = 2;
415  col_part[0] = 1;
416  col_part[1] = (equ_decomp.lbound() == 1 ? equ_decomp.ubound()+1 : equ_decomp.lbound());
417  col_part[2] = m_full+1;
418  }
419  else {
420  num_col_part = 1;
421  col_part[0] = 1;
422  col_part[1] = m_full+1;
423  }
424  if( G_perm.get() == NULL || !Gc_perm_new_basis_updated_ ) {
425  G_perm = G_full->perm_view(
426  P_row.get(),row_part,num_row_part
427  ,P_col.get(),col_part,num_col_part
428  );
429  }
430  else {
431  G_perm = G_full->perm_view_update(
432  P_row.get(),row_part,num_row_part
433  ,P_col.get(),col_part,num_col_part
434  ,G_perm
435  );
436  }
437  Gc_perm_new_basis_updated_ = true;
438 
439  //
440  // Reinitialize the aggregate matrix object.
441  //
442 
443  G_aggr.initialize(G_full,P_row,P_col,G_perm);
444 }
445 
446 // protected members
447 
449 {
451  !initialized_, UnInitialized
452  ,"NLPSerialPreprocessExplJac : The nlp has not been initialized yet" );
453 }
454 
455 // private
456 
457 void NLPSerialPreprocessExplJac::imp_fill_jacobian_entries(
458  size_type n
459  ,size_type n_full
460  ,bool load_struct
461  ,const index_type col_offset
462  ,const value_type *val_orig
463  ,const value_type *val_orig_end
464  ,const index_type *ivect_orig
465  ,const index_type *jvect_orig
466  ,index_type *nz
467  ,value_type *val_itr
468  ,index_type *ivect_itr
469  ,index_type *jvect_itr
470  ) const
471 {
472  const IVector& var_full_to_remove_fixed = this->var_full_to_remove_fixed();
473  if( load_struct ) {
474  // Fill values and i and j
475  for( ; val_orig != val_orig_end ; ++val_orig, ++ivect_orig, ++jvect_orig) {
476 #ifdef TEUCHOS_DEBUG
477  TEUCHOS_TEST_FOR_EXCEPT( !( 0 <= *ivect_orig && *ivect_orig <= n_full ) );
478 #endif
479  size_type var_idx = var_full_to_remove_fixed(*ivect_orig);
480 #ifdef TEUCHOS_DEBUG
481  TEUCHOS_TEST_FOR_EXCEPT( !( 0 < var_idx && var_idx <= n_full ) );
482 #endif
483  if(var_idx <= n) {
484  // This is not a fixed variable
485  *val_itr++ = *val_orig;
486  // Also fill the row and column indices
487  *ivect_itr++ = var_idx;
488  *jvect_itr++ = col_offset + (*jvect_orig);
489  ++(*nz);
490  }
491  }
492  }
493  else {
494  // Just fill values
495  for( ; val_orig != val_orig_end ; ++val_orig, ++ivect_orig) {
496 #ifdef TEUCHOS_DEBUG
497  TEUCHOS_TEST_FOR_EXCEPT( !( 0 <= *ivect_orig && *ivect_orig <= n_full ) );
498 #endif
499  size_type var_idx = var_full_to_remove_fixed(*ivect_orig);
500 #ifdef TEUCHOS_DEBUG
501  TEUCHOS_TEST_FOR_EXCEPT( !( 0 < var_idx && var_idx <= n_full ) );
502 #endif
503  if(var_idx <= n) {
504  // This is not a fixed variable
505  *val_itr++ = *val_orig;
506  ++(*nz);
507  }
508  }
509  }
510 }
511 
512 } // end namespace NLPInterfacePack
void set_basis(const Permutation &P_var, const Range1D &var_dep, const Permutation *P_equ, const Range1D *equ_decomp)
void set_basis(const Permutation &P_var, const Range1D &var_dep, const Permutation *P_equ, const Range1D *equ_decomp)
virtual bool imp_nlp_has_changed() const
Return if the definition of the NLP has changed since the last call to initialize() ...
const IVector & var_full_to_remove_fixed() const
Inverse permutation vector of var_remove_fixed_to_full().
NLP node subclass complementing NLPSerialPreprocess for explicit Jacobians.
MatrixOp * Gc
Pointer to Jacobian of equality constraints Gc (may be NULL if not set)
void initialize(bool test_setup)
Initialize the NLP for its first use.
virtual size_type imp_m_orig() const =0
Return the number of general equality constraints in the original problem.
const basis_sys_ptr_t basis_sys() const
Calls basis_sys_fcty()->create()
const IVector & equ_perm() const
Permutes from the original constriant ordering to the current basis selection.
void set_factory_Gc_full(const factory_mat_ptr_t &factory_Gc_full)
Initialize with matrix factory for original matrices Gc.
NLPSerialPreprocessExplJac(const basis_sys_fcty_ptr_t &basis_sys_fcty=Teuchos::rcp(new BasisSystemFactoryStd()), const factory_mat_ptr_t &factory_Gc_full=Teuchos::null)
Calls this->set_basis_sys_fcty() and this->set_mat_factories() methods.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
T_To & dyn_cast(T_From &from)
virtual size_type imp_n_orig() const =0
Return the number of variables in the original problem (including those fixed by bounds) ...
T * get() const
bool get_next_basis(Permutation *P_var, Range1D *var_dep, Permutation *P_equ, Range1D *equ_decomp)
const IVector & var_perm() const
Permutes from the compated variable vector (removing fixed variables) to the current basis selection...
DVectorSlice x_full() const
Give reference to current x_full.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual void imp_calc_Gh_orig(const DVectorSlice &x_full, bool newx, const FirstOrderExplInfo &first_order_expl_info) const =0
Calculate the COOR matrix for the gradient for all of the h(x) constaints in the original NLP...
size_t size_type
Struct for zero and first order quantities (pointers)
virtual size_type imp_Gh_nz_orig() const =0
Return the number of nonzero elements in Gh before elements are removed for fixed variables...
void set_Gc(MatrixOp *Gc)
Validates the type of Gc is correct.
Thrown if any member functions are called before initialize() has been called.
virtual size_type imp_mI_orig() const =0
Return the number of general inequality constraints in the original problem.
virtual void imp_calc_Gc_orig(const DVectorSlice &x_full, bool newx, const FirstOrderExplInfo &first_order_expl_info) const =0
Calculate the COOR matrix for the gradient for all of the c(x) constaints in the original NLP...
virtual size_type imp_Gc_nz_orig() const =0
Return the number of nonzero elements in Gc before elements are removed for fixed variables...
void set_options(const options_ptr_t &options)
Passes these options on to this->basis_sys_fcty().set_options(options).
void assert_initialized() const
Assert if we have been initizlized (throws UnInitialized)
void set_x_full(const DVectorSlice &x, bool newx, DVectorSlice *x_full) const
Set the full x vector if newx == true
void imp_calc_Gc(const Vector &x, bool newx, const FirstOrderInfo &first_order_info) const
int total_count() const
virtual void set_Gc(MatrixOp *Gc)
Set a pointer to a matrix object to be updated when this->calc_Gc() is called.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
bool get_next_basis(Permutation *P_var, Range1D *var_dep, Permutation *P_equ, Range1D *equ_decomp)