MeshKit
1.0
|
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