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