1 // (C) Copyright International Business Machines Corporation and
2 // Carnegie Mellon University 2004-2011
3 //
4 // All Rights Reserved.
5 // This code is published under the Eclipse Public License.
6 //
7 // Authors :
8 // Carl D. Laird, Carnegie Mellon University,
9 // Andreas Waechter, International Business Machines Corporation
10 // Pierre Bonami, Carnegie Mellon University,
11 //
12 // Date : 12/01/2004
13 #include "IpBlas.hpp"
14 
15 #include <list>
16 
17 #include "AmplTNLP.hpp"
18 #include "BonAmplTMINLP.hpp"
19 #include <iostream>
20 #include <fstream>
21 
22 #include "CoinHelperFunctions.hpp"
23 #include "BonExitCodes.hpp"
24 
25 using namespace Ipopt;
26 
27 namespace Bonmin{
28   void
fillAmplOptionList(ExtraCategoriesInfo which,Ipopt::AmplOptionsList * amplOptList)29   RegisteredOptions::fillAmplOptionList(ExtraCategoriesInfo which, Ipopt::AmplOptionsList * amplOptList){
30       std::list<int> test;
31       std::list< Ipopt::RegisteredOption * > options;
32       chooseOptions(which, options);
33       for(std::list< Ipopt::RegisteredOption * >::iterator i = options.begin();
34            i != options.end() ; i++)
35        {
36            std::string name = "bonmin.";
37            name += (*i)->Name();
38            Ipopt::RegisteredOptionType T = (*i)->Type();
39            Ipopt::AmplOptionsList::AmplOptionType  type;
40            switch(T){
41              case Ipopt::OT_Number: type = Ipopt::AmplOptionsList::Number_Option;
42                   break;
43              case Ipopt::OT_Integer: type = Ipopt::AmplOptionsList::Integer_Option;
44                   break;
45              case Ipopt::OT_String: type = Ipopt::AmplOptionsList::String_Option;
46                   break;
47              case Ipopt::OT_Unknown:
48              default:
49                 throw CoinError("RegisteredOptions","fillAmplOptionList","Unknown option type");
50            }
51            amplOptList->AddAmplOption(name, name, type, (*i)->ShortDescription());
52        }
53 }
54 }
55 #include "asl.h"
56 #include "asl_pfgh.h"
57 #include "getstub.h"
58 
59 namespace ampl_utils
60 {
61   void sos_kludge(int nsos, int *sosbeg, double *sosref);
62 }
63 namespace Bonmin
64 {
65 
AmplTMINLP()66   AmplTMINLP::AmplTMINLP()
67       :
68       TMINLP(),
69       appName_(),
70       upperBoundingObj_(-1),
71       ampl_tnlp_(NULL),
72       branch_(),
73       sos_(),
74       suffix_handler_(NULL),
75       constraintsConvexities_(NULL),
76       numberNonConvex_(0),
77       nonConvexConstraintsAndRelaxations_(NULL),
78       numberSimpleConcave_(0),
79       simpleConcaves_(NULL),
80       hasLinearObjective_(false)
81   {}
82 
83 
AmplTMINLP(const SmartPtr<const Journalist> & jnlst,const SmartPtr<Bonmin::RegisteredOptions> roptions,const SmartPtr<OptionsList> options,char ** & argv,AmplSuffixHandler * suffix_handler,const std::string & appName,std::string * nl_file_content)84   AmplTMINLP::AmplTMINLP(const SmartPtr<const Journalist>& jnlst,
85       const SmartPtr<Bonmin::RegisteredOptions> roptions,
86       const SmartPtr<OptionsList> options,
87       char**& argv,
88       AmplSuffixHandler* suffix_handler /*=NULL*/,
89       const std::string& appName,
90       std::string* nl_file_content /* = NULL */
91                         )
92       :
93       TMINLP(),
94       appName_(),
95       upperBoundingObj_(-1),
96       ampl_tnlp_(NULL),
97       branch_(),
98       sos_(),
99       suffix_handler_(NULL),
100       constraintsConvexities_(NULL),
101       numberNonConvex_(0),
102       nonConvexConstraintsAndRelaxations_(NULL),
103       numberSimpleConcave_(0),
104       simpleConcaves_(NULL),
105       hasLinearObjective_(false)
106   {
107     Initialize(jnlst, roptions, options, argv, suffix_handler, appName, nl_file_content);
108   }
109 
110   void
Initialize(const SmartPtr<const Journalist> & jnlst,const SmartPtr<Bonmin::RegisteredOptions> roptions,const SmartPtr<OptionsList> options,char ** & argv,AmplSuffixHandler * suffix_handler,const std::string & appName,std::string * nl_file_content)111   AmplTMINLP::Initialize(const SmartPtr<const Journalist>& jnlst,
112       const SmartPtr<Bonmin::RegisteredOptions> roptions,
113       const SmartPtr<OptionsList> options,
114       char**& argv,
115       AmplSuffixHandler* suffix_handler /*=NULL*/,
116       const std::string& appName,
117       std::string* nl_file_content /* = NULL */
118                         )
119   {
120     appName_ = appName;
121     options->GetEnumValue("file_solution",writeAmplSolFile_,"bonmin.");
122     jnlst_ = jnlst;
123 
124     if (suffix_handler==NULL)
125       suffix_handler_ = suffix_handler = new AmplSuffixHandler();
126 
127     // Add the suffix handler for scaling
128     suffix_handler->AddAvailableSuffix("scaling_factor", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
129     suffix_handler->AddAvailableSuffix("scaling_factor", AmplSuffixHandler::Constraint_Source, AmplSuffixHandler::Number_Type);
130     suffix_handler->AddAvailableSuffix("scaling_factor", AmplSuffixHandler::Objective_Source, AmplSuffixHandler::Number_Type);
131 
132     // Modified for warm-start from AMPL
133     suffix_handler->AddAvailableSuffix("ipopt_zL_out", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
134     suffix_handler->AddAvailableSuffix("ipopt_zU_out", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
135     suffix_handler->AddAvailableSuffix("ipopt_zL_in", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
136     suffix_handler->AddAvailableSuffix("ipopt_zU_in", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
137 
138     // priority suffix
139     suffix_handler->AddAvailableSuffix("priority", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Index_Type);
140     suffix_handler->AddAvailableSuffix("direction", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
141     suffix_handler->AddAvailableSuffix("downPseudocost", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
142     suffix_handler->AddAvailableSuffix("upPseudocost", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
143 
144 
145 
146     // sos suffixes
147     suffix_handler->AddAvailableSuffix("ref", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
148     suffix_handler->AddAvailableSuffix("sos",AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Index_Type);
149     suffix_handler->AddAvailableSuffix("sos",AmplSuffixHandler::Constraint_Source, AmplSuffixHandler::Index_Type);
150     suffix_handler->AddAvailableSuffix("sosno",AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
151     suffix_handler->AddAvailableSuffix("sosref",AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
152     suffix_handler->AddAvailableSuffix("sstatus", AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Index_Type);
153     suffix_handler->AddAvailableSuffix("sstatus", AmplSuffixHandler::Constraint_Source, AmplSuffixHandler::Index_Type);
154 
155 
156     // For marking convex/nonconvex constraints
157     suffix_handler->AddAvailableSuffix("non_conv",AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Index_Type);
158     suffix_handler->AddAvailableSuffix("primary_var",AmplSuffixHandler::Constraint_Source, AmplSuffixHandler::Index_Type);
159 
160     // For marking onoff constraints and indicator variables
161     suffix_handler->AddAvailableSuffix("onoff_c",AmplSuffixHandler::Constraint_Source, AmplSuffixHandler::Index_Type);
162     suffix_handler->AddAvailableSuffix("onoff_v",AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Index_Type);
163 
164     // For objectives
165     suffix_handler->AddAvailableSuffix("UBObj", AmplSuffixHandler::Objective_Source, AmplSuffixHandler::Index_Type);
166 
167 
168     // Perturbation radius
169     suffix_handler->AddAvailableSuffix("perturb_radius",AmplSuffixHandler::Variable_Source, AmplSuffixHandler::Number_Type);
170 
171     SmartPtr<AmplOptionsList> ampl_options_list = new AmplOptionsList();
172     roptions->fillAmplOptionList(RegisteredOptions::BonminCategory, GetRawPtr(ampl_options_list));
173     roptions->fillAmplOptionList(RegisteredOptions::FilterCategory, GetRawPtr(ampl_options_list));
174     roptions->fillAmplOptionList(RegisteredOptions::BqpdCategory, GetRawPtr(ampl_options_list));
175     fillApplicationOptions(GetRawPtr(ampl_options_list) );
176     std::string options_id = appName + "_options";
177     ampl_tnlp_ = new AmplTNLP(jnlst, options, argv, suffix_handler, true,
178         ampl_options_list, options_id.c_str(),
179         appName.c_str(), appName.c_str(), nl_file_content);
180 
181 
182     /* Read suffixes */
183     read_obj_suffixes();
184     read_priorities();
185     read_convexities();
186     read_onoff();
187     read_sos();
188 
189 
190     /* Determine if objective is linear.*/
191     Index n_non_linear_b= 0;
192     Index n_non_linear_bi= 0;
193     Index n_non_linear_c= 0;
194     Index n_non_linear_ci = 0;
195     Index n_non_linear_o= 0;
196     Index n_non_linear_oi = 0;
197     Index n_binaries = 0;
198     Index n_integers = 0;
199     ampl_tnlp_->get_discrete_info(n_non_linear_b, n_non_linear_bi, n_non_linear_c,
200         n_non_linear_ci, n_non_linear_o, n_non_linear_oi,
201         n_binaries, n_integers);
202     if (n_non_linear_b == 0 && n_non_linear_o == 0) {
203       hasLinearObjective_ = true;
204     }
205   }
206 
~AmplTMINLP()207   AmplTMINLP::~AmplTMINLP()
208   {
209     delete [] constraintsConvexities_;
210     delete [] simpleConcaves_;
211     delete [] nonConvexConstraintsAndRelaxations_;
212     delete ampl_tnlp_;
213   }
214 
215   void
read_priorities()216   AmplTMINLP::read_priorities()
217   {
218     int numcols, m, dummy1, dummy2;
219     TNLP::IndexStyleEnum index_style;
220     ampl_tnlp_->get_nlp_info(numcols, m, dummy1, dummy2, index_style);
221 
222     const AmplSuffixHandler * suffix_handler = GetRawPtr(suffix_handler_);
223 
224     const Index* pri = suffix_handler->GetIntegerSuffixValues("priority", AmplSuffixHandler::Variable_Source);
225     const Index* brac = suffix_handler->GetIntegerSuffixValues("direction", AmplSuffixHandler::Variable_Source);
226     const Number* upPs = suffix_handler->GetNumberSuffixValues("upPseudocost", AmplSuffixHandler::Variable_Source);
227     const Number* dwPs = suffix_handler->GetNumberSuffixValues("downPseudocost", AmplSuffixHandler::Variable_Source);
228 
229 
230     branch_.gutsOfDestructor();
231     branch_.size = numcols;
232     if (pri) {
233       branch_.priorities = new int[numcols];
234       for (int i = 0 ; i < numcols ; i++) {
235         branch_.priorities [i] = -pri[i] + 9999;
236       }
237     }
238     if (brac) {
239       branch_.branchingDirections = CoinCopyOfArray(brac,numcols);
240     }
241     if (upPs && !dwPs) dwPs = upPs;
242     else if (dwPs && !upPs) upPs = dwPs;
243 
244     if (upPs) {
245       branch_.upPsCosts = CoinCopyOfArray(upPs,numcols);
246     }
247     if (dwPs) {
248       branch_.downPsCosts = CoinCopyOfArray(dwPs,numcols);
249     }
250 
251     const double* perturb_radius =
252       suffix_handler->GetNumberSuffixValues("perturb_radius", AmplSuffixHandler::Variable_Source);
253     perturb_info_.SetPerturbationArray(numcols, perturb_radius);
254   }
255 
256   void
read_sos()257   AmplTMINLP::read_sos()
258   {
259     ASL_pfgh* asl = ampl_tnlp_->AmplSolverObject();
260     int i = 0;//ASL_suf_sos_explict_free;
261     int copri[2], **p_sospri;
262     copri[0] = 0;
263     copri[1] = 0;
264     int * starts = NULL;
265     int * indices = NULL;
266     char * types = NULL;
267     double * weights = NULL;
268     int * priorities = NULL;
269     p_sospri = &priorities;
270 
271     sos_.gutsOfDestructor();
272     int m = n_con;
273     sos_.num = suf_sos(i, &sos_.numNz, &types, p_sospri, copri,
274         &starts, &indices, &weights);
275     if(m != n_con){
276       throw CoinError("number of constraints changed by suf_sos. Not supported.",
277                        "read_sos","Bonmin::AmplTMINLP");
278    }
279     if (sos_.num) {
280       //Copy sos information
281       sos_.priorities = CoinCopyOfArray(priorities,sos_.num);
282       sos_.starts = CoinCopyOfArray(starts, sos_.num + 1);
283       sos_.indices = CoinCopyOfArray(indices, sos_.numNz);
284       sos_.types = CoinCopyOfArray(types, sos_.num);
285       sos_.weights = CoinCopyOfArray(weights, sos_.numNz);
286 
287       ampl_utils::sos_kludge(sos_.num, sos_.starts, sos_.weights);
288       for (int ii=0;ii<sos_.num;ii++) {
289         int ichar = sos_.types[ii] - '0';
290         if (ichar != 1 && ichar != 2) {
291           std::cerr<<"Unsuported type of sos constraint: "<<sos_.types[ii]<<std::endl;
292           throw;
293         }
294         sos_.types[ii]= static_cast<char>(ichar);
295       }
296     }
297   }
298 
299   void
read_obj_suffixes()300   AmplTMINLP::read_obj_suffixes()
301   {
302     ASL_pfgh* asl = ampl_tnlp_->AmplSolverObject();
303     DBG_ASSERT(asl);
304     //Get the values
305     if (n_obj < 2) return;
306 
307     const AmplSuffixHandler * suffix_handler = GetRawPtr(suffix_handler_);
308 
309     const Index* UBObj = suffix_handler->GetIntegerSuffixValues("UBObj", AmplSuffixHandler::Objective_Source);
310     if (UBObj) {
311       //get index of lower bounding objective
312       int lowerBoundingObj = (UBObj[0] == 1)? 1:0;
313       // Pass information to Ipopt
314       ampl_tnlp_->set_active_objective(lowerBoundingObj);
315 
316       //get the index of upper bounding objective
317       for (int i = 0; i < n_obj; i++) {
318         if (UBObj[i]==1) {
319           if (upperBoundingObj_ != -1) {
320             jnlst_->Printf(J_ERROR, J_MAIN,
321                 "Too many objectives for upper-bounding");
322           }
323           upperBoundingObj_ = i;
324         }
325       }
326     }
327     else {
328       ampl_tnlp_->set_active_objective(0);
329     }
330   }
331   /** To store all data stored in the nonconvex suffixes.*/
332   struct NonConvexSuff
333   {
334     /** Default constructor.*/
NonConvexSuffBonmin::NonConvexSuff335     NonConvexSuff():
336         cIdx(-1),relIdx(-1),scXIdx(-1),scYIdx(-1)
337     {}
338     /** Copy constructor.*/
NonConvexSuffBonmin::NonConvexSuff339     NonConvexSuff(const NonConvexSuff& other):
340         cIdx(other.cIdx), relIdx(other.relIdx),
341         scXIdx(other.scXIdx), scYIdx(other.scYIdx)
342     {}
343     /** Index of the nonconvex constraint.*/
344     int cIdx;
345     /** Index of its relaxation.*/
346     int relIdx;
347     /** Index of variable x in a simple concave constraint of type y >= F(x).*/
348     int scXIdx;
349     /** Index of variable y in a simple concave constraint of type y >= F(x).*/
350     int scYIdx;
351   };
read_convexities()352   void AmplTMINLP::read_convexities()
353   {
354     ASL_pfgh* asl = ampl_tnlp_->AmplSolverObject();
355     DBG_ASSERT(asl);
356 
357     const AmplSuffixHandler * suffix_handler = GetRawPtr(suffix_handler_);
358     const Index * id = suffix_handler->GetIntegerSuffixValues("non_conv", AmplSuffixHandler::Variable_Source);
359     const Index * primary_var = suffix_handler->GetIntegerSuffixValues("primary_var", AmplSuffixHandler::Constraint_Source);
360 
361 
362     if (primary_var!= NULL) {
363       if (constraintsConvexities_ != NULL) {
364         delete [] constraintsConvexities_;
365       }
366       constraintsConvexities_ = new TMINLP::Convexity[n_con];
367       if (id == NULL) {
368         std::cerr<<"Incorrect suffixes description in ampl model. n_conv's are not declared "<<std::endl;
369         exit(ERROR_IN_AMPL_SUFFIXES);
370       }
371       int numberSimpleConcave = 0;
372       std::map<int, int> id_map;
373 
374       for (int i = 0 ; i < n_var ; i++) {
375         id_map[id[i]] = i;
376       }
377 
378 
379       for (int i = 0 ; i < n_con ; i++) {
380         if (primary_var[i] != 0) {
381           constraintsConvexities_[i] = TMINLP::SimpleConcave;
382           numberSimpleConcave++;
383         }
384         else constraintsConvexities_[i] = TMINLP::Convex;
385       }
386       simpleConcaves_ = new SimpleConcaveConstraint[numberSimpleConcave];
387       nonConvexConstraintsAndRelaxations_ = new MarkedNonConvex[numberSimpleConcave];
388       numberSimpleConcave = 0;
389       int * jCol = new int[n_var];
390       for (int i = 0 ; i < n_con ; i++) {
391         if (primary_var[i] != 0) {
392           nonConvexConstraintsAndRelaxations_[numberSimpleConcave].cIdx = i;
393           nonConvexConstraintsAndRelaxations_[numberSimpleConcave].cRelaxIdx = -1;
394           simpleConcaves_[numberSimpleConcave].cIdx = i;
395           simpleConcaves_[numberSimpleConcave].yIdx = id_map[primary_var[i]];
396 
397           //Now get gradient of i to get xIdx.
398           int nnz;
399           int & yIdx = simpleConcaves_[numberSimpleConcave].yIdx;
400           int & xIdx = simpleConcaves_[numberSimpleConcave].xIdx;
401           eval_grad_gi(n_var, NULL, false, i, nnz, jCol, NULL);
402           if (nnz != 2) {//Error in ampl model
403             std::cout<<"Incorrect suffixes description in ampl model. Constraint with id "
404             <<id<<" is simple concave and should have only two nonzero elements"<<std::endl;
405             exit(ERROR_IN_AMPL_SUFFIXES);
406           }
407           if (jCol[0] - 1== yIdx) {
408             xIdx = jCol[1] - 1;
409           }
410           else {
411             if (jCol[1] - 1!= yIdx) {//Error in ampl model
412               std::cout<<"Incorrect suffixes description in ampl model. Constraint with id "
413               <<id<<" : variable marked as y does not appear in the constraint."<<std::endl;
414               exit(ERROR_IN_AMPL_SUFFIXES);
415             }
416             xIdx = jCol[0] - 1;
417           }
418           numberSimpleConcave++;
419         }
420       }
421       delete [] jCol;
422       numberSimpleConcave_ = numberSimpleConcave;
423       numberNonConvex_ = numberSimpleConcave;
424     }
425 
426   }
427 
428 
read_onoff()429   void AmplTMINLP::read_onoff()
430   {
431     ASL_pfgh* asl = ampl_tnlp_->AmplSolverObject();
432     DBG_ASSERT(asl);
433 
434     const AmplSuffixHandler * suffix_handler = GetRawPtr(suffix_handler_);
435     const Index * onoff_c = suffix_handler->GetIntegerSuffixValues("onoff_c", AmplSuffixHandler::Constraint_Source);
436     const Index * onoff_v = suffix_handler->GetIntegerSuffixValues("onoff_v", AmplSuffixHandler::Variable_Source);
437 
438     if(onoff_c == NULL && onoff_v == NULL){//No suffixes
439       return;
440     }
441     if(onoff_c == NULL || onoff_v == NULL){// If one in non-null both should be
442         std::cerr<<"Incorrect suffixes description in ampl model.  One of per_v or per_c is declared but not the other."<<std::endl;
443         exit(ERROR_IN_AMPL_SUFFIXES);
444     }
445 
446     c_extra_id_.clear();
447     c_extra_id_.resize(n_con, -1);
448     std::map<int, int> id_map;
449 
450       for (int i = 0 ; i < n_var ; i++) {
451         if(onoff_v[i] > 0)
452           id_map[onoff_v[i]] = i;
453       }
454 
455       for (int i = 0 ; i < n_con ; i++) {
456         if(onoff_c[i] > 0){
457           std::map<int, int >::iterator k = id_map.find(onoff_c[i]);
458           if(k != id_map.end()){
459             c_extra_id_[i] = (*k).second;
460           }
461           else{
462             std::cerr<<"Incorrect suffixes description in ampl model. onoff_c has value attributed to no variable "<<std::endl;
463             exit(ERROR_IN_AMPL_SUFFIXES);
464           }
465         }
466       }
467    }
468 
get_nlp_info(Index & n,Index & m,Index & nnz_jac_g,Index & nnz_h_lag,TNLP::IndexStyleEnum & index_style)469   bool AmplTMINLP::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g, Index& nnz_h_lag, TNLP::IndexStyleEnum& index_style)
470   {
471     return ampl_tnlp_->get_nlp_info(n, m, nnz_jac_g, nnz_h_lag, index_style);
472   }
473 
get_variables_types(Index n,VariableType * var_types)474   bool AmplTMINLP::get_variables_types(Index n, VariableType* var_types)
475   {
476     // The variables are sorted by type in AMPL, so all we need to
477     // know are the counts of each type.
478 
479 
480     Index n_non_linear_b= 0;
481     Index n_non_linear_bi= 0;
482     Index n_non_linear_c= 0;
483     Index n_non_linear_ci = 0;
484     Index n_non_linear_o= 0;
485     Index n_non_linear_oi = 0;
486     Index n_binaries = 0;
487     Index n_integers = 0;
488     ampl_tnlp_->get_discrete_info(n_non_linear_b, n_non_linear_bi, n_non_linear_c,
489         n_non_linear_ci, n_non_linear_o, n_non_linear_oi,
490         n_binaries, n_integers);
491     int totalNumberOfNonContinuous = 0;
492 
493 
494     //begin with variables non-linear both in the objective function and in some constraints
495     // The first ones are continuous
496     Index start = 0;
497     Index end = n_non_linear_b - n_non_linear_bi;
498     for (int i=start; i<end; i++) {
499       var_types[i] = CONTINUOUS;
500     }
501 
502     // The second ones are integers
503     start = end;
504     end = start + n_non_linear_bi;
505     for (int i=start; i < end; i++) {
506       var_types[i] = INTEGER;
507       totalNumberOfNonContinuous++;
508     }
509     //next variables non-linear in some constraints
510     // The first ones are continuous
511     start = end;
512     end = std::max(start,end + n_non_linear_c - n_non_linear_ci - n_non_linear_b);
513     for (int i=start; i<end; i++) {
514       var_types[i] = CONTINUOUS;
515     }
516 
517     // The second ones are integers
518     start = end;
519     end = start + n_non_linear_ci;
520     for (int i=start; i < end; i++) {
521       var_types[i] = INTEGER;
522       totalNumberOfNonContinuous++;
523     }
524 
525     //next variables non-linear in the objective function
526     // The first ones are continuous
527     start = end;
528     end = std::max(start,end + n_non_linear_o - std::max(n_non_linear_b, n_non_linear_c) - n_non_linear_oi);
529     for (int i=start; i<end; i++) {
530       var_types[i] = CONTINUOUS;
531     }
532 
533     // The second ones are integers
534     start = end;
535     end = start + n_non_linear_oi;
536     for (int i=start; i < end; i++) {
537       var_types[i] = INTEGER;
538       totalNumberOfNonContinuous++;
539     }
540 
541     //At last the linear variables
542     // The first ones are continuous
543     start = end;
544     end = n - n_binaries - n_integers;
545     for (int i=start; i<end; i++) {
546       var_types[i] = CONTINUOUS;
547     }
548 
549     // The second ones are binaries
550     start = end;
551     end = start + n_binaries;
552     for (int i=start; i < end; i++) {
553       var_types[i] = BINARY;
554       totalNumberOfNonContinuous++;
555     }
556 
557     // The third ones are integers
558     start = end;
559     end = start + n_integers;
560     for (int i=start; i < end; i++) {
561       var_types[i] = INTEGER;
562       totalNumberOfNonContinuous++;
563     }
564     return true;
565   }
566 
get_variables_linearity(Index n,Ipopt::TNLP::LinearityType * var_types)567   bool AmplTMINLP::get_variables_linearity(Index n, Ipopt::TNLP::LinearityType* var_types)
568   {
569     // The variables are sorted by type in AMPL, so all we need to
570     // know are the counts of each type.
571 
572 
573     Index n_non_linear_b= 0;
574     Index n_non_linear_bi= 0;
575     Index n_non_linear_c= 0;
576     Index n_non_linear_ci = 0;
577     Index n_non_linear_o= 0;
578     Index n_non_linear_oi = 0;
579     Index n_binaries = 0;
580     Index n_integers = 0;
581     ampl_tnlp_->get_discrete_info(n_non_linear_b, n_non_linear_bi, n_non_linear_c,
582         n_non_linear_ci, n_non_linear_o, n_non_linear_oi,
583         n_binaries, n_integers);
584 
585     //Compute the number of non linear variables:
586     int n_non_linear = std::max(n_non_linear_c, n_non_linear_o);//n_non_linear_c + n_non_linear_o - n_non_linear_b;
587 
588     //printf("n_non_linear_c %i n_non_linear_o %i n_non_linear_b %i\n", n_non_linear_c, n_non_linear_o, n_non_linear_b);
589 
590     int start = 0;
591     int end = n_non_linear;
592     for (int i=start; i<end; i++) {
593       var_types[i] = Ipopt::TNLP::NON_LINEAR;
594     }
595 
596     //At last the linear variables
597     // The first ones are continuous
598     start = end;
599     end = n;
600     for (int i=start; i<end; i++) {
601       var_types[i] = Ipopt::TNLP::LINEAR;
602     }
603     return true;
604   }
605 
606   /** Returns the constraint linearity.
607   * array should be alocated with length at least n.*/
608   bool
get_constraints_linearity(Index m,Ipopt::TNLP::LinearityType * const_types)609   AmplTMINLP::get_constraints_linearity(Index m,
610       Ipopt::TNLP::LinearityType* const_types)
611   {
612     return ampl_tnlp_->get_constraints_linearity(m, const_types);
613   }
614 
get_bounds_info(Index n,Number * x_l,Number * x_u,Index m,Number * g_l,Number * g_u)615   bool AmplTMINLP::get_bounds_info(Index n, Number* x_l, Number* x_u,
616       Index m, Number* g_l, Number* g_u)
617   {
618     return ampl_tnlp_->get_bounds_info(n, x_l, x_u, m, g_l, g_u);
619   }
620 
get_starting_point(Index n,bool init_x,Number * x,bool init_z,Number * z_L,Number * z_U,Index m,bool init_lambda,Number * lambda)621   bool AmplTMINLP::get_starting_point(Index n, bool init_x, Number* x,
622       bool init_z, Number* z_L, Number* z_U,
623       Index m, bool init_lambda, Number* lambda)
624   {
625     return ampl_tnlp_->get_starting_point(n, init_x, x,
626         init_z, z_L, z_U,
627         m, init_lambda, lambda);
628   }
629 
eval_f(Index n,const Number * x,bool new_x,Number & obj_value)630   bool AmplTMINLP::eval_f(Index n, const Number* x, bool new_x, Number& obj_value)
631   {
632     return ampl_tnlp_->eval_f(n, x, new_x, obj_value);
633   }
634 
eval_grad_f(Index n,const Number * x,bool new_x,Number * grad_f)635   bool AmplTMINLP::eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f)
636   {
637     return ampl_tnlp_->eval_grad_f(n, x, new_x, grad_f);
638   }
639 
eval_g(Index n,const Number * x,bool new_x,Index m,Number * g)640   bool AmplTMINLP::eval_g(Index n, const Number* x, bool new_x, Index m, Number* g)
641   {
642     return ampl_tnlp_->eval_g(n, x, new_x, m, g);
643   }
644 
eval_jac_g(Index n,const Number * x,bool new_x,Index m,Index nele_jac,Index * iRow,Index * jCol,Number * values)645   bool AmplTMINLP::eval_jac_g(Index n, const Number* x, bool new_x,
646       Index m, Index nele_jac, Index* iRow,
647       Index *jCol, Number* values)
648   {
649     return ampl_tnlp_->eval_jac_g(n, x, new_x,
650         m, nele_jac, iRow, jCol,
651         values);
652   }
653 
eval_h(Index n,const Number * x,bool new_x,Number obj_factor,Index m,const Number * lambda,bool new_lambda,Index nele_hess,Index * iRow,Index * jCol,Number * values)654   bool AmplTMINLP::eval_h(Index n, const Number* x, bool new_x,
655       Number obj_factor, Index m, const Number* lambda,
656       bool new_lambda, Index nele_hess, Index* iRow,
657       Index* jCol, Number* values)
658   {
659     return ampl_tnlp_->eval_h(n, x, new_x, obj_factor,
660         m, lambda, new_lambda, nele_hess, iRow,
661         jCol, values);
662   }
663 
eval_gi(Index n,const Number * x,bool new_x,Index i,Number & gi)664   bool AmplTMINLP::eval_gi(Index n, const Number* x, bool new_x,
665       Index i, Number& gi)
666   {
667     ASL_pfgh* asl = ampl_tnlp_->AmplSolverObject();
668 
669     // ignore new_x for now
670     xunknown();
671 
672     fint nerror = 0;
673     gi = conival(i, const_cast<real*>(x), &nerror);
674     if (nerror!=0) {
675       return false;
676     }
677     else {
678       return true;
679     }
680   }
681 
eval_grad_gi(Index n,const Number * x,bool new_x,Index i,Index & nele_grad_gi,Index * jCol,Number * values)682   bool AmplTMINLP::eval_grad_gi(Index n, const Number* x, bool new_x,
683       Index i, Index& nele_grad_gi, Index* jCol,
684       Number* values)
685   {
686     ASL_pfgh* asl = ampl_tnlp_->AmplSolverObject();
687 
688     if (jCol) {
689       // Only compute the number of nonzeros and the indices
690       DBG_ASSERT(!values);
691       nele_grad_gi = 0;
692       for (cgrad* cg=Cgrad[i]; cg; cg = cg->next) {
693         jCol[nele_grad_gi++] = cg->varno + 1;
694       }
695       return true;
696     }
697     DBG_ASSERT(values);
698 
699     // ignore new_x for now
700     xunknown();
701 
702     asl->i.congrd_mode = 1;
703     fint nerror = 0;
704     congrd(i, const_cast<real*>(x), values, &nerror);
705     if (nerror!=0) {
706       return false;
707     }
708     else {
709       return true;
710     }
711   }
712 
finalize_solution(TMINLP::SolverReturn status,Index n,const Number * x,Number obj_value)713   void AmplTMINLP::finalize_solution(TMINLP::SolverReturn status,
714       Index n, const Number* x, Number obj_value)
715   {
716     ASL_pfgh* asl = ampl_tnlp_->AmplSolverObject();
717     std::string message;
718     std::string status_str;
719     if (status == TMINLP::SUCCESS) {
720       status_str = "\t\"Finished\"";
721       message = "\n" + appName_ +": Optimal";
722       solve_result_num = 3;
723     }
724     else if (status == TMINLP::INFEASIBLE) {
725       status_str = "\t\"Finished\"";
726       message = "\n" + appName_ + ": Infeasible problem";
727       solve_result_num = 220;
728     }
729     else if (status == TMINLP::CONTINUOUS_UNBOUNDED) {
730       status_str = "\t\"Finished\"";
731       message = "\n" + appName_ +" Continuous relaxation is unbounded.";
732       solve_result_num = 300;
733     }
734     else if (status == TMINLP::LIMIT_EXCEEDED) {
735       status_str = "\t\"Not finished\"";
736       message = "\n" + appName_ + ": Optimization interrupted on limit.";
737       if(x)
738         solve_result_num = 421; /* Limit reached or user interrupt with integer feasible solution.*/
739       else
740         solve_result_num = 410; /* Limit reached or user interrupt without solution.*/
741     }
742     else if (status == TMINLP::USER_INTERRUPT) {
743       status_str = "\t\"Not finished\"";
744       message = "\n" + appName_ + ": Optimization interrupted by user.";
745       if(x)
746         solve_result_num = 422; /* Limit reached or user interrupt with integer feasible solution.*/
747       else
748         solve_result_num = 411; /* Limit reached or user interrupt without solution.*/
749     }
750     else if (status == TMINLP::MINLP_ERROR) {
751       status_str = "\t\"Aborted\"";
752       message = "\n" + appName_ + ": Error encountered in optimization.";
753       solve_result_num = 500;
754     }
755     if (writeAmplSolFile_) {
756       write_solution(message, x);
757       std::cout<<"\n "<<status_str<<std::endl;
758     }
759     else {
760       std::cout<<status_str<<message<<std::endl;
761       std::string fName = appName_ + ".sol";
762       std::ofstream of(fName.c_str());
763       for (int i = 0 ; i < n ; i++) {
764         of<<i<<"\t"<<x[i]<<std::endl;
765       }
766       of<<"-1\n";
767     }
768   }
769 
write_solution(const std::string & message,const Number * x_sol)770   void AmplTMINLP::write_solution(const std::string & message, const Number *x_sol)
771   {
772     ASL_pfgh* asl = ampl_tnlp_->AmplSolverObject();
773 
774     DBG_ASSERT(asl);
775     //    DBG_ASSERT(x_sol);
776 
777     // We need to copy the message into a non-const char array to make
778     // it work with the AMPL C function.
779     char* cmessage = new char[message.length()+1];
780     strcpy(cmessage, message.c_str());
781 
782     // In order to avoid casting into non-const, we copy the data here...
783     double* x_sol_copy = NULL;
784     if (x_sol) {
785       x_sol_copy = new double[n_var];
786       for (int i=0; i<n_var; i++) {
787         x_sol_copy[i] = x_sol[i];
788       }
789     }
790     write_sol(cmessage, x_sol_copy, NULL, NULL);
791 
792     delete [] x_sol_copy;
793     delete [] cmessage;
794 
795   }
796 
797 
798   /** This methods gives the linear part of the objective function */
getLinearPartOfObjective(double * obj)799   void AmplTMINLP::getLinearPartOfObjective(double * obj)
800   {
801     Index n, m, nnz_jac_g, nnz_h_lag;
802     TNLP::IndexStyleEnum index_style = TNLP::FORTRAN_STYLE;
803     get_nlp_info( n, m, nnz_jac_g, nnz_h_lag, index_style);
804     eval_grad_f(n, NULL, 0,obj);
805     Index n_non_linear_b= 0;
806     Index n_non_linear_bi= 0;
807     Index n_non_linear_c= 0;
808     Index n_non_linear_ci = 0;
809     Index n_non_linear_o= 0;
810     Index n_non_linear_oi = 0;
811     Index n_binaries = 0;
812     Index n_integers = 0;
813     ampl_tnlp_->get_discrete_info(n_non_linear_b, n_non_linear_bi, n_non_linear_c,
814         n_non_linear_ci, n_non_linear_o, n_non_linear_oi,
815         n_binaries, n_integers);
816 
817     // Now get the coefficients of variables wich are linear in the objective
818     // The first ones are not
819     Index start = 0;
820     Index end = n_non_linear_b;
821     for (int i=start; i<end; i++) {
822       obj[i] = 0.;
823     }
824 
825     //next variables should be linear in the objective just skip them
826     // (from current end to (end + n_non_linear_c - n_non_linear_ci - n_non_linear_b;)
827 
828 
829     // Those are nonlinear in the objective
830     start = end + n_non_linear_c;
831     end = start + n_non_linear_o;
832     for (int i=start; i < end; i++) {
833       obj[i]=0.;
834     }
835     //The rest is linear keep the values of the gradient
836   }
837 
838 
839 
840   /** This method to returns the value of an alternative objective function for
841   upper bounding (if one has been declared by using the prefix UBObj).*/
842   bool
eval_upper_bound_f(Index n,const Number * x,Number & obj_value)843   AmplTMINLP::eval_upper_bound_f(Index n, const Number* x,
844       Number& obj_value)
845   {
846     ASL_pfgh* asl = ampl_tnlp_->AmplSolverObject();
847     //xknown(x);    // This tells ampl to use a new x
848     fint nerror = -1;
849     obj_value = objval(upperBoundingObj_, const_cast<double *>(x), &nerror);
850     if (nerror > 0) {
851       jnlst_->Printf(J_ERROR, J_MAIN,
852           "Error in evaluating upper bounding objecting");
853       throw -1;
854     }
855     return nerror;
856 
857   }
858   /** Return the ampl solver object (ASL*) */
859   const ASL_pfgh*
AmplSolverObject() const860   AmplTMINLP::AmplSolverObject() const
861   {
862     return ampl_tnlp_->AmplSolverObject();
863   }
864 
865 } // namespace Bonmin
866