MeshKit  1.0
IAIntWaveNlp.cpp
Go to the documentation of this file.
00001 // IAIntWaveNlp.cpp
00002 // Interval Assignment for Meshkit
00003 //
00004 #include "meshkit/IAIntWaveNlp.hpp"
00005 
00006 #include <math.h>
00007 #include <limits>
00008 
00009 #include "meshkit/IAData.hpp"
00010 #include "meshkit/IPData.hpp"
00011 #include "meshkit/IASolution.hpp"
00012 
00013 /* structure
00014  
00015  constraints:
00016  cosine wave for each sum-even constraint, forcing integrality
00017  cosine wave for each primal variable, forcing integrality
00018  */
00019 
00020 namespace MeshKit {
00021   
00022 // constructor
00023 IAIntWaveNlp::IAIntWaveNlp(const IAData *data_ptr, const IPData *ip_data_ptr, IASolution *solution_ptr, bool set_silent): 
00024   data(data_ptr), ipData(ip_data_ptr), solution(solution_ptr), baseNlp(data_ptr, solution_ptr),
00025   base_n((int)data_ptr->num_variables()),
00026   base_m((int)(data_ptr->constraints.size() + data_ptr->sumEvenConstraints.size())),
00027   problem_n((int)data_ptr->I.size()),
00028   problem_m((int)(data_ptr->constraints.size() + 2*data_ptr->sumEvenConstraints.size() + data_ptr->num_variables())),
00029   wave_even_constraint_start((int)(data_ptr->constraints.size() + data_ptr->sumEvenConstraints.size())),
00030   wave_int_constraint_start((int)(data_ptr->constraints.size() + 2*data_ptr->sumEvenConstraints.size())),
00031   silent(set_silent), debugging(true), verbose(true) // true
00032 {
00033   printf("\nIAIntWaveNLP Problem size:\n");
00034   printf("  number of variables: %d\n", problem_n);
00035   printf("  number of base (equal, even>4) constraints: %d\n", base_m);  
00036   printf("  number of wave-even constraints: %lu\n", data_ptr->sumEvenConstraints.size());
00037   printf("  number of wave-int constraints: %d\n", data_ptr->num_variables());
00038   printf("  total constraints: %d\n\n", problem_m);  
00039 }
00040 
00041 
00042 IAIntWaveNlp::~IAIntWaveNlp() {data = NULL; ipData = NULL;}
00043 
00044 // returns the size of the problem
00045 bool IAIntWaveNlp::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
00046                            Index& nnz_h_lag, IndexStyleEnum& index_style)
00047 {
00048   bool base_ok = baseNlp.get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style);
00049   
00050   // n = number of variables = same as in base problem
00051   // m = number of constraints = equality constraints(side_1=side_2) + even_constraints(sum>4) set by base, plus
00052   //   wave even constraints
00053   //   wave integrality constraints
00054   m += (Index) data->sumEvenConstraints.size() + (Index) data->num_variables();
00055   assert( m == problem_m );
00056 
00057   if (debugging)
00058   {
00059     printf("IAIntWaveNlp::get_nlp_info\n");
00060     printf("base m=%d, wave m=%d\n", base_m, m);
00061   }
00062   // nnz_jac_g = number of non-zero entries in the jacobian of the constraints
00063   // equality constraints counted in the base program
00064   // constraints for sum-even
00065   
00066   // wave even constraints
00067   const Index base_nnz_jac_g = nnz_jac_g;
00068   int num_even_entries = 0;
00069   for (std::vector<IAData::sumEvenConstraintRow>::const_iterator i=data->sumEvenConstraints.begin(); i != data->sumEvenConstraints.end(); ++i)
00070   {
00071     num_even_entries += i->M.size();
00072   }
00073   nnz_jac_g += num_even_entries;
00074   
00075   // wave x-integer constraints
00076   nnz_jac_g += data->num_variables();
00077   
00078   if (debugging)
00079   {
00080     printf("nnz_jac_g = %d: base = %d, wave even = %d, wave int = %d\n", 
00081            nnz_jac_g, base_nnz_jac_g, num_even_entries, data->num_variables());
00082   }
00083   
00084   // hessian elements, second derivatives of objective and constraints
00085   // objectives are double counted, so we do = here rather than +=
00086   build_hessian();
00087   nnz_h_lag = (Index) hessian_vector.size();
00088   
00089   if (debugging)
00090   {
00091     printf("IAIntWaveNlp::get_nlp_info");
00092     printf(" n=%d, m=%d, nnz_jac_g=%d, num_even_entrites=%d, nnz_h_lag=%d\n", n, m, nnz_jac_g, num_even_entries, nnz_h_lag);
00093   }
00094   
00095   return true && base_ok;
00096   // need to change this if there are more variables, such as delta-minuses
00097 }
00098   
00099 // returns the variable bounds
00100 bool IAIntWaveNlp::get_bounds_info(Index n, Number* x_l, Number* x_u,
00101                                    Index m, Number* g_l, Number* g_u)
00102 {
00103   const bool base_ok = baseNlp.get_bounds_info(n, x_l, x_u, base_m, g_l, g_u);
00104   
00105   for (unsigned int i = 0; i < data->sumEvenConstraints.size(); ++i)
00106   {
00107     // cos( pi * sum_evens) == 1
00108     // equality makes ipopt think it is overdetermined, so use inequality :) 
00109     const int k = i + wave_even_constraint_start;
00110     g_l[k] = 1.; // 1.
00111     g_u[k] = MESHKIT_IA_upperUnbound; // 1.
00112   }
00113   
00114   for (int i = 0; i < data->num_variables(); ++i)
00115   {
00116     // cos( 2 pi x) == 1
00117     const int k = i+ wave_int_constraint_start;
00118     g_l[k] = 1.; // 1.
00119     g_u[k] = MESHKIT_IA_upperUnbound; // 1.
00120   }
00121   return true && base_ok;
00122 }
00123   
00124   // returns the initial point for the problem
00125 bool IAIntWaveNlp::get_starting_point(Index n, bool init_x, Number* x_init,
00126                                       bool init_z, Number* z_L, Number* z_U,
00127                                       Index m, bool init_lambda,
00128                                       Number* lambda)
00129 {
00130   // Minimal info is starting values for x, x_init
00131   // Improvement: we can provide starting values for the dual variables if we wish
00132   assert(init_x == true);
00133   assert(init_z == false);
00134   assert(init_lambda == false);
00135   
00136   // initialize x to the relaxed solution
00137   for (Index i=0; i<n; ++i) 
00138   {
00139     x_init[i] = ipData->relaxedSolution[i];
00140   }
00141   
00142   return true;
00143 }
00144   
00145   
00146 // returns the value of the objective function
00147 bool IAIntWaveNlp::eval_f(Index n, const Number* x, bool new_x, Number& obj_value)
00148 {
00149   baseNlp.eval_f(base_n,x,new_x,obj_value);
00150   return true;
00151 }
00152   
00153 // return the gradient of the objective function grad_{x} f(x)
00154 bool IAIntWaveNlp::eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f)
00155 {
00156   return baseNlp.eval_grad_f(n, x, new_x, grad_f);
00157 }
00158 
00159 // return the value of the constraints: g(x)
00160 bool IAIntWaveNlp::eval_g(Index n, const Number* x, bool new_x, Index m, Number* g)
00161 {
00162   if (debugging)
00163     printf("IAIntWaveNlp::eval_g\n");
00164   
00165   bool base_ok = baseNlp.eval_g(base_n, x, new_x, base_m, g);
00166   
00167   // cos( pi * sum_evens) == 1
00168   for (unsigned int i = 0; i < data->sumEvenConstraints.size(); ++i)
00169   {
00170     const int k = i + wave_even_constraint_start;
00171     double s = baseNlp.eval_even_sum(i,x);
00172     const double gk = eval_g_int_s(s); // e.g. cos( PI * s );
00173     g[k] = gk;    
00174     if (debugging)
00175     {
00176       printf("IAIntWaveNlp::eval_g wave even constraint %d(%d), sum = %f, g = %f\n",
00177              i, k, s, gk );
00178     }
00179   }
00180   
00181   // cos( 2 pi x) == 1
00182   for (int i = 0; i < data->num_variables(); ++i)
00183   {
00184     const int k = i + wave_int_constraint_start;
00185     const double gk = eval_g_int_x(x[i]); // e.g. cos( 2. * PI * x[i] );
00186     g[k] = gk;
00187     if (debugging)
00188     {
00189       printf("IAIntWaveNlp::eval_g wave int constraint %d(%d), x_%d = %f, g = %f\n",
00190              i, k, i, x[i], gk );
00191     }
00192   }
00193 
00194   if (debugging)
00195     printf("IAIntWaveNlp::eval_g done.\n");
00196 
00197   return true && base_ok;
00198 }
00199 
00200 // return the structure or values of the jacobian
00201 bool IAIntWaveNlp::eval_jac_g(Index n, const Number* x, bool new_x,
00202                            Index m, Index nele_jac, Index* iRow, Index *jCol,
00203                            Number* values)
00204 {
00205   if (debugging)
00206   {
00207     printf("IAIntWaveNlp::eval_jac_g");
00208     if (values)
00209       printf(" values\n");
00210     else 
00211       printf(" structure\n");
00212   }
00213 
00214   int base_nele_jac = baseNlp.get_neleJac(); // might be 0 if not computed yet, values == NULL
00215   bool base_ok = baseNlp.eval_jac_g(base_n, x, new_x, base_m, base_nele_jac, iRow, jCol, values);
00216   base_nele_jac = baseNlp.get_neleJac(); // set to true value
00217   int k = base_nele_jac;
00218 
00219   printf("base_nele_jac = %d, nele_jac = %d\n", base_nele_jac, nele_jac); // should be +1 for each equal and even constraint entry
00220   
00221   if (values == NULL) 
00222   {
00223     // return the structure of the jacobian
00224   
00225     // g = cos( pi * sum_evens) == 1
00226     // g' = -pi * sin ( pi * sum_evens ), for each of the variables contributing to the sum
00227     if (debugging)
00228     {
00229       printf("base entries: ");
00230       for (int bi = 0; bi < k; ++bi)
00231       {
00232         printf(" %d (%d,%d)", bi, iRow[bi], jCol[bi]);        
00233       }
00234       printf("\nwave even non-zero entries: ");
00235     }
00236     for (unsigned int i = 0; i< data->sumEvenConstraints.size(); ++i)
00237     {
00238       for (unsigned int j = 0; j < data->sumEvenConstraints[i].M.size(); ++j)
00239       {
00240                 iRow[k] = i + wave_even_constraint_start;
00241         jCol[k] = data->sumEvenConstraints[i].M[j].col;
00242         if (debugging)
00243         {
00244           printf(" %d (%d,%d)", k, iRow[k], jCol[k]);
00245         }
00246         ++k;
00247       }
00248     }
00249 
00250     // g = cos( 2 pi x) == 1
00251     // g' = - 2 pi sin ( 2 pi x ), for x_i
00252     if (debugging)
00253     {
00254       printf("\nwave int non-zero entries: ");
00255     }
00256     for (int i=0; i<data->num_variables(); ++i)
00257     {
00258       iRow[k] = i + wave_int_constraint_start;
00259       jCol[k] = i;
00260       if (debugging)
00261       {
00262         printf(" %d (%d,%d)", k, iRow[k], jCol[k]);
00263       }
00264       ++k;
00265     }
00266     if (debugging)
00267     {
00268       printf("\n");
00269       printf("k = %d, nele_jac = %d\n", k, nele_jac);
00270     }
00271     assert(k == nele_jac);
00272   }
00273   else
00274   {
00275     // return the values of the jacobian of the constraints    
00276     
00277     // g = cos( pi * sum_evens) == 1
00278     // g' = -pi * coeff_i * sin ( pi * sum_evens ), for each of the variables x_i contributing to the sum
00279     if (debugging)
00280     {
00281       printf("base values: ");
00282       for (int bi = 0; bi < k; ++bi)
00283       {
00284         printf(" %d (%f)", bi, values[bi]);
00285       }
00286       printf("\nwave even non-zero jacobian values: ");
00287     }
00288     for (unsigned int i = 0; i< data->sumEvenConstraints.size(); ++i)
00289     {
00290       const double s = baseNlp.eval_equal_sum(i, x);
00291       const double jac_gk = eval_jac_int_s(s); // e.g. -PI * cos( PI * s );
00292       if (debugging)
00293         printf("\n%d even wave: ", i);
00294       for (unsigned int j = 0; j < data->sumEvenConstraints[i].M.size(); ++j)
00295       {
00296         const double coeff = data->sumEvenConstraints[i].M[j].val;
00297         values[k++] = coeff * jac_gk;
00298         if (debugging)
00299         {
00300           printf("  %d: x_%d gradient %f * %f = %f\n", k-1,
00301                  data->sumEvenConstraints[i].M[j].col, coeff, jac_gk, coeff * jac_gk);
00302         }
00303       }
00304     }
00305     if (debugging)
00306       printf("\n");
00307 
00308     // g = cos( 2 pi x) == 1
00309     // g' = - 2 pi sin ( 2 pi x ), for x_i
00310     if (debugging)
00311     {
00312       printf("\nwave int non-zero jacobian values: ");
00313     }
00314     for (int i=0; i<data->num_variables(); ++i)
00315     {
00316       const double jac_gk = eval_jac_int_x(x[i]); // e.g. -2. * PI * sin( 2. * PI * x[i] );
00317       values[k++] = jac_gk;
00318       if (debugging)
00319       {
00320         printf("\n%d: x_%d (%f) gradient %f", k-1, i, x[i], jac_gk);
00321       }
00322     }
00323     if (debugging)
00324       printf("\n");
00325     assert(k == nele_jac);
00326   }
00327   
00328   return true && base_ok;
00329 }
00330 
00331 IAIntWaveNlp::SparseMatrixEntry::SparseMatrixEntry(const int iset, const int jset, const int kset)
00332 {
00333   if ( jset > iset )
00334   {
00335     i = jset;
00336     j = iset;
00337   }
00338   else
00339   {
00340     i = iset;
00341     j = jset;
00342   }
00343   k = kset;
00344   assert(j <= i);
00345 }
00346   
00347 void IAIntWaveNlp::add_hessian_entry( int i, int j, int &k )
00348 {
00349   SparseMatrixEntry sme(i, j, k);
00350   
00351   if (hessian_map.insert( std::make_pair(sme.key(), sme) ).second)
00352   {
00353     hessian_vector.push_back( sme );
00354     ++k;
00355     assert( (int) hessian_vector.size() == k );
00356     assert( (int) hessian_map.size() == k );
00357   }
00358   // else it was already inserted, nothing to do
00359 }
00360 
00361 int IAIntWaveNlp::SparseMatrixEntry::n(0);
00362 
00363 void IAIntWaveNlp::build_hessian() 
00364 {
00365   // only build once
00366   if (hessian_vector.size())
00367     return;
00368   
00369   hessian_vector.clear();
00370   hessian_map.clear();
00371   SparseMatrixEntry::n = data->num_variables();
00372   int kk = 0;
00373 
00374   // objective function hessian - the main diagonal
00375   // important to add these first and in this order, for baseNlp to do the right thing
00376   for (int i = 0; i < data->num_variables(); ++i)
00377   {  
00378     add_hessian_entry( i, i, kk );
00379   }
00380   assert( kk == data->num_variables() );
00381   
00382   // sum_evens
00383     // g = cos( pi * sum_evens) == 1
00384     // g' = -pi * sin ( pi * sum_evens ), for each of the variables contributing to the sum
00385     // g''= -pi^2 cos ( pi * sum_evens ), for each pair of variables contributing to the sum
00386     // assuming all the coefficients are 1    
00387   for (unsigned int c = 0; c< data->sumEvenConstraints.size(); ++c)
00388   {
00389     for (unsigned int i = 0; i < data->sumEvenConstraints[c].M.size(); ++i)
00390     {
00391       int ii = data->sumEvenConstraints[c].M[i].col;
00392       for (unsigned int j = 0; j <=i; ++j)
00393       {
00394         int jj = data->sumEvenConstraints[c].M[j].col;
00395         add_hessian_entry( ii, jj, kk );
00396       }
00397     }
00398   }
00399   
00400   // x integer
00401   // these are just the diagonals again, already added so skip
00402   // nele_hess = hessian_vector.size();
00403   if (debugging)
00404   {
00405     printf("==========\nBuilt Hessian\n");
00406     print_hessian();
00407     printf("==========\n");
00408   }
00409 }
00410 
00411 int IAIntWaveNlp::get_hessian_k( int i, int j )
00412 {
00413   if ( i == j )
00414     return i;
00415   SparseMatrixEntry sme(i, j, -1 );
00416   SparseMatrixEntry &entry = hessian_map[ sme.key() ]; 
00417   return entry.k;
00418 }
00419 
00420 void IAIntWaveNlp::print_hessian()
00421 {
00422   printf("Packed Hessian:\n");
00423   for (unsigned int kk = 0; kk < hessian_vector.size(); ++kk)
00424   {
00425     SparseMatrixEntry &sme = hessian_vector[kk];
00426     printf(" %d: (%d, %d)\n", sme.k, sme.i, sme.j);
00427   }
00428   printf("\n");          
00429 
00430   printf("Random Access Hessian in sequence\n");
00431   {
00432     int k = 0;
00433     SparseMatrixMap::iterator iter;
00434     for (iter = hessian_map.begin(); iter != hessian_map.end(); ++iter, ++k)
00435     {
00436       const SparseMatrixEntry &sme = iter->second;
00437       printf(" %d: (%d, %d) k:%d key:%d\n", k, sme.i, sme.j, sme.k, sme.key() );
00438     }
00439     printf("\n");          
00440   }
00441 
00442   printf("Random Access Hessian in square:\n");
00443   for (int i = 0; i < data->num_variables(); ++i)
00444   {
00445     for (int j = 0; j < data->num_variables(); ++j)
00446     {
00447       SparseMatrixEntry sme_search(i, j, -1 );
00448       SparseMatrixMap::iterator iter = hessian_map.find(sme_search.key());
00449       if (iter == hessian_map.end())
00450         printf("   . ");
00451       else
00452         printf(" %3d ", iter->second.k);
00453     }
00454     printf("\n");          
00455   }
00456   printf("\n");          
00457   
00458 }
00459   
00460 //return the structure or values of the hessian
00461 bool IAIntWaveNlp::eval_h(Index n, const Number* x, bool new_x,
00462                        Number obj_factor, Index m, const Number* lambda,
00463                        bool new_lambda, Index nele_hess, Index* iRow,
00464                        Index* jCol, Number* values)
00465 {
00466   // fill values with zeros
00467   if (values)
00468   {
00469     for (unsigned int kk = 0; kk < hessian_vector.size(); ++kk)
00470     {
00471       values[kk] = 0.;
00472     }
00473     // debug, print x
00474   }
00475     
00476   // get structure, or values, from objective function, which is just the diagonal entries
00477   baseNlp.eval_h(base_n, x, new_x, obj_factor, base_m, lambda, new_lambda, data->num_variables(), iRow, jCol, values);
00478 
00479   // hessian entry i,j is:
00480   // obj_factor fij + sum_k lambda[k] gkij
00481   // where fij =   d^2 f / d x_i d x_j
00482   //       gkij =  d^2 g[k] / d x_i d x_j
00483   // and d denotes partial derivative
00484 
00485   // first k entries are diagonal of objective function
00486 
00487   // This is a symmetric matrix, fill the lower left triangle only.
00488   if (values == NULL) {
00489     // return the structure. 
00490     for (unsigned int kk = 0; kk < hessian_vector.size(); ++kk)
00491     {
00492       iRow[kk] = hessian_vector[kk].i;
00493       jCol[kk] = hessian_vector[kk].j;
00494     } 
00495   } // structure
00496   else {
00497     // return the values. 
00498     // g = cos( pi * sum_evens) == 1
00499     // g' = -pi * sin ( pi * sum_evens ), for each of the variables contributing to the sum
00500     // g''= -pi^2 cos ( pi * sum_evens ), for each pair of variables contributing to the sum
00501     // assuming all the coefficients are 1
00502     {
00503       if (debugging)
00504       {
00505         printf("\nwave even non-zero hessian values:");
00506       }
00507       for (unsigned int i = 0; i< data->sumEvenConstraints.size(); ++i)
00508       {
00509         if (debugging)
00510         {
00511           printf("\n%d constraint: ", i);
00512         }
00513         const int k = i + wave_even_constraint_start; // index of the constraint in the problem, = lambda to use
00514         
00515         const double s = baseNlp.eval_even_sum(i, x); // sum of the variable values
00516         // second derivative of wave function, assuming coefficients of one
00517         const double wavepp = eval_hess_int_s(s); // e.g. ( -PI * PI * cos( PI * s ) ); 
00518         const double h_value = lambda[k] * wavepp;        
00519         // assign that value to all pairs, weighted by coeff_i * coeff_j
00520         for (unsigned int ii = 0; ii < data->sumEvenConstraints[i].M.size(); ++ii)
00521         {
00522           const int var_i_index = data->sumEvenConstraints[i].M[ii].col;
00523           const double coeff_i =  data->sumEvenConstraints[i].M[ii].val;
00524           for (unsigned int jj = 0; jj < data->sumEvenConstraints[i].M.size(); ++jj)
00525           {
00526             const int var_j_index = data->sumEvenConstraints[i].M[jj].col;
00527             const double coeff_j =  data->sumEvenConstraints[i].M[jj].val;
00528             
00529             const int kk = get_hessian_k(var_i_index, var_j_index);
00530             values[kk] += coeff_i * coeff_j * h_value;
00531             if (debugging)
00532             {
00533               printf("  lambda[%d] * coeff_%d * coeff_%d * d^2 wave / d x_%d d x_%d = %f * %f * %f * %f\n", 
00534                      k, var_i_index, var_j_index, var_i_index, var_j_index, 
00535                      lambda[k], coeff_i, coeff_j, wavepp );
00536             }
00537           }
00538         }
00539       }
00540       if (debugging)
00541       {
00542         printf("\n");
00543       }
00544     }
00545     
00546     // g = cos( 2 pi x) == 1
00547     // g' = - 2 pi sin ( 2 pi x ), for x_i
00548     // g'' = - 4 pi^2 cos ( 2 pi x), for x_i only
00549     {
00550       if (debugging)
00551       {
00552         printf("\nwave int non-zero hessian values:\n");
00553       }
00554       for (int i=0; i < data->num_variables(); ++i)
00555       {
00556         const int k = i + wave_int_constraint_start;
00557         // diagonal entries, again
00558         
00559         const double hg_ii = eval_hess_int_x(x[i]); // e.g. -4. * PI * PI * cos( 2. * PI * x[i] );
00560         values[i] += lambda[k] * hg_ii;
00561 
00562         if (debugging)
00563         {
00564           printf("x_%d (%f) : lambda(%f) * d^2 wave(x_ii)/ dx_i^2 (%f)\n", i, x[i], lambda[k], hg_ii);
00565         }
00566       }
00567     }
00568     if (debugging)
00569       printf("\n");
00570   } // values
00571 
00572   return true;
00573 }
00574 
00575 void IAIntWaveNlp::finalize_solution(SolverReturn status,
00576                                       Index n, const Number* x, const Number* z_L, const Number* z_U,
00577                                       Index m, const Number* g, const Number* lambda,
00578                                       Number obj_value,
00579                                       const IpoptData* ip_data,
00580                                       IpoptCalculatedQuantities* ip_cq)
00581 {
00582   baseNlp.finalize_solution(status, n, x, z_L, z_U, m, g, lambda, obj_value, ip_data, ip_cq);
00583   
00584   // todo report on how close the integer and sum-even constraints were satisfied!
00585   // or do that in the caller
00586 }
00587 
00588 } // namespace MeshKit
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines