source: trunk/Bonmin/src/IpoptInterface/TMINLP2TNLP.cpp @ 24

Last change on this file since 24 was 24, checked in by andreasw, 13 years ago

Fix ticket #2

  • Property svn:eol-style set to native
  • Property svn:keywords set to "Author Date Id Revision"
File size: 14.9 KB
Line 
1// (C) Copyright International Business Machines Corporation and Carnegie Mellon University 2004
2// All Rights Reserved.
3// This code is published under the Common Public License.
4//
5// Authors :
6// Carl D. Laird, Carnegie Mellon University,
7// Andreas Waechter, International Business Machines Corporation
8// Pierre Bonami, Carnegie Mellon University,
9//
10// Date : 12/01/2004
11
12
13#include "TMINLP2TNLP.hpp"
14#include "IpBlas.hpp"
15#include "IpAlgTypes.hpp"
16#include <string>
17#include <fstream>
18#include <sstream>
19namespace Ipopt
20{
21  TMINLP2TNLP::TMINLP2TNLP(const SmartPtr<TMINLP> tminlp,
22      const OptionsList& options)
23      :
24      tminlp_(tminlp),
25      n_(0),
26      m_(0),
27      var_types_(NULL),
28      x_l_(NULL),
29      x_u_(NULL),
30      orig_x_l_(NULL),
31      orig_x_u_(NULL),
32      g_l_(NULL),
33      g_u_(NULL),
34      x_init_(NULL),
35      x_init_user_(NULL),
36      x_sol_(NULL),
37      g_sol_(NULL),
38      duals_sol_(NULL),
39//      return_status_(NOT_SOLVED),
40      obj_value_(1e100),
41      curr_warm_starter_(NULL),
42      need_new_warm_starter_(true)
43  {
44    // read the nlp size and bounds information from
45    // the TMINLP and keep an internal copy. This way the
46    // caller can modify the bounds that are sent to Ipopt;
47    DBG_ASSERT(IsValid(tminlp_));
48
49    Index nnz_jac_g;
50    tminlp_->get_nlp_info(n_, m_, nnz_jac_g, nnz_h_lag_, index_style_);
51
52    // Allocate space for the variable types vector
53    var_types_ = new TMINLP::VariableType[n_];
54
55    // retrieve the variable types
56    tminlp_->get_var_types(n_, var_types_);
57
58    // Allocate space for the internal copy of the variable bounds
59    x_l_ = new Number[n_];
60    x_u_ = new Number[n_];
61    orig_x_l_ = new Number[n_];
62    orig_x_u_ = new Number[n_];
63
64    g_l_ = new Number[m_];
65    g_u_ = new Number[m_];
66
67    // retrieve the variable bounds
68    tminlp_->get_bounds_info(n_, x_l_, x_u_, m_, g_l_, g_u_);
69    IpBlasDcopy(n_, x_l_, 1, orig_x_l_, 1);
70    IpBlasDcopy(n_, x_u_, 1, orig_x_u_, 1);
71
72    //    // Check that the bounds make sense compared with the variable type
73    //    for (int i=0; i<n_; i++) {
74    //      throw_exception_on_bad_variable_bound(i);
75    //    }
76
77    // Allocate space for the initial point
78    x_init_ = new Number[3*n_ + m_];
79    tminlp_->get_starting_point(n_, true, x_init_, false, NULL, NULL,
80        m_, false, NULL);
81    x_init_user_ = new Number[n_];
82    IpBlasDcopy(n_, x_init_, 1, x_init_user_, 1);
83    duals_sol_ = NULL;
84    duals_init_ = NULL;
85    // Get values for parameters
86    options.GetNumericValue("nlp_lower_bound_inf", nlp_lower_bound_inf_, "");
87    options.GetNumericValue("nlp_upper_bound_inf", nlp_upper_bound_inf_, "");
88    options.GetBoolValue("warm_start_entire_iterate",
89        warm_start_entire_iterate_, "");
90  }
91
92  TMINLP2TNLP::~TMINLP2TNLP()
93  {
94    delete [] var_types_;
95    var_types_ = NULL;
96    delete [] x_l_;
97    x_l_ = NULL;
98    delete [] x_u_;
99    x_u_ = NULL;
100    delete [] orig_x_l_;
101    orig_x_l_ = NULL;
102    delete [] orig_x_u_;
103    orig_x_u_ = NULL;
104    delete [] g_l_;
105    g_l_ = NULL;
106    delete [] g_u_;
107    g_u_ = NULL;
108    delete [] x_init_;
109    x_init_ = NULL;
110    delete [] x_init_user_;
111    x_init_user_ = NULL;
112    delete [] x_sol_;
113    x_sol_ = NULL;
114    delete [] g_sol_;
115    g_sol_ = NULL;
116    delete [] duals_sol_;
117    duals_sol_ = NULL;
118  }
119
120  /** Copies the modification made to TNLP by the user (modifications
121      such as changing bound changing starting point,...).
122      this and other should be two instances of the same problem
123      I am trying to mimic a copy construction for Cbc
124      use with great care not safe.
125  */
126  void
127  TMINLP2TNLP::copyUserModification(TMINLP2TNLP& other)
128  {
129    DBG_ASSERT(x_l_);
130    DBG_ASSERT(x_u_);
131    DBG_ASSERT(other.x_l_);
132    DBG_ASSERT(other.x_u_);
133    DBG_ASSERT(n_ = other.n_);
134    DBG_ASSERT(m_ = other.m_);
135
136    IpBlasDcopy(n_, other.x_l_, 1, x_l_, 1);
137    IpBlasDcopy(n_, other.x_u_, 1, x_u_, 1);
138
139    if(other.duals_init_) {
140      duals_init_ = &x_init_[n_];
141      IpBlasDcopy(3*n_+ m_, other.x_init_, 1, x_init_, 1);
142    }
143    else
144      IpBlasDcopy(n_, other.x_init_, 1, x_init_, 1);
145    return_status_ = other.return_status_;
146
147    if(other.x_sol_ !=NULL) {
148      //DBG_ASSERT(return_status_ != NOT_SOLVED);
149      Set_x_sol(n_,other.x_sol_);
150    }
151
152    if(other.g_sol_!=NULL) {
153//      DBG_ASSERT(return_status_ != NOT_SOLVED);
154      g_sol_ = new Number [m_];
155      IpBlasDcopy(m_, other.g_sol_, 1, g_sol_, 1);
156    }
157
158    if(other.duals_sol_!=NULL) {
159//      DBG_ASSERT(return_status_ != NOT_SOLVED);
160      duals_sol_ = new Number[m_ + 2*n_];
161      IpBlasDcopy(2*n_+ m_, other.duals_sol_, 1, duals_sol_, 1);
162    }
163
164    obj_value_ = other.obj_value_;
165
166    curr_warm_starter_ = other.curr_warm_starter_;
167
168    nlp_lower_bound_inf_ = other.nlp_lower_bound_inf_;
169
170    nlp_upper_bound_inf_ = other.nlp_upper_bound_inf_;
171
172    need_new_warm_starter_ = other.need_new_warm_starter_;
173  }
174
175  void TMINLP2TNLP::SetVariableBounds(Index var_no, Number x_l, Number x_u)
176  {
177    DBG_ASSERT(var_no >= 0 && var_no < n_);
178    x_l_[var_no] = x_l;
179    x_u_[var_no] = x_u;
180    //    throw_exception_on_bad_variable_bound(var_no);
181  }
182
183  void TMINLP2TNLP::SetVariableLowerBound(Index var_no, Number x_l)
184  {
185    DBG_ASSERT(var_no >= 0 && var_no < n_);
186    x_l_[var_no] = x_l;
187    //    throw_exception_on_bad_variable_bound(var_no);
188  }
189
190  void TMINLP2TNLP::SetVariableUpperBound(Index var_no, Number x_u)
191  {
192    DBG_ASSERT(var_no >= 0 && var_no < n_);
193    x_u_[var_no] = x_u;
194    //    throw_exception_on_bad_variable_bound(var_no);
195  }
196
197  void TMINLP2TNLP::SetStartingPoint(Index n,const Number* x_init)
198  {
199    DBG_ASSERT(n == n_);
200    IpBlasDcopy(n_, x_init, 1, x_init_, 1);
201  }
202
203  void TMINLP2TNLP::resetStartingPoint()
204  {
205    curr_warm_starter_ = NULL;
206    IpBlasDcopy(n_, x_init_user_, 1, x_init_, 1);
207  }
208
209  void TMINLP2TNLP::setxInit(Index ind, const Number val)
210  {
211    x_init_[ind] = val;
212  }
213
214  void TMINLP2TNLP::setxInit(Index n,const Number* x_init)
215  {
216    DBG_ASSERT(n == n_);
217    IpBlasDcopy(n_, x_init, 1, x_init_, 1);
218  }
219
220  void TMINLP2TNLP::setDualInit(Index ind, const Number val)
221  {
222    if(!duals_init_)
223      duals_init_ = &x_init_[n_];
224    duals_init_[ind] = val;
225  }
226
227  void TMINLP2TNLP::setDualsInit(Index n, const Number* duals_init)
228  {
229    DBG_ASSERT(n == m_ + 2 * n_);
230
231    if(!duals_init_)
232      duals_init_ = &x_init_[n_];
233
234    IpBlasDcopy(n, duals_init, 1, duals_init_, 1);
235
236  }
237
238  /** Set the contiuous solution */
239  void TMINLP2TNLP::Set_x_sol(Index n, const Number* x_sol)
240  {
241    DBG_ASSERT(n == n_);
242    if (!x_sol_) {
243      x_sol_ = new Number[n];
244    }
245    IpBlasDcopy(n_, x_sol, 1, x_sol_, 1);
246  }
247
248  /** Change the type of the variable */
249  void TMINLP2TNLP::SetVariableType(Index n, TMINLP::VariableType type)
250  {
251    DBG_ASSERT(n >= 0 && n < n_);
252    var_types_[n] = type;
253  }
254
255  bool TMINLP2TNLP::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
256      Index& nnz_h_lag, TNLP::IndexStyleEnum& index_style)
257  {
258    return tminlp_->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style);
259  }
260
261  bool TMINLP2TNLP::get_bounds_info(Index n, Number* x_l, Number* x_u,
262      Index m, Number* g_l, Number* g_u)
263  {
264    IpBlasDcopy(n, x_l_, 1, x_l, 1);
265    IpBlasDcopy(n, x_u_, 1, x_u, 1);
266    IpBlasDcopy(m, g_l_, 1, g_l, 1);
267    IpBlasDcopy(m, g_u_, 1, g_u, 1);
268
269    return true;
270  }
271
272  bool TMINLP2TNLP::get_starting_point(Index n, bool init_x, Number* x,
273      bool init_z, Number* z_L, Number* z_U,
274      Index m, bool init_lambda,
275      Number* lambda)
276  {
277    assert(m==m_);
278    assert(n==n_);
279    if (init_x == true) {
280      if(x_init_==NULL)
281        return false;
282      IpBlasDcopy(n, x_init_, 1, x, 1);
283    }
284    if (init_z == true) {
285      if(duals_init_ == NULL)
286        return false;
287      IpBlasDcopy(n, &duals_init_[m], 1, z_L, 1);
288      IpBlasDcopy(n, &duals_init_[m + n], 1, z_U, 1);
289
290    }
291    if(init_lambda == true) {
292      if(duals_init_ == NULL)
293        return false;
294      IpBlasDcopy(m, duals_init_, 1, lambda, 1);
295    }
296
297    need_new_warm_starter_ = true;
298    return true;
299  }
300
301  bool TMINLP2TNLP::get_warm_start_iterate(IteratesVector& warm_start_iterate)
302  {
303    if (IsNull(curr_warm_starter_)) {
304      return false;
305    }
306
307    bool retval = curr_warm_starter_->WarmStartIterate(n_, x_l_, x_u_,
308        warm_start_iterate);
309
310    need_new_warm_starter_ = true;
311    return retval;
312  }
313
314  bool TMINLP2TNLP::eval_f(Index n, const Number* x, bool new_x,
315      Number& obj_value)
316  {
317    return tminlp_->eval_f(n, x, new_x, obj_value);
318  }
319
320  bool TMINLP2TNLP::eval_grad_f(Index n, const Number* x, bool new_x,
321      Number* grad_f)
322  {
323    return tminlp_->eval_grad_f(n, x, new_x, grad_f);
324  }
325
326  bool TMINLP2TNLP::eval_g(Index n, const Number* x, bool new_x,
327      Index m, Number* g)
328  {
329    return tminlp_->eval_g(n, x, new_x, m, g);
330  }
331
332  bool TMINLP2TNLP::eval_jac_g(Index n, const Number* x, bool new_x,
333      Index m, Index nele_jac, Index* iRow,
334      Index *jCol, Number* values)
335  {
336    return tminlp_->eval_jac_g(n, x, new_x, m, nele_jac, iRow, jCol, values);
337  }
338
339  bool TMINLP2TNLP::eval_h(Index n, const Number* x, bool new_x,
340      Number obj_factor, Index m, const Number* lambda,
341      bool new_lambda, Index nele_hess,
342      Index* iRow, Index* jCol, Number* values)
343  {
344    return tminlp_->eval_h(n, x, new_x, obj_factor, m, lambda,
345        new_lambda, nele_hess,
346        iRow, jCol, values);
347  }
348
349  void TMINLP2TNLP::finalize_solution(SolverReturn status,
350      Index n, const Number* x, const Number* z_L, const Number* z_U,
351      Index m, const Number* g, const Number* lambda,
352      Number obj_value)
353  {
354    assert(n==n_);
355    assert(m==m_);
356    if (!x_sol_) {
357      x_sol_ = new Number[n];
358    }
359    IpBlasDcopy(n, x, 1, x_sol_, 1);
360
361    if(!g_sol_) {
362      g_sol_ = new Number [m];
363    }
364    IpBlasDcopy(m, g, 1, g_sol_, 1);
365    if (!duals_sol_) {
366      duals_sol_ = new Number[m + 2*n];
367    }
368    IpBlasDcopy(m, lambda, 1, duals_sol_, 1);
369
370    IpBlasDcopy(n, z_L, 1 , &duals_sol_[m], 1);
371    IpBlasDcopy(n, z_U, 1 , &duals_sol_[m + n], 1);
372
373    return_status_ = status;
374    obj_value_ = obj_value;
375
376    if (IsValid(curr_warm_starter_)) {
377      curr_warm_starter_->Finalize();
378    }
379  }
380
381  void TMINLP2TNLP::throw_exception_on_bad_variable_bound(Index i)
382  {
383    DBG_ASSERT(i >= 0 && i < n_);
384
385    if (var_types_[i] == TMINLP::BINARY) {
386      ASSERT_EXCEPTION(x_l_[i] == 0 && x_u_[i] == 1,
387          TMINLP_INVALID_VARIABLE_BOUNDS,
388          "Invalid variable bounds in TMINLP. All binaries must have 0,1 for variable bounds."
389                      );
390    }
391    else if (var_types_[i] == TMINLP::INTEGER) {
392      if(fabs(x_l_[i])<INT_MAX && fabs(x_u_[i]) < INT_MAX)//round to closest valid integer
393      {
394        int x_l = (int)ceil(x_l_[i]);
395        int x_u = (int)floor(x_u_[i]);
396        std::cerr<<"Inconsistent bounds on an integer"<<std::endl;
397        ASSERT_EXCEPTION(x_l_[i] == (Number)x_l && x_u_[i] == (Number)x_u,
398            TMINLP_INVALID_VARIABLE_BOUNDS,
399            "Invalid variable bounds in TMINLP. All integer variables must have integer bounds."
400                        );
401      }
402    }
403  }
404  bool TMINLP2TNLP::checkZeroDimension(ApplicationReturnStatus
405      &optimization_status)
406  {
407    for(int i = 0 ; i < n_ ; i++) {
408      if(x_u_[i] - x_l_[i] > 1e-5)
409        return 0;
410    }
411
412    //Problem has no variables just check if the unique solution given by the bounds is
413    // feasible or not.
414    eval_f(n_, x_l_, true, obj_value_);
415    if (!x_sol_) {
416      x_sol_ = new Number[n_];
417    }
418    IpBlasDcopy(n_, x_l_, 1, x_sol_, 1);
419
420    if(!g_sol_) {
421      g_sol_ = new Number [m_];
422    }
423    eval_g(n_, x_l_, true, m_, g_sol_);
424    optimization_status = Solve_Succeeded;
425    for(int i = 0 ; i < m_ ; i++) {
426      if(g_sol_[i] - g_l_[i] <  - 1e-07 || g_sol_[i] - g_u_[i] > 1e-07) {
427        optimization_status = Infeasible_Problem_Detected;
428        return 1;
429      }
430    }
431    return 1;
432  }
433
434  bool TMINLP2TNLP::intermediate_callback(AlgorithmMode mode,
435      Index iter, Number obj_value,
436      Number inf_pr, Number inf_du,
437      Number mu, Number d_norm,
438      Number regularization_size,
439      Number alpha_du, Number alpha_pr,
440      Index ls_trials,
441      const IpoptData* ip_data,
442      IpoptCalculatedQuantities* ip_cq)
443  {
444    // If we don't have this swtiched on, we assume that also the
445    // "warm_start" option for bonmin is set not to refer to the
446    // interior warm start object
447    if (!warm_start_entire_iterate_) {
448      return true;
449    }
450
451    if (need_new_warm_starter_) {
452      // Create a new object for later warm start information
453      curr_warm_starter_ = new IpoptInteriorWarmStarter(n_, x_l_, x_u_,
454          nlp_lower_bound_inf_,
455          nlp_upper_bound_inf_,
456          warm_start_entire_iterate_);
457      need_new_warm_starter_ = false;
458    }
459
460    return curr_warm_starter_->UpdateStoredIterates(mode, *ip_data, *ip_cq);
461  }
462
463
464  /** Procedure to ouptut relevant informations to reproduce a sub-problem.
465  Compare the current problem to the problem to solve
466  and writes files with bounds which have changed and current starting point.
467
468  */
469  void
470  TMINLP2TNLP::outputDiffs(const std::string& probName, const std::string * varNames)
471  {
472    const int &numcols = n_;
473    const int &numrows = m_;
474
475    const double * currentLower = x_l();
476    const double * currentUpper = x_u();
477
478    const double * originalLower = orig_x_l();
479    const double * originalUpper = orig_x_u();
480    CoinRelFltEq eq;
481    std::string fBoundsName = probName;
482    std::ostringstream os;
483    fBoundsName+=".bounds";
484    std::string fModName = probName;
485    fModName+= ".mod";
486    std::ofstream fBounds;
487    std::ofstream fMod;
488    bool hasVarNames = 0;
489
490    if(varNames!=NULL )
491      hasVarNames=1;
492    if(hasVarNames)
493      fMod.open(fModName.c_str());
494    fBounds.open(fBoundsName.c_str());
495
496    for(int i = 0 ; i < numcols ; i++) {
497      if(!eq(currentLower[i],originalLower[i])) {
498        if(hasVarNames)
499          fMod<<"bounds"<<i<<": "
500          <<varNames[i]<<" >= "
501          <<currentLower[i]<<";\n";
502
503
504        fBounds<<"LO"<<"\t"<<i<<"\t"<<currentLower[i]<<std::endl;
505      }
506      if(!eq(currentUpper[i],originalUpper[i])) {
507        if(hasVarNames)
508          fMod<<"bounds"<<i<<": "
509          <<varNames[i]<<" <= "
510          <<currentUpper[i]<<";\n";
511
512        fBounds<<"UP"<<"\t"<<i<<"\t"<<currentUpper[i]<<std::endl;
513      }
514    }
515
516    //write a file with starting point
517    std::string fStartPointName=probName;
518    fStartPointName+=".start";
519
520    std::ofstream fStartPoint(fStartPointName.c_str());
521    const double * primals = x_init();
522    const double * duals = duals_init();
523    fStartPoint.precision(17);
524    fStartPoint<<numcols<<"\t"<<2*numcols+numrows<<std::endl;
525    for(int i = 0 ; i < numcols ; i++)
526      fStartPoint<<primals[i]<<std::endl;
527    int end = 2*numcols + numrows;
528    if(duals) {
529      for(int i = 0 ; i < end; i++)
530        fStartPoint<<duals[i]<<std::endl;
531    }
532
533  }
534
535  /** force solution to be fractionnal.*/
536  void
537  TMINLP2TNLP::force_fractionnal_sol()
538  {
539    for(int i=0 ; i < n_ ; i++) {
540      if( ( var_types_[i] == TMINLP::INTEGER ||
541          var_types_[i] == TMINLP::BINARY )&&
542          x_l_[i] < x_u_[i] + 0.5)//not fixed
543      {
544        x_sol_[i] = ceil(x_l_[i]) + 0.5;//make it integer infeasible
545      }
546    }
547  }
548
549}
550// namespace Ipopt
551
552
553
554
555
556
Note: See TracBrowser for help on using the repository browser.