source: stable/0.1/Bonmin/src/IpoptInterface/TMINLP2TNLP.cpp @ 526

Last change on this file since 526 was 526, checked in by pbonami, 12 years ago

Transmit time limit to Ipopt

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