1/* BEGIN LICENSE BLOCK 2 * Version: CMPL 1.1 3 * 4 * The contents of this file are subject to the Cisco-style Mozilla Public 5 * License Version 1.1 (the "License"); you may not use this file except 6 * in compliance with the License. You may obtain a copy of the License 7 * at www.eclipse-clp.org/license. 8 * 9 * Software distributed under the License is distributed on an "AS IS" 10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 11 * the License for the specific language governing rights and limitations 12 * under the License. 13 * 14 * The Original Code is The ECLiPSe Constraint Logic Programming System. 15 * The Initial Developer of the Original Code is Cisco Systems, Inc. 16 * Portions created by the Initial Developer are 17 * Copyright (C) 2006 Cisco Systems, Inc. All Rights Reserved. 18 * 19 * Contributor(s): Kish Shen, CrossCore Optimization. 20 * 21 * END LICENSE BLOCK */ 22 23// NOECLIPSE for debugging logged calls without ECLiPSe. 24//#define NOECLIPSE 25#undef NOECLIPSE 26// LOG_CALLS defined when generating logged calls, but not when linking 27// with the debugging logged call C program 28//#define LOG_CALLS 29#undef LOG_CALLS 30 31// this is needed to keep eplex.c's lpd consistent during LOG_CALLS 32#if defined(LOG_CALLS) 33# define USE_PROBLEM_ARRAY 34#endif 35 36#ifdef COIN_USE_CLP 37#define GetCbcSolver(lp) ((lp)->mipmodel) 38#define CBC_IS_MIPSOLVER 39 40#include "OsiSolverInterface.hpp" 41#include "OsiClpSolverInterface.hpp" 42#include "CbcModel.hpp" 43// Cut Generation and Heuristics 44#include "CbcCutGenerator.hpp" 45#include "CbcStrategy.hpp" 46#include "CbcHeuristic.hpp" 47#include "CbcHeuristicLocal.hpp" 48#include "CbcBranchUser.hpp" 49#include "CbcBranchActual.hpp" 50#include "CbcCompareUser.hpp" 51#include "CglGomory.hpp" 52#include "CglProbing.hpp" 53#include "CglKnapsackCover.hpp" 54//#include "CglOddHole.hpp" 55#include "CglRedSplit.hpp" 56#include "CglClique.hpp" 57#include "CglFlowCover.hpp" 58#include "CglMixedIntegerRounding2.hpp" 59// Preprocessing 60#include "CglPreProcess.hpp" 61// Barrier 62#include "ClpInterior.hpp" 63#include "ClpSimplex.hpp" 64#ifdef UFL_BARRIER 65// Use the University of Florida AMD library for pre-ordering sparse matrices 66// This considerably improves the Barrier performance. Clp must also be 67// compiled with UFL_BARRIER support. Note that the UFL AMD library is not 68// part of COIN-OR and is distributed under GNU LGPL license. 69#include "ClpCholeskyUfl.hpp" 70#endif 71#include "ClpCholeskyDense.hpp" 72//#include "ClpCholeskyWssmp.hpp" 73#include "CbcSolver.hpp" 74typedef OsiClpSolverInterface OsiXxxSolverInterface; 75 76#endif 77 78#ifdef COIN_USE_CBC 79#define GetCbcSolver(lp) ((lp)->Solver->getModelPtr()) 80#define CBC_IS_MIPSOLVER 81 82#include "OsiCbcSolverInterface.hpp" 83#include "OsiClpSolverInterface.hpp" 84#undef COIN_USE_CLP 85#include "CbcModel.hpp" 86// Cut Generation and Heuristics 87#include "CbcCutGenerator.hpp" 88#include "CbcStrategy.hpp" 89#include "CbcHeuristic.hpp" 90#include "CbcHeuristicLocal.hpp" 91#include "CbcBranchUser.hpp" 92#include "CbcCompareUser.hpp" 93#include "CglGomory.hpp" 94#include "CglProbing.hpp" 95#include "CglKnapsackCover.hpp" 96//#include "CglOddHole.hpp" 97#include "CglRedSplit.hpp" 98#include "CglClique.hpp" 99#include "CglFlowCover.hpp" 100#include "CglMixedIntegerRounding2.hpp" 101// Preprocessing 102#include "CglPreProcess.hpp" 103// Barrier 104#include "ClpInterior.hpp" 105#include "ClpSimplex.hpp" 106#ifdef UFL_BARRIER 107#include "ClpCholeskyUfl.hpp" 108#endif 109#include "ClpCholeskyDense.hpp" 110//#include "ClpCholeskyWssmp.hpp" 111 112 113typedef OsiCbcSolverInterface OsiXxxSolverInterface; 114 115#endif 116 117#ifdef COIN_USE_SYM 118 119#include "OsiSymSolverInterface.hpp" 120 121typedef OsiSymSolverInterface OsiXxxSolverInterface; 122 123#endif 124 125#ifdef COIN_USE_GLPK 126 127#include "OsiGlpkSolverInterface.hpp" 128 129typedef OsiGlpkSolverInterface OsiXxxSolverInterface; 130 131 132#endif 133 134#include "CoinPackedVector.hpp" 135#include "CoinPackedMatrix.hpp" 136#include "CoinBuild.hpp" 137#include "CoinError.hpp" 138#include "CoinMessageHandler.hpp" 139#include <stdio.h> 140#include <exception> 141#include <string> 142using std::string; 143using namespace std; 144 145#include <fstream> 146 147#include "coinplex_params.h" 148// must be defined before eplex_coin.h 149typedef struct { 150 OsiXxxSolverInterface * Solver; 151 char** varnames; /* for names of variables (columns) */ 152 unsigned int vnsize; /* number of variable names */ 153 char notfirst; /* has problem been solved? */ 154 /* solver specific */ 155#ifdef COIN_USE_CLP 156 char mipIsShared; /* 1 if shared with Solver, 0 if copied */ 157 CbcModel* mipmodel; 158 ClpInterior* interiormodel; 159#define MIPOBJSZ 1000 // temporary, replace with std::vector 160 CbcObject** mipobjects; // information such as SOS to be added to mipmodel 161 int nsos; // number of SOSs 162 double timeout; 163 string sparam[EpxClpParam_ns]; 164 int iparam[EpxClpParam_ni]; 165 double dparam[]; 166#endif 167} COINprob; 168 169#include "eplex_coin.h" 170 171 172// utility to check if a file exists (and is readable) 173bool fileExists(const char* file) 174{ 175 std::fstream fin; 176 fin.open(file, std::ios::in); 177 if (fin.is_open() ) 178 { 179 fin.close(); 180 return true; 181 } 182 fin.close(); 183 return false; 184} 185 186/***************************************************************************** 187 * Handlers * 188 *****************************************************************************/ 189 190#ifndef NOECLIPSE /* normal */ 191 192#include "external.h" 193 194extern "C" 195void eclipse_out(int msgtype, const char* message); 196 197#else /* debug without ECLiPSe */ 198 199void eclipse_out(int msgtype, const char* message) 200{ 201 printf("%s\n",message); 202} 203#endif 204 205class DerivedHandler : public CoinMessageHandler 206{ 207public: 208 virtual int print(); 209}; 210 211int DerivedHandler::print() 212{ 213 int id = currentMessage().externalNumber(); 214 int mtype = (id<3000 ? LogType : (id<6000 ? WrnType : ErrType)); 215 eclipse_out(mtype, messageBuffer()); 216 217 return 0; 218} 219 220void coin_error_handler(CoinError &e) 221{ 222 eclipse_out(ErrType, e.message().c_str()); 223} 224 225/************************************************************************* 226 * Solver Specific Code * 227 *************************************************************************/ 228 229#if defined(COIN_USE_CLP) || defined(COIN_USE_CBC) 230 231/* these parameters must correspond to their COIN Solver* declarations 232 in eplex_params.h 233*/ 234 235static CbcModel::CbcIntParam cbc_iparam[] = {CbcModel::CbcMaxNumNode, 236 CbcModel::CbcMaxNumSol}; 237 238static CbcModel::CbcDblParam cbc_dparam[] = {CbcModel::CbcIntegerTolerance, 239 CbcModel::CbcAllowableGap, 240 CbcModel::CbcAllowableFractionGap, 241 CbcModel::CbcCutoffIncrement, 242 CbcModel::CbcHeuristicGap, 243 CbcModel::CbcHeuristicFractionGap}; 244 245static ClpDblParam clp_dparam[] = {ClpPresolveTolerance}; 246 247/* Meaning of whereFrom: 248 1 after initial solve by dualsimplex etc 249 2 after preprocessing 250 3 just before branchAndBound (so user can override) 251 4 just after branchAndBound (before postprocessing) 252 5 after postprocessing 253*/ 254/* Meaning of model status is as normal 255 status 256 -1 before branchAndBound 257 0 finished - check isProvenOptimal or isProvenInfeasible to see if solution found 258 (or check value of best solution) 259 1 stopped - on maxnodes, maxsols, maxtime 260 2 difficulties so run was abandoned 261 (5 event user programmed event occurred) 262 263 cbc secondary status of problem 264 -1 unset (status_ will also be -1) 265 0 search completed with solution 266 1 linear relaxation not feasible (or worse than cutoff) 267 2 stopped on gap 268 3 stopped on nodes 269 4 stopped on time 270 5 stopped on user event 271 6 stopped on solutions 272 7 linear relaxation unbounded 273 274 but initially check if status is 0 and secondary status is 1 -> infeasible 275 or you can check solver status. 276*/ 277/* Return non-zero to return quickly */ 278static int callBack(CbcModel * model, int whereFrom) 279{ 280 int returnCode=0; 281 switch (whereFrom) { 282 case 1: 283 case 2: 284 if (!model->status()&&model->secondaryStatus()) 285 returnCode=1; 286 break; 287 case 3: 288 { 289 CbcCompareUser compare; 290 model->setNodeComparison(compare); 291 } 292 break; 293 case 4: 294 // If not good enough could skip postprocessing 295 break; 296 case 5: 297 break; 298 default: 299 returnCode=-1; 300 } 301 return returnCode; 302} 303 304int coin_branchAndBound(lp_desc* lpd, int meth, int auxmeth) 305{ 306 // copying original bounds before presolve -- Cbc's integer presolve and 307 // MIP branch-and-bound can fix some column bounds. The original bounds 308 // needs to be restored before continuing 309 int mac = lpd->lp->Solver->getNumCols(); 310 double* ups = new double[mac]; 311 double* lws = new double[mac]; 312 memcpy(ups, lpd->lp->Solver->getColUpper(), mac*sizeof(double)); 313 memcpy(lws, lpd->lp->Solver->getColLower(), mac*sizeof(double)); 314 315 // Tell solver to return fast if presolve or initial solve infeasible 316 lpd->lp->Solver->getModelPtr()->setMoreSpecialOptions(3); 317 318 // model is a new copy of lpd->lp->Solver 319 CbcModel* model = new CbcModel(static_cast<OsiSolverInterface &>(*lpd->lp->Solver)); 320 321 int loglevel = lpd->lp->iparam[EpxClpParam_loglevel]; 322 DerivedHandler* mipMessageHandler = new DerivedHandler; 323 model->passInMessageHandler(mipMessageHandler); 324 // From John Forrest 2011-03-13, to get message logging with CbcSolver: 325 model->messageHandler()->setLogLevel(0,loglevel); // CBC 326 model->messageHandler()->setLogLevel(1,lpd->lp->iparam[EpxClpParam_mip_lploglevel]); // CLP 327 model->messageHandler()->setLogLevel(2,loglevel); // Coin 328 model->messageHandler()->setLogLevel(3,loglevel); // CGL 329 model->setPrintFrequency(lpd->lp->iparam[EpxClpParam_print_freq]); 330 CbcMain0(*model); 331 332 /* 333 CbcSolver* control = new CbcSolver(*(lpd->lp->Solver)); 334 control->fillValuesInSolver(); 335 CbcModel* model = control->model(); 336 */ 337 if (lpd->lp->mipmodel != NULL) 338 { 339 // copy mipmodel's parameters -- as these may contain settings from 340 // the user (set through OSI or Solver parameters) 341 342 for (int i=0; i<CbcModel::CbcLastIntParam; i++) 343 model->setIntParam(CbcModel::CbcIntParam(i), lpd->lp->mipmodel->getIntParam(CbcModel::CbcIntParam(i))); 344 for (int i=0; i<CbcModel::CbcLastIntParam; i++) 345 model->setDblParam(CbcModel::CbcDblParam(i), lpd->lp->mipmodel->getDblParam(CbcModel::CbcDblParam(i))); 346 } 347 348 if (lpd->lp->nsos > 0) 349 {// Add any SOSs 350 model->addObjects(lpd->lp->nsos, lpd->lp->mipobjects); 351 } 352 353 if (lpd->lp->mipmodel != NULL) 354 { 355 // mipmodel has an old copy of the model that needs to be deleted 356 delete lpd->lp->mipmodel->messageHandler(); 357 delete lpd->lp->mipmodel; 358 // if mipIsShared, then Solver is also deleted, so set to NULL 359 if (lpd->lp->mipIsShared) lpd->lp->Solver = NULL; 360 } 361 362 lpd->lp->mipmodel = model; 363 //model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry); 364 365 if (lpd->lp->timeout > 0) model->setMaximumSeconds(lpd->lp->timeout); 366 // const char * argv2="-preprocess on -solve "; 367 //control->solve(argv2, 1); 368 const char * cbc_args[12]; 369 cbc_args[0] = "eplexcbcclpsolver"; 370 cbc_args[1] = "-preprocess"; 371 cbc_args[2] = (lpd->presolve ? "on" : "off"); 372 int next = 3; 373 374 switch (meth) { 375 case METHOD_DUAL: 376 cbc_args[next++] = "-dualSimplex"; 377 break; 378 case METHOD_PRIMAL: 379 cbc_args[next++] = "-primalSimplex"; 380 break; 381 case METHOD_BAR: 382 cbc_args[next++] = "-chol"; 383#ifdef UFL_BARRIER 384 if (lpd->lp->sparam[EpxClpParam_bar_ordering] == "uflamd") 385 cbc_args[next++] = "Uni"; // UFL 386 else 387#endif 388 if (lpd->lp->sparam[EpxClpParam_bar_ordering] == "dense") 389 cbc_args[next++] = "dense"; 390 else 391 cbc_args[next++] = "native"; // default 392 393 cbc_args[next++] = "-cross"; 394 cbc_args[next++] = (auxmeth == METHOD_NONE ? "off" : "on"); 395 if (lpd->lp->iparam[EpxClpParam_doKKT]) { 396 cbc_args[next++] = "-KKT"; 397 cbc_args[next++] = "on"; 398 } 399 cbc_args[next++] = "-barrier"; 400 if (auxmeth == METHOD_PRIMAL) { 401 eclipse_out(WrnType, "Eplex Warning: CbcSolver supports cross-over for barrier using dual simplex only -- dual simplex used instead of primal simplex.\n"); 402 } 403 break; 404 // falls through if METHOD_DEFAULT 405 } 406 cbc_args[next++] = "-solve"; 407 cbc_args[next++] = "-quit"; 408 CbcMain1(next,cbc_args,*model,callBack); 409 410 lpd->sol_itcnt = model->getIterationCount(); 411 lpd->sol_nodnum = model->getNodeCount(); 412 413 if (lpd->lp->Solver != NULL) 414 { 415 delete lpd->lp->Solver->getModelPtr()->messageHandler(); 416 //coin_free_solver_handlers(lpd->lp->Solver); 417 delete lpd->lp->Solver; 418 } 419 lpd->lp->Solver = dynamic_cast< OsiXxxSolverInterface*>(model->solver()); 420 //DerivedHandler* solMessageHandler = new DerivedHandler; 421 //lpd->lp->Solver->getModelPtr()->passInMessageHandler(solMessageHandler); 422 lpd->lp->mipIsShared = 1; 423 424 if (lpd->prob_type == PROBLEM_FIXEDL && 425 lpd->lp->Solver->isProvenOptimal()) 426 { 427 /* integer col bounds are already fixed to their sol values */ 428 lpd->lp->Solver->initialSolve(); 429 } 430 431 // reset the column bounds (undo fixed bounds for integer cols) 432 for (int i=0; i<mac; i++) 433 lpd->lp->Solver->setColBounds(i,lws[i],ups[i]); 434 435 delete [] lws; 436 delete [] ups; 437 438 return 0; 439 440} 441 442int coin_solveLinear(lp_desc* lpd, int meth, int auxmeth) 443{ 444 switch (meth) 445 { 446 case METHOD_BAR: 447 { 448 ClpModel* clpmodel = lpd->lp->Solver->getModelPtr(); 449 lpd->lp->interiormodel = new ClpInterior; 450 lpd->lp->interiormodel->borrowModel(*clpmodel); 451 452 lpd->lp->interiormodel->messageHandler()->setLogLevel(lpd->lp->iparam[EpxClpParam_loglevel]); 453#ifdef UFL_BARRIER 454 if (lpd->lp->sparam[EpxClpParam_bar_ordering] == "uflamd") { 455 ClpCholeskyUfl* cholesky = new ClpCholeskyUfl(-1); 456 // Quadratic QP aparently needs a KKT factorization 457 if (lpd->prob_type == PROBLEM_QP || lpd->lp->iparam[EpxClpParam_doKKT]) 458 cholesky->setKKT(true); 459 lpd->lp->interiormodel->setCholesky(cholesky); 460 } else 461#endif 462 if (lpd->lp->sparam[EpxClpParam_bar_ordering] == "dense") { 463 ClpCholeskyBase* cholesky = new ClpCholeskyDense(); 464 // Quadratic QP aparently needs a KKT factorization 465 if (lpd->prob_type == PROBLEM_QP || lpd->lp->iparam[EpxClpParam_doKKT]) 466 cholesky->setKKT(true); 467 lpd->lp->interiormodel->setCholesky(cholesky); 468 } else { 469 ClpCholeskyBase* cholesky = new ClpCholeskyBase(-1); 470 // Quadratic QP aparently needs a KKT factorization 471 if (lpd->prob_type == PROBLEM_QP || lpd->lp->iparam[EpxClpParam_doKKT]) 472 cholesky->setKKT(true); 473 lpd->lp->interiormodel->setCholesky(cholesky); 474 } 475 lpd->lp->interiormodel->primalDual(); 476 // Barrier done 477 478 //lpd->lp->interiormodel->checkSolution(); 479 if (lpd->lp->interiormodel->isProvenOptimal() 480 // infeasibility not correctly detected by ClpInterior, so need 481 // the next test to make sure solution is feasible 482 && lpd->lp->interiormodel->sumPrimalInfeasibilities() < 1e-5) 483 { 484 // Do crossover if optimal... 485 ClpSimplex model2(*lpd->lp->interiormodel); 486 // make sure no status left 487 model2.createStatus(); 488 model2.messageHandler()->setLogLevel(lpd->lp->iparam[EpxClpParam_loglevel]); 489 490 switch (auxmeth) { 491 case METHOD_PRIMAL: 492 case METHOD_DEFAULT: 493 model2.primal(1); 494 break; 495 case METHOD_DUAL: 496 model2.dual(1); 497 break; 498 case METHOD_NONE: 499 break; 500 } 501 } 502 // getIterationCount() is for barrier + crossover (if any) 503 lpd->sol_itcnt = lpd->lp->interiormodel->getIterationCount(); 504 lpd->lp->interiormodel->returnModel(*clpmodel); 505 } 506 break; 507 case METHOD_PRIMAL: 508 case METHOD_DUAL: 509 case METHOD_DEFAULT: 510 if (lpd->lp->notfirst) 511 { 512 lpd->lp->Solver->resolve(); 513 } 514 else 515 { 516 //lpd->lp->Solver->writeLp("cointest"); 517 lpd->lp->Solver->initialSolve(); 518 lpd->lp->notfirst= 1; 519 /* timeout for CLP not turned off here, but only before 520 branchAndBound() is called, because the timeout setting is 521 needed for detecting if timeout happened or not 522 */ 523 } 524 lpd->sol_itcnt = lpd->lp->Solver->getIterationCount(); 525 break; 526 } 527} 528 529 530extern "C" 531int coin_set_timeout(COINprob* lp, double timeout) 532{ 533#ifdef COIN_USE_CLP 534 if (timeout > 0) lp->timeout = timeout; 535#endif 536 537 return 0; 538} 539 540 541#else 542 543int coin_branchAndBound(lp_desc *lpd, int meth, int auxmeth) 544{ 545 if (meth != METHOD_DEFAULT) { 546 eclipse_out(WrnType, "Eplex Warning: OSI does not support specification of linear solving method for MIP problems. Specification ignored.\n"); 547 } 548 lpd->lp->Solver->branchAndBound(); 549 if (lpd->prob_type == PROBLEM_FIXEDL && 550 lpd->lp->Solver->isProvenOptimal()) { 551 int mac = lpd->lp->Solver->getNumCols(); 552 double* ups = new double[mac]; 553 double* lws = new double[mac]; 554 memcpy(ups, lpd->lp->Solver->getColUpper(), mac*sizeof(double)); 555 memcpy(lws, lpd->lp->Solver->getColLower(), mac*sizeof(double)); 556 //fix 557 lpd->lp->Solver->initialSolve(); 558 // restore original bounds 559 for (int i=0; i<mac; i++) 560 lpd->lp->Solver->setColBounds(i,lws[i],ups[i]); 561 delete [] lws; 562 delete [] ups; 563 564 } 565 lpd->sol_itcnt = lpd->lp->Solver->getIterationCount(); 566 567 return 0; 568} 569 570int coin_solveLinear(lp_desc* lpd, int meth, int aux_meth) 571{ 572#ifndef COIN_USE_SYM 573 // with OsiSym, resolve seem to ignore added constraints 574 if (lpd->lp->notfirst) 575 { 576 lpd->lp->Solver->resolve(); 577 } 578 else 579#endif 580 { 581 //lpd->lp->Solver->writeLp("cointest"); 582 lpd->lp->Solver->initialSolve(); 583 lpd->lp->notfirst= 1; 584 lpd->sol_itcnt = lpd->lp->Solver->getIterationCount(); 585 /* timeout for CLP not turned off here, but only before 586 branchAndBound() is called, because the timeout setting is 587 needed for detecting if timeout happened or not 588 */ 589 } 590} 591 592extern "C" 593int coin_set_timeout(COINprob* lp, double timeout) 594{ 595 // Osi does not provide a generic timeout, do nothing by default 596 return 0; 597} 598 599#endif 600#ifdef COIN_USE_CLP 601extern "C" 602int coin_get_solver_dblparam(COINprob* lp, int key, double* value) 603{ 604 if (lp->mipmodel == NULL) return -1; // should not happen 605 if (key >= NumSolverMipDblParams) { 606 // CLP param 607 key -= NumSolverMipDblParams; 608 lp->Solver->getModelPtr()->getDblParam(clp_dparam[key], *value); 609 } else { 610 // CBC Param 611 *value = lp->mipmodel->getDblParam(cbc_dparam[key]); 612 } 613 614 return 0; 615} 616 617extern "C" 618int coin_get_solver_intparam(COINprob* lp, int key, int* value) 619{ 620 if (lp->mipmodel == NULL) return -1; // should not happen 621 *value = lp->mipmodel->getIntParam(cbc_iparam[key]); 622 623 return 0; 624} 625 626extern "C" 627int coin_set_solver_dblparam(COINprob* lp, int key, double value) 628{ 629 if (lp->mipmodel == NULL) return -1; 630 if (key >= NumSolverMipDblParams) { 631 // CLP param 632 key -= NumSolverMipDblParams; 633 lp->Solver->getModelPtr()->setDblParam(clp_dparam[key], value); 634 } else 635 lp->mipmodel->setDblParam(cbc_dparam[key], value); // CBC param 636 637 return 0; 638} 639 640extern "C" 641int coin_set_solver_intparam(COINprob* lp, int key, int value) 642{ 643 if (lp->mipmodel == NULL) return -1; 644 lp->mipmodel->setIntParam(cbc_iparam[key], value); 645 646 return 0; 647} 648 649extern "C" 650int coin_get_eplex_intparam(COINprob* lp, int key, int* value) 651{ 652 if (lp->mipmodel == NULL) return -1; 653 *value = lp->iparam[key]; 654 655 return 0; 656} 657 658extern "C" 659int coin_get_eplex_strparam(COINprob* lp, int key, char* value) 660{ 661 if (lp->mipmodel == NULL) return -1; 662 663 int size = lp->sparam[key].length()+1; 664 if (size > STRBUFFERSIZE) size = STRBUFFERSIZE; 665 string::traits_type::copy(value, lp->sparam[key].c_str(), size); 666 667 return 0; 668 669} 670 671extern "C" 672int coin_set_eplex_intparam(COINprob* lp, int key, int value) 673{ 674 if (lp->mipmodel == NULL) return -1; 675 switch (key) { 676 case EpxClpParam_print_freq: 677 lp->mipmodel->setPrintFrequency(value); 678 lp->iparam[key] = value; 679 break; 680 case EpxClpParam_loglevel: 681 if (value >= 0 && value <= 3) { 682 lp->iparam[key] = value; 683 lp->Solver->messageHandler()->setLogLevel(value); 684 } else return -1; 685 break; 686 case EpxClpParam_mip_lploglevel: 687 if (value >= 0 && value <= 3) 688 lp->iparam[key] = value; 689 else return -1; 690 break; 691 case EpxClpParam_doKKT: 692 lp->iparam[key] = value; 693 break; 694 default: 695 return -1; 696 break; 697 } 698 return 0; 699} 700 701extern "C" 702int coin_set_eplex_strparam(COINprob* lp, int key, const char* value) 703{ 704 if (lp->mipmodel == NULL) return -1; 705 switch (key) { 706 case EpxClpParam_bar_ordering: 707 lp->sparam[key] = value; 708 break; 709 default: 710 return -1; 711 } 712 713 return 0; 714} 715 716void coin_set_solver_outputs(OsiXxxSolverInterface* Solver) 717{ 718 DerivedHandler* solMessageHandler = new DerivedHandler; 719 Solver->getModelPtr()->passInMessageHandler(solMessageHandler); 720} 721 722void coin_free_solver_handlers(OsiXxxSolverInterface* Solver) 723{ 724 delete Solver->getModelPtr()->messageHandler(); 725} 726 727 728#elif defined(COIN_USE_CBC) 729 730extern "C" 731int coin_get_solver_dblparam(COINprob* lp, int key, double* value) 732{ 733 CbcModel* model = lp->Solver->getModelPtr(); 734 735 *value = model->getDblParam(cbc_dparam[key]); 736 737 return 0; 738} 739 740extern "C" 741int coin_get_solver_intparam(COINprob* lp, int key, int* value) 742{ 743 CbcModel* model = lp->Solver->getModelPtr(); 744 745 *value = model->getIntParam(cbc_iparam[key]); 746 747 return 0; 748} 749 750extern "C" 751int coin_set_solver_intparam(COINprob* lp, int key, int value) 752{ 753 CbcModel* model = lp->Solver->getModelPtr(); 754 755 model->setIntParam(cbc_iparam[key], value); 756 return 0; 757} 758 759extern "C" 760int coin_set_solver_dblparam(COINprob* lp, int key, double value) 761{ 762 CbcModel* model = lp->Solver->getModelPtr(); 763 764 model->setDblParam(cbc_dparam[key], value); 765 return 0; 766} 767 768void coin_set_solver_outputs(OsiXxxSolverInterface* Solver) 769{ 770 CbcModel* model = Solver->getModelPtr(); 771 DerivedHandler* cbcMessageHandler = new DerivedHandler; 772 model->passInMessageHandler(cbcMessageHandler); 773 model->messageHandler()->setLogLevel(1); 774 775 OsiClpSolverInterface* clp = 776 dynamic_cast< OsiClpSolverInterface*> (Solver->getRealSolverPtr()); 777 if (clp != NULL) 778 {/* != NULL if using CLP */ 779 DerivedHandler* clpMessageHandler = new DerivedHandler; 780 clp->passInMessageHandler(clpMessageHandler); 781 clp->messageHandler()->setLogLevel(1); 782 } 783} 784 785void coin_free_solver_handlers(OsiXxxSolverInterface* Solver) 786{ 787 CbcModel* model = Solver->getModelPtr(); 788 delete model->messageHandler(); 789 790 OsiClpSolverInterface* clp = 791 dynamic_cast< OsiClpSolverInterface*> (Solver->getRealSolverPtr()); 792 if (clp != NULL) 793 {/* != NULL if using CLP */ 794 delete clp->messageHandler(); 795 } 796} 797 798#else 799 800extern "C" 801int coin_get_solver_dblparam(COINprob* lp, int key, double* value) 802{ 803 return -1; 804} 805 806extern "C" 807int coin_set_solver_dblparam(COINprob* lp, int key, double value) 808{ 809 return -1; 810} 811 812extern "C" 813int coin_get_solver_intparam(COINprob* lp, int key, int* value) 814{ 815 return -1; 816} 817 818extern "C" 819int coin_set_solver_intparam(COINprob* lp, int key, int value) 820{ 821 return -1; 822} 823 824extern "C" 825int coin_get_eplex_intparam(COINprob* lp, int key, int* value) 826{ 827 return -1; 828} 829 830extern "C" 831int coin_set_eplex_intparam(COINprob* lp, int key, int value) 832{ 833 return -1; 834} 835 836extern "C" 837int coin_get_eplex_strparam(COINprob* lp, int key, char* value) 838{ 839 return -1; 840} 841 842extern "C" 843int coin_set_eplex_strparam(COINprob* lp, int key, const char* value) 844{ 845 return -1; 846} 847 848extern "C" 849int coin_set_solver_methods(lp_desc* lpd, int method, int auxmethod, 850 int node_meth, int node_auxmeth) 851{ 852 return -1; 853} 854 855void coin_set_solver_outputs(OsiXxxSolverInterface* Solver) 856{ 857} 858 859void coin_free_solver_handlers(OsiXxxSolverInterface* Solver) 860{ 861} 862 863 864#endif 865 866 867/***************************************************************************** 868 * Generic OSI/Coin Code * 869 *****************************************************************************/ 870 871 872extern "C" 873int coin_getrhs(COINprob* lp, double* rhs, int start, int end) 874{ 875 const double *rhs0 = lp->Solver->getRightHandSide(); 876 int j=0; 877 878 if (start < 0) return -1; 879 if (end >= lp->Solver->getNumRows()) return -1; 880 881 for (int i=start; i<=end; i++) 882 { 883 rhs[j++] = rhs0[i]; 884 } 885 return 0; 886} 887 888extern "C" 889int coin_getrowsense(COINprob* lp, char* rsense, int start, int end) 890{ 891 const char* rsense0 = lp->Solver->getRowSense(); 892 int j=0; 893 894 if (start < 0) return -1; 895 if (end >= lp->Solver->getNumRows()) return -1; 896 897 for (int i=start; i<=end; i++) 898 { 899 // sense type is the same for OSI and CPLEX/Xpress 900 rsense[j++] = rsense0[i]; 901 } 902 return 0; 903} 904 905extern "C" 906int coin_getlb(COINprob* lp, double* lb, int start, int end) 907{ 908 const double* lb0 = lp->Solver->getColLower(); 909 int j=0; 910 911 if (start < 0) return -1; 912 if (end >= lp->Solver->getNumCols()) return -1; 913 914 for (int i=start; i<=end; i++) 915 { 916 lb[j++] = lb0[i]; 917 } 918 return 0; 919} 920 921extern "C" 922int coin_getub(COINprob* lp, double* ub, int start, int end) 923{ 924 const double* ub0 = lp->Solver->getColUpper(); 925 int j=0; 926 927 if (start < 0) return -1; 928 if (end >= lp->Solver->getNumCols()) return -1; 929 930 for (int i=start; i<=end; i++) 931 { 932 ub[j++] = ub0[i]; 933 } 934 return 0; 935} 936 937extern "C" 938int coin_getcoltype(COINprob* lp, char* ctype, int start, int end) 939{ 940 int j=0; 941 942 if (start < 0) return -1; 943 if (end >= lp->Solver->getNumCols()) return -1; 944 945 for (int i=start; i<=end; i++) 946 { 947 if (lp->Solver->isContinuous(i)) ctype[j++] = 'C'; 948 else if (lp->Solver->isInteger(i)) ctype[j++] = 'I'; 949 else if (lp->Solver->isBinary(i)) ctype[j++] = 'B'; 950 else return -1; /* unknown type -- error! */ 951 } 952 return 0; 953} 954 955extern "C" 956int coin_chgcoltype(COINprob* lp, int cnt, int* idxs, char* ctype) 957{ 958 959 for (int i=0; i<cnt; i++) 960 { 961 int j=idxs[i]; 962 if (j < 0 || j >= lp->Solver->getNumCols()) return -1; 963 964 if (ctype[i] == 'C') lp->Solver->setContinuous(j); 965 else if (ctype[i] == 'I') lp->Solver->setInteger(j); 966 else if (ctype[i] == 'B') lp->Solver->setInteger(j); // no setBinary() 967 else return -1; /* unknown type -- error! */ 968 } 969 return 0; 970} 971 972extern "C" 973int coin_chgbds(COINprob* lp, int cnt, int* idxs, char* lu, double* bd) 974{ 975 976 for (int i=0; i<cnt; i++) 977 { 978 int j=idxs[i]; 979 if (j < 0 || j >= lp->Solver->getNumCols()) return -1; 980 981 if (lu[i] == 'U') lp->Solver->setColUpper(j, bd[i]); 982 else if (lu[i] == 'L') lp->Solver->setColLower(j, bd[i]); 983 else if (lu[i] == 'B') lp->Solver->setColBounds(j, bd[i], bd[i]); 984 else return -1; /* unknown type -- error! */ 985 } 986 return 0; 987} 988 989extern "C" 990int coin_loadbasis(COINprob* lp, const int* cbase, const int* rbase) 991{ 992#ifndef COIN_USE_CBC 993 lp->Solver->setBasisStatus(cbase, rbase); 994#endif 995 return 0; 996} 997 998extern "C" 999int coin_getbasis(COINprob* lp, int* cbase, int* rbase) 1000{ 1001#ifndef COIN_USE_CBC 1002 // coin_getbasis() is only called when both cbase and rbase != NULL 1003 lp->Solver->getBasisStatus(cbase,rbase); 1004#endif 1005 1006 return 0; 1007} 1008 1009extern "C" 1010int coin_getobjval(COINprob* lp, double &objval) 1011{ 1012#ifdef COIN_USE_SYM 1013 // solving empty problem with OsiSym core dumps 1014 if (lp->Solver->getNumCols() == 0) objval = 0; 1015 else 1016#endif 1017 objval = lp->Solver->getObjValue(); 1018 return 0; 1019} 1020 1021extern "C" 1022int coin_get_lpobjval(lp_desc* lpd, double* objval) 1023{ 1024#ifdef COIN_USE_CLP 1025 /* return the current linear objective value */ 1026 if (IsMIPProb(lpd->prob_type)) 1027 { 1028 *objval = lpd->lp->mipmodel->getCurrentObjValue(); 1029 return 0; 1030 } 1031#endif 1032#ifdef COIN_USE_SYM 1033 // solving empty problem with OsiSym core dumps 1034 if (lpd->lp->Solver->getNumCols() == 0) *objval = 0; 1035 else 1036#endif 1037 *objval = lpd->lp->Solver->getObjValue(); 1038 return 0; 1039} 1040 1041extern "C" 1042int coin_get_mipobjval(COINprob* lp, double* objval) 1043{ 1044#ifdef COIN_USE_CLP 1045 *objval = lp->mipmodel->getObjValue(); 1046#else 1047 *objval = lp->Solver->getObjValue(); 1048#endif 1049 return 0; 1050} 1051 1052extern "C" 1053int coin_get_bestmipbound(COINprob* lp, double* bound) 1054{ 1055#ifdef COIN_USE_CLP 1056 *bound = lp->mipmodel->getBestPossibleObjValue(); 1057#elif defined(COIN_USE_CBC) 1058 *bound = lp->Solver->getModelPtr()->getBestPossibleObjValue(); 1059#else 1060 // generic: just return the right infinity (i.e. no information) 1061 *bound = (lp->Solver->getObjSense() == 1 ? -1*lp->Solver->getInfinity() : lp->Solver->getInfinity()); 1062#endif 1063 return 0; 1064} 1065 1066extern "C" 1067int coin_get_objcoeffs(COINprob* lp, double* objc, int start, int end) 1068{ 1069 const double* objc0 = lp->Solver->getObjCoefficients(); 1070 int j=0; 1071 1072 if (start < 0) return -1; 1073 if (end >= lp->Solver->getNumCols()) return -1; 1074 1075 for (int i=start; i<=end; i++) 1076 { 1077 objc[j++] = objc0[i]; 1078 } 1079 return 0; 1080} 1081 1082extern "C" 1083int coin_chg_objcoeffs(COINprob* lp, int cnt, int* idxs, double* values) 1084{ 1085 1086 for (int i=0; i<cnt; i++) 1087 { 1088 int j=idxs[i]; 1089 if (j < 0 || j >= lp->Solver->getNumCols()) return -1; 1090 1091 lp->Solver->setObjCoeff(j,values[i]); 1092 } 1093 return 0; 1094} 1095 1096extern "C" 1097int coin_get_order(COINprob* lp, int cnt, int* idxs, int* prio, int* direction) 1098{ 1099 return -1; 1100} 1101 1102extern "C" 1103int coin_set_qobj(COINprob* lp, int mac, int cb_cnt, int* cb_index, 1104 int* cb_index2, double* cb_value) 1105{ 1106#ifdef COIN_USE_CLP 1107 if (cb_cnt > 0) 1108 { 1109 CoinBigIndex* starts = new CoinBigIndex[mac+1]; 1110 int* colidx = new int[cb_cnt]; 1111 double* coeffs = new double[cb_cnt]; 1112 int cur_col = 0; 1113 int cur_start = 0; 1114 1115 for (int i=0; i<cb_cnt; i++) 1116 { 1117 // cb_index are sorted in ascending order 1118 colidx[i] = cb_index2[i]; 1119 coeffs[i] = cb_value[i]; 1120 if (cb_index[i] > cur_col) 1121 {// starting coeffs for new col 1122 for (int s=cur_col; s < cb_index[i]; s++) 1123 starts[s] = cur_start; 1124 cur_start = i; 1125 cur_col = cb_index[i]; 1126 } 1127 } 1128 // no coeffs for rest of cols, fill the starts in 1129 starts[cur_col] = cur_start; // last col with coeffs 1130 for (int s=cur_col+1; s <= mac; s++) starts[s] = cb_cnt; 1131 1132 lp->Solver->getModelPtr()->loadQuadraticObjective(mac, starts, colidx, coeffs); 1133 1134 delete [] starts; 1135 delete [] colidx; 1136 delete [] coeffs; 1137 1138 } 1139 1140 return 0; 1141 1142#else 1143 1144 return -1; 1145 1146#endif 1147} 1148 1149extern "C" 1150int coin_chgqobj(COINprob* lp, int i, int j, double value) 1151{ 1152 return -1; 1153} 1154 1155extern "C" 1156int coin_chgrhs(COINprob* lp, int cnt, int* idxs, double* values) 1157{ 1158 1159 const char* rsen = lp->Solver->getRowSense(); 1160 for (int i=0; i<cnt; i++) 1161 { 1162 int j=idxs[i]; 1163 if (j < 0 || j >= lp->Solver->getNumRows()) return -1; 1164 1165 switch (rsen[j]) 1166 { 1167 case 'L': lp->Solver->setRowUpper(j, values[i]); break; 1168 case 'G': lp->Solver->setRowLower(j, values[i]); break; 1169 case 'E': lp->Solver->setRowBounds(j,values[i],values[i]);; break; 1170 default: return -1; 1171 } 1172 } 1173 return 0; 1174} 1175 1176extern "C" 1177int coin_getnumnz(COINprob* lp) 1178{ 1179 return lp->Solver->getNumElements(); 1180} 1181 1182extern "C" 1183int coin_getnumint(COINprob* lp) 1184{ 1185 return lp->Solver->getNumIntegers(); 1186} 1187 1188extern "C" 1189int coin_loadprob(COINprob* lp, int mac, int mar, int objsen, double* objx, 1190 double* rhsx, char* senx, 1191 int* matbeg, int* matcnt, int* matind, double* matval, 1192 double* lb, double* ub) 1193{ 1194 double* range = new double[mar]; 1195 1196 /* coin doesn't use matcnt, but needs the matbeg for one more column to 1197 be specifified 1198 */ 1199 matbeg[mac] = (mac > 0 ? matbeg[mac-1]+matcnt[mac-1] : 0); 1200 for (int i=0; i<mar; i++) range[i] = 0.0; 1201 1202 // CoinPackedMatrix* mat = 1203 //new CoinPackedMatrix(true, mar, mac, matbeg[mac], 1204 // matval, matind, matbeg, matcnt, 0.6, 0.6); 1205 try { 1206 lp->Solver->loadProblem(mac, mar, matbeg, matind, matval, lb, ub, objx, senx, rhsx, range); 1207 //lp->Solver->loadProblem(*mat,lb, ub, objx, senx, rhsx, range); 1208 lp->Solver->setObjSense((objsen == SENSE_MIN ? 1 : -1)); 1209 delete [] range; 1210 //delete mat; 1211 } 1212 catch (CoinError e) 1213 { 1214 coin_error_handler(e); 1215 return -1; 1216 } 1217 catch (bad_alloc&) 1218 { 1219 eclipse_out(ErrType, "Memory allocation error in external solver\n"); 1220 return -1; 1221 } 1222 1223 return 0; 1224} 1225 1226extern "C" 1227int coin_setcoltype(COINprob* lp, char *ctype) 1228{ 1229 int mac = lp->Solver->getNumCols(); 1230 for (int i=0; i<mac; i++) 1231 { 1232 if (ctype[i] == 'C') lp->Solver->setContinuous(i); 1233 else if (ctype[i] == 'I') lp->Solver->setInteger(i); 1234 else if (ctype[i] == 'B') lp->Solver->setInteger(i); // no setBinary() 1235 else return -1; /* unknown type -- error! */ 1236 } 1237 return 0; 1238} 1239 1240extern "C" 1241int coin_addcols(COINprob* lp, int coladded, int matnz, const double* objx, 1242 int* matbeg, const int* matind, const double* matval, 1243 const double* bdl, const double* bdu) 1244{ 1245 1246 matbeg[coladded] = matnz; 1247 1248 CoinBuild build; 1249 1250 for (int i=0; i<coladded; i++) 1251 { 1252 build.addColumn(matbeg[i+1]-matbeg[i], 1253 &(matind[matbeg[i]]), 1254 &(matval[matbeg[i]]), 1255 bdl[i], bdu[i], objx[i]); 1256 } 1257 1258 static_cast<OsiSolverInterface* >(lp->Solver)->addCols(build); 1259 1260 return 0; 1261} 1262 1263extern "C" 1264int coin_addrows(COINprob* lp, const int rowadded, int nzadded, 1265 const double* rhsx, const char* senx, 1266 int* rmatbeg, int* rmatind, double* rmatval) 1267{ 1268 //CoinPackedVector * rows = new CoinPackedVector[rowadded]; 1269 1270 rmatbeg[rowadded] = nzadded; 1271 1272 // double* rrange = new double[rowadded]; 1273 double inf = lp->Solver->getInfinity(); 1274 1275 CoinBuild build; 1276 for (int i=0; i < rowadded; i++) 1277 { 1278 double ub, lb; 1279 if (senx[i] == 'L') {lb= -inf; ub= rhsx[i];} 1280 else if (senx[i] == 'E') {lb= ub= rhsx[i];} 1281 else if (senx[i] == 'G') {lb= rhsx[i]; ub= inf;} 1282 else return -1; 1283 1284 build.addRow(rmatbeg[i+1]-rmatbeg[i], 1285 &(rmatind[rmatbeg[i]]), 1286 &(rmatval[rmatbeg[i]]), 1287 lb, ub); 1288 } 1289 static_cast<OsiSolverInterface* >(lp->Solver)->addRows(build); 1290 /* 1291 for (int i=0; i < rowadded; i++) 1292 { 1293 rrange[i] = 0; 1294 1295 rows[i].setVector(rmatbeg[i+1]-rmatbeg[i], 1296 &(rmatind[rmatbeg[i]]), 1297 &(rmatval[rmatbeg[i]]), 1298 false); 1299 } 1300 1301 1302 CoinPackedVectorBase* rows1 = static_cast<CoinPackedVectorBase *>(rows); 1303 lp->Solver->addRows(rowadded, const_cast<CoinPackedVectorBase* const*>(&rows1), senx, rhsx, const_cast<const double *>(rrange)); 1304 1305 for (int l=0; l<rowadded; l++) { 1306 double* elms=rows[l].getElements(); 1307 for (int m=0; m<rows[l].getNumElements(); m++) std::cout<<elms[m]<<" "; 1308 std::cout<<std::endl; 1309 } 1310 const CoinPackedMatrix* mat = lp->Solver->getMatrixByRow(); 1311 const double* elms = mat->getElements(); 1312 for (int k=0; k<mat->getNumElements(); k++) std::cout<<elms[k]<<" "; 1313 std::cout<<std::endl; 1314 */ 1315 return 0; 1316} 1317 1318extern "C" 1319int coin_chgobjsen(COINprob* lp, int objsen) 1320{ 1321 lp->Solver->setObjSense((objsen == SENSE_MIN ? 1 : -1)); 1322 return 0; 1323} 1324 1325extern "C" 1326int coin_get_row(COINprob* lp, int* nnz, int* rmatind, double* rmatval, int idx) 1327{ 1328 try 1329 { 1330 const CoinShallowPackedVector row = 1331 lp->Solver->getMatrixByRow()->getVector(idx); 1332 1333 *nnz = row.getNumElements(); 1334 memcpy(rmatind, row.getIndices(), (*nnz)*sizeof(int)); 1335 memcpy(rmatval, row.getElements(), (*nnz)*sizeof(double)); 1336 } 1337 catch (CoinError e) 1338 { 1339 coin_error_handler(e); 1340 return -1; 1341 } 1342 1343 return 0; 1344} 1345 1346extern "C" 1347int coin_delrows(COINprob* lp, int ndr, int* idxs) 1348{ 1349 lp->Solver->deleteRows(ndr, idxs); 1350 1351 return 0; 1352} 1353 1354extern "C" 1355int coin_delcols(COINprob* lp, int ndr, int* idxs) 1356{ 1357 lp->Solver->deleteCols(ndr, idxs); 1358 1359 return 0; 1360} 1361 1362extern "C" 1363int coin_get_bar_primal_objval(COINprob* lp, double* objval) 1364{ 1365#ifdef COIN_USE_CLP 1366 if (lp->interiormodel != NULL) 1367 { 1368 *objval = lp->interiormodel->rawObjectiveValue()*lp->interiormodel->optimizationDirection(); 1369 return 0; 1370 } 1371#endif 1372 return -1; 1373} 1374 1375extern "C" 1376int coin_get_bar_dual_objval(COINprob* lp, double* objval) 1377{ 1378#ifdef COIN_USE_CLP 1379 if (lp->interiormodel != NULL) 1380 { 1381 // no information at the moment, just return the right infinity 1382 *objval = ( 1383 lp->interiormodel->isProvenOptimal() 1384 // optimal, just return obj. value 1385 ? lp->interiormodel->rawObjectiveValue()*lp->interiormodel->optimizationDirection() 1386 // opt.dir = -1 max, 1 min => inf for max, -inf for min 1387 : -1.0*lp->interiormodel->optimizationDirection()*lp->Solver->getInfinity() 1388 ); 1389 1390 return 0; 1391 } 1392#endif 1393 return -1; 1394} 1395 1396/* this should be called soon after a call to coin_solve_problem(), before 1397 any backtracking, because the result state etc. are not stored logically 1398*/ 1399extern "C" 1400state_t coin_get_result_state(lp_desc* lpd) 1401{ 1402 // OsiXxxSolverInterface* Solver = lpd->lp->Solver; 1403#ifdef COIN_USE_SYM 1404 // solving empty problem with OsiSym core dumps 1405 if (lpd->lp->Solver->getNumCols() == 0) { 1406 lpd->sol_state = S_SUCCESS; 1407 return state_success; 1408 } 1409#endif 1410#ifdef COIN_USE_CLP 1411 // get more MIP information using CLP specific methods... 1412 if (IsMIPProb(lpd->prob_type)) 1413 { 1414 CbcModel* model = lpd->lp->mipmodel; 1415 if (model->isProvenOptimal()) { 1416 lpd->sol_state = S_SUCCESS; 1417 return state_success; 1418 } 1419 if (model->isInitialSolveProvenOptimal()) // succeeded at root 1420 { 1421 if (model->isProvenInfeasible()) { 1422 lpd->sol_state = S_FAIL; 1423 return state_fail; 1424 } 1425 // MIP was aborted -- determine why 1426 if (model->isNodeLimitReached()) lpd->sol_state = S_ABORT_NODELIM; 1427 else if (model->isSecondsLimitReached()) lpd->sol_state = S_ABORT_TIMELIM; 1428 else if (model->isSolutionLimitReached()) lpd->sol_state = S_ABORT_SOLLIM; 1429 else if (model->isAbandoned()) lpd->sol_state = S_ABORT_NUM; 1430 else lpd->sol_state = S_ABORT_UNKNOWN; 1431 1432 if (model->bestSolution()) return state_mipsemisucc; 1433 return state_mipsemifail; 1434 } 1435 if (model->isInitialSolveAbandoned()) { 1436 lpd->sol_state = S_ABORT_NUM; 1437 return state_lpaborted; 1438 } 1439 // unbounded at root => MIP can be unbounded or infeasible 1440 if (model->isContinuousUnbounded()) { 1441 lpd->sol_state = S_UNBOUND_OR_FAIL; 1442 return state_unknown; 1443 } 1444 if (model->isInitialSolveProvenPrimalInfeasible()) { 1445 lpd->sol_state = S_FAIL; 1446 return state_fail; 1447 } 1448 //if (model->isInitialSolveProvenDualInfeasible()) return state_unbounded; 1449 if (lpd->lp->Solver->getModelPtr()->hitMaximumIterations()) lpd->sol_state = S_ABORT_LIM; 1450 else if (lpd->lp->Solver->getModelPtr()->isPrimalObjectiveLimitReached()) lpd->sol_state = S_ABORT_PRIMOBJLIM; 1451 else if (lpd->lp->Solver->getModelPtr()->isDualObjectiveLimitReached()) lpd->sol_state = S_ABORT_DUALOBJLIM; 1452 else lpd->sol_state = S_ABORT_UNKNOWN; 1453 return state_mipsemifail; 1454 } 1455 if (lpd->lp->interiormodel != NULL) 1456 {// CLP's interior needs special test to detect failure 1457 if (lpd->lp->Solver->isProvenOptimal()) 1458 { 1459 if (lpd->lp->interiormodel->sumPrimalInfeasibilities() < 1e-5) { 1460 lpd->sol_state = S_SUCCESS; 1461 return state_success; 1462 } else { 1463 lpd->sol_state = S_FAIL; 1464 return state_fail; 1465 } 1466 } 1467 } else if (lpd->lp->Solver->isProvenOptimal()) { 1468 lpd->sol_state = S_SUCCESS; 1469 return state_success; 1470 } 1471#else // !COIN_USE_CLP 1472 1473 if (lpd->lp->Solver->isProvenOptimal()) { 1474 lpd->sol_state = S_SUCCESS; 1475 return state_success; 1476 } 1477#endif 1478 // isAbandoned() due to numeric difficulties only 1479 if (lpd->lp->Solver->isAbandoned()) 1480 { 1481 lpd->sol_state = S_ABORT_NUM; 1482 if (IsMIPProb(lpd->prob_type)) return state_mipsemifail; 1483 else return state_lpaborted; 1484 } 1485 if (lpd->lp->Solver->isProvenPrimalInfeasible()) { 1486 lpd->sol_state = S_FAIL; 1487 return state_fail; 1488 } 1489 if (lpd->lp->Solver->isProvenDualInfeasible()) { 1490 lpd->sol_state = S_UNBOUND; 1491 return state_unbounded; 1492 } 1493 // problem is not optimal, infeasible or unbounded, solving is incomplete. 1494 // For MIP, we need to extract information from the MIP to determine 1495 // if there is any feasible solution or not. OSI's API does not provide 1496 // this, so we return semifail by default if solver specific methods 1497 // are not used earlier 1498 if (IsMIPProb(lpd->prob_type)) { 1499 lpd->sol_state = S_ABORT_UNKNOWN; 1500 return state_mipsemifail; 1501 } 1502 // is LP... 1503#ifdef COIN_USE_CLP 1504 // hit max. iterations *or timeout* 1505 if (lpd->lp->Solver->getModelPtr()->hitMaximumIterations()) { 1506 lpd->sol_state = S_ABORT_LIM; 1507 return state_lpaborted; 1508 } 1509#else 1510 if (lpd->lp->Solver->isIterationLimitReached()) { 1511 lpd->sol_state = S_ABORT_LIM; 1512 return state_lpaborted; 1513 } 1514#endif 1515 if (lpd->lp->Solver->isPrimalObjectiveLimitReached()) { 1516 lpd->sol_state = S_ABORT_LIM; 1517 return state_lpaborted; 1518 } 1519 if (lpd->lp->Solver->isDualObjectiveLimitReached()) { 1520 lpd->sol_state = S_ABORT_DUALOBJLIM; 1521 return state_lpaborted; 1522 } 1523 // no better information.... 1524 lpd->sol_state = S_ABORT_UNKNOWN; 1525 return state_unknown; 1526} 1527 1528extern "C" 1529int coin_get_mipcutoff(COINprob* lp, double* cutoff) 1530{ 1531#ifdef CBC_IS_MIPSOLVER 1532 CbcModel* mip = GetCbcSolver(lp); 1533 1534 *cutoff = (lp->Solver->getObjSense() == 1 ? mip->getCutoff() : -1.0*mip->getCutoff()); 1535#else 1536 *cutoff = (lp->Solver->getObjSense() == 1 ? lp->Solver->getInfinity() : -1.0*lp->Solver->getInfinity()); 1537#endif 1538 1539 return 0; 1540} 1541 1542extern "C" 1543double coin_infinity(COINprob* lp) 1544{ 1545 return lp->Solver->getInfinity(); 1546} 1547 1548extern "C" 1549int coin_getdblparam(COINprob* lp, int key, double* value) 1550{ 1551 lp->Solver->getDblParam(OsiDblParam(key), *value); 1552 return 0; 1553} 1554 1555extern "C" 1556int coin_getintparam(COINprob* lp, int key, int* value) 1557{ 1558 lp->Solver->getIntParam(OsiIntParam(key), *value); 1559 return 0; 1560} 1561 1562extern "C" 1563int coin_getstrparam(COINprob* lp, int key, char* value) 1564{ 1565 string svalue; 1566 lp->Solver->getStrParam(OsiStrParam(key), svalue); 1567 1568 int size = svalue.length()+1; 1569 if (size > STRBUFFERSIZE) size = STRBUFFERSIZE; 1570 string::traits_type::copy(value, svalue.c_str(), size); 1571 1572 return 0; 1573} 1574 1575extern "C" 1576int coin_setdblparam(COINprob* lp, int key, double value) 1577{ 1578 lp->Solver->setDblParam(OsiDblParam(key), value); 1579 return 0; 1580} 1581 1582extern "C" 1583int coin_setintparam(COINprob* lp, int key, int value) 1584{ 1585 lp->Solver->setIntParam(OsiIntParam(key), value); 1586 return 0; 1587} 1588 1589extern "C" 1590int coin_setstrparam(COINprob* lp, int key, const char* value) 1591{ 1592 const string svalue = value; 1593 if (lp->Solver->setStrParam(OsiStrParam(key), svalue)) 1594 return 0; 1595 else return -1; 1596} 1597 1598extern "C" 1599int coin_solve_problem(lp_desc* lpd, 1600 int meth, int auxmeth, int node_meth, int node_auxmeth) 1601{ 1602 bool doDual; 1603 1604#ifdef COIN_USE_SYM 1605 // solving empty problem with OsiSym core dumps 1606 if (lpd->lp->Solver->getNumCols() == 0) return 0; 1607 if (lpd->lp->Solver->getNumRows() == 0) return 0; 1608#endif 1609#ifdef COIN_USE_CLP 1610 // delete any old interior model of problem 1611 if (lpd->lp->interiormodel != NULL) 1612 { 1613 delete lpd->lp->interiormodel; 1614 lpd->lp->interiormodel = NULL; 1615 } 1616#endif 1617 switch (meth) 1618 {// OSI allows only primal/dual to be specified. Barrier done later 1619 default: 1620 case METHOD_DEFAULT: 1621 case METHOD_DUAL: 1622 doDual = true; 1623 break; 1624 case METHOD_PRIMAL: 1625 doDual = false; 1626 break; 1627 } 1628 1629 lpd->lp->Solver->setHintParam(OsiDoDualInInitial, doDual, OsiHintDo, NULL); 1630 lpd->lp->Solver->setHintParam(OsiDoDualInResolve, doDual, OsiHintDo, NULL); 1631 1632 lpd->lp->Solver->setHintParam(OsiDoPresolveInInitial, lpd->presolve, OsiHintDo, NULL); 1633 lpd->lp->Solver->setHintParam(OsiDoPresolveInResolve, lpd->presolve, OsiHintDo, NULL); 1634 1635 try { 1636 switch (lpd->prob_type) { 1637 case PROBLEM_MIP: 1638 case PROBLEM_FIXEDL: 1639#ifdef COIN_USE_CLP 1640 /* turn off timeout in CLP (otherwise may cause problems for MIP */ 1641 lpd->lp->Solver->getModelPtr()->setMaximumSeconds(-1); 1642 /* turn off OSI presolve hint, as this may casue CLP to presolve the 1643 problem without synchronising it with CBC, as suggested by 1644 John Forrest @ IBM (main author of CLP and CBC) 1645 */ 1646 lpd->lp->Solver->setHintParam(OsiDoPresolveInInitial, false, OsiHintDo, NULL); 1647 lpd->lp->Solver->setHintParam(OsiDoPresolveInResolve, false, OsiHintDo, NULL); 1648 1649#endif 1650 if (node_meth != METHOD_DEFAULT) { 1651 eclipse_out(WrnType, "Eplex Warning: node solving method for MIP problems not supported by COIN solvers, method ignored.\n"); 1652 } 1653 lpd->lp->Solver->setHintParam(OsiDoInBranchAndCut, true, OsiHintDo); 1654 coin_branchAndBound(lpd, meth, auxmeth); 1655 break; 1656 case PROBLEM_LP: 1657 case PROBLEM_RELAXEDL: 1658#ifdef COIN_USE_CLP 1659 case PROBLEM_QP: 1660 // case PROBLEM_RELAXEDQ: 1661 // lpd->lp->Solver->getModelPtr()->setPerturbation(50); 1662 if (lpd->lp->timeout > 0) 1663 lpd->lp->Solver->getModelPtr()->setMaximumSeconds(lpd->lp->timeout); 1664#endif 1665 //lpd->lp->Solver->setHintParam(OsiDoCrash, true, OsiHintDo); 1666 lpd->lp->Solver->setHintParam(OsiDoInBranchAndCut, false, OsiHintDo); 1667 coin_solveLinear(lpd, meth, auxmeth); 1668 break; 1669 1670 default: 1671 eclipse_out(ErrType, "Eplex Error: cannot solve problem type with this solver.\n"); 1672 return -1; 1673 break; 1674 } 1675 } /* try */ 1676 catch (CoinError e) 1677 { 1678 coin_error_handler(e); 1679 return -1; 1680 } 1681 catch (bad_alloc&) 1682 { 1683 eclipse_out(ErrType, "Memory allocation error in external solver\n"); 1684 return -1; 1685 } 1686 1687 return 0; 1688} 1689 1690extern "C" 1691int cpx_get_soln_state(lp_desc* lpd, struct lp_sol *sol) 1692{ 1693 int mac = lpd->lp->Solver->getNumCols(); 1694 int mar = lpd->lp->Solver->getNumRows(); 1695 1696#ifdef COIN_USE_SYM 1697 // solving empty problem with OsiSym core dumps 1698 if (mac == 0) return 0; 1699#endif 1700 if (lpd->mar != mar || lpd->mac != mac) 1701 { 1702 eclipse_out(ErrType, "Eplex Error: rows and columns does not match the problem!\n"); 1703 return -1; 1704 } 1705 1706 if (sol->sols != NULL) 1707 memcpy(sol->sols, lpd->lp->Solver->getColSolution(), mac*sizeof(double)); 1708 if (sol->pis != NULL) 1709 memcpy(sol->pis, lpd->lp->Solver->getRowPrice(), mar*sizeof(double)); 1710 if (sol->slacks != NULL) 1711 { 1712 const double* act = lpd->lp->Solver->getRowActivity(); 1713 const double* rhs = lpd->lp->Solver->getRightHandSide(); 1714 1715 for (int i=0; i<mar; i++) 1716 { 1717 sol->slacks[i] = rhs[i] - act[i]; 1718 } 1719 } 1720 if (sol->djs != NULL) 1721 memcpy(sol->djs, lpd->lp->Solver->getReducedCost(), mac*sizeof(double)); 1722#ifndef COIN_USE_CBC 1723 // basis not available for CBC 1724 if (sol->cbase != NULL || sol->rbase != NULL) 1725 { 1726 int* cbase0 = (sol->cbase == NULL ? new int[mac] : sol->cbase); 1727 int* rbase0 = (sol->rbase == NULL ? new int[mar] : sol->rbase); 1728 1729 lpd->lp->Solver->getBasisStatus(cbase0, rbase0); 1730 if (sol->cbase == NULL) delete [] cbase0; 1731 if (sol->rbase == NULL) delete [] rbase0; 1732 } 1733#endif 1734 return 0; 1735} 1736 1737extern "C" 1738int coin_get_objsen(COINprob* lp) 1739{ 1740 return (lp->Solver->getObjSense() == 1 ? SENSE_MIN : SENSE_MAX); 1741} 1742 1743extern "C" 1744int coin_get_numcols(COINprob* lp) 1745{ 1746 return (lp->Solver->getNumCols()); 1747} 1748 1749extern "C" 1750int coin_get_numrows(COINprob* lp) 1751{ 1752 return (lp->Solver->getNumRows()); 1753} 1754 1755extern "C" 1756int coin_get_probtype(COINprob* lp) 1757{ 1758#ifdef COIN_USE_CBC 1759 CbcModel* model = lp->Solver->getModelPtr(); 1760 1761 if (model->numberIntegers() > 0) return PROBLEM_MIP; 1762 else return PROBLEM_LP; 1763#else 1764 int mac = lp->Solver->getNumCols(); 1765 // there is no constant time method of getting the integer cols info yet 1766 // so this should be more efficient than getNumIntegers() 1767 for (int i=0; i<mac; i++) 1768 { 1769 if (lp->Solver->isInteger(i)) return PROBLEM_MIP; 1770 } 1771 return PROBLEM_LP; // no integer columns - LP problem 1772#endif 1773 1774} 1775 1776extern "C" 1777int coin_create_prob(COINprob** plp, COINprob* def) 1778{ 1779 // def is `default' problem with default settings. NULL if creating default 1780 DerivedHandler* coinMessageHandler = new DerivedHandler; 1781 COINprob* lp; 1782 *plp = lp = new COINprob; 1783 lp->Solver = new OsiXxxSolverInterface(); 1784 lp->notfirst = 0; 1785 lp->varnames = NULL; 1786 lp->vnsize = 0; 1787#ifdef COIN_USE_CLP 1788 lp->mipmodel = new CbcModel(static_cast<OsiSolverInterface &>(*lp->Solver)); 1789 lp->mipmodel->passInMessageHandler(coinMessageHandler); 1790 lp->mipIsShared = 0; 1791 // lp->control = NULL; 1792 lp->mipobjects = new CbcObject* [MIPOBJSZ]; 1793 lp->nsos = 0; 1794 lp->interiormodel = NULL; 1795 1796 if (def) 1797 {// copy the parameter values from default 1798 // this should copy the parameters from def to lp, but it does not 1799 // seem to work, so params are copied individually 1800 //lp->Solver->copyParameters(*def->Solver); 1801 for (int i=0; i<OsiLastIntParam; i++) { 1802 int val; 1803 if (def->Solver->getIntParam(OsiIntParam(i), val)) 1804 lp->Solver->setIntParam(OsiIntParam(i), val); 1805 } 1806 for (int i=0; i<OsiLastDblParam; i++) { 1807 double val; 1808 if (def->Solver->getDblParam(OsiDblParam(i), val)) 1809 lp->Solver->setDblParam(OsiDblParam(i), val); 1810 } 1811 for (int i=0; i<OsiLastStrParam; i++) { 1812 string val; 1813 if (def->Solver->getStrParam(OsiStrParam(i), val)) 1814 lp->Solver->setStrParam(OsiStrParam(i), val); 1815 } 1816 for (int i=0; i<NumSolverMipIntParams; i++) 1817 lp->mipmodel->setIntParam(cbc_iparam[i], def->mipmodel->getIntParam(cbc_iparam[i])); 1818 for (int i=0; i<NumSolverMipDblParams; i++) 1819 lp->mipmodel->setDblParam(cbc_dparam[i], def->mipmodel->getDblParam(cbc_dparam[i])); 1820 for (int i=0; i<NumSolverLpDblParams; i++) { 1821 double value; 1822 def->Solver->getModelPtr()->getDblParam(clp_dparam[i], value); 1823 lp->Solver->getModelPtr()->setDblParam(clp_dparam[i], value); 1824 } 1825 1826 for (int i=0; i<EpxClpParam_ns; i++) lp->sparam[i] = def->sparam[i]; 1827 for (int i=0; i<EpxClpParam_ni; i++) lp->iparam[i] = def->iparam[i]; 1828 } else { 1829 // initialise the defaults for eplex params 1830# ifdef UFL_BARRIER 1831 lp->sparam[EpxClpParam_bar_ordering] = "uflamd"; 1832# else 1833 lp->sparam[EpxClpParam_bar_ordering] = "native"; 1834# endif 1835 lp->iparam[EpxClpParam_print_freq] = lp->mipmodel->printFrequency(); 1836 lp->iparam[EpxClpParam_loglevel] = 1; 1837 lp->iparam[EpxClpParam_mip_lploglevel] = 0; 1838 lp->iparam[EpxClpParam_doKKT] = 0; 1839 } 1840 lp->timeout = -1; // no timeouts 1841 1842 lp->Solver->passInMessageHandler(coinMessageHandler); 1843 lp->Solver->messageHandler()->setLogLevel(lp->iparam[EpxClpParam_loglevel]); 1844#else 1845 if (def) 1846 {// this should copy the parameters from def to lp, but it does not 1847 // seem to work, so should add specific code to copy params 1848 lp->Solver->copyParameters(*def->Solver); 1849 } 1850 1851 lp->Solver->passInMessageHandler(coinMessageHandler); 1852 lp->Solver->messageHandler()->setLogLevel(1); 1853#endif 1854 1855 coin_set_solver_outputs(lp->Solver); 1856 1857 return 0; 1858} 1859 1860extern "C" 1861int coin_get_dual_infeas(COINprob* lp, int* infeas) 1862{ 1863#ifdef COIN_USE_CLP 1864 ClpSimplex* simplex = dynamic_cast<ClpSimplex*>( lp->Solver->getModelPtr()); 1865 if (simplex == NULL) return -1; 1866 *infeas = simplex->numberDualInfeasibilities(); 1867#endif 1868 return 0; 1869} 1870 1871extern "C" 1872int coin_get_primal_infeas(COINprob* lp, int* infeas) 1873{ 1874#ifdef COIN_USE_CLP 1875 ClpSimplex* simplex = dynamic_cast<ClpSimplex*>( lp->Solver->getModelPtr()); 1876 if (simplex == NULL) return -1; 1877 *infeas = simplex->numberPrimalInfeasibilities(); 1878#endif 1879 return 0; 1880} 1881 1882extern "C" 1883int coin_bar_is_dual_feas(COINprob* lp) 1884{ 1885#ifdef COIN_USE_CLP 1886 if (lp->interiormodel != NULL) 1887 { 1888 return lp->interiormodel->dualFeasible(); 1889 } 1890#endif 1891 return 0; 1892} 1893 1894extern "C" 1895int coin_bar_is_primal_feas(COINprob* lp) 1896{ 1897#ifdef COIN_USE_CLP 1898 if (lp->interiormodel != NULL) 1899 { 1900 return lp->interiormodel->primalFeasible(); 1901 } 1902#endif 1903 return 0; 1904} 1905 1906extern "C" 1907int coin_reset_prob(lp_desc* lpd) 1908{ 1909 // CBC modifies the problem state (including column bounds), and this 1910 // needs to be reset before we can solve the problem again 1911#ifdef COIN_USE_CBC 1912 if (lpd->prob_type == PROBLEM_MIP) 1913 { 1914 CbcModel* model = lpd->lp->Solver->getModelPtr(); 1915 model->resetToReferenceSolver(); 1916 } 1917#endif 1918 return 0; 1919} 1920 1921extern "C" 1922int coin_writeprob(COINprob* lp, const char* file, char* otype) 1923{ 1924 1925 try 1926 { 1927 if (strcmp(otype, "lp") == 0) 1928 { 1929 // lp->Solver->writeLp(file, "", 1e-5, 10, 10, lp->Solver->getObjSense()); 1930 lp->Solver->writeLpNative(file, NULL, lp->varnames, 1e-5, 10, 10, 1931 lp->Solver->getObjSense()); 1932 } 1933 else if (strcmp(otype, "mps") == 0) 1934 { 1935 // lp->Solver->writeMps(file, "", lp->Solver->getObjSense()); 1936 lp->Solver->writeMpsNative(file, NULL, 1937 const_cast<const char**>(lp->varnames), 1, 2, 1938 lp->Solver->getObjSense()); 1939 } 1940 else return -1; 1941 } 1942 catch (CoinError e) 1943 { 1944 coin_error_handler(e); 1945 return -1; 1946 } 1947 return 0; 1948} 1949 1950bool coin_read_prob_file(OsiXxxSolverInterface* Solver, 1951 const char* file, 1952 const char* ext, 1953 int format) 1954{ 1955 char* file1 = new char[strlen(file)+strlen(ext)+1]; 1956 int err = 0; 1957 try 1958 { 1959 strcpy(file1, file); 1960 strcat(file1, ext); 1961 // check for file existance as exit() is called if there is anything 1962 // wrong with the file! 1963 if (!fileExists(file1)) 1964 { 1965 delete [] file1; 1966 return false; 1967 } 1968 switch (format) 1969 { 1970 case 1: // LP 1971 err = Solver->readLp(file1); 1972 break; 1973 case 2: // MPS 1974 err = Solver->readMps(file1,""); 1975 break; 1976 } 1977 delete [] file1; 1978 return (err ? false : true); 1979 } 1980 catch (CoinError e) 1981 { 1982 delete [] file1; 1983 coin_error_handler(e); 1984 return false; 1985 } 1986} 1987 1988extern "C" 1989int coin_readprob(COINprob* lp, const char* file, char* otype) 1990{ 1991 1992 if (strcmp(otype, "lp") == 0) 1993 { 1994 if (coin_read_prob_file(lp->Solver, file, "", 1)) return 0; 1995 else if (coin_read_prob_file(lp->Solver, file, ".lp", 1)) return 0; 1996 else return -1; 1997 } 1998 else if (strcmp(otype, "mps") == 0) 1999 { 2000 if (coin_read_prob_file(lp->Solver, file, "", 2)) return 0; 2001 else if (coin_read_prob_file(lp->Solver, file, ".mps", 2)) return 0; 2002 else if (coin_read_prob_file(lp->Solver, file, ".mat", 2)) return 0; 2003 else return -1; 2004 } 2005 else return -1; 2006} 2007 2008 2009extern "C" 2010int coin_set_name(COINprob* lp, char ntype, int idx, const char * name) 2011{ 2012 2013 if (ntype == 'c') 2014 { 2015 int nc = lp->Solver->getNumCols(); 2016 if (lp->vnsize < nc) 2017 { 2018 int newvnsize = (int) ceil(nc*1.5)+100; 2019 lp->varnames = (char**) realloc(lp->varnames, newvnsize*sizeof(char**)); 2020 for (int i=lp->vnsize; i < newvnsize; i++) 2021 { 2022 // adapted from write.c's _int_to_string() 2023 int number = i, pos = 0; 2024 do 2025 { 2026 ++pos; 2027 number /= 10; 2028 } while (number); 2029 pos += 1; // leading 'x' and terminating '\0' 2030 lp->varnames[i] = new char[pos+1]; 2031 /* use x as default varname -- not valid var name in ECLiPSE, 2032 so cannot conflict with user supplied var names */ 2033 lp->varnames[i][0] = 'x'; 2034 lp->varnames[i][pos--] = '\0'; 2035 number = i; 2036 do 2037 { 2038 int ch = number % 10; 2039 lp->varnames[i][pos--] = ch + '0'; 2040 number /= 10; 2041 } while (number); 2042 2043 } 2044 2045 lp->vnsize = newvnsize; 2046 } 2047 if (idx < 0 || idx >= nc) 2048 return -1; 2049 delete lp->varnames[idx]; // get rid of old name 2050 lp->varnames[idx] = new char[strlen(name)+1]; // +1 for terminating \0 2051 strcpy(lp->varnames[idx], name); 2052 } 2053 else return -1; // row names not supported 2054 return 0; 2055} 2056 2057 2058extern "C" 2059int coin_add_sos(COINprob* lp, int nsos, int nsosnz, char* sostype, 2060 int* sosbeg, int* sosind, double* soswt) 2061{ 2062#ifdef COIN_USE_CLP 2063 int new_nsos = lp->nsos + nsos; 2064 2065 try { 2066 if (new_nsos > MIPOBJSZ) 2067 throw new bad_alloc; 2068 for (int i=0; i<nsos-1; i++) { 2069 lp->mipobjects[lp->nsos+i] = new CbcSOS(lp->mipmodel, sosbeg[i+1]-sosbeg[i], 2070 &sosind[sosbeg[i]], &soswt[i], i, 2071 (sostype[i] == '1' ? 1 : 2)); 2072 } 2073 if (nsos > 0) {// last set 2074 int i = nsos - 1; 2075 lp->mipobjects[lp->nsos+i] = new CbcSOS(lp->mipmodel, nsosnz-sosbeg[i], 2076 &sosind[sosbeg[i]], &soswt[i], i, 2077 (sostype[i] == '1' ? 1 : 2)); 2078 } 2079 } 2080 catch (CoinError e) { 2081 coin_error_handler(e); 2082 return -1; 2083 } 2084 catch (bad_alloc&) { 2085 eclipse_out(ErrType, "Memory allocation error in external solver\n"); 2086 return -1; 2087 } 2088 2089 lp->nsos = new_nsos; 2090 return 0; 2091#else 2092 2093 // unimplemented 2094 return -1; 2095#endif 2096} 2097 2098 2099extern "C" 2100int coin_del_sos(COINprob* lp, int from, int to) 2101{ 2102#ifdef COIN_USE_CLP 2103 if (from > to || to > lp->nsos) 2104 return -1; 2105 int ndel = to-from; 2106 for (int i=to; i<lp->nsos; i++) { 2107 lp->mipobjects[i-ndel] = lp->mipobjects[i]; 2108 } 2109 lp->nsos -= ndel; 2110 return 0; 2111#else 2112 2113 // unimplemented 2114 return -1; 2115#endif 2116} 2117 2118 2119extern "C" 2120int coin_free_prob(COINprob* lp) 2121{ 2122 if (lp == NULL) return 0; 2123 if (lp->varnames != NULL) 2124 { 2125 for (int i=0; i < lp->vnsize; i++) 2126 delete lp->varnames[i]; 2127 free(lp->varnames); 2128 } 2129 2130 delete lp->Solver->messageHandler(); 2131 /* solver specific stuff */ 2132#ifdef COIN_USE_CLP 2133 if (!lp->mipIsShared) coin_free_solver_handlers(lp->Solver); 2134 2135 if (lp->nsos > 0) 2136 { 2137 for (int i=0; i<lp->nsos; i++) delete lp->mipobjects[i]; 2138 delete [] lp->mipobjects; 2139 } 2140 2141 if (!lp->mipIsShared) 2142 { 2143 delete lp->Solver; 2144 // delete lp->mipmodel->messageHandler(); 2145 } 2146 delete lp->mipmodel; 2147 2148 if (lp->interiormodel != NULL) delete lp->interiormodel; 2149#endif 2150 2151 delete lp; 2152 lp = NULL; 2153 2154 return 0; 2155} 2156 2157extern "C" 2158void coin_get_solver_info(char* info) 2159{ 2160#ifdef COIN_USE_CLP 2161# ifdef UFL_BARRIER 2162 strcpy(info, "clp(uflamd)-cbc"); 2163# else 2164 strcpy(info, "clp-cbc"); 2165# endif 2166#endif 2167 2168#ifdef COIN_USE_CBC 2169 strcpy(info, "cbc-clp"); 2170#endif 2171 2172#ifdef COIN_USE_SYM 2173 strcpy(info, "symphony"); 2174#endif 2175 2176#ifdef COIN_USE_GLPK 2177 strcpy(info, "glpk"); 2178#endif 2179 2180} 2181 2182