BonBranchingTQP.cpp
Go to the documentation of this file.
1 // (C) Copyright International Business Machines Corporation and Carnegie Mellon University 2006, 2008
2 // All Rights Reserved.
3 // This code is published under the Eclipse Public License.
4 //
5 // Authors :
6 // Andreas Waechter, International Business Machines Corporation
7 // (derived from BonTMINLP2TNLP.cpp) 12/22/2006
8 // Authors :
9 
10 
11 #include "BonBranchingTQP.hpp"
12 #include "IpBlas.hpp"
13 #include "IpAlgTypes.hpp"
14 #include <string>
15 #include <fstream>
16 #include <sstream>
17 
18 using namespace Ipopt;
19 
20 namespace Bonmin
21 {
22  BranchingTQP::BranchingTQP(SmartPtr<TMINLP2TNLP> tminlp2tnlp)
23  :
24  tminlp2tnlp_(tminlp2tnlp)
25  {
26  bool retval = tminlp2tnlp_->get_nlp_info(n_, m_, nnz_jac_g_,
28  ASSERT_EXCEPTION(retval, TMINLP_INVALID,
29  "Can't get NLP infor in BranchingTQP");
30  //DBG_ASSERT(x_sol_);
31  //DBG_ASSERT(duals_sol_);
32 
33  obj_grad_ = new Number[n_];
34  obj_hess_ = new Number[nnz_h_lag_];
35  obj_hess_irow_ = new Index[nnz_h_lag_];
36  obj_hess_jcol_ = new Index[nnz_h_lag_];
37  g_vals_ = new Number[m_];
38  g_jac_ = new Number[nnz_jac_g_];
39  g_jac_irow_ = new Index[nnz_jac_g_];
40  g_jac_jcol_ = new Index[nnz_jac_g_];
41 
42  const Number* x_sol = tminlp2tnlp_->x_sol();
43  const Number* duals_sol = tminlp2tnlp_->duals_sol();
44 
45  // Compute all nonlinear values at the starting point so that we
46  // have all the information for the QP
47  bool new_x = true; // ToDo: maybe NOT new?
48  retval = tminlp2tnlp_->eval_f(n_, x_sol, new_x, obj_val_);
49  ASSERT_EXCEPTION(retval, TMINLP_INVALID,
50  "Can't evaluate objective function in BranchingTQP");
51  new_x = false;
52  retval = tminlp2tnlp_->eval_grad_f(n_, x_sol, new_x, obj_grad_);
53  ASSERT_EXCEPTION(retval, TMINLP_INVALID,
54  "Can't evaluate objective gradient in BranchingTQP");
55  bool new_lambda = true; // ToDo: maybe NOT new?
56  retval = tminlp2tnlp_->eval_h(n_, x_sol, new_x, 1., m_, duals_sol + 2 * n_,
57  new_lambda, nnz_h_lag_, obj_hess_irow_,
58  obj_hess_jcol_, NULL);
59  ASSERT_EXCEPTION(retval, TMINLP_INVALID,
60  "Can't evaluate objective Hessian structure in BranchingTQP");
61  if (index_style_ == TNLP::FORTRAN_STYLE) {
62  for (Index i=0; i<nnz_h_lag_; i++) {
63  obj_hess_irow_[i]--;
64  obj_hess_jcol_[i]--;
65  }
66  }
67  retval = tminlp2tnlp_->eval_h(n_, x_sol, new_x, 1., m_, duals_sol + 2*n_,
68  new_lambda, nnz_h_lag_, NULL, NULL, obj_hess_);
69  ASSERT_EXCEPTION(retval, TMINLP_INVALID,
70  "Can't evaluate objective Hessian values in BranchingTQP");
71  retval = tminlp2tnlp_->eval_g(n_, x_sol, new_x, m_, g_vals_);
72  ASSERT_EXCEPTION(retval, TMINLP_INVALID,
73  "Can't evaluate constraint values in BranchingTQP");
74  retval = tminlp2tnlp_->eval_jac_g(n_, x_sol, new_x, m_, nnz_jac_g_,
75  g_jac_irow_, g_jac_jcol_, NULL);
76  ASSERT_EXCEPTION(retval, TMINLP_INVALID,
77  "Can't evaluate constraint Jacobian structure in BranchingTQP");
78  if (index_style_ == TNLP::FORTRAN_STYLE) {
79  for (Index i=0; i<nnz_jac_g_; i++) {
80  g_jac_irow_[i]--;
81  g_jac_jcol_[i]--;
82  }
83  }
84  retval = tminlp2tnlp_->eval_jac_g(n_, x_sol, new_x, m_, nnz_jac_g_,
85  NULL, NULL, g_jac_);
86  ASSERT_EXCEPTION(retval, TMINLP_INVALID,
87  "Can't evaluate constraint Jacobian values in BranchingTQP");
88 
89  // Keep copy of original x_sol and duals_sol values
90  x_sol_copy_ = new Number[n_];
91  IpBlasDcopy(n_, x_sol, 1, x_sol_copy_, 1);
92  duals_sol_copy_ = new Number[m_ + 2*n_];
93  IpBlasDcopy(m_+2*n_, duals_sol, 1, duals_sol_copy_, 1);
94 #if 0
95  for (int i=0; i<n_; i++) {
96  printf("x_sol_copy_[%3d] = %15.8e duals_sol_copy_[%3d] = %15.8e obj_grad_[%3d] = %15.8e\n", i,x_sol_copy_[i],i,duals_sol_copy_[i],i,obj_grad_[i]);
97  }
98  for (int i=0; i<m_; i++) {
99  printf("g_vals_[%3d] = %15.8e\n", i, g_vals_[i]);
100  }
101  for (int i=0; i<nnz_h_lag_; i++) {
102  printf("Hess[%3d,%3d] = %15.8e\n",obj_hess_irow_[i],obj_hess_jcol_[i],obj_hess_[i]);
103  }
104  for (int i=0; i<nnz_jac_g_; i++) {
105  printf("Jac[%3d,%3d] = %15.8e\n",g_jac_irow_[i],g_jac_jcol_[i],g_jac_[i]);
106  }
107 #endif
108  }
109 
111  {
112  delete [] obj_grad_;
113  delete [] obj_hess_;
114  delete [] obj_hess_irow_;
115  delete [] obj_hess_jcol_;
116  delete [] g_vals_;
117  delete [] g_jac_;
118  delete [] g_jac_irow_;
119  delete [] g_jac_jcol_;
120  delete [] x_sol_copy_;
121  delete [] duals_sol_copy_;
122  }
123 
124  bool BranchingTQP::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
125  Index& nnz_h_lag,
126  IndexStyleEnum& index_style)
127  {
128  n = n_;
129  m = m_;
130  nnz_jac_g = nnz_jac_g_;
131  nnz_h_lag = nnz_h_lag_;
132  index_style = index_style_;
133  return true;
134  }
135 
136  bool BranchingTQP::get_bounds_info(Index n, Number* x_l, Number* x_u,
137  Index m, Number* g_l, Number* g_u)
138  {
139  DBG_ASSERT(n == n_);
140  DBG_ASSERT(m == m_);
141  bool retval = tminlp2tnlp_->get_bounds_info(n, x_l, x_u, m, g_l, g_u);
142  // correct for displacement
143  for (int i=0; i<n; i++) {
144  x_l[i] -= x_sol_copy_[i];
145  x_u[i] -= x_sol_copy_[i];
146  }
147  // include the right hand side of the constraint
148  for (int i=0; i<m; i++) {
149  g_l[i] -= g_vals_[i];
150  g_u[i] -= g_vals_[i];
151  }
152  return retval;
153  }
154 
155  bool BranchingTQP::get_starting_point(Index n, bool init_x, Number* x,
156  bool init_z, Number* z_L, Number* z_U,
157  Index m, bool init_lambda,
158  Number* lambda)
159  {
160  DBG_ASSERT(n==n_);
161  if (init_x == true) {
162  const double zero = 0.;
163  IpBlasDcopy(n, &zero, 0, x, 1);
164  }
165  if (init_z == true) {
166  DBG_ASSERT(duals_sol_copy_);
167  IpBlasDcopy(n, duals_sol_copy_, 1, z_L, 1);
168  IpBlasDcopy(n, duals_sol_copy_ + n, 1, z_U, 1);
169 
170  }
171  if(init_lambda == true) {
172  DBG_ASSERT(duals_sol_copy_);
173  IpBlasDcopy(m_, duals_sol_copy_ + 2*n_, 1, lambda, 1);
174  for(int i = m_ ; i < m; i++)
175  {
176  lambda[i] = 0.;
177  }
178  }
179 
180  return true;
181  }
182 
183  bool
184  BranchingTQP::get_constraints_linearity(Index m, LinearityType* const_types)
185  {
186  for (int i=0; i<m; i++) {
187  const_types[i] = LINEAR;
188  }
189  return true;
190  }
191 
192  bool BranchingTQP::eval_f(Index n, const Number* x, bool new_x,
193  Number& obj_value)
194  {
195  DBG_ASSERT(n == n_);
196 
197  obj_value = IpBlasDdot(n, x, 1, obj_grad_, 1);
198  for (int i=0; i<nnz_h_lag_; i++) {
199  Index& irow = obj_hess_irow_[i];
200  Index& jcol = obj_hess_jcol_[i];
201  if (irow!=jcol) {
202  obj_value += obj_hess_[i]*x[irow]*x[jcol];
203  }
204  else {
205  obj_value += 0.5*obj_hess_[i]*x[irow]*x[irow];
206  }
207  }
208 
209  return true;
210  }
211 
212  bool BranchingTQP::eval_grad_f(Index n, const Number* x, bool new_x,
213  Number* grad_f)
214  {
215  DBG_ASSERT(n == n_);
216 
217  IpBlasDcopy(n_, obj_grad_, 1, grad_f, 1);
218  for (int i=0; i<nnz_h_lag_; i++) {
219  Index& irow = obj_hess_irow_[i];
220  Index& jcol = obj_hess_jcol_[i];
221  grad_f[irow] += obj_hess_[i]*x[jcol];
222  if (irow!=jcol) {
223  grad_f[jcol] += obj_hess_[i]*x[irow];
224  }
225  }
226 
227  return true;
228  }
229 
230  bool BranchingTQP::eval_g(Index n, const Number* x, bool new_x,
231  Index m, Number* g)
232  {
233  DBG_ASSERT(n == n_);
234 
235  const double zero = 0.;
236  IpBlasDcopy(m_, &zero, 0, g, 1);
237  for (Index i=0; i<nnz_jac_g_; i++) {
238  Index& irow = g_jac_irow_[i];
239  Index& jcol = g_jac_jcol_[i];
240  g[irow] += g_jac_[i]*x[jcol];
241  }
242 
243  return true;
244  }
245 
246  bool BranchingTQP::eval_jac_g(Index n, const Number* x, bool new_x,
247  Index m, Index nele_jac, Index* iRow,
248  Index *jCol, Number* values)
249  {
250  if (iRow != NULL) {
251  DBG_ASSERT(jCol != NULL);
252  DBG_ASSERT(values == NULL);
253  if (index_style_ == TNLP::FORTRAN_STYLE) {
254  for (Index i=0; i<nnz_jac_g_; i++) {
255  iRow[i] = g_jac_irow_[i] + 1;
256  jCol[i] = g_jac_jcol_[i] + 1;
257  }
258  }
259  else {
260  for (Index i=0; i<nnz_jac_g_; i++) {
261  iRow[i] = g_jac_irow_[i];
262  jCol[i] = g_jac_jcol_[i];
263  }
264  }
265  }
266  else {
267  IpBlasDcopy(nnz_jac_g_, g_jac_, 1, values, 1);
268  }
269 
270  return true;
271  }
272 
273  bool BranchingTQP::eval_h(Index n, const Number* x, bool new_x,
274  Number obj_factor, Index m, const Number* lambda,
275  bool new_lambda, Index nele_hess,
276  Index* iRow, Index* jCol, Number* values)
277  {
278  DBG_ASSERT(nele_hess == nnz_h_lag_);
279 
280  if (iRow != NULL) {
281  DBG_ASSERT(jCol != NULL);
282  DBG_ASSERT(values == NULL);
283  if (index_style_ == TNLP::FORTRAN_STYLE) {
284  for (Index i=0; i<nele_hess; i++) {
285  iRow[i] = obj_hess_irow_[i] + 1;
286  jCol[i] = obj_hess_jcol_[i] + 1;
287  }
288  }
289  else {
290  for (Index i=0; i<nele_hess; i++) {
291  iRow[i] = obj_hess_irow_[i];
292  jCol[i] = obj_hess_jcol_[i];
293  }
294  }
295  }
296  else {
297  if (obj_factor==0.) {
298  const Number zero = 0.;
299  IpBlasDcopy(nele_hess, &zero, 0, values, 1);
300  }
301  else {
302  IpBlasDcopy(nele_hess, obj_hess_, 1, values, 1);
303  if (obj_factor != 1.) {
304  IpBlasDscal(nele_hess, obj_factor, values, 1);
305  }
306  }
307  }
308 
309  return true;
310  }
311 
312  void BranchingTQP::finalize_solution(SolverReturn status,
313  Index n, const Number* x,
314  const Number* z_L, const Number* z_U,
315  Index m, const Number* g,
316  const Number* lambda, Number obj_value,
317  const IpoptData* ip_data,
318  IpoptCalculatedQuantities* ip_cq)
319  {
320  // Translate displacement solution back to a solution in the real
321  // variables
322  double* xx = new double[n];
323  for (int i=0; i<n; i++) {
324  xx[i] = x_sol_copy_[i] + x[i];
325  }
326 
327  double obj = obj_value + obj_val_;
328  if(status == Ipopt::LOCAL_INFEASIBILITY)
329  obj = obj_value;
330  tminlp2tnlp_->finalize_solution(status, n, xx, z_L, z_U, m, g, lambda,
331  obj, ip_data, ip_cq);
332  delete [] xx;
333  }
334 
335 }
336 // namespace Ipopt
337 
double * values
Ipopt::Number * x_sol_copy_
Copy of original x_sol_.
virtual void finalize_solution(Ipopt::SolverReturn status, Ipopt::Index n, const Ipopt::Number *x, const Ipopt::Number *z_L, const Ipopt::Number *z_U, Ipopt::Index m, const Ipopt::Number *g, const Ipopt::Number *lambda, Ipopt::Number obj_value, const Ipopt::IpoptData *ip_data, Ipopt::IpoptCalculatedQuantities *ip_cq)
Returns the constraint linearity.
virtual bool eval_grad_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number *grad_f)
Returns the vector of the gradient of the objective w.r.t.
fint irow
Ipopt::Number * g_vals_
virtual ~BranchingTQP()
Default destructor.
virtual bool get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number *x, bool init_z, Ipopt::Number *z_L, Ipopt::Number *z_U, Ipopt::Index m, bool init_lambda, Ipopt::Number *lambda)
Method called by Ipopt to get the starting point.
Ipopt::Index * obj_hess_irow_
Ipopt::Index * g_jac_irow_
virtual bool get_bounds_info(Ipopt::Index n, Ipopt::Number *x_l, Ipopt::Number *x_u, Ipopt::Index m, Ipopt::Number *g_l, Ipopt::Number *g_u)
Returns the constraint linearity.
Ipopt::Number * obj_grad_
Ipopt::SmartPtr< TMINLP2TNLP > tminlp2tnlp_
Pointer to the TMINLP2TNLP model which stores the bounds information.
Ipopt::Number * obj_hess_
virtual bool eval_f(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number &obj_value)
Returns the value of the objective function in x.
virtual bool get_constraints_linearity(Ipopt::Index m, LinearityType *const_types)
Returns the constraint linearity.
Ipopt::Number * g_jac_
virtual bool eval_jac_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index *iRow, Ipopt::Index *jCol, Ipopt::Number *values)
Returns the jacobian of the constraints.
virtual bool get_nlp_info(Ipopt::Index &n, Ipopt::Index &m, Ipopt::Index &nnz_jac_g, Ipopt::Index &nnz_h_lag, Ipopt::TNLP::IndexStyleEnum &index_style)
Returns the constraint linearity.
void fint fint fint real fint real real real real real real * g
Ipopt::Index * g_jac_jcol_
virtual bool eval_h(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Number obj_factor, Ipopt::Index m, const Ipopt::Number *lambda, bool new_lambda, Ipopt::Index nele_hess, Ipopt::Index *iRow, Ipopt::Index *jCol, Ipopt::Number *values)
Return the hessian of the lagrangian.
void fint * m
Ipopt::Number * duals_sol_copy_
Copy of original duals_sol_.
void fint * n
Ipopt::Index * obj_hess_jcol_
Ipopt::TNLP::IndexStyleEnum index_style_
virtual bool eval_g(Ipopt::Index n, const Ipopt::Number *x, bool new_x, Ipopt::Index m, Ipopt::Number *g)
Returns the vector of constraint values in x.
void fint fint fint real fint real * x